[
  {
    "path": ".gitignore",
    "content": "glsm/\n*.[od]\n*.dll\n*.so\n*.dylib\n*.exe\n"
  },
  {
    "path": "Makefile.test",
    "content": "\nOBJDIR = ../obj-unix\n\nTEST_UNIT_CFLAGS = $(CFLAGS) -Iinclude $(LDFLAGS) -lcheck $(LIBCHECK_CFLAGS) -Werror -Wdeclaration-after-statement -fsanitize=address -fsanitize=undefined -ftest-coverage -fprofile-arcs -ggdb\n\nTEST_GENERIC_QUEUE = test/queues/test_generic_queue\nTEST_GENERIC_QUEUE_SRC = test/queues/test_generic_queue.c queues/generic_queue.c\n\nTEST_LINKED_LIST = test/lists/test_linked_list\nTEST_LINKED_LIST_SRC = test/lists/test_linked_list.c lists/linked_list.c\n\nTEST_STDSTRING = test/string/test_stdstring\nTEST_STDSTRING_SRC = test/string/test_stdstring.c string/stdstring.c encodings/encoding_utf.c \\\n\t\t     compat/compat_strl.c\n\nTEST_UTILS = test/utils/test_utils\nTEST_UTILS_SRC = test/utils/test_utils.c utils/md5.c encodings/encoding_crc32.c \\\n\t\tstreams/file_stream.c vfs/vfs_implementation.c file/file_path.c \\\n\t\tcompat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c\n\nTEST_HASH = test/hash/test_hash\nTEST_HASH_SRC = test/hash/test_hash.c hash/lrc_hash.c \\\n\t\tstreams/file_stream.c vfs/vfs_implementation.c file/file_path.c \\\n\t\tcompat/compat_strl.c time/rtime.c string/stdstring.c encodings/encoding_utf.c\n\nTEST_RPNG = test/formats/test_rpng\nTEST_RPNG_SRC = test/formats/test_rpng.c formats/png/rpng.c \\\n\t\tstreams/trans_stream.c streams/trans_stream_zlib.c \\\n\t\tstreams/trans_stream_pipe.c\nTEST_RPNG_LIBS = -lz\n\nall:\n\t# Build and execute tests in order, to avoid coverage file collision\n\t# string\n\t$(CC) $(TEST_UNIT_CFLAGS) $(TEST_STDSTRING_SRC) -o $(TEST_STDSTRING)\n\t$(TEST_STDSTRING)\n\tlcov -c -d . -o `dirname $(TEST_STDSTRING)`/coverage.info\n\t# utils\n\t$(CC) $(TEST_UNIT_CFLAGS) $(TEST_UTILS_SRC) -o $(TEST_UTILS)\n\t$(TEST_UTILS)\n\tlcov -c -d . -o `dirname $(TEST_UTILS)`/coverage.info\n\t# utils\n\t$(CC) $(TEST_UNIT_CFLAGS) $(TEST_HASH_SRC) -o $(TEST_HASH)\n\t$(TEST_HASH)\n\tlcov -c -d . -o `dirname $(TEST_HASH)`/coverage.info\n\t# list\n\t$(CC) $(TEST_UNIT_CFLAGS) $(TEST_LINKED_LIST_SRC) -o $(TEST_LINKED_LIST)\n\t$(TEST_LINKED_LIST)\n\tlcov -c -d . -o `dirname $(TEST_LINKED_LIST)`/coverage.info\n\t# queue\n\t$(CC) $(TEST_UNIT_CFLAGS) $(TEST_GENERIC_QUEUE_SRC) -o $(TEST_GENERIC_QUEUE)\n\t$(TEST_GENERIC_QUEUE)\n\tlcov -c -d . -o `dirname $(TEST_GENERIC_QUEUE)`/coverage.info\n\t# rpng\n\t$(CC) $(TEST_UNIT_CFLAGS) $(TEST_RPNG_SRC) $(TEST_RPNG_LIBS) -o $(TEST_RPNG)\n\t$(TEST_RPNG)\n\tlcov -c -d . -o `dirname $(TEST_RPNG)`/coverage.info\n\t\n\tlcov -o test/coverage.info \\\n\t     -a test/utils/coverage.info \\\n\t     -a test/string/coverage.info \\\n\t     -a test/lists/coverage.info \\\n\t     -a test/queues/coverage.info \\\n\t     -a test/formats/coverage.info\n\tgenhtml -o test/coverage/ test/coverage.info\n\nclean:\n\trm -f *.gcda *.gcno\n\n"
  },
  {
    "path": "audio/audio_mix.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (audio_mix.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <memalign.h>\n\n#include <retro_environment.h>\n\n#if defined(__SSE2__)\n#include <emmintrin.h>\n#elif defined(__ALTIVEC__)\n#include <altivec.h>\n#endif\n\n#include <retro_miscellaneous.h>\n#include <audio/audio_mix.h>\n#include <streams/file_stream.h>\n#include <audio/conversion/float_to_s16.h>\n#include <audio/conversion/s16_to_float.h>\n\nvoid audio_mix_volume_C(float *s, const float *in, float vol, size_t len)\n{\n   size_t i;\n   for (i = 0; i < len; i++)\n      s[i] += in[i] * vol;\n}\n\n#ifdef __SSE2__\nvoid audio_mix_volume_SSE2(float *s, const float *in, float vol, size_t len)\n{\n   size_t i, remaining_samples;\n   __m128 volume = _mm_set1_ps(vol);\n\n   for (i = 0; i + 16 <= len; i += 16, s += 16, in += 16)\n   {\n      unsigned j;\n      __m128 input[4];\n      __m128 additive[4];\n\n      input[0]    = _mm_loadu_ps(s +  0);\n      input[1]    = _mm_loadu_ps(s +  4);\n      input[2]    = _mm_loadu_ps(s +  8);\n      input[3]    = _mm_loadu_ps(s + 12);\n\n      additive[0] = _mm_mul_ps(volume, _mm_loadu_ps(in +  0));\n      additive[1] = _mm_mul_ps(volume, _mm_loadu_ps(in +  4));\n      additive[2] = _mm_mul_ps(volume, _mm_loadu_ps(in +  8));\n      additive[3] = _mm_mul_ps(volume, _mm_loadu_ps(in + 12));\n\n      for (j = 0; j < 4; j++)\n         _mm_storeu_ps(s + 4 * j, _mm_add_ps(input[j], additive[j]));\n   }\n\n   remaining_samples = len - i;\n\n   for (i = 0; i < remaining_samples; i++)\n      s[i] += in[i] * vol;\n}\n#endif\n\nvoid audio_mix_free_chunk(audio_chunk_t *chunk)\n{\n   if (!chunk)\n      return;\n\n#ifdef HAVE_RWAV\n   if (chunk->rwav && chunk->rwav->samples)\n   {\n      /* rwav_free only frees the samples */\n      rwav_free(chunk->rwav);\n      free(chunk->rwav);\n   }\n#endif\n\n   if (chunk->buf)\n      free(chunk->buf);\n\n   if (chunk->upsample_buf)\n      memalign_free(chunk->upsample_buf);\n\n   if (chunk->float_buf)\n      memalign_free(chunk->float_buf);\n\n   if (chunk->float_resample_buf)\n      memalign_free(chunk->float_resample_buf);\n\n   if (chunk->resample_buf)\n      memalign_free(chunk->resample_buf);\n\n   if (chunk->resampler && chunk->resampler_data)\n      chunk->resampler->free(chunk->resampler_data);\n\n   free(chunk);\n}\n\naudio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,\n      const char *resampler_ident, enum resampler_quality quality)\n{\n#ifdef HAVE_RWAV\n   int sample_size;\n   int64_t len                = 0;\n   void *buf                  = NULL;\n   audio_chunk_t *chunk       = (audio_chunk_t*)malloc(sizeof(*chunk));\n\n   if (!chunk)\n      return NULL;\n\n   chunk->buf                 = NULL;\n   chunk->upsample_buf        = NULL;\n   chunk->float_buf           = NULL;\n   chunk->float_resample_buf  = NULL;\n   chunk->resample_buf        = NULL;\n   chunk->len                 = 0;\n   chunk->resample_len        = 0;\n   chunk->sample_rate         = sample_rate;\n   chunk->resample            = false;\n   chunk->resampler           = NULL;\n   chunk->resampler_data      = NULL;\n   chunk->ratio               = 0.00f;\n   chunk->rwav                = (rwav_t*)malloc(sizeof(rwav_t));\n\n   if (!chunk->rwav)\n      goto error;\n\n   chunk->rwav->bitspersample = 0;\n   chunk->rwav->numchannels   = 0;\n   chunk->rwav->samplerate    = 0;\n   chunk->rwav->numsamples    = 0;\n   chunk->rwav->subchunk2size = 0;\n   chunk->rwav->samples       = NULL;\n\n   if (!filestream_read_file(path, &buf, &len))\n      goto error;\n\n   chunk->buf                 = buf;\n   chunk->len                 = len;\n\n   if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)\n      goto error;\n\n   /* numsamples does not know or care about\n    * multiple channels, but we need space for 2 */\n   chunk->upsample_buf        = (int16_t*)memalign_alloc(128,\n         chunk->rwav->numsamples * 2 * sizeof(int16_t));\n\n   sample_size                = chunk->rwav->bitspersample / 8;\n\n   if (sample_size == 1)\n   {\n      unsigned i;\n\n      if (chunk->rwav->numchannels == 1)\n      {\n         for (i = 0; i < chunk->rwav->numsamples; i++)\n         {\n            uint8_t *sample                  = (\n                  (uint8_t*)chunk->rwav->samples) + i;\n\n            chunk->upsample_buf[i * 2]       =\n               (int16_t)((sample[0] - 128) << 8);\n            chunk->upsample_buf[(i * 2) + 1] =\n               (int16_t)((sample[0] - 128) << 8);\n         }\n      }\n      else if (chunk->rwav->numchannels == 2)\n      {\n         for (i = 0; i < chunk->rwav->numsamples; i++)\n         {\n            uint8_t *sample                  = (\n                  (uint8_t*)chunk->rwav->samples) +\n               (i * 2);\n\n            chunk->upsample_buf[i * 2]       =\n               (int16_t)((sample[0] - 128) << 8);\n            chunk->upsample_buf[(i * 2) + 1] =\n               (int16_t)((sample[1] - 128) << 8);\n         }\n      }\n   }\n   else if (sample_size == 2)\n   {\n      if (chunk->rwav->numchannels == 1)\n      {\n         unsigned i;\n\n         for (i = 0; i < chunk->rwav->numsamples; i++)\n         {\n            int16_t sample                   = ((int16_t*)\n                  chunk->rwav->samples)[i];\n\n            chunk->upsample_buf[i * 2]       = sample;\n            chunk->upsample_buf[(i * 2) + 1] = sample;\n         }\n      }\n      else if (chunk->rwav->numchannels == 2)\n         memcpy(chunk->upsample_buf, chunk->rwav->samples,\n               chunk->rwav->subchunk2size);\n   }\n   else if (sample_size != 2)\n   {\n      /* we don't support any other sample size besides 8 and 16-bit yet */\n      goto error;\n   }\n\n   if (sample_rate != (int)chunk->rwav->samplerate)\n   {\n      chunk->resample = true;\n      chunk->ratio    = (double)sample_rate / chunk->rwav->samplerate;\n\n      retro_resampler_realloc(&chunk->resampler_data,\n            &chunk->resampler,\n            resampler_ident,\n            quality,\n            chunk->ratio);\n\n      if (chunk->resampler && chunk->resampler_data)\n      {\n         struct resampler_data info;\n\n         chunk->float_buf          = (float*)memalign_alloc(128,\n               chunk->rwav->numsamples * 2 *\n               chunk->ratio * sizeof(float));\n\n         /* why is *3 needed instead of just *2? Does the\n          * sinc driver require more space than we know about? */\n         chunk->float_resample_buf = (float*)memalign_alloc(128,\n               chunk->rwav->numsamples * 3 *\n               chunk->ratio * sizeof(float));\n\n         convert_s16_to_float(chunk->float_buf,\n               chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);\n\n         info.data_in       = (const float*)chunk->float_buf;\n         info.data_out      = chunk->float_resample_buf;\n         /* a 'frame' consists of two channels, so we set this\n          * to the number of samples irrespective of channel count */\n         info.input_frames  = chunk->rwav->numsamples;\n         info.output_frames = 0;\n         info.ratio         = chunk->ratio;\n\n         chunk->resampler->process(chunk->resampler_data, &info);\n\n         /* number of output_frames does not increase with\n          * multiple channels, but assume we need space for 2 */\n         chunk->resample_buf = (int16_t*)memalign_alloc(128,\n               info.output_frames * 2 * sizeof(int16_t));\n         chunk->resample_len = info.output_frames;\n         convert_float_to_s16(chunk->resample_buf,\n               chunk->float_resample_buf, info.output_frames * 2);\n      }\n   }\n\n   return chunk;\n\nerror:\n   audio_mix_free_chunk(chunk);\n#endif\n   return NULL;\n}\n\nsize_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)\n{\n   if (!chunk)\n      return 0;\n\n#ifdef HAVE_RWAV\n   if (chunk->rwav)\n   {\n      if (chunk->resample)\n         return chunk->resample_len;\n      return chunk->rwav->numsamples;\n   }\n#endif\n\n   /* no other filetypes supported yet */\n   return 0;\n}\n\n/**\n * audio_mix_get_chunk_sample:\n * @chunk              : audio chunk instance\n * @channel            : channel of the sample (0=left, 1=right)\n * @index              : index of the sample\n *\n * Get a sample from an audio chunk.\n *\n * Returns: A signed 16-bit audio sample.\n **/\nint16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk,\n      unsigned channel, size_t index)\n{\n   if (!chunk)\n      return 0;\n\n#ifdef HAVE_RWAV\n   if (chunk->rwav)\n   {\n      int sample_size    = chunk->rwav->bitspersample / 8;\n      int16_t sample_out = 0;\n\n      /* 0 is the first/left channel */\n      uint8_t *sample    = NULL;\n\n      if (chunk->resample)\n         sample = (uint8_t*)chunk->resample_buf +\n            (sample_size * index * chunk->rwav->numchannels)\n            + (channel * sample_size);\n      else\n         sample = (uint8_t*)chunk->upsample_buf +\n            (sample_size * index * chunk->rwav->numchannels)\n            + (channel * sample_size);\n\n      sample_out = (int16_t)*sample;\n\n      return sample_out;\n   }\n#endif\n\n   /* no other filetypes supported yet */\n   return 0;\n}\n\nint16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)\n{\n   if (!chunk)\n      return 0;\n\n#ifdef HAVE_RWAV\n   if (chunk->rwav)\n   {\n      int16_t *sample;\n\n      if (chunk->resample)\n         sample = chunk->resample_buf;\n      else\n         sample = chunk->upsample_buf;\n\n      return sample;\n   }\n#endif\n\n   return NULL;\n}\n\nint audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)\n{\n   if (!chunk)\n      return 0;\n\n#ifdef HAVE_RWAV\n   if (chunk->rwav)\n      return chunk->rwav->numchannels;\n#endif\n\n   /* don't support other formats yet */\n   return 0;\n}\n"
  },
  {
    "path": "audio/audio_mixer.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (audio_mixer.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifdef HAVE_CONFIG_H\n#include \"../../config.h\"\n#endif\n\n#include <audio/audio_mixer.h>\n#include <audio/audio_resampler.h>\n\n#ifdef HAVE_RWAV\n#include <formats/rwav.h>\n#endif\n#include <memalign.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#ifdef HAVE_STB_VORBIS\n#define STB_VORBIS_NO_PUSHDATA_API\n#define STB_VORBIS_NO_STDIO\n#define STB_VORBIS_NO_CRT\n\n#include <stb/stb_vorbis.h>\n#endif\n\n#ifdef HAVE_DR_FLAC\n#include <retro_inline.h>\n#define DR_FLAC_IMPLEMENTATION\n#define DRFLAC_API static INLINE\n#include <dr/dr_flac.h>\n#endif\n\n#ifdef HAVE_DR_MP3\n#define DR_MP3_IMPLEMENTATION\n#include <retro_assert.h>\n#define DRMP3_ASSERT(expression) retro_assert(expression)\n#include <dr/dr_mp3.h>\n#endif\n\n#ifdef HAVE_IBXM\n#include <ibxm/ibxm.h>\n#endif\n\n#ifdef HAVE_THREADS\n#include <rthreads/rthreads.h>\n#define AUDIO_MIXER_LOCK(voice)   slock_lock(voice->lock)\n#define AUDIO_MIXER_UNLOCK(voice) slock_unlock(voice->lock)\n#else\n#define AUDIO_MIXER_LOCK(voice)   do {} while(0)\n#define AUDIO_MIXER_UNLOCK(voice) do {} while(0)\n#endif\n\n#define AUDIO_MIXER_MAX_VOICES      8\n#define AUDIO_MIXER_TEMP_BUFFER 8192\n\nstruct audio_mixer_sound\n{\n   enum audio_mixer_type type;\n   void* user_data;\n\n   union\n   {\n      struct\n      {\n         /* wav */\n         const float* pcm;\n         unsigned frames;\n      } wav;\n\n#ifdef HAVE_STB_VORBIS\n      struct\n      {\n         /* ogg */\n         const void* data;\n         unsigned size;\n      } ogg;\n#endif\n\n#ifdef HAVE_DR_FLAC\n      struct\n      {\n          /* flac */\n         const void* data;\n         unsigned size;\n      } flac;\n#endif\n\n#ifdef HAVE_DR_MP3\n      struct\n      {\n          /* mp */\n         const void* data;\n         unsigned size;\n      } mp3;\n#endif\n\n#ifdef HAVE_IBXM\n      struct\n      {\n         /* mod/s3m/xm */\n         const void* data;\n         unsigned size;\n      } mod;\n#endif\n   } types;\n};\n\nstruct audio_mixer_voice\n{\n   struct\n   {\n      struct\n      {\n         unsigned position;\n      } wav;\n\n#ifdef HAVE_STB_VORBIS\n      struct\n      {\n         stb_vorbis *stream;\n         void       *resampler_data;\n         const retro_resampler_t *resampler;\n         float      *buffer;\n         unsigned    position;\n         unsigned    samples;\n         unsigned    buf_samples;\n         float       ratio;\n      } ogg;\n#endif\n\n#ifdef HAVE_DR_FLAC\n      struct\n      {\n         float*      buffer;\n         drflac      *stream;\n         void        *resampler_data;\n         const retro_resampler_t *resampler;\n         unsigned    position;\n         unsigned    samples;\n         unsigned    buf_samples;\n         float       ratio;\n      } flac;\n#endif\n\n#ifdef HAVE_DR_MP3\n      struct\n      {\n         drmp3       stream;\n         void        *resampler_data;\n         const retro_resampler_t *resampler;\n         float*      buffer;\n         unsigned    position;\n         unsigned    samples;\n         unsigned    buf_samples;\n         float       ratio;\n      } mp3;\n#endif\n\n#ifdef HAVE_IBXM\n      struct\n      {\n         int*              buffer;\n         struct replay*    stream;\n         struct module*    module;\n         unsigned          position;\n         unsigned          samples;\n         unsigned          buf_samples;\n      } mod;\n#endif\n   } types;\n   audio_mixer_sound_t *sound;\n   audio_mixer_stop_cb_t stop_cb;\n   unsigned type;\n   float    volume;\n   bool     repeat;\n#ifdef HAVE_THREADS\n   slock_t *lock;\n#endif\n};\n\n/* TODO/FIXME - static globals */\nstatic struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0};\nstatic unsigned s_rate = 0;\n\nstatic void audio_mixer_release(audio_mixer_voice_t* voice);\n\n#ifdef HAVE_RWAV\nstatic bool wav_to_float(const rwav_t* wav, float** pcm, size_t len)\n{\n   size_t i;\n   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */\n   float *f           = (float*)memalign_alloc(16,\n         ((len + 15) & ~15) * sizeof(float));\n\n   if (!f)\n      return false;\n\n   *pcm = f;\n\n   if (wav->bitspersample == 8)\n   {\n      float sample      = 0.0f;\n      const uint8_t *u8 = (const uint8_t*)wav->samples;\n\n      if (wav->numchannels == 1)\n      {\n         for (i = wav->numsamples; i != 0; i--)\n         {\n            sample = (float)*u8++ / 255.0f;\n            sample = sample * 2.0f - 1.0f;\n            *f++   = sample;\n            *f++   = sample;\n         }\n      }\n      else if (wav->numchannels == 2)\n      {\n         for (i = wav->numsamples; i != 0; i--)\n         {\n            sample = (float)*u8++ / 255.0f;\n            sample = sample * 2.0f - 1.0f;\n            *f++   = sample;\n            sample = (float)*u8++ / 255.0f;\n            sample = sample * 2.0f - 1.0f;\n            *f++   = sample;\n         }\n      }\n   }\n   else\n   {\n      /* TODO/FIXME note to leiradel - can we use audio/conversion/s16_to_float\n       * functions here? */\n\n      float sample       = 0.0f;\n      const int16_t *s16 = (const int16_t*)wav->samples;\n\n      if (wav->numchannels == 1)\n      {\n         for (i = wav->numsamples; i != 0; i--)\n         {\n            sample = (float)((int)*s16++ + 32768) / 65535.0f;\n            sample = sample * 2.0f - 1.0f;\n            *f++   = sample;\n            *f++   = sample;\n         }\n      }\n      else if (wav->numchannels == 2)\n      {\n         for (i = wav->numsamples; i != 0; i--)\n         {\n            sample = (float)((int)*s16++ + 32768) / 65535.0f;\n            sample = sample * 2.0f - 1.0f;\n            *f++   = sample;\n            sample = (float)((int)*s16++ + 32768) / 65535.0f;\n            sample = sample * 2.0f - 1.0f;\n            *f++   = sample;\n         }\n      }\n   }\n\n   return true;\n}\n\nstatic bool one_shot_resample(const float* in, size_t samples_in,\n      unsigned rate, const char *resampler_ident, enum resampler_quality quality,\n      float** out, size_t* samples_out)\n{\n   struct resampler_data info;\n   void* data                         = NULL;\n   const retro_resampler_t* resampler = NULL;\n   float ratio                        = (double)s_rate / (double)rate;\n\n   if (!retro_resampler_realloc(&data, &resampler,\n         resampler_ident, quality, ratio))\n      return false;\n\n   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We\n    * add 16 more samples in the formula below just as safeguard, because\n    * resampler->process sometimes reports more output samples than the\n    * formula below calculates. Ideally, audio resamplers should have a\n    * function to return the number of samples they will output given a\n    * count of input samples. */\n   *samples_out                       = (size_t)(samples_in * ratio);\n   *out                               = (float*)memalign_alloc(16,\n         (((*samples_out + 16) + 15) & ~15) * sizeof(float));\n\n   if (*out == NULL)\n      return false;\n\n   info.data_in                       = in;\n   info.data_out                      = *out;\n   info.input_frames                  = samples_in / 2;\n   info.output_frames                 = 0;\n   info.ratio                         = ratio;\n\n   resampler->process(data, &info);\n   resampler->free(data);\n   return true;\n}\n#endif\n\nvoid audio_mixer_init(unsigned rate)\n{\n   unsigned i;\n\n   s_rate = rate;\n\n   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)\n   {\n      audio_mixer_voice_t *voice = &s_voices[i];\n\n      voice->type = AUDIO_MIXER_TYPE_NONE;\n#ifdef HAVE_THREADS\n      if (!voice->lock)\n         voice->lock = slock_new();\n#endif\n   }\n}\n\nvoid audio_mixer_done(void)\n{\n   unsigned i;\n\n   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++)\n   {\n      audio_mixer_voice_t *voice = &s_voices[i];\n\n      AUDIO_MIXER_LOCK(voice);\n      audio_mixer_release(voice);\n      AUDIO_MIXER_UNLOCK(voice);\n#ifdef HAVE_THREADS\n      slock_free(voice->lock);\n      voice->lock = NULL;\n#endif\n   }\n}\n\naudio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,\n      const char *resampler_ident, enum resampler_quality quality)\n{\n#ifdef HAVE_RWAV\n   /* WAV data */\n   rwav_t wav;\n   /* WAV samples converted to float */\n   float* pcm                 = NULL;\n   size_t samples             = 0;\n   /* Result */\n   audio_mixer_sound_t* sound = NULL;\n\n   wav.bitspersample          = 0;\n   wav.numchannels            = 0;\n   wav.samplerate             = 0;\n   wav.numsamples             = 0;\n   wav.subchunk2size          = 0;\n   wav.samples                = NULL;\n\n   if ((rwav_load(&wav, buffer, size)) != RWAV_ITERATE_DONE)\n      return NULL;\n\n   samples       = wav.numsamples * 2;\n\n   if (!wav_to_float(&wav, &pcm, samples))\n      return NULL;\n\n   if (wav.samplerate != s_rate)\n   {\n      float* resampled           = NULL;\n\n      if (!one_shot_resample(pcm, samples, wav.samplerate,\n            resampler_ident, quality,\n            &resampled, &samples))\n         return NULL;\n\n      memalign_free((void*)pcm);\n      pcm = resampled;\n   }\n\n   sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));\n\n   if (!sound)\n   {\n      memalign_free((void*)pcm);\n      return NULL;\n   }\n\n   sound->type             = AUDIO_MIXER_TYPE_WAV;\n   sound->types.wav.frames = (unsigned)(samples / 2);\n   sound->types.wav.pcm    = pcm;\n\n   rwav_free(&wav);\n\n   return sound;\n#else\n   return NULL;\n#endif\n}\n\naudio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size)\n{\n#ifdef HAVE_STB_VORBIS\n   audio_mixer_sound_t* sound;\n\n   if (!buffer || size <= 0)\n      return NULL;\n\n   sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));\n\n   if (!sound)\n      return NULL;\n\n   sound->type           = AUDIO_MIXER_TYPE_OGG;\n   sound->types.ogg.size = size;\n   sound->types.ogg.data = buffer;\n\n   return sound;\n#else\n   return NULL;\n#endif\n}\n\naudio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size)\n{\n#ifdef HAVE_DR_FLAC\n   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));\n\n   if (!sound)\n      return NULL;\n\n   sound->type           = AUDIO_MIXER_TYPE_FLAC;\n   sound->types.flac.size = size;\n   sound->types.flac.data = buffer;\n\n   return sound;\n#else\n   return NULL;\n#endif\n}\n\naudio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size)\n{\n#ifdef HAVE_DR_MP3\n   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));\n\n   if (!sound)\n      return NULL;\n\n   sound->type           = AUDIO_MIXER_TYPE_MP3;\n   sound->types.mp3.size = size;\n   sound->types.mp3.data = buffer;\n\n   return sound;\n#else\n   return NULL;\n#endif\n}\n\naudio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size)\n{\n#ifdef HAVE_IBXM\n   audio_mixer_sound_t* sound = (audio_mixer_sound_t*)calloc(1, sizeof(*sound));\n\n   if (!sound)\n      return NULL;\n\n   sound->type           = AUDIO_MIXER_TYPE_MOD;\n   sound->types.mod.size = size;\n   sound->types.mod.data = buffer;\n\n   return sound;\n#else\n   return NULL;\n#endif\n}\n\nvoid audio_mixer_destroy(audio_mixer_sound_t* sound)\n{\n   void *handle = NULL;\n   if (!sound)\n      return;\n\n   switch (sound->type)\n   {\n      case AUDIO_MIXER_TYPE_WAV:\n         handle = (void*)sound->types.wav.pcm;\n         if (handle)\n            memalign_free(handle);\n         break;\n      case AUDIO_MIXER_TYPE_OGG:\n#ifdef HAVE_STB_VORBIS\n         handle = (void*)sound->types.ogg.data;\n         if (handle)\n            free(handle);\n#endif\n         break;\n      case AUDIO_MIXER_TYPE_MOD:\n#ifdef HAVE_IBXM\n         handle = (void*)sound->types.mod.data;\n         if (handle)\n            free(handle);\n#endif\n         break;\n      case AUDIO_MIXER_TYPE_FLAC:\n#ifdef HAVE_DR_FLAC\n         handle = (void*)sound->types.flac.data;\n         if (handle)\n            free(handle);\n#endif\n         break;\n      case AUDIO_MIXER_TYPE_MP3:\n#ifdef HAVE_DR_MP3\n         handle = (void*)sound->types.mp3.data;\n         if (handle)\n            free(handle);\n#endif\n         break;\n      case AUDIO_MIXER_TYPE_NONE:\n         break;\n   }\n\n   free(sound);\n}\n\nstatic bool audio_mixer_play_wav(audio_mixer_sound_t* sound,\n      audio_mixer_voice_t* voice, bool repeat, float volume,\n      audio_mixer_stop_cb_t stop_cb)\n{\n   voice->types.wav.position = 0;\n   return true;\n}\n\n#ifdef HAVE_STB_VORBIS\nstatic bool audio_mixer_play_ogg(\n      audio_mixer_sound_t* sound,\n      audio_mixer_voice_t* voice,\n      bool repeat, float volume,\n      const char *resampler_ident,\n      enum resampler_quality quality,\n      audio_mixer_stop_cb_t stop_cb)\n{\n   stb_vorbis_info info;\n   int res                         = 0;\n   float ratio                     = 1.0f;\n   unsigned samples                = 0;\n   void *ogg_buffer                = NULL;\n   void *resampler_data            = NULL;\n   const retro_resampler_t* resamp = NULL;\n   stb_vorbis *stb_vorbis          = stb_vorbis_open_memory(\n         (const unsigned char*)sound->types.ogg.data,\n         sound->types.ogg.size, &res, NULL);\n\n   if (!stb_vorbis)\n      return false;\n\n   info                    = stb_vorbis_get_info(stb_vorbis);\n\n   if (info.sample_rate != s_rate)\n   {\n      ratio = (double)s_rate / (double)info.sample_rate;\n\n      if (!retro_resampler_realloc(&resampler_data,\n               &resamp, resampler_ident, quality,\n               ratio))\n         goto error;\n   }\n\n   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We\n    * add 16 more samples in the formula below just as safeguard, because\n    * resampler->process sometimes reports more output samples than the\n    * formula below calculates. Ideally, audio resamplers should have a\n    * function to return the number of samples they will output given a\n    * count of input samples. */\n   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);\n   ogg_buffer                      = (float*)memalign_alloc(16,\n         (((samples + 16) + 15) & ~15) * sizeof(float));\n\n   if (!ogg_buffer)\n   {\n      if (resamp && resampler_data)\n         resamp->free(resampler_data);\n      goto error;\n   }\n\n   voice->types.ogg.resampler      = resamp;\n   voice->types.ogg.resampler_data = resampler_data;\n   voice->types.ogg.buffer         = (float*)ogg_buffer;\n   voice->types.ogg.buf_samples    = samples;\n   voice->types.ogg.ratio          = ratio;\n   voice->types.ogg.stream         = stb_vorbis;\n   voice->types.ogg.position       = 0;\n   voice->types.ogg.samples        = 0;\n\n   return true;\n\nerror:\n   stb_vorbis_close(stb_vorbis);\n   return false;\n}\n\nstatic void audio_mixer_release_ogg(audio_mixer_voice_t* voice)\n{\n   if (voice->types.ogg.stream)\n      stb_vorbis_close(voice->types.ogg.stream);\n   if (voice->types.ogg.resampler && voice->types.ogg.resampler_data)\n      voice->types.ogg.resampler->free(voice->types.ogg.resampler_data);\n   if (voice->types.ogg.buffer)\n      memalign_free(voice->types.ogg.buffer);\n}\n\n#endif\n\n#ifdef HAVE_IBXM\nstatic bool audio_mixer_play_mod(\n      audio_mixer_sound_t* sound,\n      audio_mixer_voice_t* voice,\n      bool repeat, float volume,\n      audio_mixer_stop_cb_t stop_cb)\n{\n   struct data data;\n   char message[64];\n   int buf_samples               = 0;\n   int samples                   = 0;\n   void *mod_buffer              = NULL;\n   struct module* module         = NULL;\n   struct replay* replay         = NULL;\n\n   data.buffer                   = (char*)sound->types.mod.data;\n   data.length                   = sound->types.mod.size;\n   module                        = module_load(&data, message);\n\n   if (!module)\n   {\n      printf(\"audio_mixer_play_mod module_load() failed with error: %s\\n\", message);\n      goto error;\n   }\n\n   if (voice->types.mod.module)\n      dispose_module(voice->types.mod.module);\n\n   voice->types.mod.module = module;\n\n   replay = new_replay(module, s_rate, 1);\n\n   if (!replay)\n   {\n      printf(\"audio_mixer_play_mod new_replay() failed\\n\");\n      goto error;\n   }\n\n   buf_samples = calculate_mix_buf_len(s_rate);\n   mod_buffer  = memalign_alloc(16, ((buf_samples + 15) & ~15) * sizeof(int));\n\n   if (!mod_buffer)\n   {\n      printf(\"audio_mixer_play_mod cannot allocate mod_buffer !\\n\");\n      goto error;\n   }\n\n   samples = replay_calculate_duration(replay);\n\n   if (!samples)\n   {\n      printf(\"audio_mixer_play_mod cannot retrieve duration !\\n\");\n      goto error;\n   }\n\n   voice->types.mod.buffer         = (int*)mod_buffer;\n   voice->types.mod.buf_samples    = buf_samples;\n   voice->types.mod.stream         = replay;\n   voice->types.mod.position       = 0;\n   voice->types.mod.samples        = 0; /* samples; */\n\n   return true;\n\nerror:\n   if (mod_buffer)\n      memalign_free(mod_buffer);\n   if (module)\n      dispose_module(module);\n   return false;\n\n}\n\nstatic void audio_mixer_release_mod(audio_mixer_voice_t* voice)\n{\n   if (voice->types.mod.stream)\n      dispose_replay(voice->types.mod.stream);\n   if (voice->types.mod.buffer)\n      memalign_free(voice->types.mod.buffer);\n}\n#endif\n\n#ifdef HAVE_DR_FLAC\nstatic bool audio_mixer_play_flac(\n      audio_mixer_sound_t* sound,\n      audio_mixer_voice_t* voice,\n      bool repeat, float volume,\n      const char *resampler_ident,\n      enum resampler_quality quality,\n      audio_mixer_stop_cb_t stop_cb)\n{\n   float ratio                     = 1.0f;\n   unsigned samples                = 0;\n   void *flac_buffer                = NULL;\n   void *resampler_data            = NULL;\n   const retro_resampler_t* resamp = NULL;\n   drflac *dr_flac          = drflac_open_memory((const unsigned char*)sound->types.flac.data, sound->types.flac.size, NULL);\n\n   if (!dr_flac)\n      return false;\n\n   /* The downstream mixer (audio_mixer_mix_flac) requests\n    * AUDIO_MIXER_TEMP_BUFFER / 2 frames into a stack buffer\n    * sized AUDIO_MIXER_TEMP_BUFFER floats.  drflac writes\n    * frame_count * channel_count floats, so this only fits\n    * exactly for stereo.  Mono fits but the downstream\n    * accounting is wrong (per existing comment); >2 channels\n    * overflows the stack buffer (e.g. 8-channel FLAC writes\n    * 4 * AUDIO_MIXER_TEMP_BUFFER floats = 4x the buffer).\n    * Reject anything that isn't stereo here rather than risk a\n    * stack overflow during mix.  Mono should be fixed\n    * separately by adjusting the mixer's per-channel\n    * accounting. */\n   if (dr_flac->channels != 2)\n   {\n      drflac_close(dr_flac);\n      return false;\n   }\n\n   if (dr_flac->sampleRate != s_rate)\n   {\n      ratio = (double)s_rate / (double)(dr_flac->sampleRate);\n\n      if (!retro_resampler_realloc(&resampler_data,\n               &resamp, resampler_ident, quality,\n               ratio))\n         goto error;\n   }\n\n   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We\n    * add 16 more samples in the formula below just as safeguard, because\n    * resampler->process sometimes reports more output samples than the\n    * formula below calculates. Ideally, audio resamplers should have a\n    * function to return the number of samples they will output given a\n    * count of input samples. */\n   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);\n   flac_buffer                     = (float*)memalign_alloc(16,\n         (((samples + 16) + 15) & ~15) * sizeof(float));\n\n   if (!flac_buffer)\n   {\n      if (resamp && resamp->free)\n         resamp->free(resampler_data);\n      goto error;\n   }\n\n   voice->types.flac.resampler      = resamp;\n   voice->types.flac.resampler_data = resampler_data;\n   voice->types.flac.buffer         = (float*)flac_buffer;\n   voice->types.flac.buf_samples    = samples;\n   voice->types.flac.ratio          = ratio;\n   voice->types.flac.stream         = dr_flac;\n   voice->types.flac.position       = 0;\n   voice->types.flac.samples        = 0;\n\n   return true;\n\nerror:\n   drflac_close(dr_flac);\n   return false;\n}\n\nstatic void audio_mixer_release_flac(audio_mixer_voice_t* voice)\n{\n   if (voice->types.flac.stream)\n      drflac_close(voice->types.flac.stream);\n   if (voice->types.flac.resampler && voice->types.flac.resampler_data)\n      voice->types.flac.resampler->free(voice->types.flac.resampler_data);\n   if (voice->types.flac.buffer)\n      memalign_free(voice->types.flac.buffer);\n}\n#endif\n\n#ifdef HAVE_DR_MP3\nstatic bool audio_mixer_play_mp3(\n      audio_mixer_sound_t* sound,\n      audio_mixer_voice_t* voice,\n      bool repeat, float volume,\n      const char *resampler_ident,\n      enum resampler_quality quality,\n      audio_mixer_stop_cb_t stop_cb)\n{\n   float ratio                     = 1.0f;\n   unsigned samples                = 0;\n   void *mp3_buffer                = NULL;\n   void *resampler_data            = NULL;\n   const retro_resampler_t* resamp = NULL;\n   bool res;\n\n   res = drmp3_init_memory(&voice->types.mp3.stream, (const unsigned char*)sound->types.mp3.data, sound->types.mp3.size, NULL);\n\n   if (!res)\n      return false;\n\n   if (voice->types.mp3.stream.sampleRate != s_rate)\n   {\n      ratio = (double)s_rate / (double)(voice->types.mp3.stream.sampleRate);\n\n      if (!retro_resampler_realloc(&resampler_data,\n               &resamp, resampler_ident, quality,\n               ratio))\n         goto error;\n   }\n\n   /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes. We\n    * add 16 more samples in the formula below just as safeguard, because\n    * resampler->process sometimes reports more output samples than the\n    * formula below calculates. Ideally, audio resamplers should have a\n    * function to return the number of samples they will output given a\n    * count of input samples. */\n   samples                         = (unsigned)(AUDIO_MIXER_TEMP_BUFFER * ratio);\n   mp3_buffer                      = (float*)memalign_alloc(16,\n         (((samples + 16) + 15) & ~15) * sizeof(float));\n\n   if (!mp3_buffer)\n   {\n      if (resamp && resampler_data)\n         resamp->free(resampler_data);\n      goto error;\n   }\n\n   voice->types.mp3.resampler      = resamp;\n   voice->types.mp3.resampler_data = resampler_data;\n   voice->types.mp3.buffer         = (float*)mp3_buffer;\n   voice->types.mp3.buf_samples    = samples;\n   voice->types.mp3.ratio          = ratio;\n   voice->types.mp3.position       = 0;\n   voice->types.mp3.samples        = 0;\n\n   return true;\n\nerror:\n   drmp3_uninit(&voice->types.mp3.stream);\n   return false;\n}\n\nstatic void audio_mixer_release_mp3(audio_mixer_voice_t* voice)\n{\n   if (voice->types.mp3.resampler && voice->types.mp3.resampler_data)\n      voice->types.mp3.resampler->free(voice->types.mp3.resampler_data);\n   if (voice->types.mp3.buffer)\n      memalign_free(voice->types.mp3.buffer);\n   if (voice->types.mp3.stream.pData)\n      drmp3_uninit(&voice->types.mp3.stream);\n}\n\n#endif\n\naudio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,\n      bool repeat, float volume,\n      const char *resampler_ident,\n      enum resampler_quality quality,\n      audio_mixer_stop_cb_t stop_cb)\n{\n   unsigned i;\n   bool res                   = false;\n   audio_mixer_voice_t* voice = s_voices;\n\n   if (!sound)\n      return NULL;\n\n   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)\n   {\n      if (voice->type != AUDIO_MIXER_TYPE_NONE)\n         continue;\n\n      AUDIO_MIXER_LOCK(voice);\n\n      if (voice->type != AUDIO_MIXER_TYPE_NONE)\n      {\n         AUDIO_MIXER_UNLOCK(voice);\n         continue;\n      }\n\n      /* claim the voice, also helps with cleanup on error */\n      voice->type = sound->type;\n\n      switch (sound->type)\n      {\n         case AUDIO_MIXER_TYPE_WAV:\n            res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb);\n            break;\n         case AUDIO_MIXER_TYPE_OGG:\n#ifdef HAVE_STB_VORBIS\n            res = audio_mixer_play_ogg(sound, voice, repeat, volume,\n                  resampler_ident, quality, stop_cb);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_MOD:\n#ifdef HAVE_IBXM\n            res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_FLAC:\n#ifdef HAVE_DR_FLAC\n            res = audio_mixer_play_flac(sound, voice, repeat, volume,\n                  resampler_ident, quality, stop_cb);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_MP3:\n#ifdef HAVE_DR_MP3\n            res = audio_mixer_play_mp3(sound, voice, repeat, volume,\n                  resampler_ident, quality, stop_cb);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_NONE:\n            break;\n      }\n\n      break;\n   }\n\n   if (res)\n   {\n      voice->repeat   = repeat;\n      voice->volume   = volume;\n      voice->sound    = sound;\n      voice->stop_cb  = stop_cb;\n      AUDIO_MIXER_UNLOCK(voice);\n   }\n   else\n   {\n      if (i < AUDIO_MIXER_MAX_VOICES)\n      {\n         audio_mixer_release(voice);\n         AUDIO_MIXER_UNLOCK(voice);\n      }\n      voice = NULL;\n   }\n\n   return voice;\n}\n\n/* Need to hold lock for voice.  */\nstatic void audio_mixer_release(audio_mixer_voice_t* voice)\n{\n   if (!voice)\n      return;\n\n   switch (voice->type)\n   {\n#ifdef HAVE_STB_VORBIS\n      case AUDIO_MIXER_TYPE_OGG:\n         audio_mixer_release_ogg(voice);\n         break;\n#endif\n#ifdef HAVE_IBXM\n      case AUDIO_MIXER_TYPE_MOD:\n         audio_mixer_release_mod(voice);\n         break;\n#endif\n#ifdef HAVE_DR_FLAC\n      case AUDIO_MIXER_TYPE_FLAC:\n         audio_mixer_release_flac(voice);\n         break;\n#endif\n#ifdef HAVE_DR_MP3\n      case AUDIO_MIXER_TYPE_MP3:\n         audio_mixer_release_mp3(voice);\n         break;\n#endif\n      default:\n         break;\n   }\n\n   memset(&voice->types, 0, sizeof(voice->types));\n   voice->type = AUDIO_MIXER_TYPE_NONE;\n}\n\nvoid audio_mixer_stop(audio_mixer_voice_t* voice)\n{\n   audio_mixer_stop_cb_t stop_cb = NULL;\n   audio_mixer_sound_t* sound    = NULL;\n\n   if (voice)\n   {\n      AUDIO_MIXER_LOCK(voice);\n      stop_cb     = voice->stop_cb;\n      sound       = voice->sound;\n\n      audio_mixer_release(voice);\n\n      AUDIO_MIXER_UNLOCK(voice);\n\n      if (stop_cb)\n         stop_cb(sound, AUDIO_MIXER_SOUND_STOPPED);\n   }\n}\n\nstatic void audio_mixer_mix_wav(float* buffer, size_t num_frames,\n      audio_mixer_voice_t* voice,\n      float volume)\n{\n   int i;\n   unsigned buf_free                = (unsigned)(num_frames * 2);\n   const audio_mixer_sound_t* sound = voice->sound;\n   unsigned pcm_available           = sound->types.wav.frames\n      * 2 - voice->types.wav.position;\n   const float* pcm                 = sound->types.wav.pcm +\n      voice->types.wav.position;\n\nagain:\n   if (pcm_available < buf_free)\n   {\n      for (i = pcm_available; i != 0; i--)\n         *buffer++ += *pcm++ * volume;\n\n      if (voice->repeat)\n      {\n         if (voice->stop_cb)\n            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);\n\n         buf_free                  -= pcm_available;\n         pcm_available              = sound->types.wav.frames * 2;\n         pcm                        = sound->types.wav.pcm;\n         voice->types.wav.position  = 0;\n         goto again;\n      }\n\n      if (voice->stop_cb)\n         voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);\n\n      audio_mixer_release(voice);\n   }\n   else\n   {\n      for (i = buf_free; i != 0; i--)\n         *buffer++ += *pcm++ * volume;\n\n      voice->types.wav.position += buf_free;\n   }\n}\n\n#ifdef HAVE_STB_VORBIS\nstatic void audio_mixer_mix_ogg(float* buffer, size_t num_frames,\n      audio_mixer_voice_t* voice,\n      float volume)\n{\n   int i;\n   float* temp_buffer = NULL;\n   unsigned buf_free                = (unsigned)(num_frames * 2);\n   unsigned temp_samples            = 0;\n   float* pcm                       = NULL;\n\n   if (!voice->types.ogg.stream)\n      return;\n\n   if (voice->types.ogg.position == voice->types.ogg.samples)\n   {\nagain:\n      if (temp_buffer == NULL)\n         temp_buffer = (float*)malloc(AUDIO_MIXER_TEMP_BUFFER * sizeof(float));\n\n      temp_samples = stb_vorbis_get_samples_float_interleaved(\n            voice->types.ogg.stream, 2, temp_buffer,\n            AUDIO_MIXER_TEMP_BUFFER) * 2;\n\n      if (temp_samples == 0)\n      {\n         if (voice->repeat)\n         {\n            if (voice->stop_cb)\n               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);\n\n            stb_vorbis_seek_start(voice->types.ogg.stream);\n            goto again;\n         }\n\n         if (voice->stop_cb)\n            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);\n\n         audio_mixer_release(voice);\n         goto cleanup;\n      }\n\n      if (voice->types.ogg.resampler)\n      {\n         struct resampler_data info;\n         info.data_in = temp_buffer;\n         info.data_out = voice->types.ogg.buffer;\n         info.input_frames = temp_samples / 2;\n         info.output_frames = 0;\n         info.ratio = voice->types.ogg.ratio;\n\n         voice->types.ogg.resampler->process(\n               voice->types.ogg.resampler_data, &info);\n      }\n      else\n         memcpy(voice->types.ogg.buffer, temp_buffer,\n               temp_samples * sizeof(float));\n\n      voice->types.ogg.position = 0;\n      voice->types.ogg.samples  = voice->types.ogg.buf_samples;\n   }\n\n   pcm = voice->types.ogg.buffer + voice->types.ogg.position;\n\n   if (voice->types.ogg.samples < buf_free)\n   {\n      for (i = voice->types.ogg.samples; i != 0; i--)\n         *buffer++ += *pcm++ * volume;\n\n      buf_free -= voice->types.ogg.samples;\n      goto again;\n   }\n\n   for (i = buf_free; i != 0; --i )\n      *buffer++ += *pcm++ * volume;\n\n   voice->types.ogg.position += buf_free;\n   voice->types.ogg.samples  -= buf_free;\n\ncleanup:\n   if (temp_buffer != NULL)\n      free(temp_buffer);\n}\n#endif\n\n#ifdef HAVE_IBXM\nstatic void audio_mixer_mix_mod(float* buffer, size_t num_frames,\n      audio_mixer_voice_t* voice,\n      float volume)\n{\n   int i;\n   float samplef                    = 0.0f;\n   unsigned temp_samples            = 0;\n   unsigned buf_free                = (unsigned)(num_frames * 2);\n   int* pcm                         = NULL;\n\n   if (voice->types.mod.samples == 0)\n   {\nagain:\n      temp_samples = replay_get_audio(\n            voice->types.mod.stream, voice->types.mod.buffer, 0 ) * 2;\n\n      if (temp_samples == 0)\n      {\n         if (voice->repeat)\n         {\n            if (voice->stop_cb)\n               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);\n\n            replay_seek( voice->types.mod.stream, 0);\n            goto again;\n         }\n\n         if (voice->stop_cb)\n            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);\n\n         audio_mixer_release(voice);\n         return;\n      }\n\n      voice->types.mod.position = 0;\n      voice->types.mod.samples  = temp_samples;\n   }\n   pcm = voice->types.mod.buffer + voice->types.mod.position;\n\n   if (voice->types.mod.samples < buf_free)\n   {\n      for (i = voice->types.mod.samples; i != 0; i--)\n      {\n         samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;\n         samplef     = samplef * 2.0f - 1.0f;\n         *buffer++  += samplef * volume;\n      }\n\n      buf_free -= voice->types.mod.samples;\n      goto again;\n   }\n\n   for (i = buf_free; i != 0; --i )\n   {\n      samplef     = ((float)(*pcm++) + 32768.0f) / 65535.0f;\n      samplef     = samplef * 2.0f - 1.0f;\n      *buffer++  += samplef * volume;\n   }\n\n   voice->types.mod.position += buf_free;\n   voice->types.mod.samples  -= buf_free;\n}\n#endif\n\n#ifdef HAVE_DR_FLAC\nstatic void audio_mixer_mix_flac(float* buffer, size_t num_frames,\n      audio_mixer_voice_t* voice,\n      float volume)\n{\n   int i;\n   struct resampler_data info;\n   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };\n   unsigned buf_free                = (unsigned)(num_frames * 2);\n   unsigned temp_samples            = 0;\n   float *pcm                       = NULL;\n\n   if (voice->types.flac.position == voice->types.flac.samples)\n   {\nagain:\n      /* drflac_read_pcm_frames_f32 takes a frame count and\n       * writes frame_count * channel_count floats into the\n       * output buffer.  Request at most AUDIO_MIXER_TEMP_BUFFER\n       * / 2 frames so a stereo FLAC fills temp_buffer[AUDIO_\n       * MIXER_TEMP_BUFFER] exactly, then multiply the return\n       * value by 2 to convert frame count to interleaved float\n       * count.  This matches the convention the downstream code\n       * (info.input_frames = temp_samples / 2, memcpy length\n       * of temp_samples * sizeof(float)) and the sibling mp3\n       * and ogg mix paths already use.\n       *\n       * Pre-patch this passed AUDIO_MIXER_TEMP_BUFFER as the\n       * frame count without the '/ 2' and stored the return as\n       * 'temp_samples' without the '* 2'.  For a stereo FLAC\n       * (by far the most common case) drflac wrote 2 *\n       * AUDIO_MIXER_TEMP_BUFFER = 16384 floats into a 8192-\n       * float stack buffer - a 32 KiB stack overflow.  Any\n       * stereo FLAC asset played through the mixer (cheevo\n       * unlock sounds, menu BGM, user-loaded content via the\n       * audio mixer playlist, etc.) corrupted the stack on\n       * every mix tick.  The downstream 'temp_samples / 2'\n       * and memcpy length were also off by 2x under the old\n       * convention, but the stack overflow hit first.\n       *\n       * For mono FLAC: the '* 2' overstates the float count by\n       * 2x, causing the memcpy / resampler to read\n       * uninitialised stack past the actual data.  That matches\n       * the pre-existing implicit stereo-only assumption of\n       * the FLAC/MP3/OGG mixer paths (voice->types.flac.\n       * buf_samples is sized as TEMP_BUFFER * ratio, with no\n       * per-channel adjustment) rather than introducing new\n       * mono handling here.  Fixing mono playback is a separate\n       * change. */\n      temp_samples = (unsigned)drflac_read_pcm_frames_f32(\n            voice->types.flac.stream,\n            AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2;\n      if (temp_samples == 0)\n      {\n         if (voice->repeat)\n         {\n            if (voice->stop_cb)\n               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);\n\n            drflac_seek_to_pcm_frame(voice->types.flac.stream,0);\n            goto again;\n         }\n\n         if (voice->stop_cb)\n            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);\n\n         audio_mixer_release(voice);\n         return;\n      }\n\n      info.data_in              = temp_buffer;\n      info.data_out             = voice->types.flac.buffer;\n      info.input_frames         = temp_samples / 2;\n      info.output_frames        = 0;\n      info.ratio                = voice->types.flac.ratio;\n\n      if (voice->types.flac.resampler)\n         voice->types.flac.resampler->process(\n               voice->types.flac.resampler_data, &info);\n      else\n         memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float));\n      voice->types.flac.position = 0;\n      voice->types.flac.samples  = voice->types.flac.buf_samples;\n   }\n\n   pcm = voice->types.flac.buffer + voice->types.flac.position;\n\n   if (voice->types.flac.samples < buf_free)\n   {\n      for (i = voice->types.flac.samples; i != 0; i--)\n         *buffer++ += *pcm++ * volume;\n\n      buf_free -= voice->types.flac.samples;\n      goto again;\n   }\n\n   for (i = buf_free; i != 0; --i )\n      *buffer++ += *pcm++ * volume;\n\n   voice->types.flac.position += buf_free;\n   voice->types.flac.samples  -= buf_free;\n}\n#endif\n\n#ifdef HAVE_DR_MP3\nstatic void audio_mixer_mix_mp3(float* buffer, size_t num_frames,\n      audio_mixer_voice_t* voice,\n      float volume)\n{\n   int i;\n   struct resampler_data info;\n   float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };\n   unsigned buf_free                = (unsigned)(num_frames * 2);\n   unsigned temp_samples            = 0;\n   float* pcm                       = NULL;\n\n   if (voice->types.mp3.position == voice->types.mp3.samples)\n   {\nagain:\n      temp_samples = (unsigned)drmp3_read_f32(\n            &voice->types.mp3.stream,\n            AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2;\n\n      if (temp_samples == 0)\n      {\n         if (voice->repeat)\n         {\n            if (voice->stop_cb)\n               voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_REPEATED);\n\n            drmp3_seek_to_frame(&voice->types.mp3.stream,0);\n            goto again;\n         }\n\n         if (voice->stop_cb)\n            voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);\n\n         audio_mixer_release(voice);\n         return;\n      }\n\n      info.data_in              = temp_buffer;\n      info.data_out             = voice->types.mp3.buffer;\n      info.input_frames         = temp_samples / 2;\n      info.output_frames        = 0;\n      info.ratio                = voice->types.mp3.ratio;\n\n      if (voice->types.mp3.resampler)\n         voice->types.mp3.resampler->process(\n               voice->types.mp3.resampler_data, &info);\n      else\n         memcpy(voice->types.mp3.buffer, temp_buffer,\n               temp_samples * sizeof(float));\n      voice->types.mp3.position = 0;\n      voice->types.mp3.samples  = voice->types.mp3.buf_samples;\n   }\n\n   pcm = voice->types.mp3.buffer + voice->types.mp3.position;\n\n   if (voice->types.mp3.samples < buf_free)\n   {\n      for (i = voice->types.mp3.samples; i != 0; i--)\n         *buffer++ += *pcm++ * volume;\n\n      buf_free -= voice->types.mp3.samples;\n      goto again;\n   }\n\n   for (i = buf_free; i != 0; --i )\n      *buffer++ += *pcm++ * volume;\n\n   voice->types.mp3.position += buf_free;\n   voice->types.mp3.samples  -= buf_free;\n}\n#endif\n\nvoid audio_mixer_mix(float* buffer, size_t num_frames,\n      float volume_override, bool override)\n{\n   unsigned i;\n   size_t j                   = 0;\n   float* sample              = NULL;\n   audio_mixer_voice_t* voice = s_voices;\n\n   for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++)\n   {\n      float volume;\n\n      AUDIO_MIXER_LOCK(voice);\n\n      volume = (override) ? volume_override : voice->volume;\n\n      switch (voice->type)\n      {\n         case AUDIO_MIXER_TYPE_WAV:\n            audio_mixer_mix_wav(buffer, num_frames, voice, volume);\n            break;\n         case AUDIO_MIXER_TYPE_OGG:\n#ifdef HAVE_STB_VORBIS\n            audio_mixer_mix_ogg(buffer, num_frames, voice, volume);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_MOD:\n#ifdef HAVE_IBXM\n            audio_mixer_mix_mod(buffer, num_frames, voice, volume);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_FLAC:\n#ifdef HAVE_DR_FLAC\n            audio_mixer_mix_flac(buffer, num_frames, voice, volume);\n#endif\n            break;\n            case AUDIO_MIXER_TYPE_MP3:\n#ifdef HAVE_DR_MP3\n            audio_mixer_mix_mp3(buffer, num_frames, voice, volume);\n#endif\n            break;\n         case AUDIO_MIXER_TYPE_NONE:\n            break;\n      }\n\n      AUDIO_MIXER_UNLOCK(voice);\n   }\n\n   for (j = 0, sample = buffer; j < num_frames * 2; j++, sample++)\n   {\n      if (*sample < -1.0f)\n         *sample = -1.0f;\n      else if (*sample > 1.0f)\n         *sample = 1.0f;\n   }\n}\n\nfloat audio_mixer_voice_get_volume(audio_mixer_voice_t *voice)\n{\n   if (!voice)\n      return 0.0f;\n\n   return voice->volume;\n}\n\nvoid audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val)\n{\n   if (!voice)\n      return;\n\n   AUDIO_MIXER_LOCK(voice);\n   voice->volume = val;\n   AUDIO_MIXER_UNLOCK(voice);\n}\n"
  },
  {
    "path": "audio/conversion/float_to_s16.c",
    "content": "/* Copyright  (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (float_to_s16.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <stdint.h>\n#include <stddef.h>\n\n#if defined(__SSE2__)\n#include <emmintrin.h>\n#elif defined(__ALTIVEC__)\n#include <altivec.h>\n#endif\n\n#include <features/features_cpu.h>\n#include <audio/conversion/float_to_s16.h>\n\n#if (defined(__ARM_NEON__) || defined(HAVE_NEON))\nstatic bool float_to_s16_neon_enabled = false;\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\nvoid convert_float_s16_asm(int16_t *s, const float *in, size_t len);\n#else\n#include <arm_neon.h>\n#endif\n\nvoid convert_float_to_s16(int16_t *s, const float *in, size_t len)\n{\n   size_t i           = 0;\n   if (float_to_s16_neon_enabled)\n   {\n      float        gf = (1<<15);\n      float32x4_t vgf = {gf, gf, gf, gf};\n      while (len >= 8)\n      {\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\n         size_t aligned_samples = len & ~7;\n         if (aligned_samples)\n            convert_float_s16_asm(s, in, aligned_samples);\n\n         s        += aligned_samples;\n         in       += aligned_samples;\n         samples  -= aligned_samples;\n         i         = 0;\n#else\n         int16x4x2_t oreg;\n         int32x4x2_t creg;\n         float32x4x2_t inreg = vld2q_f32(in);\n         creg.val[0]         = vcvtq_s32_f32(vmulq_f32(inreg.val[0], vgf));\n         creg.val[1]         = vcvtq_s32_f32(vmulq_f32(inreg.val[1], vgf));\n         oreg.val[0]         = vqmovn_s32(creg.val[0]);\n         oreg.val[1]         = vqmovn_s32(creg.val[1]);\n         vst2_s16(s, oreg);\n         in      += 8;\n         s       += 8;\n         len     -= 8;\n#endif\n      }\n   }\n\n   for (; i < len; i++)\n   {\n      int32_t val = (int32_t)(in[i] * 0x8000);\n      s[i]        = (val > 0x7FFF) ? 0x7FFF :\n         (val < -0x8000 ? -0x8000 : (int16_t)val);\n   }\n}\n\nvoid convert_float_to_s16_init_simd(void)\n{\n   uint64_t cpu = cpu_features_get();\n\n   if (cpu & RETRO_SIMD_NEON)\n      float_to_s16_neon_enabled = true;\n}\n#else\nvoid convert_float_to_s16(int16_t *s, const float *in, size_t len)\n{\n   size_t i          = 0;\n#if defined(__SSE2__)\n   __m128 factor     = _mm_set1_ps((float)0x8000);\n   /* Initialize a 4D vector with 32768.0 for its elements */\n\n   for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)\n   { /* Skip forward 8 samples at a time... */\n      __m128 input_a = _mm_loadu_ps(in + 0); /* Create a 4-float vector from the next four samples... */\n      __m128 input_b = _mm_loadu_ps(in + 4); /* ...and another from the *next* next four. */\n      __m128 res_a   = _mm_mul_ps(input_a, factor);\n      __m128 res_b   = _mm_mul_ps(input_b, factor); /* Multiply these samples by 32768 */\n      __m128i ints_a = _mm_cvtps_epi32(res_a);\n      __m128i ints_b = _mm_cvtps_epi32(res_b); /* Convert the samples to 32-bit integers */\n      __m128i packed = _mm_packs_epi32(ints_a, ints_b); /* Then convert them to 16-bit ints, clamping to [-32768, 32767] */\n\n      _mm_storeu_si128((__m128i *)s, packed); /* Then put the result in the output array */\n   }\n\n   len               = len - i;\n   i                 = 0;\n   /* If there are any stray samples at the end, we need to convert them\n    * (maybe the original array didn't contain a multiple of 8 samples) */\n#elif defined(__ALTIVEC__)\n   int samples_in    = len;\n\n   /* Unaligned loads/store is a bit expensive,\n    * so we optimize for the good path (very likely). */\n   if (((uintptr_t)s & 15) + ((uintptr_t)in & 15) == 0)\n   {\n      size_t i;\n      for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)\n      {\n         vector float       input0 = vec_ld( 0, in);\n         vector float       input1 = vec_ld(16, in);\n         vector signed int result0 = vec_cts(input0, 15);\n         vector signed int result1 = vec_cts(input1, 15);\n         vec_st(vec_packs(result0, result1), 0, s);\n      }\n\n      samples_in    -= i;\n   }\n\n   len               = samples_in;\n   i                 = 0;\n#elif defined(_MIPS_ARCH_ALLEGREX)\n#ifdef DEBUG\n   /* Make sure the buffers are 16 byte aligned, this should be\n    * the default behaviour of malloc in the PSPSDK.\n    * Assume alignment. */\n   retro_assert(((uintptr_t)in  & 0xf) == 0);\n   retro_assert(((uintptr_t)s & 0xf) == 0);\n#endif\n\n   for (i = 0; i + 8 <= len; i += 8)\n   {\n      __asm__ (\n            \".set    push                 \\n\"\n            \".set    noreorder            \\n\"\n\n            \"lv.q    c100,  0(%0)         \\n\"\n            \"lv.q    c110,  16(%0)        \\n\"\n\n            \"vf2in.q c100, c100, 31       \\n\"\n            \"vf2in.q c110, c110, 31       \\n\"\n            \"vi2s.q  c100, c100           \\n\"\n            \"vi2s.q  c102, c110           \\n\"\n\n            \"sv.q    c100,  0(%1)         \\n\"\n\n            \".set    pop                  \\n\"\n            :: \"r\"(in + i), \"r\"(s + i));\n   }\n#endif\n\n   /* This loop converts stray samples to the right format,\n    * but it's also a fallback in case no SIMD instructions are available. */\n   for (; i < len; i++)\n   {\n      int32_t val    = (int32_t)(in[i] * 0x8000);\n      s[i]           = (val > 0x7FFF)\n         ? 0x7FFF\n         : (val < -0x8000 ? -0x8000 : (int16_t)val);\n   }\n}\n\nvoid convert_float_to_s16_init_simd(void) { }\n#endif\n"
  },
  {
    "path": "audio/conversion/float_to_s16_neon.S",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (float_to_s16_neon.S).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)\n\n#ifndef __MACH__\n.arm\n#endif\n\n.align 4\n.globl convert_float_s16_asm\n#ifndef __MACH__\n.type convert_float_s16_asm, %function\n#endif\n.globl _convert_float_s16_asm\n#ifndef __MACH__\n.type _convert_float_s16_asm, %function\n#endif\n# convert_float_s16_asm(int16_t *out, const float *in, size_t samples)\nconvert_float_s16_asm:\n_convert_float_s16_asm:\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\n1:\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\n"
  },
  {
    "path": "audio/conversion/float_to_s16_neon.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (float_to_s16_neon.S).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)\n\n#if defined(__thumb__)\n#define DECL_ARMMODE(x) \"  .align 2\\n\" \"  .global \" x \"\\n\" \"  .thumb\\n\" \"  .thumb_func\\n\" \"  .type \" x \", %function\\n\" x \":\\n\"\n#else\n#define DECL_ARMMODE(x) \"  .align 4\\n\" \"  .global \" x \"\\n\" \"  .arm\\n\" x \":\\n\"\n#endif\n\nasm(\n    DECL_ARMMODE(\"convert_float_s16_asm\")\n    DECL_ARMMODE(\"_convert_float_s16_asm\")\n    \"# convert_float_s16_asm(int16_t *s, const float *in, size_t len)\\n\"\n    \"   # Hacky way to get a constant of 2^15.\\n\"\n    \"   # ((2^4)^2)^2 * 0.5 = 2^15\\n\"\n    \"   vmov.f32 q8, #16.0\\n\"\n    \"   vmov.f32 q9, #0.5\\n\"\n    \"   vmul.f32 q8, q8, q8\\n\"\n    \"   vmul.f32 q8, q8, q8\\n\"\n    \"   vmul.f32 q8, q8, q9\\n\"\n    \"\\n\"\n    \"1:\\n\"\n    \"   # Preload here?\\n\"\n    \"   vld1.f32 {q0-q1}, [r1]!\\n\"\n    \"\\n\"\n    \"   vmul.f32 q0, q0, q8\\n\"\n    \"   vmul.f32 q1, q1, q8\\n\"\n    \"\\n\"\n    \"   vcvt.s32.f32 q0, q0\\n\"\n    \"   vcvt.s32.f32 q1, q1\\n\"\n    \"\\n\"\n    \"   vqmovn.s32 d4, q0\\n\"\n    \"   vqmovn.s32 d5, q1\\n\"\n    \"\\n\"\n    \"   vst1.f32 {d4-d5}, [r0]!\\n\"\n    \"\\n\"\n    \"   # Guaranteed to get samples in multiples of 8.\\n\"\n    \"   subs r2, r2, #8\\n\"\n    \"   bne 1b\\n\"\n    \"\\n\"\n    \"   bx lr\\n\"\n    \"\\n\"\n    );\n#endif\n"
  },
  {
    "path": "audio/conversion/mono_to_stereo_float.c",
    "content": "/* Copyright  (C) 2010-2023 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (mono_to_stereo.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <stdint.h>\n#include <stddef.h>\n\n#include <audio/conversion/dual_mono.h>\n\n/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */\nvoid convert_to_dual_mono_float(float *s, const float *in, size_t len)\n{\n   unsigned i = 0;\n\n   if (!s || !in || !len)\n      return;\n\n   for (; i < len; i++)\n   {\n      s[i * 2]     = in[i];\n      s[i * 2 + 1] = in[i];\n   }\n}\n\n/* Why is there no equivalent for int16_t samples?\n * No inherent reason, I just didn't need one.\n * If you do, open a pull request. */\n"
  },
  {
    "path": "audio/conversion/s16_to_float.c",
    "content": "/* Copyright  (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (s16_to_float.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#if defined(__SSE2__)\n#include <emmintrin.h>\n#elif defined(__ALTIVEC__)\n#include <altivec.h>\n#endif\n\n#include <boolean.h>\n#include <features/features_cpu.h>\n#include <audio/conversion/s16_to_float.h>\n\n#if (defined(__ARM_NEON__) || defined(HAVE_NEON))\nstatic bool s16_to_float_neon_enabled = false;\n\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\n/* Avoid potential hard-float/soft-float ABI issues. */\nvoid convert_s16_float_asm(float *s, const int16_t *in,\n      size_t len, const float *gain);\n#else\n#include <arm_neon.h>\n#endif\n\nvoid convert_s16_to_float(float *s,\n      const int16_t *in, size_t len, float gain)\n{\n   unsigned i      = 0;\n\n   if (s16_to_float_neon_enabled)\n   {\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\n      size_t aligned_samples = len & ~7;\n      if (aligned_samples)\n         convert_s16_float_asm(s, in, aligned_samples, &gain);\n\n      /* Could do all conversion in ASM, but keep it simple for now. */\n      s                 += aligned_samples;\n      in                += aligned_samples;\n      len               -= aligned_samples;\n      i                  = 0;\n#else\n      float        gf    = gain / (1 << 15);\n      float32x4_t vgf    = {gf, gf, gf, gf};\n      while (len >= 8)\n      {\n         float32x4x2_t oreg;\n         int16x4x2_t inreg   = vld2_s16(in);\n         int32x4_t      p1   = vmovl_s16(inreg.val[0]);\n         int32x4_t      p2   = vmovl_s16(inreg.val[1]);\n         oreg.val[0]         = vmulq_f32(vcvtq_f32_s32(p1), vgf);\n         oreg.val[1]         = vmulq_f32(vcvtq_f32_s32(p2), vgf);\n         vst2q_f32(s, oreg);\n         in                 += 8;\n         s                  += 8;\n         len                -= 8;\n      }\n#endif\n   }\n\n   gain /= 0x8000;\n\n   for (; i < len; i++)\n      s[i] = (float)in[i] * gain;\n}\n\nvoid convert_s16_to_float_init_simd(void)\n{\n   uint64_t cpu = cpu_features_get();\n\n   if (cpu & RETRO_SIMD_NEON)\n      s16_to_float_neon_enabled = true;\n}\n#else\nvoid convert_s16_to_float(float *s,\n      const int16_t *in, size_t len, float gain)\n{\n   unsigned i      = 0;\n\n#if defined(__SSE2__)\n   float fgain   = gain / UINT32_C(0x80000000);\n   __m128 factor = _mm_set1_ps(fgain);\n\n   for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)\n   {\n      __m128i input    = _mm_loadu_si128((const __m128i *)in);\n      __m128i regs_l   = _mm_unpacklo_epi16(_mm_setzero_si128(), input);\n      __m128i regs_r   = _mm_unpackhi_epi16(_mm_setzero_si128(), input);\n      __m128 output_l  = _mm_mul_ps(_mm_cvtepi32_ps(regs_l), factor);\n      __m128 output_r  = _mm_mul_ps(_mm_cvtepi32_ps(regs_r), factor);\n\n      _mm_storeu_ps(s + 0, output_l);\n      _mm_storeu_ps(s + 4, output_r);\n   }\n\n   len     = len - i;\n   i       = 0;\n#elif defined(__ALTIVEC__)\n   size_t samples_in = len;\n\n   /* Unaligned loads/store is a bit expensive, so we\n    * optimize for the good path (very likely). */\n   if (((uintptr_t)s & 15) + ((uintptr_t)in & 15) == 0)\n   {\n      const vector float gain_vec = { gain, gain , gain, gain };\n      const vector float zero_vec = { 0.0f, 0.0f, 0.0f, 0.0f};\n\n      for (i = 0; i + 8 <= len; i += 8, in += 8, s += 8)\n      {\n         vector signed short input = vec_ld(0, in);\n         vector signed int hi      = vec_unpackh(input);\n         vector signed int lo      = vec_unpackl(input);\n         vector float out_hi       = vec_madd(vec_ctf(hi, 15), gain_vec, zero_vec);\n         vector float out_lo       = vec_madd(vec_ctf(lo, 15), gain_vec, zero_vec);\n\n         vec_st(out_hi,  0, s);\n         vec_st(out_lo, 16, s);\n      }\n\n      samples_in -= i;\n   }\n\n   len     = samples_in;\n   i       = 0;\n#endif\n\n   gain   /= 0x8000;\n\n#if defined(_MIPS_ARCH_ALLEGREX)\n#ifdef DEBUG\n   /* Make sure the buffer is 16 byte aligned, this should be the\n    * default behaviour of malloc in the PSPSDK.\n    * Only the output buffer can be assumed to be 16-byte aligned. */\n   retro_assert(((uintptr_t)s & 0xf) == 0);\n#endif\n\n   __asm__ (\n         \".set    push                    \\n\"\n         \".set    noreorder               \\n\"\n         \"mtv     %0, s200                \\n\"\n         \".set    pop                     \\n\"\n         ::\"r\"(gain));\n\n   for (i = 0; i + 16 <= len; i += 16)\n   {\n      __asm__ (\n            \".set    push                 \\n\"\n            \".set    noreorder            \\n\"\n\n            \"lv.s    s100,  0(%0)         \\n\"\n            \"lv.s    s101,  4(%0)         \\n\"\n            \"lv.s    s110,  8(%0)         \\n\"\n            \"lv.s    s111, 12(%0)         \\n\"\n            \"lv.s    s120, 16(%0)         \\n\"\n            \"lv.s    s121, 20(%0)         \\n\"\n            \"lv.s    s130, 24(%0)         \\n\"\n            \"lv.s    s131, 28(%0)         \\n\"\n\n            \"vs2i.p  c100, c100           \\n\"\n            \"vs2i.p  c110, c110           \\n\"\n            \"vs2i.p  c120, c120           \\n\"\n            \"vs2i.p  c130, c130           \\n\"\n\n            \"vi2f.q  c100, c100, 16       \\n\"\n            \"vi2f.q  c110, c110, 16       \\n\"\n            \"vi2f.q  c120, c120, 16       \\n\"\n            \"vi2f.q  c130, c130, 16       \\n\"\n\n            \"vmscl.q e100, e100, s200     \\n\"\n\n            \"sv.q    c100,  0(%1)         \\n\"\n            \"sv.q    c110, 16(%1)         \\n\"\n            \"sv.q    c120, 32(%1)         \\n\"\n            \"sv.q    c130, 48(%1)         \\n\"\n\n            \".set    pop                  \\n\"\n            :: \"r\"(in + i), \"r\"(s + i));\n   }\n#endif\n\n   for (; i < len; i++)\n      s[i] = (float)in[i] * gain;\n}\n\nvoid convert_s16_to_float_init_simd(void) { }\n#endif\n\n"
  },
  {
    "path": "audio/conversion/s16_to_float_neon.S",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (s16_to_float_neon.S).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)\n\n#ifndef __MACH__\n.arm\n#endif\n\n.align 4\n.globl convert_s16_float_asm\n#ifndef __MACH__\n.type convert_s16_float_asm, %function\n#endif\n.globl _convert_s16_float_asm\n#ifndef __MACH__\n.type _convert_s16_float_asm, %function\n#endif\n# convert_s16_float_asm(float *out, const int16_t *in, size_t samples, const float *gain)\nconvert_s16_float_asm:\n_convert_s16_float_asm:\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\n1:\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\n"
  },
  {
    "path": "audio/conversion/s16_to_float_neon.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (s16_to_float_neon.S).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)\n\n#if defined(__thumb__)\n#define DECL_ARMMODE(x) \"  .align 2\\n\" \"  .global \" x \"\\n\" \"  .thumb\\n\" \"  .thumb_func\\n\" \"  .type \" x \", %function\\n\" x \":\\n\"\n#else\n#define DECL_ARMMODE(x) \"  .align 4\\n\" \"  .global \" x \"\\n\" \"  .arm\\n\" x \":\\n\"\n#endif\n\nasm(\n    DECL_ARMMODE(\"convert_s16_float_asm\")\n    DECL_ARMMODE(\"_convert_s16_float_asm\")\n    \"# convert_s16_float_asm(float *s, const int16_t *in, size_t len, const float *gain)\\n\"\n    \"   # Hacky way to get a constant of 2^-15.\\n\"\n    \"   # Might be faster to just load a constant from memory.\\n\"\n    \"   # It's just done once however ...\\n\"\n    \"   vmov.f32 q8, #0.25\\n\"\n    \"   vmul.f32 q8, q8, q8\\n\"\n    \"   vmul.f32 q8, q8, q8\\n\"\n    \"   vmul.f32 q8, q8, q8\\n\"\n    \"   vadd.f32 q8, q8, q8\\n\"\n    \"\\n\"\n    \"   # Apply gain\\n\"\n    \"   vld1.f32 {d6[0]}, [r3]\\n\"\n    \"   vmul.f32 q8, q8, d6[0]\\n\"\n    \"\\n\"\n    \"1:\\n\"\n    \"   # Preload here?\\n\"\n    \"   vld1.s16 {q0}, [r1]!\\n\"\n    \"\\n\"\n    \"   # Widen to 32-bit\\n\"\n    \"   vmovl.s16 q1, d0\\n\"\n    \"   vmovl.s16 q2, d1\\n\"\n    \"\\n\"\n    \"   # Convert to float\\n\"\n    \"   vcvt.f32.s32 q1, q1\\n\"\n    \"   vcvt.f32.s32 q2, q2\\n\"\n    \"\\n\"\n    \"   vmul.f32 q1, q1, q8\\n\"\n    \"   vmul.f32 q2, q2, q8\\n\"\n    \"\\n\"\n    \"   vst1.f32 {q1-q2}, [r0]!\\n\"\n    \"\\n\"\n    \"   # Guaranteed to get samples in multiples of 8.\\n\"\n    \"   subs r2, r2, #8\\n\"\n    \"   bne 1b\\n\"\n    \"\\n\"\n    \"   bx lr\\n\"\n    \"\\n\"\n    );\n#endif\n"
  },
  {
    "path": "audio/conversion/stereo_to_mono_float.c",
    "content": "/* Copyright  (C) 2010-2023 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (mono_to_stereo.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <stdint.h>\n#include <stddef.h>\n\n#include <audio/conversion/dual_mono.h>\n\n/* TODO: Use SIMD instructions to make this faster (or show that it's not needed) */\nvoid convert_to_mono_float_left(float *out, const float *in, size_t frames)\n{\n   unsigned i = 0;\n\n   if (!out || !in || !frames)\n      return;\n\n   for (; i < frames; i++)\n   {\n      out[i] = in[i * 2];\n   }\n}\n\n/* Why is there no equivalent for int16_t samples?\n * No inherent reason, I just didn't need one.\n * If you do, open a pull request.\n * Same goes for the lack of a convert_to_mono_float_right;\n * I didn't need one, so I didn't write one. */"
  },
  {
    "path": "audio/dsp_filter.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (dsp_filter.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include <retro_miscellaneous.h>\n\n#include <compat/posix_string.h>\n#include <dynamic/dylib.h>\n\n#include <file/file_path.h>\n#include <file/config_file_userdata.h>\n#include <features/features_cpu.h>\n#include <lists/string_list.h>\n#include <string/stdstring.h>\n#include <libretro_dspfilter.h>\n\n#include <audio/dsp_filter.h>\n\nstruct retro_dsp_plug\n{\n#ifdef HAVE_DYLIB\n   dylib_t lib;\n#endif\n   const struct dspfilter_implementation *impl;\n};\n\nstruct retro_dsp_instance\n{\n   const struct dspfilter_implementation *impl;\n   void *impl_data;\n};\n\nstruct retro_dsp_filter\n{\n   config_file_t *conf;\n\n   struct retro_dsp_plug *plugs;\n   unsigned num_plugs;\n\n   struct retro_dsp_instance *instances;\n   unsigned num_instances;\n};\n\nstatic const struct dspfilter_implementation *find_implementation(\n      retro_dsp_filter_t *dsp, const char *ident)\n{\n   unsigned i;\n   for (i = 0; i < dsp->num_plugs; i++)\n   {\n      if (string_is_equal(dsp->plugs[i].impl->short_ident, ident))\n         return dsp->plugs[i].impl;\n   }\n\n   return NULL;\n}\n\nstatic const struct dspfilter_config dspfilter_config = {\n   config_userdata_get_float,\n   config_userdata_get_int,\n   config_userdata_get_float_array,\n   config_userdata_get_int_array,\n   config_userdata_get_string,\n   config_userdata_free,\n};\n\nstatic bool create_filter_graph(retro_dsp_filter_t *dsp, float sample_rate)\n{\n   unsigned i;\n   struct retro_dsp_instance *instances = NULL;\n   unsigned filters                     = 0;\n\n   if (!config_get_uint(dsp->conf, \"filters\", &filters))\n      return false;\n\n   instances = (struct retro_dsp_instance*)calloc(filters, sizeof(*instances));\n   if (!instances)\n      return false;\n\n   dsp->instances     = instances;\n   dsp->num_instances = filters;\n\n   for (i = 0; i < filters; i++)\n   {\n      struct config_file_userdata userdata;\n      struct dspfilter_info info;\n      char key[64];\n      char name[64];\n\n      key[0] = name[0] = '\\0';\n\n      info.input_rate  = sample_rate;\n\n      snprintf(key, sizeof(key), \"filter%u\", i);\n\n      if (!config_get_array(dsp->conf, key, name, sizeof(name)))\n         return false;\n\n      dsp->instances[i].impl = find_implementation(dsp, name);\n      if (!dsp->instances[i].impl)\n         return false;\n\n      userdata.conf = dsp->conf;\n      /* Index-specific configs take priority over ident-specific. */\n      userdata.prefix[0] = key;\n      userdata.prefix[1] = dsp->instances[i].impl->short_ident;\n\n      dsp->instances[i].impl_data = dsp->instances[i].impl->init(&info,\n            &dspfilter_config, &userdata);\n      if (!dsp->instances[i].impl_data)\n         return false;\n   }\n\n   return true;\n}\n\n#if defined(HAVE_FILTERS_BUILTIN)\nextern const struct dspfilter_implementation *chorus_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *delta_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *echo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *eq_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *iir_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *panning_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *phaser_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *reverb_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *tremolo_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *vibrato_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\nextern const struct dspfilter_implementation *wahwah_dspfilter_get_implementation(dspfilter_simd_mask_t mask);\n\nstatic const dspfilter_get_implementation_t dsp_plugs_builtin[] = {\n   chorus_dspfilter_get_implementation,\n   delta_dspfilter_get_implementation,\n   echo_dspfilter_get_implementation,\n   eq_dspfilter_get_implementation,\n   iir_dspfilter_get_implementation,\n   panning_dspfilter_get_implementation,\n   phaser_dspfilter_get_implementation,\n   reverb_dspfilter_get_implementation,\n   tremolo_dspfilter_get_implementation,\n   vibrato_dspfilter_get_implementation,\n   wahwah_dspfilter_get_implementation,\n};\n\nstatic bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)\n{\n   unsigned i;\n   dspfilter_simd_mask_t mask   = (dspfilter_simd_mask_t)cpu_features_get();\n   struct retro_dsp_plug *plugs = (struct retro_dsp_plug*)\n      calloc(ARRAY_SIZE(dsp_plugs_builtin), sizeof(*plugs));\n\n   if (!plugs)\n      return false;\n\n   dsp->plugs     = plugs;\n   dsp->num_plugs = ARRAY_SIZE(dsp_plugs_builtin);\n\n   for (i = 0; i < ARRAY_SIZE(dsp_plugs_builtin); i++)\n   {\n      dsp->plugs[i].impl = dsp_plugs_builtin[i](mask);\n      if (!dsp->plugs[i].impl)\n         return false;\n   }\n\n   return true;\n}\n#elif defined(HAVE_DYLIB)\nstatic bool append_plugs(retro_dsp_filter_t *dsp, struct string_list *list)\n{\n   unsigned i;\n   dspfilter_simd_mask_t mask = (dspfilter_simd_mask_t)cpu_features_get();\n   unsigned list_size         = list ? (unsigned)list->size : 0;\n\n   for (i = 0; i < list_size; i++)\n   {\n      dspfilter_get_implementation_t cb;\n      const struct dspfilter_implementation *impl = NULL;\n      struct retro_dsp_plug *new_plugs            = NULL;\n      dylib_t lib                                 =\n         dylib_load(list->elems[i].data);\n\n      if (!lib)\n         continue;\n\n      cb = (dspfilter_get_implementation_t)dylib_proc(lib, \"dspfilter_get_implementation\");\n      if (!cb)\n      {\n         dylib_close(lib);\n         continue;\n      }\n\n      impl = cb(mask);\n      if (!impl)\n      {\n         dylib_close(lib);\n         continue;\n      }\n\n      if (impl->api_version != DSPFILTER_API_VERSION)\n      {\n         dylib_close(lib);\n         continue;\n      }\n\n      new_plugs = (struct retro_dsp_plug*)\n         realloc(dsp->plugs, sizeof(*dsp->plugs) * (dsp->num_plugs + 1));\n      if (!new_plugs)\n      {\n         dylib_close(lib);\n         return false;\n      }\n\n      /* Found plug. */\n\n      dsp->plugs = new_plugs;\n      dsp->plugs[dsp->num_plugs].lib = lib;\n      dsp->plugs[dsp->num_plugs].impl = impl;\n      dsp->num_plugs++;\n   }\n\n   return true;\n}\n#endif\n\nretro_dsp_filter_t *retro_dsp_filter_new(\n      const char *filter_config,\n      void *string_data,\n      float sample_rate)\n{\n   config_file_t *conf           = NULL;\n   struct string_list *plugs     = NULL;\n   retro_dsp_filter_t *dsp       = (retro_dsp_filter_t*)calloc(1, sizeof(*dsp));\n\n   if (!dsp)\n      return NULL;\n\n   if (!(conf = config_file_new_from_path_to_string(filter_config)))\n      goto error;\n\n   dsp->conf = conf;\n\n   if (string_data)\n      plugs = (struct string_list*)string_data;\n\n#if defined(HAVE_DYLIB) || defined(HAVE_FILTERS_BUILTIN)\n   if (!append_plugs(dsp, plugs))\n      goto error;\n#endif\n\n   if (plugs)\n      string_list_free(plugs);\n   plugs = NULL;\n\n   if (!create_filter_graph(dsp, sample_rate))\n      goto error;\n\n   return dsp;\n\nerror:\n   if (plugs)\n      string_list_free(plugs);\n   retro_dsp_filter_free(dsp);\n   return NULL;\n}\n\nvoid retro_dsp_filter_free(retro_dsp_filter_t *dsp)\n{\n   unsigned i;\n   if (!dsp)\n      return;\n\n   for (i = 0; i < dsp->num_instances; i++)\n   {\n      if (dsp->instances[i].impl_data && dsp->instances[i].impl)\n         dsp->instances[i].impl->free(dsp->instances[i].impl_data);\n   }\n   free(dsp->instances);\n\n#ifdef HAVE_DYLIB\n   for (i = 0; i < dsp->num_plugs; i++)\n   {\n      if (dsp->plugs[i].lib)\n         dylib_close(dsp->plugs[i].lib);\n   }\n   free(dsp->plugs);\n#endif\n\n   if (dsp->conf)\n      config_file_free(dsp->conf);\n\n   free(dsp);\n}\n\nvoid retro_dsp_filter_process(retro_dsp_filter_t *dsp,\n      struct retro_dsp_data *data)\n{\n   unsigned i;\n   struct dspfilter_output output = {0};\n   struct dspfilter_input input   = {0};\n\n   output.samples = data->input;\n   output.frames  = data->input_frames;\n\n   for (i = 0; i < dsp->num_instances; i++)\n   {\n      input.samples = output.samples;\n      input.frames  = output.frames;\n      dsp->instances[i].impl->process(\n            dsp->instances[i].impl_data, &output, &input);\n   }\n\n   data->output        = output.samples;\n   data->output_frames = output.frames;\n}\n"
  },
  {
    "path": "audio/dsp_filters/BassBoost.dsp",
    "content": "filters = 2\nfilter0 = iir\nfilter1 = panning\n\niir_gain = 10.0\niir_type = BBOOST\niir_frequency = 200.0\n\n# Avoids clipping.\npanning_left_mix = \"0.3 0.0\"\npanning_right_mix = \"0.0 0.3\"\n"
  },
  {
    "path": "audio/dsp_filters/ChipTune-Lowpass.dsp",
    "content": "filters = 1\nfilter0 = iir\n\niir_frequency = 8600.0\niir_quality = 0.707\niir_gain = 6.0\niir_type = LPF\n"
  },
  {
    "path": "audio/dsp_filters/ChipTuneEnhance.dsp",
    "content": "filters = 4\nfilter0 = eq\nfilter1 = reverb\nfilter2 = iir\nfilter3 = panning\n\neq_frequencies = \"32 64 125 250 500 1000 2000 4000 8000 16000 20000\"\neq_gains = \"6 9 12 7 6 5 7 9 11 6 0\"\n\n# Reverb - slight reverb\n reverb_drytime = 0.5\n reverb_wettime = 0.15\n reverb_damping = 0.8\n reverb_roomwidth = 0.25\n reverb_roomsize = 0.25\n\n# IIR - filters out some harsh sounds on the upper end\niir_type = RIAA_CD\n\n# Panning - cut the volume a bit\npanning_left_mix = \"0.75 0.0\"\npanning_right_mix = \"0.0 0.75\"\n"
  },
  {
    "path": "audio/dsp_filters/Chorus.dsp",
    "content": "filters = 1\nfilter0 = chorus\n\n# Controls the base delay of the chorus (milliseconds).\n# chorus_delay_ms = 25.0\n#\n# Controls the depth of the delay. The delay will vary between delay_ms +/- depth_ms.\n# chorus_depth_ms = 1.0\n#\n# Frequency of LFO which controls delay.\n# chorus_lfo_freq = 0.5\n#\n# Controls dry/wet-ness of effect. 1.0 = full chorus, 0.0 = no chorus.\n# chorus_drywet = 0.8\n"
  },
  {
    "path": "audio/dsp_filters/Crystalizer.dsp",
    "content": "filters = 1\nfilter0 = crystalizer\n# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max.\ncrystalizer_intensity = 5.0\n"
  },
  {
    "path": "audio/dsp_filters/EQ.dsp",
    "content": "filters = 1\nfilter0 = eq\n\n# Defaults\n\n# Beta factor for Kaiser window.\n# Lower values will allow better frequency resolution, but more ripple.\n# eq_window_beta = 4.0\n\n# The block size on which FFT is done.\n# Too high value requires more processing as well as longer latency but\n# allows finer-grained control over the spectrum.\n# eq_block_size_log2 = 8\n\n# An array of which frequencies to control.\n# You can create an arbitrary amount of these sampling points.\n# The EQ will try to create a frequency response which fits well to these points.\n# The filter response is linearly interpolated between sampling points here.\n#\n# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.\n# If you want a \"peak\" in the spectrum or similar, you have to define close points to say, 0 dB.\n#\n# E.g.: A boost of 3 dB at 1 kHz can be expressed as.\n# eq_frequencies = \"500 1000 2000\"\n# eq_gains = \"0 3 0\"\n# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.\n\n# By default, this filter has a flat frequency response.\n\n# Dumps the impulse response generated by the EQ as a plain-text file\n# with one coefficient per line.\n# eq_impulse_response_output = \"eq_impulse.txt\"\n#\n# Using GNU Octave or Matlab, you can plot the response with:\n#\n# f = fopen('/path/to/eq_impulse.txt');\n# l = textscan(f, '%f');\n# res = l{1};\n# freqz(res, 1, 4096, 48000);\n#\n# It will give the response in Hz; 48000 is the default Output Rate of RetroArch\n"
  },
  {
    "path": "audio/dsp_filters/Echo.dsp",
    "content": "filters = 1\nfilter0 = echo\n\n# Somewhat fancy Echo filter. Can take any number of echo channels with varying delays (ms) and feedback factors.\n# Echo output from all channels can be fed back into each other to create a somewhat reverb-like effect if desired.\n\n# Defaults, 200 ms delay echo with feedback:\n# Delay in ms. Takes an array with multiple channels.\n# echo_delay = \"200\"\n# Feedback factor for echo.\n# echo_feedback = \"0.5\"\n# Overall echo amplification. If too high, the echo becomes unstable due to feedback.\n# echo_amp = \"0.2\"\n\n# Reverby preset.\n# echo_delay    = \" 60  80 120 172 200 320 380\"\n# echo_feedback = \"0.5 0.5 0.4 0.3 0.5 0.3 0.2\"\n\n# echo_amp = \"0.12\"\n"
  },
  {
    "path": "audio/dsp_filters/EchoReverb.dsp",
    "content": "filters = 2\nfilter0 = echo\nfilter1 = reverb\n\necho_delay = \"200\"\necho_feedback = \"0.6\"\necho_amp = \"0.25\"\n\nreverb_roomwidth = 0.75\nreverb_roomsize = 0.75\nreverb_damping = 1.0\nreverb_wettime = 0.3\n"
  },
  {
    "path": "audio/dsp_filters/HighShelfDampen.dsp",
    "content": "filters = 1\nfilter0 = iir\n\niir_gain = -12.0\niir_type = HSH\niir_frequency = 8000.0\n"
  },
  {
    "path": "audio/dsp_filters/IIR.dsp",
    "content": "filters = 1\nfilter0 = iir\n\n# Defaults.\n#iir_frequency = 1024.0\n#iir_quality = 0.707\n#iir_gain = 0.0\n#iir_type = LPF\n\n# Filter types:\n# LPF: Low-pass\n# HPF: High-pass\n# BPCSGF: Band-pass #1\n# BPZPGF: Band-pass #2\n# APF: Allpass\n# NOTCH: Notch filter\n# RIAA_phono: RIAA record/tape deemphasis\n# PEQ: peaking band EQ\n# BBOOST: Bassboost\n# LSH: Low-shelf\n# HSH: High-shelf\n# RIAA_CD: CD de-emphasis\n"
  },
  {
    "path": "audio/dsp_filters/LowPassCPS.dsp",
    "content": "filters = 1\nfilter0 = eq\n\neq_frequencies = \"8000 10000 12500 16000 20000\"\neq_gains = \"0 -30 -30 -30 -30\"\n\n# Low pass filter for the QSound chip from CPS-1/2.\n# Some games have aliasing due low quality samples, so you can hear some annoying noisy near 11 kHz\n\n# Defaults\n\n# Beta factor for Kaiser window.\n# Lower values will allow better frequency resolution, but more ripple.\n# eq_window_beta = 4.0\n\n# The block size on which FFT is done.\n# Too high value requires more processing as well as longer latency but\n# allows finer-grained control over the spectrum.\n# eq_block_size_log2 = 8\n\n# An array of which frequencies to control.\n# You can create an arbitrary amount of these sampling points.\n# The EQ will try to create a frequency response which fits well to these points.\n# The filter response is linearly interpolated between sampling points here.\n#\n# It is implied that 0 Hz (DC) and Nyquist have predefined gains of 0 dB which are interpolated against.\n# If you want a \"peak\" in the spectrum or similar, you have to define close points to say, 0 dB.\n#\n# E.g.: A boost of 3 dB at 1 kHz can be expressed as.\n# eq_frequencies = \"500 1000 2000\"\n# eq_gains = \"0 3 0\"\n# Due to frequency domain smearing, you will not get exactly +3 dB at 1 kHz.\n\n# By default, this filter has a low pass response with cuttof frequency at ~8600 Hz.\n\n# Dumps the impulse response generated by the EQ as a plain-text file\n# with one coefficient per line.\n# eq_impulse_response_output = \"eq_impulse.txt\"\n#\n# Using GNU Octave or Matlab, you can plot the response with:\n#\n# f = fopen('/path/to/eq_impulse.txt');\n# l = textscan(f, '%f');\n# res = l{1};\n# freqz(res, 1, 4096, 48000);\n#\n# It will give the response in Hz; 48000 is the default Output Rate of RetroArch\n"
  },
  {
    "path": "audio/dsp_filters/Makefile",
    "content": "compiler    := gcc\nextra_flags :=\nuse_neon    := 0\nbuild       = release\nDYLIB\t      := so\nPREFIX      := /usr\nINSTALLDIR  := $(PREFIX)/lib/retroarch/filters/audio\n\nifeq ($(platform),)\n   platform = unix\n   ifeq ($(shell uname -s),)\n      platform = win\n   else ifneq ($(findstring Darwin,$(shell uname -s)),)\n      platform = osx\n      arch     = intel\n      ifeq ($(shell uname -p),powerpc)\n         arch = ppc\n      endif\n   else ifneq ($(findstring MINGW,$(shell uname -s)),)\n      platform = win\n   endif\nendif\n\nifeq ($(platform),gcc)\n   extra_rules_gcc := $(shell $(compiler) -dumpmachine)\nendif\n\nifneq (,$(findstring armv7,$(extra_rules_gcc)))\n   extra_flags += -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon\n   use_neon := 1\nendif\n\nifneq (,$(findstring hardfloat,$(extra_rules_gcc)))\n   extra_flags += -mfloat-abi=hard\nendif\n\nifeq (release,$(build))\n   extra_flags += -O2\nendif\n\nifeq (debug,$(build))\n   extra_flags += -O0 -g\nendif\n\nldflags := $(LDFLAGS) -shared -lm -Wl,--version-script=link.T\n\nifeq ($(platform), unix)\n   DYLIB = so\nelse ifeq ($(platform), osx)\n   compiler := $(CC)\n   DYLIB = dylib\n   ldflags := -dynamiclib\n   ARCHFLAGS=\n   MINVERFLAGS=\n   ifeq ($(shell uname -p),arm)\n      MINVERFLAGS = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)\n   else ifeq ($(HAVE_METAL),1)\n      MINVERFLAGS = -mmacosx-version-min=10.13 -stdlib=libc++  # macOS  (Metal, x86 64bit)\n   else ifeq ($(shell uname -p),powerpc)\n      MINVERFLAGS = -mmacosx-version-min=10.5  # macOSX (PowerPC 32-bit)\n   else ifeq ($(shell uname -m),i386)\n      MINVERFLAGS = -mmacosx-version-min=10.6  # macOSX (OpenGL, x86 32bit)\n   else\n      MINVERFLAGS = -mmacosx-version-min=10.7 -stdlib=libc++ # macOSX (OpenGL, x86 64bit)\n   endif\n\n\t# Build for a specific architecture when ARCH is defined as a switch\n   ifeq ($(ARCH),arm64)\n      MINVERFLAGS  = -mmacosx-version-min=10.15 -stdlib=libc++ # macOS  (Metal, ARM 64bit)\n      ARCHFLAGS    = -arch arm64\n   else ifeq ($(ARCH),x86_64)\n      ifeq ($(HAVE_METAL),1)\n         MINVERFLAGS  = -mmacosx-version-min=10.13 -stdlib=libc++\n      else\n         MINVERFLAGS  = -mmacosx-version-min=10.7  -stdlib=libc++\n      endif\n      ARCHFLAGS       = -arch x86_64\n   else ifeq ($(ARCH),x86)\n      MINVERFLAGS     = -mmacosx-version-min=10.6\n      ARCHFLAGS       = -arch x86\n   else ifeq ($(ARCH),ppc)\n      MINVERFLAGS     = -mmacosx-version-min=10.5\n      ARCHFLAGS       = -arch ppc\n   endif\n   ifeq ($(BUILDBOT),1)\n      ARCHFLAGS       = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)\n   endif\n\textraflags += $(MINVERFLAGS) $(ARCHFLAGS)\n\tldflags += $(MINVERFLAGS) $(ARCHFLAGS)\nelse\n   extra_flags += -static-libgcc -static-libstdc++\n   DYLIB = dll\nendif\n\nCC      := $(compiler) -Wall\nCXX     := $(subst CC,++,$(compiler)) -std=gnu++0x -Wall\nflags   := $(CPPFLAGS) $(CFLAGS) -fPIC $(extra_flags) -I../../include\nasflags := $(ASFLAGS) -fPIC  $(extra_flags)\nobjects :=\n\nifeq (1,$(use_neon))\n   ASMFLAGS := -INEON/asm\n   asflags += -mfpu=neon\nendif\n\nplugs := $(wildcard *.c)\nobjects := $(plugs:.c=.o)\ntargets := $(objects:.o=.$(DYLIB))\n\nall: build;\n\n%.o: %.S\n\t$(CC) -c -o $@ $(asflags)  $(ASMFLAGS)  $<\n\n%.o: %.c\n\t$(CC) -c -o $@ $(flags) $<\n\n%.$(DYLIB): %.o\n\t$(CC) -o $@ $(ldflags) $(flags) $^\n\nbuild: $(targets)\n\nclean:\n\trm -f *.o\n\trm -f *.$(DYLIB)\n\nstrip:\n\tstrip -s *.$(DYLIB)\n\ninstall:\n\tmkdir -p $(DESTDIR)$(INSTALLDIR)\n\tcp -t $(DESTDIR)$(INSTALLDIR) $(targets) *.dsp\n\ntest-install:\n\tDESTDIR=/tmp/build $(MAKE) install\n"
  },
  {
    "path": "audio/dsp_filters/Mono.dsp",
    "content": "filters = 1\nfilter0 = panning\n\n# Gains are linear.\n\n# Stereo Mono:\n panning_left_mix = \"0.5 0.5\"\n panning_right_mix = \"0.5 0.5\"\n\n# Mono on one speaker:\n# panning_left_mix = \"0.5 0.5\"\n# panning_right_mix = \"0.0 0.0\"\n"
  },
  {
    "path": "audio/dsp_filters/Panning.dsp",
    "content": "filters = 1\nfilter0 = panning\n\n# Gains are linear.\n\n# The default. Left and right channels map to each other.\npanning_left_mix = \"1.0 0.0\"\npanning_right_mix = \"0.0 1.0\"\n\n# Some examples:\n#\n# Mono:\n# panning_left_mix = \"0.5 0.5\"\n# panning_right_mix = \"0.5 0.5\"\n\n# Swap left and right channels:\n# panning_left_mix = \"0.0 1.0\"\n# panning_right_mix = \"1.0 0.0\"\n#\n# Mono on one speaker:\n# panning_left_mix = \"0.5 0.5\"\n# panning_right_mix = \"0.0 0.0\"\n"
  },
  {
    "path": "audio/dsp_filters/Phaser.dsp",
    "content": "filters = 1\nfilter0 = phaser\n\n# Defaults.\n# phaser_lfo_freq = 0.4\n# phaser_lfo_start_phase = 0.0\n# phaser_feedback = 0.0\n# phaser_depth = 0.4\n# phaser_dry_wet = 0.5\n# phaser_stages = 2\n"
  },
  {
    "path": "audio/dsp_filters/Reverb.dsp",
    "content": "filters = 1\nfilter0 = reverb\n\n# Defaults.\n# reverb_drytime = 0.43\n# reverb_wettime = 0.4\n# reverb_damping = 0.8\n# reverb_roomwidth = 0.56\n# reverb_roomsize = 0.56\n"
  },
  {
    "path": "audio/dsp_filters/Tremolo.dsp",
    "content": "filters = 1\nfilter0 = tremolo\n\n# Defaults.\n#tremolo_frequency = 4.0\n#tremolo_depth = 0.9\n"
  },
  {
    "path": "audio/dsp_filters/Vibrato.dsp",
    "content": "filters = 1\nfilter0 = vibrato\n\n# Defaults.\n#vibrato_frequency = 5.0\n#vibrato_depth = 0.5\n"
  },
  {
    "path": "audio/dsp_filters/WahWah.dsp",
    "content": "filters = 1\nfilter0 = wahwah\n\n# Defaults.\n# wahwah_lfo_freq = 1.5\n# wahwah_lfo_start_phase = 0.0\n# wahwah_freq_offset = 0.3\n# wahwah_depth = 0.7\n# wahwah_resonance = 2.5\n"
  },
  {
    "path": "audio/dsp_filters/chorus.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (chorus.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\n#define CHORUS_MAX_DELAY 4096\n#define CHORUS_DELAY_MASK (CHORUS_MAX_DELAY - 1)\n\nstruct chorus_data\n{\n   float old[2][CHORUS_MAX_DELAY];\n   float delay;\n   float depth;\n   float input_rate;\n   float mix_dry;\n   float mix_wet;\n   unsigned old_ptr;\n   unsigned lfo_ptr;\n   unsigned lfo_period;\n};\n\nstatic void chorus_free(void *data)\n{\n   if (data)\n      free(data);\n}\n\nstatic void chorus_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   float *out             = NULL;\n   struct chorus_data *ch = (struct chorus_data*)data;\n\n   output->samples        = input->samples;\n   output->frames         = input->frames;\n   out                    = output->samples;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      unsigned delay_int;\n      float delay_frac, l_a, l_b, r_a, r_b;\n      float chorus_l, chorus_r;\n      float in[2]             = { out[0], out[1] };\n      float delay             = ch->delay + ch->depth * sin((2.0 * M_PI * ch->lfo_ptr++) / ch->lfo_period);\n\n      delay                  *= ch->input_rate;\n      if (ch->lfo_ptr >= ch->lfo_period)\n         ch->lfo_ptr          = 0;\n\n      delay_int               = (unsigned)delay;\n\n      if (delay_int >= CHORUS_MAX_DELAY - 1)\n         delay_int            = CHORUS_MAX_DELAY - 2;\n\n      delay_frac              = delay - delay_int;\n\n      ch->old[0][ch->old_ptr] = in[0];\n      ch->old[1][ch->old_ptr] = in[1];\n\n      l_a                     = ch->old[0][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];\n      l_b                     = ch->old[0][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];\n      r_a                     = ch->old[1][(ch->old_ptr - delay_int - 0) & CHORUS_DELAY_MASK];\n      r_b                     = ch->old[1][(ch->old_ptr - delay_int - 1) & CHORUS_DELAY_MASK];\n\n      /* Lerp introduces aliasing of the chorus component,\n       * but doing full polyphase here is probably overkill. */\n      chorus_l                = l_a * (1.0f - delay_frac) + l_b * delay_frac;\n      chorus_r                = r_a * (1.0f - delay_frac) + r_b * delay_frac;\n\n      out[0]                  = ch->mix_dry * in[0] + ch->mix_wet * chorus_l;\n      out[1]                  = ch->mix_dry * in[1] + ch->mix_wet * chorus_r;\n\n      ch->old_ptr             = (ch->old_ptr + 1) & CHORUS_DELAY_MASK;\n   }\n}\n\nstatic void *chorus_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   float delay, depth, lfo_freq, drywet;\n   struct chorus_data *ch = (struct chorus_data*)calloc(1, sizeof(*ch));\n   if (!ch)\n      return NULL;\n\n   config->get_float(userdata, \"delay_ms\", &delay, 25.0f);\n   config->get_float(userdata, \"depth_ms\", &depth, 1.0f);\n   config->get_float(userdata, \"lfo_freq\", &lfo_freq, 0.5f);\n   config->get_float(userdata, \"drywet\", &drywet, 0.8f);\n\n   delay            /= 1000.0f;\n   depth            /= 1000.0f;\n\n   if (depth > delay)\n      depth          = delay;\n\n   if (drywet < 0.0f)\n      drywet         = 0.0f;\n   else if (drywet > 1.0f)\n      drywet         = 1.0f;\n\n   ch->mix_dry       = 1.0f - 0.5f * drywet;\n   ch->mix_wet       = 0.5f * drywet;\n\n   ch->delay         = delay;\n   ch->depth         = depth;\n   ch->lfo_period    = (1.0f / lfo_freq) * info->input_rate;\n   ch->input_rate    = info->input_rate;\n   if (!ch->lfo_period)\n      ch->lfo_period = 1;\n   return ch;\n}\n\nstatic const struct dspfilter_implementation chorus_plug = {\n   chorus_init,\n   chorus_process,\n   chorus_free,\n\n   DSPFILTER_API_VERSION,\n   \"Chorus\",\n   \"chorus\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation chorus_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *\ndspfilter_get_implementation(dspfilter_simd_mask_t mask) { return &chorus_plug; }\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/configure",
    "content": "#!/bin/sh\n\nPACKAGE_NAME=retroarch-filters-audio"
  },
  {
    "path": "audio/dsp_filters/crystalizer.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (echo.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\nstruct delta_data\n{\n   float intensity;\n   float old[2];\n};\n\nstatic void delta_free(void *data)\n{\n   free(data);\n}\n\nstatic void delta_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i, c;\n   struct delta_data *d   = (struct delta_data*)data;\n   float *out             = output->samples;\n   output->samples        = input->samples;\n   output->frames         = input->frames;\n\n   for (i = 0; i < input->frames; i++)\n   {\n      for (c = 0; c < 2; c++)\n      {\n           float current  = *out;\n           *out++         = current + (current - d->old[c]) * d->intensity;\n           d->old[c]      = current;\n      }\n   }\n}\n\nstatic void *delta_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d));\n   if (!d)\n      return NULL;\n   config->get_float(userdata, \"intensity\", &d->intensity, 5.0f);\n   return d;\n}\n\nstatic const struct dspfilter_implementation delta_plug = {\n   delta_init,\n   delta_process,\n   delta_free,\n   DSPFILTER_API_VERSION,\n   \"Delta Sharpening\",\n   \"crystalizer\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation delta_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &delta_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/echo.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (echo.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\nstruct echo_channel\n{\n   float *buffer;\n   unsigned ptr;\n   unsigned frames;\n   float feedback;\n};\n\nstruct echo_data\n{\n   struct echo_channel *channels;\n   unsigned num_channels;\n   float amp;\n};\n\nstatic void echo_free(void *data)\n{\n   unsigned i;\n   struct echo_data *echo = (struct echo_data*)data;\n\n   for (i = 0; i < echo->num_channels; i++)\n      free(echo->channels[i].buffer);\n   free(echo->channels);\n   free(echo);\n}\n\nstatic void echo_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i, c;\n   float *out             = NULL;\n   struct echo_data *echo = (struct echo_data*)data;\n\n   output->samples        = input->samples;\n   output->frames         = input->frames;\n\n   out                    = output->samples;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float left, right;\n      float echo_left  = 0.0f;\n      float echo_right = 0.0f;\n\n      for (c = 0; c < echo->num_channels; c++)\n      {\n         echo_left  += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0];\n         echo_right += echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1];\n      }\n\n      echo_left     *= echo->amp;\n      echo_right    *= echo->amp;\n\n      left           = out[0] + echo_left;\n      right          = out[1] + echo_right;\n\n      for (c = 0; c < echo->num_channels; c++)\n      {\n         float feedback_left  = out[0] + echo->channels[c].feedback * echo_left;\n         float feedback_right = out[1] + echo->channels[c].feedback * echo_right;\n\n         echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 0] = feedback_left;\n         echo->channels[c].buffer[(echo->channels[c].ptr << 1) + 1] = feedback_right;\n\n         echo->channels[c].ptr = (echo->channels[c].ptr + 1) % echo->channels[c].frames;\n      }\n\n      out[0] = left;\n      out[1] = right;\n   }\n}\n\nstatic void *echo_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   unsigned i, channels;\n   struct echo_channel *echo_channels    = NULL;\n   float *delay                          = NULL;\n   float *feedback                       = NULL;\n   unsigned num_delay                    = 0;\n   unsigned num_feedback                 = 0;\n\n   static const float default_delay[]    = { 200.0f };\n   static const float default_feedback[] = { 0.5f };\n   struct echo_data *echo                = (struct echo_data*)\n      calloc(1, sizeof(*echo));\n\n   if (!echo)\n      return NULL;\n\n   config->get_float_array(userdata, \"delay\", &delay,\n         &num_delay, default_delay, 1);\n   config->get_float_array(userdata, \"feedback\", &feedback,\n         &num_feedback, default_feedback, 1);\n   config->get_float(userdata, \"amp\", &echo->amp, 0.2f);\n\n   channels            = num_feedback = num_delay = MIN(num_delay, num_feedback);\n\n   if (!(echo_channels = (struct echo_channel*)calloc(channels,\n         sizeof(*echo_channels))))\n      goto error;\n\n   echo->channels      = echo_channels;\n   echo->num_channels  = channels;\n\n   for (i = 0; i < channels; i++)\n   {\n      unsigned frames  = (unsigned)(delay[i] * info->input_rate / 1000.0f + 0.5f);\n      if (!frames)\n         goto error;\n\n      if (!(echo->channels[i].buffer = (float*)calloc(frames, 2 * sizeof(float))))\n         goto error;\n\n      echo->channels[i].frames   = frames;\n      echo->channels[i].feedback = feedback[i];\n   }\n\n   config->free(delay);\n   config->free(feedback);\n   return echo;\n\nerror:\n   config->free(delay);\n   config->free(feedback);\n   echo_free(echo);\n   return NULL;\n}\n\nstatic const struct dspfilter_implementation echo_plug = {\n   echo_init,\n   echo_process,\n   echo_free,\n\n   DSPFILTER_API_VERSION,\n   \"Multi-Echo\",\n   \"echo\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation echo_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &echo_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/eq.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (eq.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_inline.h>\n#include <retro_miscellaneous.h>\n#include <filters.h>\n#include <libretro_dspfilter.h>\n\n#include \"fft/fft.c\"\n\nstruct eq_data\n{\n   fft_t *fft;\n   float *save;\n   float *block;\n   fft_complex_t *filter;\n   fft_complex_t *fftblock;\n   float buffer[8 * 1024];\n   unsigned block_size;\n   unsigned block_ptr;\n};\n\nstruct eq_gain\n{\n   float freq;\n   float gain; /* Linear. */\n};\n\nstatic void eq_free(void *data)\n{\n   struct eq_data *eq = (struct eq_data*)data;\n   if (!eq)\n      return;\n\n   fft_free(eq->fft);\n   free(eq->save);\n   free(eq->block);\n   free(eq->fftblock);\n   free(eq->filter);\n   free(eq);\n}\n\nstatic void eq_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   float *out;\n   const float *in;\n   unsigned input_frames;\n   struct eq_data *eq = (struct eq_data*)data;\n\n   output->samples    = eq->buffer;\n   output->frames     = 0;\n\n   out                = eq->buffer;\n   in                 = input->samples;\n   input_frames       = input->frames;\n\n   while (input_frames)\n   {\n      unsigned write_avail = eq->block_size - eq->block_ptr;\n\n      if (input_frames < write_avail)\n         write_avail = input_frames;\n\n      memcpy(eq->block + eq->block_ptr * 2, in, write_avail * 2 * sizeof(float));\n\n      in            += write_avail * 2;\n      input_frames  -= write_avail;\n      eq->block_ptr += write_avail;\n\n      /* Convolve a new block. */\n      if (eq->block_ptr == eq->block_size)\n      {\n         unsigned i, c;\n\n         for (c = 0; c < 2; c++)\n         {\n            fft_process_forward(eq->fft, eq->fftblock, eq->block + c, 2);\n            for (i = 0; i < 2 * eq->block_size; i++)\n               eq->fftblock[i] = fft_complex_mul(eq->fftblock[i], eq->filter[i]);\n            fft_process_inverse(eq->fft, out + c, eq->fftblock, 2);\n         }\n\n         /* Overlap add method, so add in saved block now. */\n         for (i = 0; i < 2 * eq->block_size; i++)\n            out[i]      += eq->save[i];\n\n         /* Save block for later. */\n         memcpy(eq->save, out + 2 * eq->block_size, 2 * eq->block_size * sizeof(float));\n\n         out            += eq->block_size * 2;\n         output->frames += eq->block_size;\n         eq->block_ptr   = 0;\n      }\n   }\n}\n\nstatic int gains_cmp(const void *a_, const void *b_)\n{\n   const struct eq_gain *a = (const struct eq_gain*)a_;\n   const struct eq_gain *b = (const struct eq_gain*)b_;\n   if (a->freq < b->freq)\n      return -1;\n   if (a->freq > b->freq)\n      return 1;\n   return 0;\n}\n\nstatic void generate_response(fft_complex_t *response,\n      const struct eq_gain *gains, unsigned num_gains, unsigned samples)\n{\n   unsigned i;\n\n   float start_freq = 0.0f;\n   float start_gain = 1.0f;\n\n   float end_freq   = 1.0f;\n   float end_gain   = 1.0f;\n\n   if (num_gains)\n   {\n      end_freq = gains->freq;\n      end_gain = gains->gain;\n      num_gains--;\n      gains++;\n   }\n\n   /* Create a response by linear interpolation between\n    * known frequency sample points. */\n   for (i = 0; i <= samples; i++)\n   {\n      float gain;\n      float lerp = 0.5f;\n      float freq = (float)i / samples;\n\n      while (freq >= end_freq)\n      {\n         if (num_gains)\n         {\n            start_freq = end_freq;\n            start_gain = end_gain;\n            end_freq = gains->freq;\n            end_gain = gains->gain;\n\n            gains++;\n            num_gains--;\n         }\n         else\n         {\n            start_freq = end_freq;\n            start_gain = end_gain;\n            end_freq = 1.0f;\n            end_gain = 1.0f;\n            break;\n         }\n      }\n\n      /* Edge case where i == samples. */\n      if (end_freq > start_freq)\n         lerp = (freq - start_freq) / (end_freq - start_freq);\n      gain = (1.0f - lerp) * start_gain + lerp * end_gain;\n\n      response[i].real               = gain;\n      response[i].imag               = 0.0f;\n      response[2 * samples - i].real = gain;\n      response[2 * samples - i].imag = 0.0f;\n   }\n}\n\nstatic void create_filter(struct eq_data *eq, unsigned size_log2,\n      struct eq_gain *gains, unsigned num_gains, double beta, const char *filter_path)\n{\n   int i;\n   int half_block_size = eq->block_size >> 1;\n   double window_mod   = 1.0 / kaiser_window_function(0.0, beta);\n   fft_t *fft          = fft_new(size_log2);\n   float *time_filter  = (float*)calloc(eq->block_size * 2 + 1, sizeof(*time_filter));\n   if (!fft || !time_filter)\n      goto end;\n\n   /* Make sure bands are in correct order. */\n   qsort(gains, num_gains, sizeof(*gains), gains_cmp);\n\n   /* Compute desired filter response. */\n   generate_response(eq->filter, gains, num_gains, half_block_size);\n\n   /* Get equivalent time-domain filter. */\n   fft_process_inverse(fft, time_filter, eq->filter, 1);\n\n   /* ifftshift() to create the correct linear phase filter.\n    * The filter response was designed with zero phase, which\n    * won't work unless we compensate\n    * for the repeating property of the FFT here\n    * by flipping left and right blocks. */\n   for (i = 0; i < half_block_size; i++)\n   {\n      float tmp = time_filter[i + half_block_size];\n      time_filter[i + half_block_size] = time_filter[i];\n      time_filter[i] = tmp;\n   }\n\n   /* Apply a window to smooth out the frequency response. */\n   for (i = 0; i < (int)eq->block_size; i++)\n   {\n      /* Kaiser window. */\n      double phase    = (double)i / eq->block_size;\n      phase           = 2.0 * (phase - 0.5);\n      time_filter[i] *= window_mod * kaiser_window_function(phase, beta);\n   }\n\n#ifdef DEBUG\n   /* Debugging. */\n   if (filter_path)\n   {\n      FILE *file = fopen(filter_path, \"w\");\n      if (file)\n      {\n         for (i = 0; i < (int)eq->block_size - 1; i++)\n            fprintf(file, \"%.8f\\n\", time_filter[i + 1]);\n         fclose(file);\n      }\n   }\n#endif\n\n   /* Padded FFT to create our FFT filter.\n    * Make our even-length filter odd by discarding the first coefficient.\n    * For some interesting reason, this allows us to design an odd-length linear phase filter.\n    */\n   fft_process_forward(eq->fft, eq->filter, time_filter + 1, 1);\n\nend:\n   fft_free(fft);\n   free(time_filter);\n}\n\nstatic void *eq_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   int size_log2;\n   float beta;\n   float *frequencies, *gain;\n   unsigned num_freq, num_gain, i, size;\n   struct eq_gain *gains      = NULL;\n   char *filter_path          = NULL;\n   const float default_freq[] = { 0.0f, info->input_rate };\n   const float default_gain[] = { 0.0f, 0.0f };\n   struct eq_data *eq         = (struct eq_data*)calloc(1, sizeof(*eq));\n   if (!eq)\n      return NULL;\n\n   config->get_float(userdata, \"window_beta\", &beta, 4.0f);\n\n   config->get_int(userdata, \"block_size_log2\", &size_log2, 8);\n   size = 1 << size_log2;\n\n   config->get_float_array(userdata, \"frequencies\", &frequencies, &num_freq, default_freq, 2);\n   config->get_float_array(userdata, \"gains\", &gain, &num_gain, default_gain, 2);\n\n   if (!config->get_string(userdata, \"impulse_response_output\", &filter_path, \"\"))\n   {\n      config->free(filter_path);\n      filter_path = NULL;\n   }\n\n   num_gain = num_freq = MIN(num_gain, num_freq);\n\n   if (!(gains = (struct eq_gain*)calloc(num_gain, sizeof(*gains))))\n      goto error;\n\n   for (i = 0; i < num_gain; i++)\n   {\n      gains[i].freq = frequencies[i] / (0.5f * info->input_rate);\n      gains[i].gain = pow(10.0, gain[i] / 20.0);\n   }\n   config->free(frequencies);\n   config->free(gain);\n\n   eq->block_size = size;\n\n   eq->save       = (float*)calloc(    size, 2 * sizeof(*eq->save));\n   eq->block      = (float*)calloc(2 * size, 2 * sizeof(*eq->block));\n   eq->fftblock   = (fft_complex_t*)calloc(2 * size, sizeof(*eq->fftblock));\n   eq->filter     = (fft_complex_t*)calloc(2 * size, sizeof(*eq->filter));\n\n   /* Use an FFT which is twice the block size with zero-padding\n    * to make circular convolution => proper convolution.\n    */\n   eq->fft        = fft_new(size_log2 + 1);\n\n   if (!eq->fft || !eq->fftblock || !eq->save || !eq->block || !eq->filter)\n      goto error;\n\n   create_filter(eq, size_log2, gains, num_gain, beta, filter_path);\n   config->free(filter_path);\n   filter_path = NULL;\n\n   free(gains);\n   return eq;\n\nerror:\n   free(gains);\n   eq_free(eq);\n   return NULL;\n}\n\nstatic const struct dspfilter_implementation eq_plug = {\n   eq_init,\n   eq_process,\n   eq_free,\n\n   DSPFILTER_API_VERSION,\n   \"Linear-Phase FFT Equalizer\",\n   \"eq\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation eq_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &eq_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/fft/fft.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fft.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n\n#include \"fft.h\"\n\n#include <retro_miscellaneous.h>\n\nstruct fft\n{\n   fft_complex_t *interleave_buffer;\n   fft_complex_t *phase_lut;\n   unsigned *bitinverse_buffer;\n   unsigned size;\n};\n\nstatic unsigned bitswap(unsigned x, unsigned size_log2)\n{\n   unsigned i;\n   unsigned ret = 0;\n   for (i = 0; i < size_log2; i++)\n      ret |= ((x >> i) & 1) << (size_log2 - i - 1);\n   return ret;\n}\n\nstatic void build_bitinverse(unsigned *bitinverse, unsigned size_log2)\n{\n   unsigned i;\n   unsigned size = 1 << size_log2;\n   for (i = 0; i < size; i++)\n      bitinverse[i] = bitswap(i, size_log2);\n}\n\nstatic fft_complex_t exp_imag(double phase)\n{\n   fft_complex_t out = { cos(phase), sin(phase) };\n   return out;\n}\n\nstatic void build_phase_lut(fft_complex_t *out, int size)\n{\n   int i;\n   out += size;\n   for (i = -size; i <= size; i++)\n      out[i] = exp_imag((M_PI * i) / size);\n}\n\nstatic void interleave_complex(const unsigned *bitinverse,\n      fft_complex_t *out, const fft_complex_t *in,\n      unsigned samples, unsigned step)\n{\n   unsigned i;\n   for (i = 0; i < samples; i++, in += step)\n      out[bitinverse[i]] = *in;\n}\n\nstatic void interleave_float(const unsigned *bitinverse,\n      fft_complex_t *out, const float *in,\n      unsigned samples, unsigned step)\n{\n   unsigned i;\n   for (i = 0; i < samples; i++, in += step)\n   {\n      unsigned inv_i = bitinverse[i];\n      out[inv_i].real = *in;\n      out[inv_i].imag = 0.0f;\n   }\n}\n\nstatic void resolve_float(float *out, const fft_complex_t *in, unsigned samples,\n      float gain, unsigned step)\n{\n   unsigned i;\n   for (i = 0; i < samples; i++, in++, out += step)\n      *out = gain * in->real;\n}\n\nfft_t *fft_new(unsigned block_size_log2)\n{\n   unsigned size;\n   fft_t *fft = (fft_t*)calloc(1, sizeof(*fft));\n   if (!fft)\n      return NULL;\n\n   size                   = 1 << block_size_log2;\n   fft->interleave_buffer = (fft_complex_t*)calloc(size, sizeof(*fft->interleave_buffer));\n   fft->bitinverse_buffer = (unsigned*)calloc(size, sizeof(*fft->bitinverse_buffer));\n   fft->phase_lut         = (fft_complex_t*)calloc(2 * size + 1, sizeof(*fft->phase_lut));\n\n   if (!fft->interleave_buffer || !fft->bitinverse_buffer || !fft->phase_lut)\n      goto error;\n\n   fft->size = size;\n\n   build_bitinverse(fft->bitinverse_buffer, block_size_log2);\n   build_phase_lut(fft->phase_lut, size);\n   return fft;\n\nerror:\n   fft_free(fft);\n   return NULL;\n}\n\nvoid fft_free(fft_t *fft)\n{\n   if (!fft)\n      return;\n\n   free(fft->interleave_buffer);\n   free(fft->bitinverse_buffer);\n   free(fft->phase_lut);\n   free(fft);\n}\n\nstatic void butterfly(fft_complex_t *a, fft_complex_t *b, fft_complex_t mod)\n{\n   mod = fft_complex_mul(mod, *b);\n   *b  = fft_complex_sub(*a, mod);\n   *a  = fft_complex_add(*a, mod);\n}\n\nstatic void butterflies(fft_complex_t *butterfly_buf,\n      const fft_complex_t *phase_lut,\n      int phase_dir, unsigned step_size, unsigned samples)\n{\n   unsigned i, j;\n   for (i = 0; i < samples; i += step_size << 1)\n   {\n      int phase_step = (int)samples * phase_dir / (int)step_size;\n      for (j = i; j < i + step_size; j++)\n         butterfly(&butterfly_buf[j], &butterfly_buf[j + step_size],\n               phase_lut[phase_step * (int)(j - i)]);\n   }\n}\n\nvoid fft_process_forward_complex(fft_t *fft,\n      fft_complex_t *out, const fft_complex_t *in, unsigned step)\n{\n   unsigned step_size;\n   unsigned samples = fft->size;\n   interleave_complex(fft->bitinverse_buffer, out, in, samples, step);\n\n   for (step_size = 1; step_size < samples; step_size <<= 1)\n   {\n      butterflies(out,\n            fft->phase_lut + samples,\n            -1, step_size, samples);\n   }\n}\n\nvoid fft_process_forward(fft_t *fft,\n      fft_complex_t *out, const float *in, unsigned step)\n{\n   unsigned step_size;\n   unsigned samples = fft->size;\n   interleave_float(fft->bitinverse_buffer, out, in, samples, step);\n\n   for (step_size = 1; step_size < fft->size; step_size <<= 1)\n   {\n      butterflies(out,\n            fft->phase_lut + samples,\n            -1, step_size, samples);\n   }\n}\n\nvoid fft_process_inverse(fft_t *fft,\n      float *out, const fft_complex_t *in, unsigned step)\n{\n   unsigned step_size;\n   unsigned samples = fft->size;\n\n   interleave_complex(fft->bitinverse_buffer, fft->interleave_buffer,\n         in, samples, 1);\n\n   for (step_size = 1; step_size < samples; step_size <<= 1)\n   {\n      butterflies(fft->interleave_buffer,\n            fft->phase_lut + samples,\n            1, step_size, samples);\n   }\n\n   resolve_float(out, fft->interleave_buffer, samples, 1.0f / samples, step);\n}\n"
  },
  {
    "path": "audio/dsp_filters/fft/fft.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fft.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef RARCH_FFT_H__\n#define RARCH_FFT_H__\n\n#include <retro_inline.h>\n#include <math/complex.h>\n\ntypedef struct fft fft_t;\n\nfft_t *fft_new(unsigned block_size_log2);\n\nvoid fft_free(fft_t *fft);\n\nvoid fft_process_forward_complex(fft_t *fft,\n      fft_complex_t *out, const fft_complex_t *in, unsigned step);\n\nvoid fft_process_forward(fft_t *fft,\n      fft_complex_t *out, const float *in, unsigned step);\n\nvoid fft_process_inverse(fft_t *fft,\n      float *out, const fft_complex_t *in, unsigned step);\n\n#endif\n"
  },
  {
    "path": "audio/dsp_filters/iir.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (iir.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\n#define sqr(a) ((a) * (a))\n\n/* filter types */\nenum IIRFilter\n{\n   LPF,        /* low pass filter */\n   HPF,        /* High pass filter */\n   BPCSGF,     /* band pass filter 1 */\n   BPZPGF,     /* band pass filter 2 */\n   APF,        /* Allpass filter*/\n   NOTCH,      /* Notch Filter */\n   RIAA_phono, /* RIAA record/tape deemphasis */\n   PEQ,        /* Peaking band EQ filter */\n   BBOOST,     /* Bassboost filter */\n   LSH,        /* Low shelf filter */\n   HSH,        /* High shelf filter */\n   RIAA_CD     /* CD de-emphasis */\n};\n\nstruct iir_data\n{\n   float b0, b1, b2;\n   float a0, a1, a2;\n\n   struct\n   {\n      float xn1, xn2;\n      float yn1, yn2;\n   } l, r;\n};\n\nstatic void iir_free(void *data)\n{\n   free(data);\n}\n\nstatic void iir_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   struct iir_data *iir = (struct iir_data*)data;\n   float *out           = output->samples;\n\n   float b0             = iir->b0;\n   float b1             = iir->b1;\n   float b2             = iir->b2;\n   float a0             = iir->a0;\n   float a1             = iir->a1;\n   float a2             = iir->a2;\n\n   float xn1_l          = iir->l.xn1;\n   float xn2_l          = iir->l.xn2;\n   float yn1_l          = iir->l.yn1;\n   float yn2_l          = iir->l.yn2;\n\n   float xn1_r          = iir->r.xn1;\n   float xn2_r          = iir->r.xn2;\n   float yn1_r          = iir->r.yn1;\n   float yn2_r          = iir->r.yn2;\n\n   output->samples      = input->samples;\n   output->frames       = input->frames;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float in_l = out[0];\n      float in_r = out[1];\n\n      float l    = (b0 * in_l + b1 * xn1_l + b2 * xn2_l - a1 * yn1_l - a2 * yn2_l) / a0;\n      float r    = (b0 * in_r + b1 * xn1_r + b2 * xn2_r - a1 * yn1_r - a2 * yn2_r) / a0;\n\n      xn2_l      = xn1_l;\n      xn1_l      = in_l;\n      yn2_l      = yn1_l;\n      yn1_l      = l;\n\n      xn2_r      = xn1_r;\n      xn1_r      = in_r;\n      yn2_r      = yn1_r;\n      yn1_r      = r;\n\n      out[0]     = l;\n      out[1]     = r;\n   }\n\n   iir->l.xn1 = xn1_l;\n   iir->l.xn2 = xn2_l;\n   iir->l.yn1 = yn1_l;\n   iir->l.yn2 = yn2_l;\n\n   iir->r.xn1 = xn1_r;\n   iir->r.xn2 = xn2_r;\n   iir->r.yn1 = yn1_r;\n   iir->r.yn2 = yn2_r;\n}\n\n#define CHECK(x) if (strcmp(str, #x) == 0) return x\nstatic enum IIRFilter str_to_type(const char *str)\n{\n   CHECK(LPF);\n   CHECK(HPF);\n   CHECK(BPCSGF);\n   CHECK(BPZPGF);\n   CHECK(APF);\n   CHECK(NOTCH);\n   CHECK(RIAA_phono);\n   CHECK(PEQ);\n   CHECK(BBOOST);\n   CHECK(LSH);\n   CHECK(HSH);\n   CHECK(RIAA_CD);\n\n   return LPF; /* Fallback. */\n}\n#undef CHECK\n\nstatic void make_poly_from_roots(\n      const double *roots, unsigned num_roots, float *poly)\n{\n   unsigned i, j;\n\n   poly[0] = 1;\n   poly[1] = -roots[0];\n   memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));\n\n   for (i = 1; i < num_roots; i++)\n      for (j = num_roots; j > 0; j--)\n         poly[j] -= poly[j - 1] * roots[i];\n}\n\nstatic void iir_filter_init(struct iir_data *iir,\n      float sample_rate, float freq, float qual, float gain, enum IIRFilter filter_type)\n{\n\tdouble omega = 2.0 * M_PI * freq / sample_rate;\n   double cs    = cos(omega);\n   double sn    = sin(omega);\n   double a1pha = sn / (2.0 * qual);\n   double A     = exp(log(10.0) * gain / 40.0);\n   double beta  = sqrt(A + A);\n\n   float b0     = 0.0, b1 = 0.0, b2 = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0;\n\n   /* Set up filter coefficients according to type */\n   switch (filter_type)\n   {\n      case LPF:\n         b0 =  (1.0 - cs) / 2.0;\n         b1 =   1.0 - cs ;\n         b2 =  (1.0 - cs) / 2.0;\n         a0 =   1.0 + a1pha;\n         a1 =  -2.0 * cs;\n         a2 =   1.0 - a1pha;\n         break;\n      case HPF:\n         b0 =  (1.0 + cs) / 2.0;\n         b1 = -(1.0 + cs);\n         b2 =  (1.0 + cs) / 2.0;\n         a0 =   1.0 + a1pha;\n         a1 =  -2.0 * cs;\n         a2 =   1.0 - a1pha;\n         break;\n      case APF:\n         b0 =  1.0 - a1pha;\n         b1 = -2.0 * cs;\n         b2 =  1.0 + a1pha;\n         a0 =  1.0 + a1pha;\n         a1 = -2.0 * cs;\n         a2 =  1.0 - a1pha;\n         break;\n      case BPZPGF:\n         b0 =  a1pha;\n         b1 =  0.0;\n         b2 = -a1pha;\n         a0 =  1.0 + a1pha;\n         a1 = -2.0 * cs;\n         a2 =  1.0 - a1pha;\n         break;\n      case BPCSGF:\n         b0 =  sn / 2.0;\n         b1 =  0.0;\n         b2 = -sn / 2.0;\n         a0 =  1.0 + a1pha;\n         a1 = -2.0 * cs;\n         a2 =  1.0 - a1pha;\n         break;\n      case NOTCH:\n         b0 =  1.0;\n         b1 = -2.0 * cs;\n         b2 =  1.0;\n         a0 =  1.0 + a1pha;\n         a1 = -2.0 * cs;\n         a2 =  1.0 - a1pha;\n         break;\n      case RIAA_phono: /* http://www.dsprelated.com/showmessage/73300/3.php */\n      {\n         double y, b_re, a_re, b_im, a_im, g;\n         float b[3] = {0.0f};\n         float a[3] = {0.0f};\n\n         if ((int)sample_rate == 44100)\n         {\n            static const double zeros[] = {-0.2014898, 0.9233820};\n            static const double poles[] = {0.7083149, 0.9924091};\n            make_poly_from_roots(zeros, 2, b);\n            make_poly_from_roots(poles, 2, a);\n         }\n         else if ((int)sample_rate == 48000)\n         {\n            static const double zeros[] = {-0.1766069, 0.9321590};\n            static const double poles[] = {0.7396325, 0.9931330};\n            make_poly_from_roots(zeros, 2, b);\n            make_poly_from_roots(poles, 2, a);\n         }\n         else if ((int)sample_rate == 88200)\n         {\n            static const double zeros[] = {-0.1168735, 0.9648312};\n            static const double poles[] = {0.8590646, 0.9964002};\n            make_poly_from_roots(zeros, 2, b);\n            make_poly_from_roots(poles, 2, a);\n         }\n         else if ((int)sample_rate == 96000)\n         {\n            static const double zeros[] = {-0.1141486, 0.9676817};\n            static const double poles[] = {0.8699137, 0.9966946};\n            make_poly_from_roots(zeros, 2, b);\n            make_poly_from_roots(poles, 2, a);\n         }\n\n         b0    = b[0];\n         b1    = b[1];\n         b2    = b[2];\n         a0    = a[0];\n         a1    = a[1];\n         a2    = a[2];\n\n         /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */\n         y     = 2.0 * M_PI * 1000.0 / sample_rate;\n         b_re  = b0 + b1 * cos(-y) + b2 * cos(-2.0 * y);\n         a_re  = a0 + a1 * cos(-y) + a2 * cos(-2.0 * y);\n         b_im  = b1 * sin(-y) + b2 * sin(-2.0 * y);\n         a_im  = a1 * sin(-y) + a2 * sin(-2.0 * y);\n         g     = 1.0 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));\n         b0   *= g; b1 *= g; b2 *= g;\n         break;\n      }\n      case PEQ:\n         b0 =  1.0 + a1pha * A;\n         b1 = -2.0 * cs;\n         b2 =  1.0 - a1pha * A;\n         a0 =  1.0 + a1pha / A;\n         a1 = -2.0 * cs;\n         a2 =  1.0 - a1pha / A;\n         break;\n      case BBOOST:\n         beta = sqrt((A * A + 1) / 1.0 - (pow((A - 1), 2)));\n         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);\n         b1 = 2 * A * ((A - 1) - (A + 1) * cs);\n         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);\n         a0 = ((A + 1) + (A - 1) * cs + beta * sn);\n         a1 = -2 * ((A - 1) + (A + 1) * cs);\n         a2 = (A + 1) + (A - 1) * cs - beta * sn;\n         break;\n      case LSH:\n         b0 = A * ((A + 1) - (A - 1) * cs + beta * sn);\n         b1 = 2 * A * ((A - 1) - (A + 1) * cs);\n         b2 = A * ((A + 1) - (A - 1) * cs - beta * sn);\n         a0 = (A + 1) + (A - 1) * cs + beta * sn;\n         a1 = -2 * ((A - 1) + (A + 1) * cs);\n         a2 = (A + 1) + (A - 1) * cs - beta * sn;\n         break;\n      case RIAA_CD:\n         omega = 2.0 * M_PI * 5283.0 / sample_rate;\n         cs = cos(omega);\n         sn = sin(omega);\n         a1pha = sn / (2.0 * 0.4845);\n         A = exp(log(10.0) * -9.477 / 40.0);\n         beta = sqrt(A + A);\n         (void)a1pha;\n      case HSH:\n         b0 = A * ((A + 1.0) + (A - 1.0) * cs + beta * sn);\n         b1 = -2.0 * A * ((A - 1.0) + (A + 1.0) * cs);\n         b2 = A * ((A + 1.0) + (A - 1.0) * cs - beta * sn);\n         a0 = (A + 1.0) - (A - 1.0) * cs + beta * sn;\n         a1 = 2.0 * ((A - 1.0) - (A + 1.0) * cs);\n         a2 = (A + 1.0) - (A - 1.0) * cs - beta * sn;\n         break;\n      default:\n         break;\n   }\n\n   iir->b0 = b0;\n   iir->b1 = b1;\n   iir->b2 = b2;\n   iir->a0 = a0;\n   iir->a1 = a1;\n   iir->a2 = a2;\n}\n\nstatic void *iir_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   float freq, qual, gain;\n   enum IIRFilter filter  = LPF;\n   char           *type   = NULL;\n   struct iir_data *iir   = (struct iir_data*)calloc(1, sizeof(*iir));\n   if (!iir)\n      return NULL;\n\n   config->get_float(userdata, \"frequency\", &freq, 1024.0f);\n   config->get_float(userdata, \"quality\", &qual, 0.707f);\n   config->get_float(userdata, \"gain\", &gain, 0.0f);\n\n   config->get_string(userdata, \"type\", &type, \"LPF\");\n\n   filter = str_to_type(type);\n   config->free(type);\n\n   iir_filter_init(iir, info->input_rate, freq, qual, gain, filter);\n   return iir;\n}\n\nstatic const struct dspfilter_implementation iir_plug = {\n   iir_init,\n   iir_process,\n   iir_free,\n\n   DSPFILTER_API_VERSION,\n   \"IIR\",\n   \"iir\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation iir_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &iir_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/link.T",
    "content": "{\n  global: dspfilter_get_implementation;\n  local: *;\n};\n"
  },
  {
    "path": "audio/dsp_filters/panning.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (panning.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <libretro_dspfilter.h>\n\nstruct panning_data\n{\n   float left[2];\n   float right[2];\n};\n\nstatic void panning_free(void *data)\n{\n   free(data);\n}\n\nstatic void panning_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   struct panning_data *pan = (struct panning_data*)data;\n   float *out               = output->samples;\n\n   output->samples          = input->samples;\n   output->frames           = input->frames;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float left  = out[0];\n      float right = out[1];\n      out[0]      = left * pan->left[0]  + right * pan->left[1];\n      out[1]      = left * pan->right[0] + right * pan->right[1];\n   }\n}\n\nstatic void *panning_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   static const float default_left[]  = { 1.0f, 0.0f };\n   static const float default_right[] = { 0.0f, 1.0f };\n   float *left                        = NULL;\n   float *right                       = NULL;\n   unsigned num_left                  = 0;\n   unsigned num_right                 = 0;\n   struct panning_data *pan           = (struct panning_data*)\n      calloc(1, sizeof(*pan));\n\n   if (!pan)\n      return NULL;\n\n   config->get_float_array(userdata, \"left_mix\",\n         &left, &num_left, default_left, 2);\n   config->get_float_array(userdata, \"right_mix\",\n         &right, &num_right, default_right, 2);\n\n   memcpy(pan->left,  (num_left  == 2) ?\n         left :  default_left,  sizeof(pan->left));\n   memcpy(pan->right, (num_right == 2) ?\n         right : default_right, sizeof(pan->right));\n\n   config->free(left);\n   config->free(right);\n\n   return pan;\n}\n\nstatic const struct dspfilter_implementation panning = {\n   panning_init,\n   panning_process,\n   panning_free,\n\n   DSPFILTER_API_VERSION,\n   \"Panning\",\n   \"panning\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation panning_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *\ndspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &panning;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/phaser.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (phaser.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\n#define PHASER_LFO_SHAPE 4.0\n#define PHASER_LFO_SKIP_SAMPLES 20\n\nstruct phaser_data\n{\n   float freq;\n   float startphase;\n   float fb;\n   float depth;\n   float drywet;\n   float old[2][24];\n   float gain;\n   float fbout[2];\n   float lfoskip;\n   float phase;\n\n   int stages;\n   unsigned long skipcount;\n};\n\nstatic void phaser_free(void *data)\n{\n   free(data);\n}\n\nstatic void phaser_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i, c;\n   int s;\n   float m[2], tmp[2];\n   struct phaser_data *ph = (struct phaser_data*)data;\n   float *out             = output->samples;\n\n   output->samples        = input->samples;\n   output->frames         = input->frames;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float in[2] = { out[0], out[1] };\n\n      for (c = 0; c < 2; c++)\n         m[c] = in[c] + ph->fbout[c] * ph->fb * 0.01f;\n\n      if ((ph->skipcount++ % PHASER_LFO_SKIP_SAMPLES) == 0)\n      {\n         ph->gain = 0.5 * (1.0 + cos(ph->skipcount * ph->lfoskip + ph->phase));\n         ph->gain = (exp(ph->gain * PHASER_LFO_SHAPE) - 1.0) / (exp(PHASER_LFO_SHAPE) - 1);\n         ph->gain = 1.0 - ph->gain * ph->depth;\n      }\n\n      for (s = 0; s < ph->stages; s++)\n      {\n         for (c = 0; c < 2; c++)\n         {\n            tmp[c] = ph->old[c][s];\n            ph->old[c][s] = ph->gain * tmp[c] + m[c];\n            m[c] = tmp[c] - ph->gain * ph->old[c][s];\n         }\n      }\n\n      for (c = 0; c < 2; c++)\n      {\n         ph->fbout[c] = m[c];\n         out[c] = m[c] * ph->drywet + in[c] * (1.0f - ph->drywet);\n      }\n   }\n}\n\nstatic void *phaser_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   float lfo_freq, lfo_start_phase;\n   struct phaser_data *ph = (struct phaser_data*)calloc(1, sizeof(*ph));\n   if (!ph)\n      return NULL;\n\n   config->get_float(userdata, \"lfo_freq\", &lfo_freq, 0.4f);\n   config->get_float(userdata, \"lfo_start_phase\", &lfo_start_phase, 0.0f);\n   config->get_float(userdata, \"feedback\", &ph->fb, 0.0f);\n   config->get_float(userdata, \"depth\", &ph->depth, 0.4f);\n   config->get_float(userdata, \"dry_wet\", &ph->drywet, 0.5f);\n   config->get_int(userdata, \"stages\", &ph->stages, 2);\n\n   if (ph->stages < 1)\n      ph->stages = 1;\n   else if (ph->stages > 24)\n      ph->stages = 24;\n\n   ph->lfoskip = lfo_freq * 2.0 * M_PI / info->input_rate;\n   ph->phase   = lfo_start_phase * M_PI / 180.0;\n\n   return ph;\n}\n\nstatic const struct dspfilter_implementation phaser_plug = {\n   phaser_init,\n   phaser_process,\n   phaser_free,\n\n   DSPFILTER_API_VERSION,\n   \"Phaser\",\n   \"phaser\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation phaser_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &phaser_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/reverb.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (reverb.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_inline.h>\n#include <libretro_dspfilter.h>\n\nstruct comb\n{\n   float *buffer;\n   unsigned bufsize;\n   unsigned bufidx;\n\n   float feedback;\n   float filterstore;\n   float damp1, damp2;\n};\n\nstruct allpass\n{\n   float *buffer;\n   float feedback;\n   unsigned bufsize;\n   unsigned bufidx;\n};\n\nstatic INLINE float comb_process(struct comb *c, float input)\n{\n   float output         = c->buffer[c->bufidx];\n   c->filterstore       = (output * c->damp2) + (c->filterstore * c->damp1);\n\n   c->buffer[c->bufidx] = input + (c->filterstore * c->feedback);\n\n   c->bufidx++;\n   if (c->bufidx >= c->bufsize)\n      c->bufidx = 0;\n\n   return output;\n}\n\nstatic INLINE float allpass_process(struct allpass *a, float input)\n{\n   float bufout         = a->buffer[a->bufidx];\n   float output         = -input + bufout;\n   a->buffer[a->bufidx] = input + bufout * a->feedback;\n\n   a->bufidx++;\n   if (a->bufidx >= a->bufsize)\n      a->bufidx = 0;\n\n   return output;\n}\n\n#define numcombs 8\n#define numallpasses 4\nstatic const float muted = 0;\nstatic const float fixedgain = 0.015f;\nstatic const float scalewet = 3;\nstatic const float scaledry = 2;\nstatic const float scaledamp = 0.4f;\nstatic const float scaleroom = 0.28f;\nstatic const float offsetroom = 0.7f;\nstatic const float initialroom = 0.5f;\nstatic const float initialdamp = 0.5f;\nstatic const float initialwet = 1.0f / 3.0f;\nstatic const float initialdry = 0;\nstatic const float initialwidth = 1;\nstatic const float initialmode = 0;\nstatic const float freezemode = 0.5f;\n\nstruct revmodel\n{\n   struct comb combL[numcombs];\n   struct allpass allpassL[numallpasses];\n\n   float *bufcomb[numcombs];\n   float *bufallpass[numallpasses];\n\n   float gain;\n   float roomsize, roomsize1;\n   float damp, damp1;\n   float wet, wet1, wet2;\n   float dry;\n   float width;\n   float mode;\n};\n\nstatic float revmodel_process(struct revmodel *rev, float in)\n{\n   unsigned i;\n   float mono_out = 0.0f;\n   float mono_in  = in;\n   float input    = mono_in * rev->gain;\n\n   for (i = 0; i < numcombs; i++)\n      mono_out += comb_process(&rev->combL[i], input);\n\n   for (i = 0; i < numallpasses; i++)\n      mono_out = allpass_process(&rev->allpassL[i], mono_out);\n\n   return mono_in * rev->dry + mono_out * rev->wet1;\n}\n\nstatic void revmodel_update(struct revmodel *rev)\n{\n   unsigned i;\n   rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);\n\n   if (rev->mode >= freezemode)\n   {\n      rev->roomsize1 = 1.0f;\n      rev->damp1 = 0.0f;\n      rev->gain = muted;\n   }\n   else\n   {\n      rev->roomsize1 = rev->roomsize;\n      rev->damp1 = rev->damp;\n      rev->gain = fixedgain;\n   }\n\n   for (i = 0; i < numcombs; i++)\n   {\n      rev->combL[i].feedback = rev->roomsize1;\n      rev->combL[i].damp1 = rev->damp1;\n      rev->combL[i].damp2 = 1.0f - rev->damp1;\n   }\n}\n\nstatic void revmodel_setroomsize(struct revmodel *rev, float value)\n{\n   rev->roomsize = value * scaleroom + offsetroom;\n   revmodel_update(rev);\n}\n\nstatic void revmodel_setdamp(struct revmodel *rev, float value)\n{\n   rev->damp = value * scaledamp;\n   revmodel_update(rev);\n}\n\nstatic void revmodel_setwet(struct revmodel *rev, float value)\n{\n   rev->wet = value * scalewet;\n   revmodel_update(rev);\n}\n\nstatic void revmodel_setdry(struct revmodel *rev, float value)\n{\n   rev->dry = value * scaledry;\n   revmodel_update(rev);\n}\n\nstatic void revmodel_setwidth(struct revmodel *rev, float value)\n{\n   rev->width = value;\n   revmodel_update(rev);\n}\n\nstatic void revmodel_setmode(struct revmodel *rev, float value)\n{\n   rev->mode = value;\n   revmodel_update(rev);\n}\n\nstatic void revmodel_init(struct revmodel *rev,int srate)\n{\n   unsigned c;\n   static const int comb_lengths[8]    = { 1116,1188,1277,1356,1422,1491,1557,1617 };\n   static const int allpass_lengths[4] = { 225,341,441,556 };\n   double r = srate * (1 / 44100.0);\n\n   for (c = 0; c < numcombs; ++c)\n   {\n      unsigned bufsize         = (unsigned)(r * comb_lengths[c]);\n      rev->bufcomb[c]          = (float*)calloc(bufsize, sizeof(float));\n      rev->combL[c].buffer     = rev->bufcomb[c];\n      rev->combL[c].bufsize    = bufsize;\n   }\n\n   for (c = 0; c < numallpasses; ++c)\n   {\n      unsigned bufsize          = (unsigned)(r * allpass_lengths[c]);\n      rev->bufallpass[c]        = (float*)calloc(bufsize, sizeof(float));\n      rev->allpassL[c].buffer   = rev->bufallpass[c];\n      rev->allpassL[c].bufsize  = bufsize;\n      rev->allpassL[c].feedback = 0.5f;\n   }\n\n   revmodel_setwet(rev, initialwet);\n   revmodel_setroomsize(rev, initialroom);\n   revmodel_setdry(rev, initialdry);\n   revmodel_setdamp(rev, initialdamp);\n   revmodel_setwidth(rev, initialwidth);\n   revmodel_setmode(rev, initialmode);\n}\n\nstruct reverb_data\n{\n   struct revmodel left, right;\n};\n\nstatic void reverb_free(void *data)\n{\n   unsigned i;\n   struct reverb_data *rev = (struct reverb_data*)data;\n\n   for (i = 0; i < numcombs; i++)\n   {\n      free(rev->left.bufcomb[i]);\n      free(rev->right.bufcomb[i]);\n   }\n\n   for (i = 0; i < numallpasses; i++)\n   {\n      free(rev->left.bufallpass[i]);\n      free(rev->right.bufallpass[i]);\n   }\n   free(data);\n}\n\nstatic void reverb_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   float *out;\n   struct reverb_data *rev = (struct reverb_data*)data;\n\n   output->samples         = input->samples;\n   output->frames          = input->frames;\n   out                     = output->samples;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float in[2] = { out[0], out[1] };\n\n      out[0] = revmodel_process(&rev->left, in[0]);\n      out[1] = revmodel_process(&rev->right, in[1]);\n   }\n}\n\nstatic void *reverb_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   float drytime, wettime, damping, roomwidth, roomsize;\n   struct reverb_data *rev = (struct reverb_data*)\n      calloc(1, sizeof(*rev));\n   if (!rev)\n      return NULL;\n\n   config->get_float(userdata, \"drytime\", &drytime, 0.43f);\n   config->get_float(userdata, \"wettime\", &wettime, 0.4f);\n   config->get_float(userdata, \"damping\", &damping, 0.8f);\n   config->get_float(userdata, \"roomwidth\", &roomwidth, 0.56f);\n   config->get_float(userdata, \"roomsize\", &roomsize, 0.56f);\n\n   revmodel_init(&rev->left,info->input_rate);\n   revmodel_init(&rev->right,info->input_rate);\n\n   revmodel_setdamp(&rev->left, damping);\n   revmodel_setdry(&rev->left, drytime);\n   revmodel_setwet(&rev->left, wettime);\n   revmodel_setwidth(&rev->left, roomwidth);\n   revmodel_setroomsize(&rev->left, roomsize);\n\n   revmodel_setdamp(&rev->right, damping);\n   revmodel_setdry(&rev->right, drytime);\n   revmodel_setwet(&rev->right, wettime);\n   revmodel_setwidth(&rev->right, roomwidth);\n   revmodel_setroomsize(&rev->right, roomsize);\n\n   return rev;\n}\n\nstatic const struct dspfilter_implementation reverb_plug = {\n   reverb_init,\n   reverb_process,\n   reverb_free,\n\n   DSPFILTER_API_VERSION,\n   \"Reverb\",\n   \"reverb\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation reverb_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &reverb_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/tremolo.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (tremolo.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\n#define sqr(a) ((a) * (a))\n\nstruct tremolo_core\n{\n   float *wavetable;\n   float freq;\n   float depth;\n   unsigned index;\n   unsigned maxindex;\n};\n\nstruct tremolo\n{\n   struct tremolo_core left, right;\n};\n\nstatic void tremolo_free(void *data)\n{\n   struct tremolo *tre = (struct tremolo*)data;\n   free(tre->left.wavetable);\n   free(tre->right.wavetable);\n   free(data);\n}\n\nstatic void tremolocore_init(struct tremolo_core *core,float depth,int samplerate,float freq)\n{\n   double env;\n   unsigned i;\n   const double offset = 1. - depth / 2.;\n   core->index     = 0;\n   core->maxindex  = samplerate / freq;\n   core->wavetable = (float*)malloc(core->maxindex   * sizeof(float));\n   memset(core->wavetable, 0, core->maxindex * sizeof(float));\n   for (i = 0; i < core->maxindex; i++)\n   {\n      env                = freq * i / samplerate;\n      env                = sin((M_PI*2) * fmod(env + 0.25, 1.0));\n      core->wavetable[i] = env * (1 - fabs(offset)) + offset;\n   }\n}\n\nfloat tremolocore_core(struct tremolo_core *core,float in)\n{\n   core->index = core->index % core->maxindex;\n   return in * core->wavetable[core->index++];\n}\n\nstatic void tremolo_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   float *out;\n   struct tremolo *tre = (struct tremolo*)data;\n\n   output->samples     = input->samples;\n   output->frames      = input->frames;\n   out                 = output->samples;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float in[2]      = { out[0], out[1] };\n      out[0]           = tremolocore_core(&tre->left, in[0]);\n      out[1]           = tremolocore_core(&tre->right, in[1]);\n   }\n}\n\nstatic void *tremolo_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   float freq, depth;\n   struct tremolo *tre = (struct tremolo*)calloc(1, sizeof(*tre));\n   if (!tre)\n      return NULL;\n\n   config->get_float(userdata, \"freq\", &freq,4.0f);\n   config->get_float(userdata, \"depth\", &depth, 0.9f);\n   tremolocore_init(&tre->left,depth,info->input_rate,freq);\n   tremolocore_init(&tre->right,depth,info->input_rate,freq);\n   return tre;\n}\n\nstatic const struct dspfilter_implementation tremolo_plug = {\n   tremolo_init,\n   tremolo_process,\n   tremolo_free,\n\n   DSPFILTER_API_VERSION,\n   \"Tremolo\",\n   \"tremolo\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation tremolo_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &tremolo_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/vibrato.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (vibrato.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\n#define sqr(a) ((a) * (a))\n\n#define VIBRATO_BASE_DELAY_SEC 0.002f /* 2 ms */\n#define VIBRATO_FREQUENCY_DEFAULT_HZ 2.0f\n#define VIBRATO_FREQUENCY_MAX_HZ 14.0f\n#define VIBRATO_DEPTH_DEFAULT_PERCENT 50.0f\n#define VIBRATO_ADD_DELAY 3\n\nstatic float hermite_interp(float x, float *y)\n{\n   float c0 = y[1];\n   float c1 = (1.0f / 2.0f) * (y[2] - y[0]);\n   float c2 = (y[0] - (5.0f / 2.0f) * y[1]) + (2.0f * y[2] - (1.0f / 2.0f) * y[3]);\n   float c3 = (1.0f / 2.0f) * (y[3] - y[0]) + (3.0f / 2.0f) * (y[1] - y[2]);\n   return ((c3 * x + c2) * x + c1) * x + c0;\n}\n\nstruct vibrato_core\n{\n   float* buffer;\n   float freq;\n   float samplerate;\n   float depth;\n   int phase;\n   int writeindex;\n   int size;\n};\n\nstruct vibrato\n{\n   struct vibrato_core left, right;\n};\n\nstatic void vibrato_free(void *data)\n{\n   struct vibrato *vib = (struct vibrato*)data;\n   free(vib->left.buffer);\n   free(vib->right.buffer);\n   free(data);\n}\n\nstatic void vibratocore_init(struct vibrato_core *core,float depth,int samplerate,float freq)\n{\n\tcore->size       = VIBRATO_BASE_DELAY_SEC * samplerate * 2;\n\tcore->buffer     = (float*)malloc((core->size + VIBRATO_ADD_DELAY) * sizeof(float));\n\tmemset(core->buffer, 0, (core->size   + VIBRATO_ADD_DELAY) * sizeof(float));\n\tcore->samplerate = samplerate;\n\tcore->freq       = freq;\n\tcore->depth      = depth;\n\tcore->phase      = 0;\n\tcore->writeindex = 0;\n}\n\nfloat vibratocore_core(struct vibrato_core *core,float in)\n{\n   int ipart;\n   float delay, readindex, fpart, value;\n   float M                        = core->freq / core->samplerate;\n   int maxphase                   = core->samplerate / core->freq;\n   float lfo                      = sin(M * 2. * M_PI * core->phase++);\n   int maxdelay                   = VIBRATO_BASE_DELAY_SEC * core->samplerate;\n   core->phase                    = core->phase % maxphase;\n   lfo                            = (lfo + 1) * 1.; /* Transform from [-1; 1] to [0; 1] */\n   delay                          =  lfo * core->depth * maxdelay;\n   delay                         += VIBRATO_ADD_DELAY;\n   readindex                      = core->writeindex - 1 - delay;\n   while (readindex < 0)\n      readindex                  += core->size;\n   while (readindex >= core->size)\n      readindex                  -= core->size;\n   ipart                          = (int)readindex;    /* Integer part of the delay */\n   fpart                          = readindex - ipart; /* fractional part of the delay */\n   value                          = hermite_interp(fpart, &(core->buffer[ipart]));\n   core->buffer[core->writeindex] = in;\n   if (core->writeindex < VIBRATO_ADD_DELAY)\n      core->buffer[core->size + core->writeindex] = in;\n   core->writeindex++;\n   if (core->writeindex == core->size)\n      core->writeindex = 0;\n   return value;\n}\n\nstatic void vibrato_process(void *data,\n      struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   float *out;\n   struct vibrato *vib = (struct vibrato*)data;\n\n   output->samples     = input->samples;\n   output->frames      = input->frames;\n   out                 = output->samples;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float in[2] = { out[0], out[1] };\n      out[0]      = vibratocore_core(&vib->left, in[0]);\n      out[1]      = vibratocore_core(&vib->right, in[1]);\n   }\n}\n\nstatic void *vibrato_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   float freq, depth;\n   struct vibrato *vib = (struct vibrato*)calloc(1, sizeof(*vib));\n   if (!vib)\n      return NULL;\n\n   config->get_float(userdata, \"freq\", &freq,5.0f);\n   config->get_float(userdata, \"depth\", &depth, 0.5f);\n   vibratocore_init(&vib->left,depth,info->input_rate,freq);\n   vibratocore_init(&vib->right,depth,info->input_rate,freq);\n   return vib;\n}\n\nstatic const struct dspfilter_implementation vibrato_plug = {\n   vibrato_init,\n   vibrato_process,\n   vibrato_free,\n\n   DSPFILTER_API_VERSION,\n   \"Vibrato\",\n   \"vibrato\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation vibrato_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   return &vibrato_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/dsp_filters/wahwah.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (wahwah.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_miscellaneous.h>\n#include <libretro_dspfilter.h>\n\n#define WAHWAH_LFO_SKIP_SAMPLES 30\n\nstruct wahwah_data\n{\n   float phase;\n   float lfoskip;\n   float b0, b1, b2, a0, a1, a2;\n   float freq, startphase;\n   float depth, freqofs, res;\n   unsigned long skipcount;\n\n   struct\n   {\n      float xn1, xn2, yn1, yn2;\n   } l, r;\n};\n\nstatic void wahwah_free(void *data)\n{\n   if (data)\n      free(data);\n}\n\nstatic void wahwah_process(void *data, struct dspfilter_output *output,\n      const struct dspfilter_input *input)\n{\n   unsigned i;\n   struct wahwah_data *wah = (struct wahwah_data*)data;\n   float *out              = output->samples;\n\n   output->samples         = input->samples;\n   output->frames          = input->frames;\n\n   for (i = 0; i < input->frames; i++, out += 2)\n   {\n      float out_l, out_r;\n      float in[2] = { out[0], out[1] };\n\n      if ((wah->skipcount++ % WAHWAH_LFO_SKIP_SAMPLES) == 0)\n      {\n         float omega, sn, cs, alpha;\n         float frequency = (1.0f + cos(wah->skipcount * wah->lfoskip + wah->phase)) / 2.0f;\n\n         frequency       = frequency * wah->depth * (1.0f - wah->freqofs) + wah->freqofs;\n         frequency       = exp((frequency - 1.0f) * 6.0f);\n\n         omega           = M_PI * frequency;\n         sn              = sin(omega);\n         cs              = cos(omega);\n         alpha           = sn / (2.0f * wah->res);\n\n         wah->b0         = (1.0f - cs) / 2.0f;\n         wah->b1         = 1.0f  - cs;\n         wah->b2         = (1.0f - cs) / 2.0f;\n         wah->a0         = 1.0f + alpha;\n         wah->a1         = -2.0f * cs;\n         wah->a2         = 1.0f - alpha;\n      }\n\n      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;\n      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;\n\n      wah->l.xn2         = wah->l.xn1;\n      wah->l.xn1         = in[0];\n      wah->l.yn2         = wah->l.yn1;\n      wah->l.yn1         = out_l;\n\n      wah->r.xn2         = wah->r.xn1;\n      wah->r.xn1         = in[1];\n      wah->r.yn2         = wah->r.yn1;\n      wah->r.yn1         = out_r;\n\n      out[0]             = out_l;\n      out[1]             = out_r;\n   }\n}\n\nstatic void *wahwah_init(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata)\n{\n   struct wahwah_data *wah = (struct wahwah_data*)calloc(1, sizeof(*wah));\n   if (!wah)\n      return NULL;\n\n   config->get_float(userdata, \"lfo_freq\", &wah->freq, 1.5f);\n   config->get_float(userdata, \"lfo_start_phase\", &wah->startphase, 0.0f);\n   config->get_float(userdata, \"freq_offset\", &wah->freqofs, 0.3f);\n   config->get_float(userdata, \"depth\", &wah->depth, 0.7f);\n   config->get_float(userdata, \"resonance\", &wah->res, 2.5f);\n\n   wah->lfoskip = wah->freq * 2.0f * M_PI / info->input_rate;\n   wah->phase   = wah->startphase * M_PI / 180.0f;\n\n   return wah;\n}\n\nstatic const struct dspfilter_implementation wahwah_plug = {\n   wahwah_init,\n   wahwah_process,\n   wahwah_free,\n\n   DSPFILTER_API_VERSION,\n   \"Wah-Wah\",\n   \"wahwah\",\n};\n\n#ifdef HAVE_FILTERS_BUILTIN\n#define dspfilter_get_implementation wahwah_dspfilter_get_implementation\n#endif\n\nconst struct dspfilter_implementation *\ndspfilter_get_implementation(dspfilter_simd_mask_t mask)\n{\n   (void)mask;\n   return &wahwah_plug;\n}\n\n#undef dspfilter_get_implementation\n"
  },
  {
    "path": "audio/resampler/audio_resampler.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (audio_resampler.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include <string/stdstring.h>\n#include <features/features_cpu.h>\n#include <file/config_file_userdata.h>\n\n#include <audio/audio_resampler.h>\n\nstatic void resampler_null_process(void *a, struct resampler_data *b) { }\nstatic void resampler_null_free(void *a) { }\nstatic void *resampler_null_init(const struct resampler_config *a, double b,\n      enum resampler_quality c, resampler_simd_mask_t d) { return (void*)0; }\n\nretro_resampler_t null_resampler = {\n   resampler_null_init,\n   resampler_null_process,\n   resampler_null_free,\n   RESAMPLER_API_VERSION,\n   \"null\",\n   \"null\"\n};\n\nstatic const retro_resampler_t *resampler_drivers[] = {\n   &sinc_resampler,\n#ifdef HAVE_CC_RESAMPLER\n   &CC_resampler,\n#endif\n#ifdef HAVE_NEAREST_RESAMPLER\n   &nearest_resampler,\n#endif\n   &null_resampler,\n   NULL,\n};\n\nstatic const struct resampler_config resampler_config = {\n   config_userdata_get_float,\n   config_userdata_get_int,\n   config_userdata_get_float_array,\n   config_userdata_get_int_array,\n   config_userdata_get_string,\n   config_userdata_free,\n};\n\n/**\n * find_resampler_driver_index:\n * @ident                      : Identifier of resampler driver to find.\n *\n * Finds resampler driver index by @ident name.\n *\n * Returns: resampler driver index if resampler driver was found, otherwise\n * -1.\n **/\nstatic int find_resampler_driver_index(const char *ident)\n{\n   unsigned i;\n\n   for (i = 0; resampler_drivers[i]; i++)\n      if (string_is_equal_noncase(ident, resampler_drivers[i]->ident))\n         return i;\n   return -1;\n}\n\n/**\n * find_resampler_driver:\n * @ident                      : Identifier of resampler driver to find.\n *\n * Finds resampler by @ident name.\n *\n * Returns: resampler driver if resampler driver was found, otherwise\n * NULL.\n **/\nstatic const retro_resampler_t *find_resampler_driver(const char *ident)\n{\n   int i = find_resampler_driver_index(ident);\n\n   if (i >= 0)\n      return resampler_drivers[i];\n\n   return resampler_drivers[0];\n}\n\n/**\n * resampler_append_plugs:\n * @re                         : Resampler handle\n * @backend                    : Resampler backend that is about to be set.\n * @bw_ratio                   : Bandwidth ratio.\n *\n * Initializes resampler driver based on queried CPU features.\n *\n * Returns: true (1) if successfully initialized, otherwise false (0).\n **/\nstatic bool resampler_append_plugs(void **re,\n      const retro_resampler_t **backend,\n      enum resampler_quality quality,\n      double bw_ratio)\n{\n   resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();\n\n   if (*backend)\n      *re = (*backend)->init(&resampler_config, bw_ratio, quality, mask);\n\n   if (!*re)\n      return false;\n   return true;\n}\n\n\n/**\n * audio_resampler_driver_find_handle:\n * @idx                : index of driver to get handle to.\n *\n * Returns: handle to audio resampler driver at index. Can be NULL\n * if nothing found.\n **/\nconst void *audio_resampler_driver_find_handle(int idx)\n{\n   const void *drv = resampler_drivers[idx];\n   if (!drv)\n      return NULL;\n   return drv;\n}\n\n/**\n * audio_resampler_driver_find_ident:\n * @idx                : index of driver to get handle to.\n *\n * Returns: Human-readable identifier of audio resampler driver at index.\n * Can be NULL if nothing found.\n **/\nconst char *audio_resampler_driver_find_ident(int idx)\n{\n   const retro_resampler_t *drv = resampler_drivers[idx];\n   if (!drv)\n      return NULL;\n   return drv->ident;\n}\n\n/**\n * retro_resampler_realloc:\n * @re                         : Resampler handle\n * @backend                    : Resampler backend that is about to be set.\n * @ident                      : Identifier name for resampler we want.\n * @bw_ratio                   : Bandwidth ratio.\n *\n * Reallocates resampler. Will free previous handle before\n * allocating a new one. If ident is NULL, first resampler will be used.\n *\n * Returns: true (1) if successful, otherwise false (0).\n **/\nbool retro_resampler_realloc(void **re, const retro_resampler_t **backend,\n      const char *ident, enum resampler_quality quality, double bw_ratio)\n{\n   if (*re && *backend)\n      (*backend)->free(*re);\n\n   *re      = NULL;\n   *backend = find_resampler_driver(ident);\n\n   if (!resampler_append_plugs(re, backend, quality, bw_ratio))\n   {\n      if (!*re)\n         *backend = NULL;\n      return false;\n   }\n\n   return true;\n}\n"
  },
  {
    "path": "audio/resampler/drivers/nearest_resampler.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nearest_resampler.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <math.h>\n\n#include <audio/audio_resampler.h>\n\ntypedef struct rarch_nearest_resampler\n{\n   float fraction;\n} rarch_nearest_resampler_t;\n\nstatic void resampler_nearest_process(\n      void *re_, struct resampler_data *data)\n{\n   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;\n   audio_frame_float_t  *inp     = (audio_frame_float_t*)data->data_in;\n   audio_frame_float_t  *inp_max = (audio_frame_float_t*)inp + data->input_frames;\n   audio_frame_float_t  *outp    = (audio_frame_float_t*)data->data_out;\n   float                   ratio = 1.0 / data->ratio;\n\n   while (inp != inp_max)\n   {\n      while (re->fraction > 1)\n      {\n         *outp++       = *inp;\n         re->fraction -= ratio;\n      }\n      re->fraction++;\n      inp++;\n   }\n\n   data->output_frames = (outp - (audio_frame_float_t*)data->data_out);\n}\n\nstatic void resampler_nearest_free(void *re_)\n{\n   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)re_;\n   if (re)\n      free(re);\n}\n\nstatic void *resampler_nearest_init(const struct resampler_config *config,\n      double bandwidth_mod,\n      enum resampler_quality quality,\n      resampler_simd_mask_t mask)\n{\n   rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)\n      calloc(1, sizeof(rarch_nearest_resampler_t));\n   if (!re)\n      return NULL;\n   re->fraction = 0;\n   return re;\n}\n\nretro_resampler_t nearest_resampler = {\n   resampler_nearest_init,\n   resampler_nearest_process,\n   resampler_nearest_free,\n   RESAMPLER_API_VERSION,\n   \"nearest\",\n   \"nearest\"\n};\n"
  },
  {
    "path": "audio/resampler/drivers/sinc_resampler.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (sinc_resampler.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Bog-standard windowed SINC implementation. */\n\n#if defined(__GNUC__) && defined(__OPTIMIZE__) && !defined(__clang__)\n#pragma GCC push_options\n#pragma GCC optimize (\"fast-math\")\n#endif\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <math.h>\n#include <string.h>\n\n#include <retro_environment.h>\n#include <retro_inline.h>\n#include <filters.h>\n#include <memalign.h>\n\n#include <audio/audio_resampler.h>\n\n#ifdef __SSE__\n#include <xmmintrin.h>\n#endif\n\n#if defined(__AVX__)\n#include <immintrin.h>\n#endif\n\n/* Rough SNR values for upsampling:\n * LOWEST: 40 dB\n * LOWER: 55 dB\n * NORMAL: 70 dB\n * HIGHER: 110 dB\n * HIGHEST: 140 dB\n */\n\n/* TODO, make all this more configurable. */\n\nenum sinc_window\n{\n   SINC_WINDOW_NONE   = 0,\n   SINC_WINDOW_KAISER,\n   SINC_WINDOW_LANCZOS\n};\n\n/* For the little amount of taps we're using,\n * SSE1 is faster than AVX for some reason.\n * AVX code is kept here though as by increasing number\n * of sinc taps, the AVX code is clearly faster than SSE1.\n */\n\ntypedef struct rarch_sinc_resampler\n{\n   /* A buffer for phase_table, buffer_l and buffer_r\n    * are created in a single calloc().\n    * Ensure that we get as good cache locality as we can hope for. */\n   float *main_buffer;\n   float *phase_table;\n   float *buffer_l;\n   float *buffer_r;\n   unsigned phase_bits;\n   unsigned subphase_bits;\n   unsigned subphase_mask;\n   unsigned taps;\n   unsigned ptr;\n   uint32_t time;\n   float subphase_mod;\n   float kaiser_beta;\n} rarch_sinc_resampler_t;\n\n/*\n * Macro to handle the common \"push input samples into ring buffer\"\n * logic shared by every process function. Reduces code duplication and\n * ensures the input-feeding logic stays consistent across all paths.\n */\n#define SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames) \\\n   do {                                                              \\\n      while ((frames) && (resamp)->time >= (phases))                 \\\n      {                                                              \\\n         if (!(resamp)->ptr)                                         \\\n            (resamp)->ptr = (taps);                                  \\\n         (resamp)->ptr--;                                            \\\n         (resamp)->buffer_l[(resamp)->ptr + (taps)] =                \\\n            (resamp)->buffer_l[(resamp)->ptr]       = *(input)++;    \\\n         (resamp)->buffer_r[(resamp)->ptr + (taps)] =                \\\n            (resamp)->buffer_r[(resamp)->ptr]       = *(input)++;    \\\n         (resamp)->time -= (phases);                                 \\\n         (frames)--;                                                 \\\n      }                                                              \\\n   } while (0)\n\n\n#if (defined(__ARM_NEON__) || defined(HAVE_NEON))\n\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\nvoid process_sinc_neon_asm(float *out, const float *left,\n      const float *right, const float *coeff, unsigned taps);\n#else\n#include <arm_neon.h>\n\n/* Assumes that taps >= 8, and that taps is a multiple of 8.\n * Not bothering to reimplement this one for the external .S\n */\nstatic void resampler_sinc_process_neon_kaiser(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n   unsigned taps2                 = taps * 2;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            float32x2_t p3, p4;\n            unsigned phase           = resamp->time >> resamp->subphase_bits;\n            const float *phase_table = resamp->phase_table + phase * taps2;\n            const float *delta_table = phase_table + taps;\n            float32x4_t delta        = vdupq_n_f32((resamp->time & resamp->subphase_mask) * resamp->subphase_mod);\n            float32x4_t p1           = vdupq_n_f32(0.0f);\n            float32x4_t p2           = vdupq_n_f32(0.0f);\n\n            for (i = 0; i < (int)taps; i += 8)\n            {\n               float32x4x2_t coeff8  = vld2q_f32(&phase_table[i]);\n               float32x4x2_t delta8  = vld2q_f32(&delta_table[i]);\n               float32x4x2_t left8   = vld2q_f32(&buffer_l[i]);\n               float32x4x2_t right8  = vld2q_f32(&buffer_r[i]);\n\n               coeff8.val[0] = vmlaq_f32(coeff8.val[0], delta8.val[0], delta);\n               coeff8.val[1] = vmlaq_f32(coeff8.val[1], delta8.val[1], delta);\n\n               p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);\n               p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);\n               p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);\n               p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);\n            }\n\n            p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));\n            p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));\n            vst1_f32(output, vpadd_f32(p3, p4));\n            output                 += 2;\n            out_frames++;\n            resamp->time           += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n#endif\n\n/* Assumes that taps >= 8, and that taps is a multiple of 8. */\nstatic void resampler_sinc_process_neon(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            unsigned phase           = resamp->time >> resamp->subphase_bits;\n            const float *phase_table = resamp->phase_table + phase * taps;\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\n            process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);\n#else\n            {\n               /* C89: declarations at top of block */\n               int i;\n               float32x2_t p3, p4;\n               float32x4_t p1 = vdupq_n_f32(0.0f);\n               float32x4_t p2 = vdupq_n_f32(0.0f);\n\n               for (i = 0; i < (int)taps; i += 8)\n               {\n                  float32x4x2_t coeff8  = vld2q_f32(&phase_table[i]);\n                  float32x4x2_t left8   = vld2q_f32(&buffer_l[i]);\n                  float32x4x2_t right8  = vld2q_f32(&buffer_r[i]);\n\n                  p1 = vmlaq_f32(p1,  left8.val[0], coeff8.val[0]);\n                  p2 = vmlaq_f32(p2, right8.val[0], coeff8.val[0]);\n                  p1 = vmlaq_f32(p1,  left8.val[1], coeff8.val[1]);\n                  p2 = vmlaq_f32(p2, right8.val[1], coeff8.val[1]);\n               }\n\n               p3 = vadd_f32(vget_low_f32(p1), vget_high_f32(p1));\n               p4 = vadd_f32(vget_low_f32(p2), vget_high_f32(p2));\n               vst1_f32(output, vpadd_f32(p3, p4));\n            }\n#endif\n            output                 += 2;\n            out_frames++;\n            resamp->time           += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n#endif\n\n#if defined(__AVX__)\nstatic void resampler_sinc_process_avx_kaiser(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n   unsigned taps2                 = taps * 2;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            __m256 res_l, res_r;\n            unsigned phase     = resamp->time >> resamp->subphase_bits;\n            float *phase_table = resamp->phase_table + phase * taps2;\n            float *delta_table = phase_table + taps;\n            __m256 delta       = _mm256_set1_ps((float)\n                  (resamp->time & resamp->subphase_mask) * resamp->subphase_mod);\n            __m256 sum_l       = _mm256_setzero_ps();\n            __m256 sum_r       = _mm256_setzero_ps();\n\n            for (i = 0; i < (int)taps; i += 8)\n            {\n               __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);\n               __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);\n               __m256 deltas = _mm256_load_ps(delta_table + i);\n               __m256 sinc_v = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),\n                     _mm256_mul_ps(deltas, delta));\n\n               sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc_v));\n               sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc_v));\n            }\n\n            /* hadd on AVX is weird, and acts on low-lanes\n             * and high-lanes separately. */\n            res_l = _mm256_hadd_ps(sum_l, sum_l);\n            res_r = _mm256_hadd_ps(sum_r, sum_r);\n            res_l = _mm256_hadd_ps(res_l, res_l);\n            res_r = _mm256_hadd_ps(res_r, res_r);\n            res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);\n            res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);\n\n            /* This is optimized to mov %xmmN, [mem].\n             * There doesn't seem to be any _mm256_store_ss intrinsic. */\n            _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));\n            _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));\n\n            output += 2;\n            out_frames++;\n            resamp->time += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n\nstatic void resampler_sinc_process_avx(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases    = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio     = phases / data->ratio;\n   const float *input = data->data_in;\n   float *output      = data->data_out;\n   size_t frames      = data->input_frames;\n   size_t out_frames  = 0;\n   unsigned taps      = resamp->taps;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            __m256 res_l, res_r;\n            unsigned phase     = resamp->time >> resamp->subphase_bits;\n            float *phase_table = resamp->phase_table + phase * taps;\n            __m256 sum_l       = _mm256_setzero_ps();\n            __m256 sum_r       = _mm256_setzero_ps();\n\n            for (i = 0; i < (int)taps; i += 8)\n            {\n               __m256 buf_l  = _mm256_loadu_ps(buffer_l + i);\n               __m256 buf_r  = _mm256_loadu_ps(buffer_r + i);\n               __m256 sinc_v = _mm256_load_ps((const float*)phase_table + i);\n\n               sum_l         = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc_v));\n               sum_r         = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc_v));\n            }\n\n            /* hadd on AVX is weird, and acts on low-lanes\n             * and high-lanes separately. */\n            res_l = _mm256_hadd_ps(sum_l, sum_l);\n            res_r = _mm256_hadd_ps(sum_r, sum_r);\n            res_l = _mm256_hadd_ps(res_l, res_l);\n            res_r = _mm256_hadd_ps(res_r, res_r);\n            res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);\n            res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);\n\n            /* This is optimized to mov %xmmN, [mem].\n             * There doesn't seem to be any _mm256_store_ss intrinsic. */\n            _mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));\n            _mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));\n\n            output += 2;\n            out_frames++;\n            resamp->time += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n#endif\n\n#if defined(__SSE__)\nstatic void resampler_sinc_process_sse_kaiser(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n   unsigned taps2                 = taps * 2;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            __m128 sum;\n            unsigned phase     = resamp->time >> resamp->subphase_bits;\n            float *phase_table = resamp->phase_table + phase * taps2;\n            float *delta_table = phase_table + taps;\n            __m128 delta       = _mm_set1_ps((float)\n                  (resamp->time & resamp->subphase_mask) * resamp->subphase_mod);\n            __m128 sum_l       = _mm_setzero_ps();\n            __m128 sum_r       = _mm_setzero_ps();\n\n            for (i = 0; i < (int)taps; i += 4)\n            {\n               __m128 buf_l  = _mm_loadu_ps(buffer_l + i);\n               __m128 buf_r  = _mm_loadu_ps(buffer_r + i);\n               __m128 deltas = _mm_load_ps(delta_table + i);\n               __m128 sinc_v = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),\n                     _mm_mul_ps(deltas, delta));\n               sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, sinc_v));\n               sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, sinc_v));\n            }\n\n            /* Them annoying shuffles.\n             * sum_l = { l3, l2, l1, l0 }\n             * sum_r = { r3, r2, r1, r0 }\n             */\n\n            sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,\n                     _MM_SHUFFLE(1, 0, 1, 0)),\n                  _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));\n\n            /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }\n             * sum   = { R1, R0, L1, L0 }\n             */\n\n            sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);\n\n            /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }\n             * sum   = { X,  R,  X,  L }\n             */\n\n            /* Store L */\n            _mm_store_ss(output + 0, sum);\n\n            /* movehl { X, R, X, L } == { X, R, X, R } */\n            _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));\n\n            output += 2;\n            out_frames++;\n            resamp->time += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n\nstatic void resampler_sinc_process_sse(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            __m128 sum;\n            unsigned phase     = resamp->time >> resamp->subphase_bits;\n            float *phase_table = resamp->phase_table + phase * taps;\n            __m128 sum_l       = _mm_setzero_ps();\n            __m128 sum_r       = _mm_setzero_ps();\n\n            for (i = 0; i < (int)taps; i += 4)\n            {\n               __m128 buf_l  = _mm_loadu_ps(buffer_l + i);\n               __m128 buf_r  = _mm_loadu_ps(buffer_r + i);\n               __m128 sinc_v = _mm_load_ps((const float*)phase_table + i);\n               sum_l        = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, sinc_v));\n               sum_r        = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, sinc_v));\n            }\n\n            /* Them annoying shuffles.\n             * sum_l = { l3, l2, l1, l0 }\n             * sum_r = { r3, r2, r1, r0 }\n             */\n\n            sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,\n                     _MM_SHUFFLE(1, 0, 1, 0)),\n                  _mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));\n\n            /* sum   = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }\n             * sum   = { R1, R0, L1, L0 }\n             */\n\n            sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);\n\n            /* sum   = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }\n             * sum   = { X,  R,  X,  L }\n             */\n\n            /* Store L */\n            _mm_store_ss(output + 0, sum);\n\n            /* movehl { X, R, X, L } == { X, R, X, R } */\n            _mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));\n\n            output += 2;\n            out_frames++;\n            resamp->time += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n#endif\n\nstatic void resampler_sinc_process_c_kaiser(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n   unsigned taps2                 = taps * 2;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            float sum_l        = 0.0f;\n            float sum_r        = 0.0f;\n            unsigned phase     = resamp->time >> resamp->subphase_bits;\n            float *phase_table = resamp->phase_table + phase * taps2;\n            float *delta_table = phase_table + taps;\n            float delta        = (float)\n               (resamp->time & resamp->subphase_mask) * resamp->subphase_mod;\n\n            /* Manual 4x unroll for scalar path.\n             * Taps is guaranteed to be a multiple of 4 \n               (see SIMD alignment in init). */\n            int taps_aligned   = (int)taps & ~3;\n            for (i = 0; i < taps_aligned; i += 4)\n            {\n               float s0 = phase_table[i]     + delta_table[i]     * delta;\n               float s1 = phase_table[i + 1] + delta_table[i + 1] * delta;\n               float s2 = phase_table[i + 2] + delta_table[i + 2] * delta;\n               float s3 = phase_table[i + 3] + delta_table[i + 3] * delta;\n\n               sum_l += buffer_l[i]     * s0 + buffer_l[i + 1] * s1\n                      + buffer_l[i + 2] * s2 + buffer_l[i + 3] * s3;\n               sum_r += buffer_r[i]     * s0 + buffer_r[i + 1] * s1\n                      + buffer_r[i + 2] * s2 + buffer_r[i + 3] * s3;\n            }\n            /* Handle any remaining taps (safety net). */\n            for (; i < (int)taps; i++)\n            {\n               float sinc_val  = phase_table[i] + delta_table[i] * delta;\n               sum_l          += buffer_l[i] * sinc_val;\n               sum_r          += buffer_r[i] * sinc_val;\n            }\n\n            output[0]          = sum_l;\n            output[1]          = sum_r;\n\n            output            += 2;\n            out_frames++;\n            resamp->time      += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n\nstatic void resampler_sinc_process_c(void *re_, struct resampler_data *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)re_;\n   unsigned phases                = 1 << (resamp->phase_bits + resamp->subphase_bits);\n   uint32_t ratio                 = phases / data->ratio;\n   const float *input             = data->data_in;\n   float *output                  = data->data_out;\n   size_t frames                  = data->input_frames;\n   size_t out_frames              = 0;\n   unsigned taps                  = resamp->taps;\n\n   while (frames)\n   {\n      SINC_PUSH_INPUT_SAMPLES(resamp, input, taps, phases, frames);\n\n      {\n         const float *buffer_l    = resamp->buffer_l + resamp->ptr;\n         const float *buffer_r    = resamp->buffer_r + resamp->ptr;\n         while (resamp->time < phases)\n         {\n            /* C89: all declarations at top of block */\n            int i;\n            float sum_l        = 0.0f;\n            float sum_r        = 0.0f;\n            unsigned phase     = resamp->time >> resamp->subphase_bits;\n            float *phase_table = resamp->phase_table + phase * taps;\n            /* Manual 4x unroll for scalar path. */\n            int taps_aligned   = (int)taps & ~3;\n            for (i = 0; i < taps_aligned; i += 4)\n            {\n               float s0 = phase_table[i];\n               float s1 = phase_table[i + 1];\n               float s2 = phase_table[i + 2];\n               float s3 = phase_table[i + 3];\n\n               sum_l += buffer_l[i]     * s0 + buffer_l[i + 1] * s1\n                      + buffer_l[i + 2] * s2 + buffer_l[i + 3] * s3;\n               sum_r += buffer_r[i]     * s0 + buffer_r[i + 1] * s1\n                      + buffer_r[i + 2] * s2 + buffer_r[i + 3] * s3;\n            }\n            /* Handle any remaining taps. */\n            for (; i < (int)taps; i++)\n            {\n               float sinc_val     = phase_table[i];\n               sum_l             += buffer_l[i] * sinc_val;\n               sum_r             += buffer_r[i] * sinc_val;\n            }\n\n            output[0]             = sum_l;\n            output[1]             = sum_r;\n\n            output               += 2;\n            out_frames++;\n            resamp->time         += ratio;\n         }\n      }\n   }\n\n   data->output_frames = out_frames;\n}\n\nstatic void resampler_sinc_free(void *data)\n{\n   rarch_sinc_resampler_t *resamp = (rarch_sinc_resampler_t*)data;\n   if (resamp)\n      memalign_free(resamp->main_buffer);\n   free(resamp);\n}\n\nstatic void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp,\n      double cutoff,\n      float *phase_table, int phases, int taps, int calculate_delta)\n{\n   int i, j;\n   /* Kaiser window function - need to normalize w(0) to 1.0f */\n   double kaiser_beta = (double)resamp->kaiser_beta;\n   double window_mod  = besseli0(kaiser_beta);\n   int stride         = calculate_delta ? 2 : 1;\n   double sidelobes   = taps / 2.0;\n\n   for (i = 0; i < phases; i++)\n   {\n      for (j = 0; j < taps; j++)\n      {\n         double sinc_phase;\n         double arg;\n         float val;\n         int               n = j * phases + i;\n         double window_phase = (double)n / (phases * taps); /* [0, 1). */\n         window_phase        = 2.0 * window_phase - 1.0;    /* [-1, 1) */\n         sinc_phase          = sidelobes * window_phase;\n\n         /* clamp argument to sqrt to avoid NaN from\n          * floating-point precision loss at boundaries where\n          * 1 - window_phase^2 can go slightly negative.\n          * Also use double-precision sqrt() instead of sqrtf()\n          * for better accuracy during table generation. */\n         arg                 = 1.0 - window_phase * window_phase;\n         if (arg < 0.0)\n            arg = 0.0;\n\n         val                 = (float)(cutoff * sinc(M_PI * sinc_phase * cutoff) *\n              besseli0(kaiser_beta * sqrt(arg))\n            / window_mod);\n         phase_table[i * stride * taps + j] = val;\n      }\n   }\n\n   if (calculate_delta)\n   {\n      int phase;\n      int p;\n      for (p = 0; p < phases - 1; p++)\n      {\n         for (j = 0; j < taps; j++)\n         {\n            float delta = phase_table[(p + 1) * stride * taps + j] -\n               phase_table[p * stride * taps + j];\n            phase_table[(p * stride + 1) * taps + j] = delta;\n         }\n      }\n\n      phase = phases - 1;\n      for (j = 0; j < taps; j++)\n      {\n         double sinc_phase;\n         double arg;\n         float val, delta;\n         int n               = j * phases + (phase + 1);\n         double window_phase = (double)n / (phases * taps); /* (0, 1]. */\n         window_phase        = 2.0 * window_phase - 1.0;    /* (-1, 1] */\n         sinc_phase          = sidelobes * window_phase;\n\n         /* Same clamp + double-precision sqrt as above. */\n         arg                 = 1.0 - window_phase * window_phase;\n         if (arg < 0.0)\n            arg = 0.0;\n\n         val                 = (float)(cutoff * sinc(M_PI * sinc_phase * cutoff) *\n              besseli0(kaiser_beta * sqrt(arg)) / window_mod);\n         delta = (val - phase_table[phase * stride * taps + j]);\n         phase_table[(phase * stride + 1) * taps + j] = delta;\n      }\n   }\n}\n\nstatic void sinc_init_table_lanczos(\n      rarch_sinc_resampler_t *resamp, double cutoff,\n      float *phase_table, int phases, int taps, int calculate_delta)\n{\n   int i, j;\n   /* Lanczos window function - need to normalize w(0) to 1.0f */\n   double window_mod = 1.0;\n   int stride        = calculate_delta ? 2 : 1;\n   double sidelobes  = taps / 2.0;\n\n   for (i = 0; i < phases; i++)\n   {\n      for (j = 0; j < taps; j++)\n      {\n         double sinc_phase;\n         float val;\n         int               n = j * phases + i;\n         double window_phase = (double)n / (phases * taps); /* [0, 1). */\n         window_phase        = 2.0 * window_phase - 1.0; /* [-1, 1) */\n         sinc_phase          = sidelobes * window_phase;\n         val                 = (float)(cutoff * sinc(M_PI * sinc_phase * cutoff) *\n            sinc(M_PI * window_phase) / window_mod);\n         phase_table[i * stride * taps + j] = val;\n      }\n   }\n\n   if (calculate_delta)\n   {\n      int p;\n      int phase;\n\n      for (p = 0; p < phases - 1; p++)\n      {\n         for (j = 0; j < taps; j++)\n         {\n            float delta = phase_table[(p + 1) * stride * taps + j] -\n               phase_table[p * stride * taps + j];\n            phase_table[(p * stride + 1) * taps + j] = delta;\n         }\n      }\n\n      phase = phases - 1;\n      for (j = 0; j < taps; j++)\n      {\n         double sinc_phase;\n         float val, delta;\n         int n               = j * phases + (phase + 1);\n         double window_phase = (double)n / (phases * taps); /* (0, 1]. */\n         window_phase        = 2.0 * window_phase - 1.0; /* (-1, 1] */\n         sinc_phase          = sidelobes * window_phase;\n\n         val                 = (float)(cutoff * sinc(M_PI * sinc_phase * cutoff) *\n            sinc(M_PI * window_phase) / window_mod);\n         delta = (val - phase_table[phase * stride * taps + j]);\n         phase_table[(phase * stride + 1) * taps + j] = delta;\n      }\n   }\n}\n\nstatic void *resampler_sinc_new(const struct resampler_config *config,\n      double bandwidth_mod, enum resampler_quality quality,\n      resampler_simd_mask_t mask)\n{\n   double cutoff                  = 0.0;\n   size_t phase_elems             = 0;\n   size_t elems                   = 0;\n   unsigned enable_avx            = 0;\n   unsigned sidelobes             = 0;\n   enum sinc_window window_type   = SINC_WINDOW_NONE;\n   rarch_sinc_resampler_t *re     = (rarch_sinc_resampler_t*)\n      calloc(1, sizeof(*re));\n\n   if (!re)\n      return NULL;\n\n   switch (quality)\n   {\n      case RESAMPLER_QUALITY_LOWEST:\n         cutoff            = 0.98;\n         sidelobes         = 2;\n         re->phase_bits    = 12;\n         re->subphase_bits = 10;\n         window_type       = SINC_WINDOW_LANCZOS;\n         break;\n      case RESAMPLER_QUALITY_LOWER:\n         cutoff            = 0.98;\n         sidelobes         = 4;\n         re->phase_bits    = 12;\n         re->subphase_bits = 10;\n         window_type       = SINC_WINDOW_LANCZOS;\n         break;\n      case RESAMPLER_QUALITY_HIGHER:\n         cutoff            = 0.90;\n         sidelobes         = 32;\n         re->phase_bits    = 10;\n         re->subphase_bits = 14;\n         window_type       = SINC_WINDOW_KAISER;\n         re->kaiser_beta   = 10.5;\n         enable_avx        = 1;\n         break;\n      case RESAMPLER_QUALITY_HIGHEST:\n         cutoff            = 0.962;\n         sidelobes         = 128;\n         re->phase_bits    = 10;\n         re->subphase_bits = 14;\n         window_type       = SINC_WINDOW_KAISER;\n         re->kaiser_beta   = 14.5;\n         enable_avx        = 1;\n         break;\n      case RESAMPLER_QUALITY_NORMAL:\n      case RESAMPLER_QUALITY_DONTCARE:\n         cutoff            = 0.825;\n         sidelobes         = 8;\n         re->phase_bits    = 8;\n         re->subphase_bits = 16;\n         window_type       = SINC_WINDOW_KAISER;\n         re->kaiser_beta   = 5.5;\n         break;\n   }\n\n   re->subphase_mask = (1 << re->subphase_bits) - 1;\n   re->subphase_mod  = 1.0f / (1 << re->subphase_bits);\n   re->taps          = sidelobes * 2;\n\n   /* Downsampling, must lower cutoff, and extend number of\n    * taps accordingly to keep same stopband attenuation. */\n   if (bandwidth_mod < 1.0)\n   {\n      cutoff  *= bandwidth_mod;\n      re->taps = (unsigned)ceil(re->taps / bandwidth_mod);\n   }\n\n   /* Be SIMD-friendly. */\n#if defined(__AVX__)\n   if (enable_avx)\n      re->taps = (re->taps + 7) & ~7;\n   else\n#endif\n   {\n#if (defined(__ARM_NEON__) || defined(HAVE_NEON))\n      re->taps = (re->taps + 7) & ~7;\n#else\n      re->taps = (re->taps + 3) & ~3;\n#endif\n   }\n\n   phase_elems = ((1 << re->phase_bits) * re->taps);\n   if (window_type == SINC_WINDOW_KAISER)\n      phase_elems  = phase_elems * 2;\n   elems       = phase_elems + 4 * re->taps;\n\n   re->main_buffer = (float*)memalign_alloc(128, sizeof(float) * elems);\n   if (!re->main_buffer)\n      goto error;\n\n   memset(re->main_buffer, 0, sizeof(float) * elems);\n\n   re->phase_table = re->main_buffer;\n   re->buffer_l    = re->main_buffer + phase_elems;\n   re->buffer_r    = re->buffer_l + 2 * re->taps;\n\n   switch (window_type)\n   {\n      case SINC_WINDOW_LANCZOS:\n         sinc_init_table_lanczos(re, cutoff, re->phase_table,\n               1 << re->phase_bits, re->taps, 0);\n         break;\n      case SINC_WINDOW_KAISER:\n         sinc_init_table_kaiser(re, cutoff, re->phase_table,\n               1 << re->phase_bits, re->taps, 1);\n         break;\n      case SINC_WINDOW_NONE:\n         goto error;\n   }\n\n   sinc_resampler.process = resampler_sinc_process_c;\n   if (window_type == SINC_WINDOW_KAISER)\n      sinc_resampler.process    = resampler_sinc_process_c_kaiser;\n\n   if (mask & RESAMPLER_SIMD_AVX && enable_avx)\n   {\n#if defined(__AVX__)\n      sinc_resampler.process    = resampler_sinc_process_avx;\n      if (window_type == SINC_WINDOW_KAISER)\n         sinc_resampler.process = resampler_sinc_process_avx_kaiser;\n#endif\n   }\n   else if (mask & RESAMPLER_SIMD_SSE)\n   {\n#if defined(__SSE__)\n      sinc_resampler.process = resampler_sinc_process_sse;\n      if (window_type == SINC_WINDOW_KAISER)\n         sinc_resampler.process = resampler_sinc_process_sse_kaiser;\n#endif\n   }\n   else if (mask & RESAMPLER_SIMD_NEON)\n   {\n#if (defined(__ARM_NEON__) || defined(HAVE_NEON))\n#ifdef HAVE_ARM_NEON_ASM_OPTIMIZATIONS\n      if (window_type != SINC_WINDOW_KAISER)\n         sinc_resampler.process = resampler_sinc_process_neon;\n#else\n      sinc_resampler.process = resampler_sinc_process_neon;\n      if (window_type == SINC_WINDOW_KAISER)\n         sinc_resampler.process = resampler_sinc_process_neon_kaiser;\n#endif\n#endif\n   }\n\n   return re;\n\nerror:\n   resampler_sinc_free(re);\n   return NULL;\n}\n\nretro_resampler_t sinc_resampler = {\n   resampler_sinc_new,\n   resampler_sinc_process_c,\n   resampler_sinc_free,\n   RESAMPLER_API_VERSION,\n   \"sinc\",\n   \"sinc\"\n};\n\n#if defined(__GNUC__) && defined(__OPTIMIZE__) && !defined(__clang__)\n#pragma GCC pop_options\n#endif\n"
  },
  {
    "path": "audio/resampler/drivers/sinc_resampler_neon.S",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (sinc_resampler_neon.S).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#if defined(__ARM_NEON__) && defined(HAVE_ARM_NEON_ASM_OPTIMIZATIONS)\n\n#ifndef __MACH__\n.arm\n#endif\n.align 4\n.globl process_sinc_neon_asm\n#ifndef __MACH__\n.type process_sinc_neon_asm, %function\n#endif\n.globl _process_sinc_neon_asm\n#ifndef __MACH__\n.type _process_sinc_neon_asm, %function\n#endif\n# void process_sinc_neon(float *out, const float *left, const float *right, const float *coeff, unsigned taps)\n# Assumes taps is >= 8, and a multiple of 8.\nprocess_sinc_neon_asm:\n_process_sinc_neon_asm:\n\n   push {r4, lr}\n   vmov.f32 q0, #0.0\n   vmov.f32 q8, #0.0\n\n   # Taps argument (r4) goes on stack in armeabi.\n   ldr r4, [sp, #8]\n\n1:\n   # Left\n   vld1.f32 {q2-q3}, [r1]!\n   # Right\n   vld1.f32 {q10-q11}, [r2]!\n   # Coeff\n   vld1.f32 {q12-q13}, [r3, :128]!\n\n   # Left / Right\n   vmla.f32 q0, q2, q12\n   vmla.f32 q8, q10, q12\n   vmla.f32 q0, q3, q13\n   vmla.f32 q8, q11, q13\n\n   subs r4, r4, #8\n   bne 1b\n\n   # Add everything together\n   vadd.f32 d0, d0, d1\n   vadd.f32 d16, d16, d17\n   vpadd.f32 d0, d0, d16\n   vst1.f32 d0, [r0]\n\n   pop {r4, pc}\n\n#endif\n"
  },
  {
    "path": "cdrom/cdrom.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (cdrom.c).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <cdrom/cdrom.h>\n#include <libretro.h>\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <compat/strl.h>\n#include <compat/strcasestr.h>\n#include <retro_math.h>\n#include <retro_timers.h>\n#include <streams/file_stream.h>\n#include <retro_endianness.h>\n#include <retro_miscellaneous.h>\n#include <vfs/vfs_implementation.h>\n#include <lists/string_list.h>\n#include <lists/dir_list.h>\n#include <string/stdstring.h>\n#include <memalign.h>\n\n#include <math.h>\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\n#if defined(__linux__) && !defined(ANDROID)\n#include <sys/ioctl.h>\n#include <scsi/sg.h>\n#endif\n\n#if defined(_WIN32) && !defined(_XBOX)\n#include <windows.h>\n#include <winioctl.h>\n#include <ntddscsi.h>\n#endif\n\n#define CDROM_CUE_TRACK_BYTES 107\n#define CDROM_MAX_SENSE_BYTES 16\n#define CDROM_MAX_RETRIES 10\n#define CDROM_MIN_BUFSIZE 9\n\ntypedef enum\n{\n   DIRECTION_NONE,\n   DIRECTION_IN,\n   DIRECTION_OUT\n} CDROM_CMD_Direction;\n\nvoid cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame)\n{\n   if (!min || !sec || !frame)\n      return;\n\n   *frame  = lba % 75;\n   lba    /= 75;\n   *sec    = lba % 60;\n   lba    /= 60;\n   *min    = lba;\n}\n\nunsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame)\n{\n   return (min * 60 + sec) * 75 + frame;\n}\n\nvoid increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)\n{\n   if (!min || !sec || !frame)\n      return;\n\n   *min   = (*frame == 74) ? (*sec < 59 ? *min : *min + 1) : *min;\n   *sec   = (*frame == 74) ? (*sec < 59 ? (*sec + 1) : 0) : *sec;\n   *frame = (*frame  < 74) ? (*frame + 1) : 0;\n}\n\n#ifdef CDROM_DEBUG\nstatic void cdrom_print_sense_data(const unsigned char *s, size_t len)\n{\n   unsigned i;\n   const char *sense_key_text = NULL;\n   unsigned char key;\n   unsigned char asc;\n   unsigned char ascq;\n\n   if (len < 16)\n   {\n      printf(\"[CDROM] Sense data buffer length too small.\\n\");\n      fflush(stdout);\n      return;\n   }\n\n   key  = s[2] & 0xF;\n   asc  = s[12];\n   ascq = s[13];\n\n   printf(\"[CDROM] Sense Data: \");\n\n   for (i = 0; i < MIN(len, 16); i++)\n      printf(\"%02X \", s[i]);\n\n   printf(\"\\n\");\n\n   if (s[0] == 0x70)\n      printf(\"[CDROM] CURRENT ERROR:\\n\");\n   if (s[0] == 0x71)\n      printf(\"[CDROM] DEFERRED ERROR:\\n\");\n\n   switch (key)\n   {\n      case 0:\n         sense_key_text = \"NO SENSE\";\n         break;\n      case 1:\n         sense_key_text = \"RECOVERED ERROR\";\n         break;\n      case 2:\n         sense_key_text = \"NOT READY\";\n         break;\n      case 3:\n         sense_key_text = \"MEDIUM ERROR\";\n         break;\n      case 4:\n         sense_key_text = \"HARDWARE ERROR\";\n         break;\n      case 5:\n         sense_key_text = \"ILLEGAL REQUEST\";\n         break;\n      case 6:\n         sense_key_text = \"UNIT ATTENTION\";\n         break;\n      case 7:\n         sense_key_text = \"DATA PROTECT\";\n         break;\n      case 8:\n         sense_key_text = \"BLANK CHECK\";\n         break;\n      case 9:\n         sense_key_text = \"VENDOR SPECIFIC\";\n         break;\n      case 10:\n         sense_key_text = \"COPY ABORTED\";\n         break;\n      case 11:\n         sense_key_text = \"ABORTED COMMAND\";\n         break;\n      case 13:\n         sense_key_text = \"VOLUME OVERFLOW\";\n         break;\n      case 14:\n         sense_key_text = \"MISCOMPARE\";\n         break;\n   }\n\n   printf(\"[CDROM] Sense Key: %02X (%s)\\n\", key, sense_key_text ? sense_key_text : \"null\");\n   printf(\"[CDROM] ASC: %02X\\n\", asc);\n   printf(\"[CDROM] ASCQ: %02X\\n\", ascq);\n\n   switch (key)\n   {\n      case 2:\n      {\n         switch (asc)\n         {\n            case 4:\n            {\n               switch (ascq)\n               {\n                  case 1:\n                     printf(\"[CDROM] Description: LOGICAL UNIT IS IN PROCESS OF BECOMING READY\\n\");\n                     break;\n                  default:\n                     break;\n               }\n\n               break;\n            }\n            case 0x3a:\n            {\n               switch (ascq)\n               {\n                  case 0:\n                     printf(\"[CDROM] Description: MEDIUM NOT PRESENT\\n\");\n                     break;\n                  case 3:\n                     printf(\"[CDROM] Description: MEDIUM NOT PRESENT - LOADABLE\\n\");\n                     break;\n                  case 1:\n                     printf(\"[CDROM] Description: MEDIUM NOT PRESENT - TRAY CLOSED\\n\");\n                     break;\n                  case 2:\n                     printf(\"[CDROM] Description: MEDIUM NOT PRESENT - TRAY OPEN\\n\");\n                     break;\n                  default:\n                     break;\n               }\n\n               break;\n            }\n            default:\n               break;\n         }\n      }\n      case 3:\n      {\n         if (asc == 0x11 && ascq == 0x5)\n            printf(\"[CDROM] Description: L-EC UNCORRECTABLE ERROR\\n\");\n         break;\n      }\n      case 5:\n      {\n         if (asc == 0x20 && ascq == 0)\n            printf(\"[CDROM] Description: INVALID COMMAND OPERATION CODE\\n\");\n         else if (asc == 0x24 && ascq == 0)\n            printf(\"[CDROM] Description: INVALID FIELD IN CDB\\n\");\n         else if (asc == 0x26 && ascq == 0)\n            printf(\"[CDROM] Description: INVALID FIELD IN PARAMETER LIST\\n\");\n         break;\n      }\n      case 6:\n      {\n         if (asc == 0x28 && ascq == 0)\n            printf(\"[CDROM] Description: NOT READY TO READY CHANGE, MEDIUM MAY HAVE CHANGED\\n\");\n         break;\n      }\n      default:\n         break;\n   }\n\n   fflush(stdout);\n}\n#endif\n\n#if defined(_WIN32) && !defined(_XBOX)\nstatic 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)\n{\n   DWORD ioctl_bytes;\n   BOOL ioctl_rv;\n#ifdef CDROM_DEBUG\n   clock_t t                       = clock();\n   const char *extra               = \" \";\n   static unsigned char last_min   = 0;\n   static unsigned char last_sec   = 0;\n   static unsigned char last_frame = 0;\n\n   unsigned lba_cur = cdrom_msf_to_lba(last_min, last_sec, last_frame);\n   unsigned lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);\n#endif\n   struct sptd_with_sense\n   {\n     SCSI_PASS_THROUGH_DIRECT s;\n     UCHAR sense[128];\n   } sptd;\n\n   memset(&sptd, 0, sizeof(sptd));\n\n   sptd.s.Length    = sizeof(sptd.s);\n   sptd.s.CdbLength = cmd_len;\n\n   switch (dir)\n   {\n      case DIRECTION_IN:\n         sptd.s.DataIn = SCSI_IOCTL_DATA_IN;\n         break;\n      case DIRECTION_OUT:\n         sptd.s.DataIn = SCSI_IOCTL_DATA_OUT;\n         break;\n      case DIRECTION_NONE:\n      default:\n         sptd.s.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED;\n         break;\n   }\n\n   sptd.s.TimeOutValue       = 5;\n   sptd.s.DataBuffer         = buf;\n   sptd.s.DataTransferLength = len;\n   sptd.s.SenseInfoLength    = sizeof(sptd.sense);\n   sptd.s.SenseInfoOffset    = offsetof(struct sptd_with_sense, sense);\n\n   memcpy(sptd.s.Cdb, cmd, cmd_len);\n\n   ioctl_rv = DeviceIoControl(stream->fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd,\n      sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL);\n\n#ifdef CDROM_DEBUG\n   if (lba_req < lba_cur)\n      extra = \" BACKWARDS SECTOR READ\";\n   else if (lba_req > lba_cur)\n      extra = \" SKIPPED SECTOR READ\";\n\n   if (cmd[0] == 0xB9)\n   {\n      double time_taken = (double)(((clock() - t) * 1000) / CLOCKS_PER_SEC);\n      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);\n      fflush(stdout);\n   }\n\n   last_min   = cmd[3];\n   last_sec   = cmd[4];\n   last_frame = cmd[5];\n   increment_msf(&last_min, &last_sec, &last_frame);\n#endif\n\n   if (!ioctl_rv || sptd.s.ScsiStatus != 0)\n      return 1;\n\n   return 0;\n}\n#endif\n\n#if defined(__linux__) && !defined(ANDROID)\nstatic 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)\n{\n   int rv;\n   sg_io_hdr_t sgio = {0};\n\n   switch (dir)\n   {\n      case DIRECTION_IN:\n         sgio.dxfer_direction = SG_DXFER_FROM_DEV;\n         break;\n      case DIRECTION_OUT:\n         sgio.dxfer_direction = SG_DXFER_TO_DEV;\n         break;\n      case DIRECTION_NONE:\n      default:\n         sgio.dxfer_direction = SG_DXFER_NONE;\n         break;\n   }\n\n   sgio.interface_id = 'S';\n   sgio.cmd_len      = cmd_len;\n   sgio.cmdp         = cmd;\n   sgio.dxferp       = buf;\n   sgio.dxfer_len    = len;\n   sgio.sbp          = sense;\n   sgio.mx_sb_len    = sense_len;\n   sgio.timeout      = 5000;\n\n   rv = ioctl(fileno(stream->fp), SG_IO, &sgio);\n\n   if (rv == -1 || sgio.info & SG_INFO_CHECK)\n      return 1;\n\n   return 0;\n}\n#endif\n\nstatic int cdrom_send_command(libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir,\n      void *s, size_t len, unsigned char *cmd, size_t cmd_len, size_t skip)\n{\n   int i, rv = 0;\n   int frames = 1;\n   unsigned char *xfer_buf     = NULL;\n   unsigned char *xfer_buf_pos = xfer_buf;\n   unsigned char sense[CDROM_MAX_SENSE_BYTES] = {0};\n   unsigned char retries_left  = CDROM_MAX_RETRIES;\n   size_t padded_req_bytes;\n   size_t copied_bytes         = 0;\n   bool read_cd                = false;\n\n   if (!cmd || cmd_len == 0 || cmd_len < CDROM_MIN_BUFSIZE)\n      return 1;\n\n   if (cmd[0] == 0xBE || cmd[0] == 0xB9)\n   {\n      frames = ceil((len + skip) / 2352.0);\n      padded_req_bytes = 2352 * frames;\n      read_cd = true;\n      /* these will be incremented below */\n      cmd[6] = cmd[3];\n      cmd[7] = cmd[4];\n      cmd[8] = cmd[5];\n   }\n   else\n   {\n      padded_req_bytes = len + skip;\n   }\n\n   xfer_buf     = (unsigned char*)memalign_alloc(4096, padded_req_bytes);\n   xfer_buf_pos = xfer_buf;\n\n   if (!xfer_buf)\n      return 1;\n\n   memset(xfer_buf, 0, padded_req_bytes);\n#ifdef CDROM_DEBUG\n   printf(\"Number of frames to read: %d\\n\", frames);\n   fflush(stdout);\n#endif\n   for (i = 0; i < frames; i++)\n   {\n      size_t request_len = padded_req_bytes;\n      size_t copy_len = request_len;\n      bool cached_read = false;\n\n      if (read_cd)\n      {\n         unsigned lba_req = 0;\n\n         request_len = 2352;\n         copy_len = request_len;\n\n         increment_msf(&cmd[6], &cmd[7], &cmd[8]);\n\n         if (i > 0)\n         {\n            skip = 0;\n            increment_msf(&cmd[3], &cmd[4], &cmd[5]);\n         }\n         else\n         {\n            if (skip)\n               copy_len -= skip;\n         }\n\n         if (i == frames - 1)\n         {\n            copy_len = len - copied_bytes;\n         }\n\n         lba_req = cdrom_msf_to_lba(cmd[3], cmd[4], cmd[5]);\n\n         if (stream->cdrom.last_frame_valid && lba_req == stream->cdrom.last_frame_lba)\n         {\n            /* use cached frame */\n            cached_read = true;\n#ifdef CDROM_DEBUG\n            printf(\"[CDROM] Using cached frame\\n\");\n            fflush(stdout);\n#endif\n            /* assumes request_len is always equal to the size of last_frame */\n            memcpy(xfer_buf_pos, stream->cdrom.last_frame, sizeof(stream->cdrom.last_frame));\n         }\n\n      }\n\n#ifdef CDROM_DEBUG\n      if (!cached_read)\n      {\n         unsigned j;\n\n         printf(\"[CDROM] Send Command: \");\n\n         for (j = 0; j < cmd_len / sizeof(*cmd); j++)\n         {\n            printf(\"%02X \", cmd[j]);\n         }\n\n         if (len)\n            printf(\"(buffer of size %\" PRId64 \" with skip bytes %\" PRId64 \" padded to %\" PRId64 \"), frame %d\\n\", len, skip, padded_req_bytes, i);\n         else\n            printf(\"\\n\");\n\n         fflush(stdout);\n      }\n#endif\n\nretry:\n#if defined(__linux__) && !defined(ANDROID)\n      if (cached_read || !cdrom_send_command_linux(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))\n#else\n#if defined(_WIN32) && !defined(_XBOX)\n      if (cached_read || !cdrom_send_command_win32(stream, dir, xfer_buf_pos, request_len, cmd, cmd_len, sense, sizeof(sense)))\n#endif\n#endif\n      {\n         rv = 0;\n\n         if (s)\n         {\n#if 0\n            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);\n            fflush(stdout);\n#endif\n            memcpy((char*)s + copied_bytes, xfer_buf_pos + skip, copy_len);\n            copied_bytes += copy_len;\n\n            if (read_cd && !cached_read && request_len >= 2352)\n            {\n               unsigned frame_end = cdrom_msf_to_lba(cmd[6], cmd[7], cmd[8]);\n\n               /* cache the last received frame */\n               memcpy(stream->cdrom.last_frame, xfer_buf_pos, sizeof(stream->cdrom.last_frame));\n               stream->cdrom.last_frame_valid = true;\n               /* the ending frame is never actually read, so what we really just read is the one right before that */\n               stream->cdrom.last_frame_lba = frame_end - 1;\n            }\n            else\n               stream->cdrom.last_frame_valid = false;\n\n#if 0\n            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);\n            fflush(stdout);\n#endif\n            xfer_buf_pos += request_len;\n         }\n      }\n      else\n      {\n#ifdef CDROM_DEBUG\n         cdrom_print_sense_data(sense, sizeof(sense));\n#endif\n\n         /* INQUIRY/TEST/SENSE should never fail, don't retry. */\n         /* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */\n         if (cmd[0] != 0x0 && cmd[0] != 0x12 && cmd[0] != 0x5A && !(cmd[0] == 0x43 && cmd[2] == 0x4))\n         {\n            unsigned char key = sense[2] & 0xF;\n\n            switch (key)\n            {\n               case 0:\n               case 2:\n               case 3:\n               case 4:\n               case 6:\n                  if (retries_left)\n                  {\n   #ifdef CDROM_DEBUG\n                     printf(\"[CDROM] Read Retry...\\n\");\n                     fflush(stdout);\n   #endif\n                     retries_left--;\n                      retro_sleep(1000);\n                     goto retry;\n                  }\n                  else\n                  {\n                     rv = 1;\n   #ifdef CDROM_DEBUG\n                     printf(\"[CDROM] Read retries failed, giving up.\\n\");\n                     fflush(stdout);\n   #endif\n                  }\n\n                  break;\n               default:\n                  break;\n            }\n         }\n\n         rv = 1;\n      }\n   }\n\n   if (xfer_buf)\n      memalign_free(xfer_buf);\n   return rv;\n}\n\nstatic const char *cdrom_get_profile(unsigned short profile)\n{\n   switch (profile)\n   {\n      case 2:\n         return \"Removable disk\";\n      case 8:\n         return \"CD-ROM\";\n      case 9:\n         return \"CD-R\";\n      case 0xA:\n         return \"CD-RW\";\n      case 0x10:\n         return \"DVD-ROM\";\n      case 0x11:\n         return \"DVD-R Sequential Recording\";\n      case 0x12:\n         return \"DVD-RAM\";\n      case 0x13:\n         return \"DVD-RW Restricted Overwrite\";\n      case 0x14:\n         return \"DVD-RW Sequential recording\";\n      case 0x15:\n         return \"DVD-R Dual Layer Sequential Recording\";\n      case 0x16:\n         return \"DVD-R Dual Layer Jump Recording\";\n      case 0x17:\n         return \"DVD-RW Dual Layer\";\n      case 0x1A:\n         return \"DVD+RW\";\n      case 0x1B:\n         return \"DVD+R\";\n      case 0x2A:\n         return \"DVD+RW Dual Layer\";\n      case 0x2B:\n         return \"DVD+R Dual Layer\";\n      case 0x40:\n         return \"BD-ROM\";\n      case 0x41:\n         return \"BD-R SRM\";\n      case 0x42:\n         return \"BD-R RRM\";\n      case 0x43:\n         return \"BD-RE\";\n      case 0x50:\n         return \"HD DVD-ROM\";\n      case 0x51:\n         return \"HD DVD-R\";\n      case 0x52:\n         return \"HD DVD-RAM\";\n      case 0x53:\n         return \"HD DVD-RW\";\n      case 0x58:\n         return \"HD DVD-R Dual Layer\";\n      case 0x5A:\n         return \"HD DVD-RW Dual Layer\";\n      default:\n         break;\n   }\n\n   return \"Unknown\";\n}\n\n/* TODO/FIXME - sense never used here? */\nint cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len)\n{\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x3, 0, 0, 0, 0xFC, 0};\n   unsigned char buf[0xFC] = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] get sense data status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return 1;\n\n#ifdef CDROM_DEBUG\n   cdrom_print_sense_data(buf, sizeof(buf));\n#endif\n\n   return 0;\n}\n\nvoid cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream)\n{\n   unsigned char cdb[] = {0x46, 0x2, 0, 0x10, 0, 0, 0, 0, 0x14, 0};\n   unsigned char buf[0x14] = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n   int i;\n\n   printf(\"[CDROM] get current config random readable status code %d\\n\", rv);\n\n   if (rv)\n      return;\n\n   printf(\"[CDROM] Feature Header: \");\n\n   for (i = 0; i < 8; i++)\n   {\n      printf(\"%02X \", buf[i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] Random Readable Feature Descriptor: \");\n\n   for (i = 0; i < 12; i++)\n   {\n      printf(\"%02X \", buf[8 + i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] Supported commands: READ CAPACITY, READ (10)\\n\");\n}\n\nvoid cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream)\n{\n   unsigned char cdb[] = {0x46, 0x2, 0, 0x1D, 0, 0, 0, 0, 0xC, 0};\n   unsigned char buf[0xC] = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n   int i;\n\n   printf(\"[CDROM] get current config multi-read status code %d\\n\", rv);\n\n   if (rv)\n      return;\n\n   printf(\"[CDROM] Feature Header: \");\n\n   for (i = 0; i < 8; i++)\n   {\n      printf(\"%02X \", buf[i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] Multi-Read Feature Descriptor: \");\n\n   for (i = 0; i < 4; i++)\n   {\n      printf(\"%02X \", buf[8 + i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] Supported commands: READ (10), READ CD, READ DISC INFORMATION, READ TRACK INFORMATION\\n\");\n}\n\nvoid cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream)\n{\n   unsigned char cdb[] = {0x46, 0x2, 0, 0x1E, 0, 0, 0, 0, 0x10, 0};\n   unsigned char buf[0x10] = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n   int i;\n\n   printf(\"[CDROM] get current config cd read status code %d\\n\", rv);\n\n   if (rv)\n      return;\n\n   printf(\"[CDROM] Feature Header: \");\n\n   for (i = 0; i < 8; i++)\n   {\n      printf(\"%02X \", buf[i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] CD Read Feature Descriptor: \");\n\n   for (i = 0; i < 8; i++)\n   {\n      printf(\"%02X \", buf[8 + i]);\n   }\n\n   if (buf[8 + 2] & 1)\n      printf(\"(current)\\n\");\n\n   printf(\"[CDROM] Supported commands: READ CD, READ CD MSF, READ TOC/PMA/ATIP\\n\");\n}\n\nvoid cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream)\n{\n   unsigned char cdb[] = {0x46, 0x2, 0, 0x0, 0, 0, 0, 0xFF, 0xFA, 0};\n   unsigned char buf[0xFFFA] = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n   int i;\n\n   printf(\"[CDROM] get current config profiles status code %d\\n\", rv);\n\n   if (rv)\n      return;\n\n   printf(\"[CDROM] Feature Header: \");\n\n   for (i = 0; i < 8; i++)\n   {\n      printf(\"%02X \", buf[i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] Profile List Descriptor: \");\n\n   for (i = 0; i < 4; i++)\n   {\n      printf(\"%02X \", buf[8 + i]);\n   }\n\n   printf(\"\\n\");\n\n   printf(\"[CDROM] Number of profiles: %u\\n\", buf[8 + 3] / 4);\n\n   for (i = 0; i < buf[8 + 3] / 4; i++)\n   {\n      unsigned short profile = (buf[8 + (4 * (i + 1))] << 8) | buf[8 + (4 * (i + 1)) + 1];\n\n      printf(\"[CDROM] Profile Number: %04X (%s) \", profile, cdrom_get_profile(profile));\n\n      if (buf[8 + (4 * (i + 1)) + 2] & 1)\n         printf(\"(current)\\n\");\n      else\n         printf(\"\\n\");\n   }\n}\n\nvoid cdrom_get_current_config_core(libretro_vfs_implementation_file *stream)\n{\n   unsigned char cdb[] = {0x46, 0x2, 0, 0x1, 0, 0, 0, 0, 0x14, 0};\n   unsigned char buf[20] = {0};\n   unsigned intf_std = 0;\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n   int i;\n   const char *intf_std_name = \"Unknown\";\n\n   printf(\"[CDROM] get current config core status code %d\\n\", rv);\n\n   if (rv)\n      return;\n\n   printf(\"[CDROM] Feature Header: \");\n\n   for (i = 0; i < 8; i++)\n   {\n      printf(\"%02X \", buf[i]);\n   }\n\n   printf(\"\\n\");\n\n   if (buf[6] == 0 && buf[7] == 8)\n      printf(\"[CDROM] Current Profile: CD-ROM\\n\");\n   else\n      printf(\"[CDROM] Current Profile: %02X%02X\\n\", buf[6], buf[7]);\n\n   printf(\"[CDROM] Core Feature Descriptor: \");\n\n   for (i = 0; i < 12; i++)\n   {\n      printf(\"%02X \", buf[8 + i]);\n   }\n\n   printf(\"\\n\");\n\n   intf_std = buf[8 + 4] << 24 | buf[8 + 5] << 16 | buf[8 + 6] << 8 | buf[8 + 7];\n\n   switch (intf_std)\n   {\n      case 0:\n         intf_std_name = \"Unspecified\";\n         break;\n      case 1:\n         intf_std_name = \"SCSI Family\";\n         break;\n      case 2:\n         intf_std_name = \"ATAPI\";\n         break;\n      case 7:\n         intf_std_name = \"Serial ATAPI\";\n         break;\n      case 8:\n         intf_std_name = \"USB\";\n         break;\n      default:\n         break;\n   }\n\n   printf(\"[CDROM] Physical Interface Standard: %u (%s)\\n\", intf_std, intf_std_name);\n}\n\nint cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *s, size_t len)\n{\n   /* MMC Command: READ TOC/PMA/ATIP */\n   unsigned char cdb[] = {0x43, 0x2, 0x2, 0, 0, 0, 0x1, 0x9, 0x30, 0};\n#ifdef CDROM_DEBUG\n   unsigned short data_len = 0;\n   unsigned char first_session = 0;\n   unsigned char last_session = 0;\n   int i;\n#endif\n   int rv;\n\n   if (!s)\n      return 1;\n\n   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), 0);\n\n   if (rv)\n     return 1;\n\n#ifdef CDROM_DEBUG\n   data_len      = s[0] << 8 | s[1];\n   first_session = s[2];\n   last_session  = s[3];\n\n   printf(\"[CDROM] Data Length: %d\\n\", data_len);\n   printf(\"[CDROM] First Session: %d\\n\", first_session);\n   printf(\"[CDROM] Last Session: %d\\n\", last_session);\n\n   for (i = 0; i < (data_len - 2) / 11; i++)\n   {\n      unsigned char session_num = s[4 + (i * 11) + 0];\n      unsigned char adr         = (s[4 + (i * 11) + 1] >> 4) & 0xF;\n#if 0\n      unsigned char control     = s[4 + (i * 11) + 1] & 0xF;\n#endif\n      unsigned char tno         = s[4 + (i * 11) + 2];\n      unsigned char point       = s[4 + (i * 11) + 3];\n      unsigned char pmin        = s[4 + (i * 11) + 8];\n      unsigned char psec        = s[4 + (i * 11) + 9];\n      unsigned char pframe      = s[4 + (i * 11) + 10];\n\n      /*printf(\"i %d control %d adr %d tno %d point %d: \", i, control, adr, tno, point);*/\n      /* why is control always 0? */\n\n      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)\n      {\n         printf(\"[CDROM] - Session#: %d TNO %d POINT %d \", session_num, tno, point);\n         printf(\"Track start time: (aMSF %02u:%02u:%02u) \", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);\n      }\n      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA0)\n      {\n         printf(\"[CDROM] - Session#: %d TNO %d POINT %d \", session_num, tno, point);\n         printf(\"First Track Number: %d \", pmin);\n         printf(\"Disc Type: %d \", psec);\n      }\n      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)\n      {\n         printf(\"[CDROM] - Session#: %d TNO %d POINT %d \", session_num, tno, point);\n         printf(\"Last Track Number: %d \", pmin);\n      }\n      else if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA2)\n      {\n         printf(\"[CDROM] - Session#: %d TNO %d POINT %d \", session_num, tno, point);\n         printf(\"Lead-out start time: (aMSF %02u:%02u:%02u) \", (unsigned)pmin, (unsigned)psec, (unsigned)pframe);\n      }\n\n      printf(\"\\n\");\n   }\n\n   fflush(stdout);\n#endif\n   return 0;\n}\n\nstatic int cdrom_read_track_info(libretro_vfs_implementation_file *stream, unsigned char track, cdrom_toc_t *toc)\n{\n   /* MMC Command: READ TRACK INFORMATION */\n   unsigned char cdb[] = {0x52, 0x1, 0, 0, 0, 0, 0, 0x1, 0x80, 0};\n   unsigned char buf[384] = {0};\n   unsigned lba = 0;\n   unsigned track_size = 0;\n   int rv;\n   ssize_t pregap_lba_len;\n\n   cdb[5] = track;\n\n   if ((rv = cdrom_send_command(stream, DIRECTION_IN, buf,\n         sizeof(buf), cdb, sizeof(cdb), 0)))\n     return 1;\n\n   memcpy(&lba, buf + 8, 4);\n   memcpy(&track_size, buf + 24, 4);\n\n   lba = swap_if_little32(lba);\n   track_size = swap_if_little32(track_size);\n\n   /* lba_start may be earlier than the MSF start times seen in read_subq */\n   toc->track[track - 1].lba_start = lba;\n   toc->track[track - 1].track_size = track_size;\n\n   pregap_lba_len = (toc->track[track - 1].audio ? 0 : (toc->track[track - 1].lba - toc->track[track - 1].lba_start));\n\n   toc->track[track - 1].track_bytes = (track_size - pregap_lba_len) * 2352;\n   toc->track[track - 1].mode = buf[6] & 0xF;\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] Track %d Info: \", track);\n   printf(\"Copy: %d \", (buf[5] & 0x10) > 0);\n   printf(\"Data Mode: %d \", toc->track[track - 1].mode);\n   printf(\"LBA Start: %d (%d) \", lba, toc->track[track - 1].lba);\n   printf(\"Track Size: %d\\n\", track_size);\n   fflush(stdout);\n#endif\n\n   return 0;\n}\n\nint cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed)\n{\n   /* MMC Command: SET CD SPEED */\n   unsigned char cmd[] = {0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\n\n   cmd[2] = (speed >> 24) & 0xFF;\n   cmd[3] = (speed >> 16) & 0xFF;\n   cmd[4] = (speed >> 8) & 0xFF;\n   cmd[5] = speed & 0xFF;\n\n   return cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cmd, sizeof(cmd), 0);\n}\n\nint 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)\n{\n   int i;\n   unsigned char buf[2352] = {0};\n   unsigned short data_len = 0;\n   size_t _len = 0, pos = 0;\n   int rv = 0;\n\n   if (!out_buf || !out_len || !num_tracks || !toc)\n   {\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] Invalid buffer/length pointer for CDROM cue sheet\\n\");\n      fflush(stdout);\n#endif\n      return 1;\n   }\n\n   cdrom_set_read_speed(stream, 0xFFFFFFFF);\n\n   rv = cdrom_read_subq(stream, buf, sizeof(buf));\n\n   if (rv)\n      return rv;\n\n   data_len = buf[0] << 8 | buf[1];\n\n   for (i = 0; i < (data_len - 2) / 11; i++)\n   {\n      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;\n      unsigned char tno = buf[4 + (i * 11) + 2];\n      unsigned char point = buf[4 + (i * 11) + 3];\n      unsigned char pmin = buf[4 + (i * 11) + 8];\n\n      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point == 0xA1)\n      {\n         *num_tracks = pmin;\n#ifdef CDROM_DEBUG\n         printf(\"[CDROM] Number of CDROM tracks: %d\\n\", *num_tracks);\n         fflush(stdout);\n#endif\n         break;\n      }\n   }\n\n   if (!*num_tracks || *num_tracks > 99)\n   {\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] Invalid number of CDROM tracks: %d\\n\", *num_tracks);\n      fflush(stdout);\n#endif\n      return 1;\n   }\n\n   _len            = CDROM_CUE_TRACK_BYTES * (*num_tracks);\n   toc->num_tracks = *num_tracks;\n   *out_buf        = (char*)calloc(1, _len);\n   *out_len        = _len;\n\n   for (i = 0; i < (data_len - 2) / 11; i++)\n   {\n      /*unsigned char session_num = buf[4 + (i * 11) + 0];*/\n      unsigned char adr = (buf[4 + (i * 11) + 1] >> 4) & 0xF;\n      unsigned char control = buf[4 + (i * 11) + 1] & 0xF;\n      unsigned char tno = buf[4 + (i * 11) + 2];\n      unsigned char point = buf[4 + (i * 11) + 3];\n      /*unsigned char amin = buf[4 + (i * 11) + 4];\n      unsigned char asec = buf[4 + (i * 11) + 5];\n      unsigned char aframe = buf[4 + (i * 11) + 6];*/\n      unsigned char pmin = buf[4 + (i * 11) + 8];\n      unsigned char psec = buf[4 + (i * 11) + 9];\n      unsigned char pframe = buf[4 + (i * 11) + 10];\n      unsigned lba = cdrom_msf_to_lba(pmin, psec, pframe);\n\n      /*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);*/\n      /* why is control always 0? */\n\n      if (/*(control == 4 || control == 6) && */adr == 1 && tno == 0 && point >= 1 && point <= 99)\n      {\n         bool audio = false;\n         const char *track_type = \"MODE1/2352\";\n\n         audio = (!(control & 0x4) && !(control & 0x5));\n\n#ifdef CDROM_DEBUG\n         printf(\"[CDROM] Track %02d CONTROL %01X ADR %01X AUDIO? %d\\n\", point, control, adr, audio);\n         fflush(stdout);\n#endif\n\n         toc->track[point - 1].track_num = point;\n         toc->track[point - 1].min = pmin;\n         toc->track[point - 1].sec = psec;\n         toc->track[point - 1].frame = pframe;\n         toc->track[point - 1].lba = lba;\n         toc->track[point - 1].audio = audio;\n\n         cdrom_read_track_info(stream, point, toc);\n\n         if (audio)\n            track_type = \"AUDIO\";\n         else if (toc->track[point - 1].mode == 1)\n            track_type = \"MODE1/2352\";\n         else if (toc->track[point - 1].mode == 2)\n            track_type = \"MODE2/2352\";\n\n#if defined(_WIN32) && !defined(_XBOX)\n         pos += snprintf(*out_buf + pos, _len - pos, \"FILE \\\"cdrom://%c:/drive-track%02d.bin\\\" BINARY\\n\", cdrom_drive, point);\n#else\n         pos += snprintf(*out_buf + pos, _len - pos, \"FILE \\\"cdrom://drive%c-track%02d.bin\\\" BINARY\\n\", cdrom_drive, point);\n#endif\n         pos += snprintf(*out_buf + pos, _len - pos, \"  TRACK %02d %s\\n\", point, track_type);\n\n         {\n            unsigned pregap_lba_len = toc->track[point - 1].lba - toc->track[point - 1].lba_start;\n\n            if (toc->track[point - 1].audio && pregap_lba_len > 0)\n            {\n               unsigned char min = 0;\n               unsigned char sec = 0;\n               unsigned char frame = 0;\n\n               cdrom_lba_to_msf(pregap_lba_len, &min, &sec, &frame);\n\n               pos += snprintf(*out_buf + pos, _len - pos, \"    INDEX 00 00:00:00\\n\");\n               pos += snprintf(*out_buf + pos, _len - pos, \"    INDEX 01 %02u:%02u:%02u\\n\", (unsigned)min, (unsigned)sec, (unsigned)frame);\n            }\n            else\n               pos += snprintf(*out_buf + pos, _len - pos, \"    INDEX 01 00:00:00\\n\");\n         }\n      }\n   }\n\n   return 0;\n}\n\n/* needs 32 bytes for full vendor, product and version */\nint cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *s, size_t len, bool *is_cdrom)\n{\n   /* MMC Command: INQUIRY */\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x12, 0, 0, 0, 0xff, 0};\n   unsigned char buf[256] = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n   bool cdrom = false;\n\n   if (rv)\n      return 1;\n\n   if (s && len >= 32)\n   {\n      memset(s, 0, len);\n      /* vendor */\n      memcpy(s, buf + 8, 8);\n      s[8] = ' ';\n      /* product */\n      memcpy(s + 9, buf + 16, 16);\n      s[25] = ' ';\n      /* version */\n      memcpy(s + 26, buf + 32, 4);\n   }\n\n   cdrom = (buf[0] == 5);\n\n   if (is_cdrom && cdrom)\n      *is_cdrom = true;\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] Device Model: %s (is CD-ROM? %s)\\n\", s, (cdrom ? \"yes\" : \"no\"));\n#endif\n   return 0;\n}\n\nint cdrom_read(libretro_vfs_implementation_file *stream,\n      cdrom_group_timeouts_t *timeouts, unsigned char min,\n      unsigned char sec, unsigned char frame, void *s,\n      size_t len, size_t skip)\n{\n   /* MMC Command: READ CD MSF */\n   unsigned char cdb[] = {0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0xF8, 0, 0};\n   int rv;\n   double frames = ceil((len + skip) / 2352.0);\n   unsigned frame_end = cdrom_msf_to_lba(min, sec, frame) + frames;\n\n   cdb[3] = min;\n   cdb[4] = sec;\n   cdb[5] = frame;\n\n   if (frames <= 1)\n   {\n      cdrom_lba_to_msf(frame_end, &cdb[6], &cdb[7], &cdb[8]);\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] single-frame read: %d %d %d skip %\" PRId64 \"\\n\", cdb[3], cdb[4], cdb[5], skip);\n      fflush(stdout);\n#endif\n   }\n   else\n   {\n      cdrom_lba_to_msf(frame_end, &cdb[6], &cdb[7], &cdb[8]);\n\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] multi-frame read: %d sectors starting from %02d:%02d:%02d skip %\" PRId64 \"\\n\", (int)frames, cdb[3], cdb[4], cdb[5], skip);\n      fflush(stdout);\n#endif\n   }\n\n   /* regardless of the length specified here, a new buffer will be allocated and padded to a sector multiple inside cdrom_send_command */\n   rv = cdrom_send_command(stream, DIRECTION_IN, s, len, cdb, sizeof(cdb), skip);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] read msf status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n   {\n      stream->cdrom.last_frame_valid = false;\n      return 1;\n   }\n\n   return 0;\n}\n\nint cdrom_stop(libretro_vfs_implementation_file *stream)\n{\n   /* MMC Command: START STOP UNIT */\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x0, 0};\n   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] stop status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return 1;\n\n   return 0;\n}\n\nint cdrom_unlock(libretro_vfs_implementation_file *stream)\n{\n   /* MMC Command: PREVENT ALLOW MEDIUM REMOVAL */\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1E, 0, 0, 0, 0x2, 0};\n   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] persistent prevent clear status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return 1;\n\n   cdb[4] = 0x0;\n\n   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] prevent clear status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return 1;\n\n   return 0;\n}\n\nint cdrom_open_tray(libretro_vfs_implementation_file *stream)\n{\n   /* MMC Command: START STOP UNIT */\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x2, 0};\n   int rv;\n\n   cdrom_unlock(stream);\n   cdrom_stop(stream);\n\n   rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] open tray status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return 1;\n\n   return 0;\n}\n\nint cdrom_close_tray(libretro_vfs_implementation_file *stream)\n{\n   /* MMC Command: START STOP UNIT */\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x1B, 0, 0, 0, 0x3, 0};\n   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] close tray status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return 1;\n\n   return 0;\n}\n\nstruct string_list* cdrom_get_available_drives(void)\n{\n   struct string_list *list = string_list_new();\n#if defined(__linux__) && !defined(ANDROID)\n   struct string_list *dir_list = dir_list_new(\"/dev\", NULL, false, false, false, false);\n   int i;\n   bool found = false;\n\n   if (!dir_list)\n      return list;\n\n   for (i = 0; i < (int)dir_list->size; i++)\n   {\n      if (string_starts_with_size(dir_list->elems[i].data, \"/dev/sg\",\n               STRLEN_CONST(\"/dev/sg\")))\n      {\n         char drive_string[33];\n         libretro_vfs_implementation_file *stream;\n         char drive_model[32]             = {0};\n         union string_list_elem_attr attr = {0};\n         int dev_index                    = 0;\n         RFILE *file                      = filestream_open(\n               dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);\n         bool is_cdrom                    = false;\n\n         found = true;\n\n         if (!file)\n         {\n#ifdef CDROM_DEBUG\n            printf(\"[CDROM] Could not open %s, please check permissions.\\n\", dir_list->elems[i].data);\n            fflush(stdout);\n#endif\n            continue;\n         }\n\n         stream = filestream_get_vfs_handle(file);\n         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);\n         filestream_close(file);\n\n         if (!is_cdrom)\n            continue;\n\n         dev_index = (int)strtol(\n               dir_list->elems[i].data + STRLEN_CONST(\"/dev/sg\"),\n               NULL, 10);\n\n         dev_index = '0' + dev_index;\n         attr.i    = dev_index;\n\n         if (*drive_model)\n            strlcpy(drive_string, drive_model, sizeof(drive_string));\n         else\n            strlcpy(drive_string, \"Unknown Drive\", sizeof(drive_string));\n\n         string_list_append(list, drive_string, attr);\n      }\n   }\n\n   if (!found)\n   {\n      char *buf   = NULL;\n      int64_t len = 0;\n\n      if (filestream_read_file(\"/proc/modules\", (void**)&buf, &len))\n      {\n#ifdef CDROM_DEBUG\n         bool found              = false;\n#endif\n         struct string_list mods = {0};\n\n         string_list_initialize(&mods);\n\n         if (string_split_noalloc(&mods, buf, \"\\n\"))\n         {\n            for (i = 0; i < (int)mods.size; i++)\n            {\n               if (strcasestr(mods.elems[i].data, \"sg \"))\n               {\n#ifdef CDROM_DEBUG\n                  found = true;\n#endif\n                  break;\n               }\n            }\n         }\n         string_list_deinitialize(&mods);\n         free(buf);\n\n#ifdef CDROM_DEBUG\n         if (found)\n         {\n            printf(\"[CDROM] No sg devices found but kernel module is loaded.\\n\");\n            fflush(stdout);\n         }\n         else\n         {\n            printf(\"[CDROM] No sg devices found and sg kernel module is not loaded.\\n\");\n            fflush(stdout);\n         }\n#endif\n      }\n#ifdef CDROM_DEBUG\n      else\n      {\n         printf(\"[CDROM] No sg devices found, could not check if sg kernel module is loaded.\\n\");\n         fflush(stdout);\n      }\n#endif\n   }\n\n   string_list_free(dir_list);\n#endif\n#if defined(_WIN32) && !defined(_XBOX)\n   DWORD drive_mask = GetLogicalDrives();\n   int i;\n\n   for (i = 0; i < (int)(sizeof(DWORD) * 8); i++)\n   {\n      char path[]       = {\"a:\\\\\"};\n      char cdrom_path[] = {\"cdrom://a:/drive-track01.bin\"};\n\n      path[0]          += i;\n      cdrom_path[8]    += i;\n\n      /* this drive letter doesn't exist */\n      if (!(drive_mask & (1 << i)))\n         continue;\n\n      if (GetDriveType(path) != DRIVE_CDROM)\n         continue;\n\n      {\n         char drive_string[33];\n         libretro_vfs_implementation_file *stream;\n         bool is_cdrom                    = false;\n         char drive_model[32]             = {0};\n         union string_list_elem_attr attr = {0};\n         RFILE *file = filestream_open(cdrom_path, RETRO_VFS_FILE_ACCESS_READ, 0);\n         if (!file)\n            continue;\n\n         stream = filestream_get_vfs_handle(file);\n         cdrom_get_inquiry(stream, drive_model, sizeof(drive_model), &is_cdrom);\n         filestream_close(file);\n\n         if (!is_cdrom)\n            continue;\n\n         attr.i = path[0];\n\n         if (*drive_model)\n            strlcpy(drive_string, drive_model, sizeof(drive_string));\n         else\n            strlcpy(drive_string, \"Unknown Drive\", sizeof(drive_string));\n\n         string_list_append(list, drive_string, attr);\n      }\n   }\n#endif\n   return list;\n}\n\nbool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream)\n{\n   /* MMC Command: TEST UNIT READY */\n   unsigned char cdb[CDROM_MIN_BUFSIZE] = {0x00, 0, 0, 0, 0, 0};\n   int rv = cdrom_send_command(stream, DIRECTION_NONE, NULL, 0, cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] media inserted status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   /* Will also return false if the drive is simply not ready yet (tray open, disc spinning back up after tray closed etc).\n    * Command will not block or wait for media to become ready. */\n   if (rv)\n      return false;\n\n   return true;\n}\n\nbool cdrom_drive_has_media(const char drive)\n{\n   RFILE *file;\n   char cdrom_path_bin[256] = {0};\n\n   cdrom_device_fillpath(cdrom_path_bin, sizeof(cdrom_path_bin), drive, 1, false);\n\n   file = filestream_open(cdrom_path_bin, RETRO_VFS_FILE_ACCESS_READ, 0);\n\n   if (file)\n   {\n      libretro_vfs_implementation_file *stream = filestream_get_vfs_handle(file);\n      bool has_media = cdrom_is_media_inserted(stream);\n\n      filestream_close(file);\n\n      return has_media;\n   }\n\n   return false;\n}\n\nbool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled)\n{\n   int i;\n   /* MMC Command: MODE SENSE (10) and MODE SELECT (10) */\n   unsigned char cdb_sense_changeable[] = {0x5A, 0, 0x48, 0, 0, 0, 0, 0, 0x14, 0};\n   unsigned char cdb_sense[]            = {0x5A, 0, 0x8, 0, 0, 0, 0, 0, 0x14, 0};\n   unsigned char cdb_select[]           = {0x55, 0x10, 0, 0, 0, 0, 0, 0, 0x14, 0};\n   unsigned char buf[20]                = {0};\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf),\n         cdb_sense_changeable, sizeof(cdb_sense_changeable), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] mode sense changeable status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return false;\n\n   if (!(buf[10] & 0x1))\n   {\n      /* RCD (read cache disable) bit is not changeable */\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] RCD (read cache disable) bit is not changeable.\\n\");\n      fflush(stdout);\n#endif\n      return false;\n   }\n\n   memset(buf, 0, sizeof(buf));\n\n   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb_sense, sizeof(cdb_sense), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"mode sense status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return false;\n\n#ifdef CDROM_DEBUG\n   printf(\"Mode sense data for caching mode page: \");\n\n   for (i = 0; i < (int)sizeof(buf); i++)\n      printf(\"%02X \", buf[i]);\n\n   printf(\"\\n\");\n   fflush(stdout);\n#endif\n\n   /* \"When transferred during execution of the MODE SELECT (10) command, Mode Data Length is reserved.\" */\n   for (i = 0; i < 8; i++)\n      buf[i] = 0;\n\n   if (enabled)\n      buf[10] &= ~1;\n   else\n      buf[10] |=  1;\n\n   rv = cdrom_send_command(stream, DIRECTION_OUT, buf, sizeof(buf), cdb_select, sizeof(cdb_select), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"mode select status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return false;\n\n   return true;\n}\n\nbool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts)\n{\n   /* MMC Command: MODE SENSE (10) */\n   int rv;\n   unsigned char cdb[]   = {0x5A, 0, 0x1D, 0, 0, 0, 0, 0, 0x14, 0};\n   unsigned char buf[20] = {0};\n   unsigned short g1     = 0;\n   unsigned short g2     = 0;\n   unsigned short g3     = 0;\n\n   if (!timeouts)\n      return false;\n\n   rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n\n#ifdef CDROM_DEBUG\n   printf(\"get timeouts status code %d\\n\", rv);\n   fflush(stdout);\n#endif\n\n   if (rv)\n      return false;\n\n   g1 = buf[14] << 8 | buf[15];\n   g2 = buf[16] << 8 | buf[17];\n   g3 = buf[18] << 8 | buf[19];\n\n#ifdef CDROM_DEBUG\n   {\n      int i;\n\n      printf(\"Mode sense data for timeout groups: \");\n\n      for (i = 0; i < (int)sizeof(buf); i++)\n         printf(\"%02X \", buf[i]);\n\n      printf(\"\\n\");\n\n      printf(\"Group 1 Timeout: %d\\n\", g1);\n      printf(\"Group 2 Timeout: %d\\n\", g2);\n      printf(\"Group 3 Timeout: %d\\n\", g3);\n\n      fflush(stdout);\n   }\n#endif\n\n   timeouts->g1_timeout = g1;\n   timeouts->g2_timeout = g2;\n   timeouts->g3_timeout = g3;\n\n   return true;\n}\n\nbool cdrom_has_atip(libretro_vfs_implementation_file *stream)\n{\n   /* MMC Command: READ TOC/PMA/ATIP */\n   unsigned char cdb[]     = {0x43, 0x2, 0x4, 0, 0, 0, 0, 0x9, 0x30, 0};\n   unsigned char buf[32]   = {0};\n   unsigned short atip_len = 0;\n   int rv = cdrom_send_command(stream, DIRECTION_IN, buf, sizeof(buf), cdb, sizeof(cdb), 0);\n\n   if (rv)\n     return false;\n\n   atip_len = buf[0] << 8 | buf[1];\n\n#ifdef CDROM_DEBUG\n   printf(\"ATIP Length %d, Disc Type %d, Disc Sub-Type %d\\n\",\n         atip_len,\n         (buf[6]  >> 6) & 0x1,\n         ((buf[6] >> 5) & 0x1) << 2 | ((buf[6] >> 4) & 0x1) << 1 | ((buf[6] >> 3) & 0x1) << 0);\n#endif\n\n   if (atip_len < 5)\n      return false;\n\n   return true;\n}\n\nsize_t cdrom_device_fillpath(char *s, size_t len, char drive, unsigned char track, bool is_cue)\n{\n   if (s && len > 0)\n   {\n      if (is_cue)\n      {\n#ifdef _WIN32\n         size_t _len = strlcpy(s, \"cdrom://\", len);\n         if (len > _len)\n            s[_len++] = drive;\n         _len += strlcpy(s + _len, \":/drive.cue\", len - _len);\n         return _len;\n#else\n#ifdef __linux__\n         size_t _len = strlcpy(s, \"cdrom://drive\", len);\n         if (len > _len + 1)\n         {\n            s[_len++] = drive;\n            s[_len]   = '\\0';\n         }\n         _len += strlcpy(s + _len, \".cue\", len - _len);\n         return _len;\n#endif\n#endif\n      }\n      else\n      {\n#ifdef _WIN32\n         size_t _len = strlcpy(s, \"cdrom://\", len);\n         if (len > _len + 1)\n         {\n            s[_len++] = drive;\n            s[_len]   = '\\0';\n         }\n         _len += snprintf(s + _len, len - _len, \":/drive-track%02d.bin\", track);\n         return _len;\n#else\n#ifdef __linux__\n         size_t _len = strlcpy(s, \"cdrom://drive\", len);\n         if (len > _len)\n            s[_len++] = drive;\n         _len += snprintf(s + _len, len - _len, \"-track%02d.bin\", track);\n         return _len;\n#endif\n#endif\n      }\n   }\n   return 0;\n}\n"
  },
  {
    "path": "compat/compat_fnmatch.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_fnmatch.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stddef.h>\n\n#include <compat/fnmatch.h>\n\n/* Implementation of fnmatch(3) so it can be\n * distributed to non *nix platforms.\n *\n * No flags are implemented ATM.\n * We don't use them. Add flags as needed. */\n\nint rl_fnmatch(const char *pattern, const char *string, int flags)\n{\n   int rv;\n   const char *c = NULL;\n   int charmatch = 0;\n\n   for (c = pattern; *c != '\\0'; c++)\n   {\n      /* String ended before pattern */\n      if ((*c != '*') && (*string == '\\0'))\n         return FNM_NOMATCH;\n\n      switch (*c)\n      {\n         /* Match any number of unknown chars */\n         case '*':\n            /* Find next node in the pattern\n             * ignoring multiple asterixes\n             */\n            do {\n               c++;\n               if (*c == '\\0')\n                  return 0;\n            } while (*c == '*');\n\n            /* Match the remaining pattern\n             * ignoring more and more characters. */\n            do {\n               /* We reached the end of the string without a\n                * match. There is a way to optimize this by\n                * calculating the minimum chars needed to\n                * match the remaining pattern but I don't\n                * think it is worth the work ATM.\n                */\n               if (*string == '\\0')\n                  return FNM_NOMATCH;\n\n               rv = rl_fnmatch(c, string, flags);\n               string++;\n            } while (rv != 0);\n\n            return 0;\n            /* Match char from list */\n         case '[':\n            charmatch = 0;\n            for (c++; *c != ']'; c++)\n            {\n               /* Bad format */\n               if (*c == '\\0')\n                  return FNM_NOMATCH;\n\n               /* Match already found */\n               if (charmatch)\n                  continue;\n\n               if (*c == *string)\n                  charmatch = 1;\n            }\n\n            /* No match in list */\n            if (!charmatch)\n               return FNM_NOMATCH;\n\n            string++;\n            break;\n            /* Has any character */\n         case '?':\n            string++;\n            break;\n            /* Match following character verbatim */\n         case '\\\\':\n            c++;\n            /* Dangling escape at end of pattern.\n             * FIXME: Was c == '\\0' (makes no sense).\n             * Not sure if c == NULL or *c == '\\0'\n             * is intended. Assuming *c due to c++ right before. */\n            if (*c == '\\0')\n               return FNM_NOMATCH;\n         default:\n            if (*c != *string)\n               return FNM_NOMATCH;\n            string++;\n      }\n   }\n\n   /* End of string and end of pattend */\n   if (*string == '\\0')\n      return 0;\n   return FNM_NOMATCH;\n}\n"
  },
  {
    "path": "compat/compat_getopt.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_getopt.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <ctype.h>\n\n#include <string.h>\n#include <boolean.h>\n#include <stddef.h>\n#include <stdlib.h>\n\n#include <retro_miscellaneous.h>\n\n#include <compat/getopt.h>\n#include <compat/strl.h>\n#include <compat/strcasestr.h>\n#include <compat/posix_string.h>\n\nchar *optarg;\nint optind, opterr, optopt;\n\nstatic bool is_short_option(const char *str)\n{\n   return str[0] == '-' && str[1] != '-';\n}\n\nstatic bool is_long_option(const char *str)\n{\n   return str[0] == '-' && str[1] == '-';\n}\n\nstatic int find_short_index(char * const *argv)\n{\n   int idx;\n   for (idx = 0; argv[idx]; idx++)\n   {\n      if (is_short_option(argv[idx]))\n         return idx;\n   }\n\n   return -1;\n}\n\nstatic int find_long_index(char * const *argv)\n{\n   int idx;\n   for (idx = 0; argv[idx]; idx++)\n   {\n      if (is_long_option(argv[idx]))\n         return idx;\n   }\n\n   return -1;\n}\n\nstatic int parse_short(const char *optstring, char * const *argv)\n{\n   bool extra_opt, takes_arg, embedded_arg;\n   const char *opt = NULL;\n   char        arg = argv[0][1];\n\n   if (arg == ':')\n      return '?';\n\n   opt = strchr(optstring, arg);\n   if (!opt)\n      return '?';\n\n   extra_opt = argv[0][2];\n   takes_arg = opt[1] == ':';\n\n   /* If we take an argument, and we see additional characters,\n    * this is in fact the argument (i.e. -cfoo is same as -c foo). */\n   embedded_arg = extra_opt && takes_arg;\n\n   if (takes_arg)\n   {\n      if (embedded_arg)\n      {\n         optarg = argv[0] + 2;\n         optind++;\n      }\n      else\n      {\n         optarg = argv[1];\n         optind += 2;\n      }\n\n      return optarg ? opt[0] : '?';\n   }\n\n   /* If we see additional characters,\n    * and they don't take arguments, this\n    * means we have multiple flags in one. */\n   if (embedded_arg)\n      memmove(&argv[0][1], &argv[0][2], strlen(&argv[0][2]) + 1);\n   else\n      optind++;\n\n   return opt[0];\n}\n\nstatic int parse_long(const struct option *longopts, char * const *argv)\n{\n   const char *arg = &argv[0][2];\n   const char *eq  = strchr(arg, '=');\n   size_t len      = eq ? (size_t)(eq - arg) : strlen(arg);\n\n   for (; longopts->name; longopts++)\n   {\n      const char *n = longopts->name;\n      const char *a = arg;\n      size_t rem    = len;\n\n      while (rem && *n == *a)\n      {\n         n++;\n         a++;\n         rem--;\n      }\n\n      if (rem || *n)\n         continue;\n\n      if (longopts->has_arg)\n      {\n         if (eq)\n         {\n            optarg = (char *)(eq + 1);\n            optind++;\n         }\n         else if (argv[1])\n         {\n            optarg = argv[1];\n            optind += 2;\n         }\n         else\n            return '?';\n      }\n      else\n         optind++;\n\n      if (longopts->flag)\n      {\n         *longopts->flag = longopts->val;\n         return 0;\n      }\n      return longopts->val;\n   }\n\n   return '?';\n}\n\nstatic void shuffle_block(char **begin, char **last, char **end)\n{\n   ptrdiff_t    len = last - begin;\n   const char **tmp = (const char**)calloc(len, sizeof(const char*));\n\n   memcpy((void*)tmp, begin, len * sizeof(const char*));\n   memmove(begin, last, (end - last) * sizeof(const char*));\n   memcpy(end - len, tmp, len * sizeof(const char*));\n\n   free((void*)tmp);\n}\n\nint getopt_long(int argc, char *argv[],\n      const char *optstring, const struct option *longopts, int *longindex)\n{\n   int short_index, long_index;\n\n   if (optind == 0)\n      optind = 1;\n\n   if (argc < 2)\n      return -1;\n\n   short_index = find_short_index(&argv[optind]);\n   long_index  = find_long_index(&argv[optind]);\n\n   /* We're done here. */\n   if (short_index == -1 && long_index == -1)\n      return -1;\n\n   /* Reorder argv so that non-options come last.\n    * Non-POSIXy, but that's what getopt does by default. */\n   if ((short_index > 0) && ((short_index < long_index) || (long_index == -1)))\n   {\n      shuffle_block(&argv[optind], &argv[optind + short_index], &argv[argc]);\n      short_index = 0;\n   }\n   else if ((long_index > 0) && ((long_index < short_index)\n            || (short_index == -1)))\n   {\n      shuffle_block(&argv[optind], &argv[optind + long_index], &argv[argc]);\n      long_index = 0;\n   }\n\n   if (short_index == 0)\n      return parse_short(optstring, &argv[optind]);\n   if (long_index == 0)\n      return parse_long(longopts, &argv[optind]);\n\n   return '?';\n}\n"
  },
  {
    "path": "compat/compat_ifaddrs.c",
    "content": "/*\nCopyright (c) 2013, Kenneth MacKay\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n * Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#include <compat/strl.h>\n#include <compat/ifaddrs.h>\n\n#include <string.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <errno.h>\n#include <unistd.h>\n#include <sys/socket.h>\n#include <netpacket/packet.h>\n#include <net/if_arp.h>\n#include <netinet/in.h>\n#include <linux/netlink.h>\n#include <linux/rtnetlink.h>\n\ntypedef struct NetlinkList\n{\n    struct NetlinkList *m_next;\n    struct nlmsghdr *m_data;\n    unsigned int m_size;\n} NetlinkList;\n\nstatic int netlink_socket(void)\n{\n   struct sockaddr_nl l_addr;\n   int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);\n\n   if (l_socket < 0)\n      return -1;\n\n   memset(&l_addr, 0, sizeof(l_addr));\n   l_addr.nl_family = AF_NETLINK;\n\n   if (bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)\n   {\n      close(l_socket);\n      return -1;\n   }\n\n   return l_socket;\n}\n\nstatic int netlink_send(int p_socket, int p_request)\n{\n   struct\n   {\n      struct nlmsghdr m_hdr;\n      struct rtgenmsg m_msg;\n   } l_data;\n   struct sockaddr_nl l_addr;\n\n   memset(&l_data, 0, sizeof(l_data));\n\n   l_data.m_hdr.nlmsg_len    = NLMSG_LENGTH(sizeof(struct rtgenmsg));\n   l_data.m_hdr.nlmsg_type   = p_request;\n   l_data.m_hdr.nlmsg_flags  = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;\n   l_data.m_hdr.nlmsg_pid    = 0;\n   l_data.m_hdr.nlmsg_seq    = p_socket;\n   l_data.m_msg.rtgen_family = AF_UNSPEC;\n\n   memset(&l_addr, 0, sizeof(l_addr));\n   l_addr.nl_family = AF_NETLINK;\n   return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));\n}\n\nstatic int netlink_recv(int p_socket, void *p_buffer, size_t p_len)\n{\n   struct msghdr l_msg;\n   struct sockaddr_nl l_addr;\n   struct iovec l_iov = { p_buffer, p_len };\n\n   for (;;)\n   {\n      int l_result;\n\n      l_msg.msg_name       = (void *)&l_addr;\n      l_msg.msg_namelen    = sizeof(l_addr);\n      l_msg.msg_iov        = &l_iov;\n      l_msg.msg_iovlen     = 1;\n      l_msg.msg_control    = NULL;\n      l_msg.msg_controllen = 0;\n      l_msg.msg_flags      = 0;\n\n      l_result             = recvmsg(p_socket, &l_msg, 0);\n\n      if (l_result < 0)\n      {\n         if (errno == EINTR)\n            continue;\n         return -2;\n      }\n\n      if (l_msg.msg_flags & MSG_TRUNC) /* buffer too small */\n         return -1;\n      return l_result;\n   }\n   return 0;\n}\n\nstatic struct nlmsghdr *ifaddrs_get_netlink_response(int p_socket,\n      int *p_size, int *p_done)\n{\n   size_t l_size  = 4096;\n   void *l_buffer = NULL;\n\n   for (;;)\n   {\n      int l_read;\n\n      free(l_buffer);\n      l_buffer = malloc(l_size);\n      if (!l_buffer)\n         return NULL;\n\n      l_read  = netlink_recv(p_socket, l_buffer, l_size);\n      *p_size = l_read;\n\n      if (l_read == -2)\n      {\n         free(l_buffer);\n         return NULL;\n      }\n\n      if (l_read >= 0)\n      {\n         pid_t l_pid = getpid();\n         struct nlmsghdr *l_hdr;\n\n         for (l_hdr = (struct nlmsghdr *)l_buffer;\n               NLMSG_OK(l_hdr, (unsigned int)l_read);\n               l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))\n         {\n            if (   (pid_t)l_hdr->nlmsg_pid != l_pid\n                  || (int)l_hdr->nlmsg_seq != p_socket)\n               continue;\n\n            if (l_hdr->nlmsg_type == NLMSG_DONE)\n            {\n               *p_done = 1;\n               break;\n            }\n\n            if (l_hdr->nlmsg_type == NLMSG_ERROR)\n            {\n               free(l_buffer);\n               return NULL;\n            }\n         }\n         return l_buffer;\n      }\n\n      l_size *= 2;\n   }\n}\n\nstatic NetlinkList *ifaddr_new_list_item(struct nlmsghdr *p_data,\n   unsigned int p_size)\n{\n   NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));\n   if (!l_item)\n      return NULL;\n\n   l_item->m_next = NULL;\n   l_item->m_data = p_data;\n   l_item->m_size = p_size;\n   return l_item;\n}\n\nstatic void ifaddr_free_result_list(NetlinkList *p_list)\n{\n   NetlinkList *l_cur;\n\n   while (p_list)\n   {\n      l_cur = p_list;\n      p_list = p_list->m_next;\n      free(l_cur->m_data);\n      free(l_cur);\n   }\n}\n\nstatic NetlinkList *ifaddrs_get_resultlist(int p_socket, int p_request)\n{\n   int l_size;\n   NetlinkList *l_list = NULL;\n   NetlinkList *l_end  = NULL;\n   int l_done          = 0;\n\n   if (netlink_send(p_socket, p_request) < 0)\n      return NULL;\n\n   while (!l_done)\n   {\n      NetlinkList *l_item    = NULL;\n      struct nlmsghdr *l_hdr = ifaddrs_get_netlink_response(\n      p_socket, &l_size, &l_done);\n      if (!l_hdr)\n         goto error;\n\n      l_item = ifaddr_new_list_item(l_hdr, l_size);\n      if (!l_item)\n         goto error;\n\n      if (!l_list)\n         l_list        = l_item;\n      else\n         l_end->m_next = l_item;\n      l_end            = l_item;\n   }\n\n   return l_list;\n\nerror:\n   ifaddr_free_result_list(l_list);\n   return NULL;\n}\n\nstatic size_t ifaddrs_max_size(size_t a, size_t b) { return (a > b ? a : b); }\n\nstatic size_t ifaddrs_calc_addr_len(sa_family_t p_family, int p_dataSize)\n{\n   switch(p_family)\n   {\n      case AF_INET:\n         return sizeof(struct sockaddr_in);\n      case AF_INET6:\n         return sizeof(struct sockaddr_in6);\n      case AF_PACKET:\n         return ifaddrs_max_size(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);\n      default:\n         break;\n   }\n\n   return ifaddrs_max_size(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);\n}\n\nstatic void ifaddrs_make_sock_addr(sa_family_t p_family,\n   struct sockaddr *p_dest, void *p_data, size_t p_size)\n{\n   switch(p_family)\n   {\n      case AF_INET:\n         memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);\n         break;\n      case AF_INET6:\n         memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);\n         break;\n      case AF_PACKET:\n         memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);\n         ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;\n         break;\n      default:\n         memcpy(p_dest->sa_data, p_data, p_size);\n         break;\n   }\n   p_dest->sa_family = p_family;\n}\n\nstatic void ifaddrs_add_to_end(struct ifaddrs **p_resultList,\n   struct ifaddrs *p_entry)\n{\n   if (!*p_resultList)\n      *p_resultList = p_entry;\n   else\n   {\n      struct ifaddrs *l_cur = *p_resultList;\n      while (l_cur->ifa_next)\n         l_cur = l_cur->ifa_next;\n      l_cur->ifa_next = p_entry;\n   }\n}\n\nstatic int ifaddrs_interpret_link(struct nlmsghdr *p_hdr,\n   struct ifaddrs **p_resultList)\n{\n   char *l_index, *l_addr, *l_name, *l_data;\n   struct ifaddrs *l_entry  = NULL;\n   struct rtattr *l_rta     = NULL;\n   struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);\n   size_t l_nameSize        = 0;\n   size_t l_addrSize        = 0;\n   size_t l_dataSize        = 0;\n   size_t l_rtaSize         = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));\n\n   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);\n         l_rta = RTA_NEXT(l_rta, l_rtaSize))\n   {\n      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);\n      switch(l_rta->rta_type)\n      {\n         case IFLA_ADDRESS:\n         case IFLA_BROADCAST:\n            l_addrSize += NLMSG_ALIGN(ifaddrs_calc_addr_len(AF_PACKET, l_rtaDataSize));\n            break;\n         case IFLA_IFNAME:\n            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);\n            break;\n         case IFLA_STATS:\n            l_dataSize += NLMSG_ALIGN(l_rtaSize);\n            break;\n         default:\n            break;\n      }\n   }\n\n   l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);\n   if (!l_entry)\n      return -1;\n\n   memset(l_entry, 0, sizeof(struct ifaddrs));\n   l_entry->ifa_name = \"\";\n\n   l_index = ((char *)l_entry) + sizeof(struct ifaddrs);\n   l_name  = l_index + sizeof(int);\n   l_addr  = l_name + l_nameSize;\n   l_data  = l_addr + l_addrSize;\n\n   /* save the interface index so we can look \n    * it up when handling the addresses. */\n   memcpy(l_index, &l_info->ifi_index, sizeof(int));\n\n   l_entry->ifa_flags = l_info->ifi_flags;\n\n   l_rtaSize          = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));\n\n   for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);\n         l_rta = RTA_NEXT(l_rta, l_rtaSize))\n   {\n      void      *l_rtaData = RTA_DATA(l_rta);\n      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);\n\n      switch(l_rta->rta_type)\n      {\n         case IFLA_ADDRESS:\n         case IFLA_BROADCAST:\n            {\n               size_t l_addr_len = ifaddrs_calc_addr_len(AF_PACKET, l_rtaDataSize);\n               ifaddrs_make_sock_addr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);\n               ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;\n               ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;\n               if (l_rta->rta_type == IFLA_ADDRESS)\n                  l_entry->ifa_addr      = (struct sockaddr *)l_addr;\n               else\n                  l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;\n               l_addr += NLMSG_ALIGN(l_addr_len);\n            }\n            break;\n         case IFLA_IFNAME:\n            memcpy(l_name, l_rtaData, l_rtaDataSize);\n            l_name[l_rtaDataSize] = '\\0';\n            l_entry->ifa_name = l_name;\n            break;\n         case IFLA_STATS:\n            memcpy(l_data, l_rtaData, l_rtaDataSize);\n            l_entry->ifa_data = l_data;\n            break;\n         default:\n            break;\n      }\n   }\n\n   ifaddrs_add_to_end(p_resultList, l_entry);\n   return 0;\n}\n\nstatic struct ifaddrs *ifaddrs_find_interface(int p_index,\n      struct ifaddrs **p_links, int p_numLinks)\n{\n   int l_num             = 0;\n   struct ifaddrs *l_cur = *p_links;\n\n   while (l_cur && l_num < p_numLinks)\n   {\n      int l_index;\n      char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);\n\n      memcpy(&l_index, l_indexPtr, sizeof(int));\n      if (l_index == p_index)\n         return l_cur;\n\n      l_cur = l_cur->ifa_next;\n      ++l_num;\n   }\n   return NULL;\n}\n\nstatic int ifaddrs_interpret_addr(struct nlmsghdr *p_hdr,\n      struct ifaddrs **p_resultList, int p_numLinks)\n{\n   char *l_name, *l_addr;\n   struct rtattr *l_rta;\n   struct ifaddrs *l_entry;\n   size_t l_rtaSize;\n   size_t l_nameSize           = 0;\n   size_t l_addrSize           = 0;\n   int l_addedNetmask          = 0;\n   struct ifaddrmsg *l_info    = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);\n   struct ifaddrs *l_interface = ifaddrs_find_interface(l_info->ifa_index, p_resultList, p_numLinks);\n\n   if (l_info->ifa_family == AF_PACKET)\n      return 0;\n\n   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));\n\n   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);\n         l_rta = RTA_NEXT(l_rta, l_rtaSize))\n   {\n      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);\n\n      switch(l_rta->rta_type)\n      {\n         case IFA_ADDRESS:\n         case IFA_LOCAL:\n            if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)\n            {\n               /* make room for netmask */\n               l_addrSize += NLMSG_ALIGN(ifaddrs_calc_addr_len(l_info->ifa_family, l_rtaDataSize));\n               l_addedNetmask = 1;\n            }\n         case IFA_BROADCAST:\n            l_addrSize += NLMSG_ALIGN(ifaddrs_calc_addr_len(l_info->ifa_family, l_rtaDataSize));\n            break;\n         case IFA_LABEL:\n            l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);\n            break;\n         default:\n            break;\n      }\n   }\n\n   l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);\n   if (!l_entry)\n      return -1;\n\n   memset(l_entry, 0, sizeof(struct ifaddrs));\n   l_entry->ifa_name = (l_interface ? l_interface->ifa_name : \"\");\n\n   l_name = ((char *)l_entry) + sizeof(struct ifaddrs);\n   l_addr = l_name + l_nameSize;\n\n   l_entry->ifa_flags = l_info->ifa_flags;\n   if (l_interface)\n      l_entry->ifa_flags |= l_interface->ifa_flags;\n\n   l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));\n   for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);\n         l_rta = RTA_NEXT(l_rta, l_rtaSize))\n   {\n      void *l_rtaData      = RTA_DATA(l_rta);\n      size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);\n      switch(l_rta->rta_type)\n      {\n         case IFA_ADDRESS:\n         case IFA_BROADCAST:\n         case IFA_LOCAL:\n            {\n               size_t l_addrLen = ifaddrs_calc_addr_len(l_info->ifa_family, l_rtaDataSize);\n               ifaddrs_make_sock_addr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);\n               if (l_info->ifa_family == AF_INET6)\n               {\n                  if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) \n                   || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))\n                     ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;\n               }\n\n               if (l_rta->rta_type == IFA_ADDRESS)\n               {\n                  /* Apparently in a point-to-point network IFA_ADDRESS\n                   * contains the dest address and IFA_LOCAL contains \n                   * the local address */\n                  if (l_entry->ifa_addr)\n                     l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;\n                  else\n                     l_entry->ifa_addr    = (struct sockaddr *)l_addr;\n               }\n               else if (l_rta->rta_type == IFA_LOCAL)\n               {\n                  if (l_entry->ifa_addr)\n                     l_entry->ifa_dstaddr = l_entry->ifa_addr;\n                  l_entry->ifa_addr = (struct sockaddr *)l_addr;\n               }\n               else\n                  l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;\n               l_addr += NLMSG_ALIGN(l_addrLen);\n               break;\n            }\n         case IFA_LABEL:\n            strlcpy(l_name, l_rtaData, l_rtaDataSize + 1);\n            l_entry->ifa_name = l_name;\n            break;\n         default:\n            break;\n      }\n   }\n\n   if (          l_entry->ifa_addr\n          && (   l_entry->ifa_addr->sa_family == AF_INET\n          ||     l_entry->ifa_addr->sa_family == AF_INET6))\n   {\n      unsigned i;\n      char l_mask[16];\n      unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET\n            ? 32 : 128);\n      unsigned l_prefix    = (l_info->ifa_prefixlen > l_maxPrefix\n            ? l_maxPrefix : l_info->ifa_prefixlen);\n\n      l_mask[0] = '\\0';\n\n      for (i = 0; i < (l_prefix/8); ++i)\n         l_mask[i] = 0xff;\n      if (l_prefix % 8)\n         l_mask[i] = 0xff << (8 - (l_prefix % 8));\n\n      ifaddrs_make_sock_addr(l_entry->ifa_addr->sa_family,\n            (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);\n      l_entry->ifa_netmask = (struct sockaddr *)l_addr;\n   }\n\n   ifaddrs_add_to_end(p_resultList, l_entry);\n   return 0;\n}\n\nstatic int ifaddrs_interpret_links(int p_socket,\n      NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)\n{\n   int l_numLinks = 0;\n   pid_t l_pid    = getpid();\n\n   for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)\n   {\n      struct nlmsghdr *l_hdr = NULL;\n      unsigned int l_nlsize  = p_netlinkList->m_size;\n\n      for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);\n           l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))\n      {\n         if (     (pid_t)l_hdr->nlmsg_pid != l_pid \n               ||   (int)l_hdr->nlmsg_seq != p_socket)\n            continue;\n\n         if (l_hdr->nlmsg_type == NLMSG_DONE)\n            break;\n\n         if (l_hdr->nlmsg_type == RTM_NEWLINK)\n         {\n            if (ifaddrs_interpret_link(l_hdr, p_resultList) == -1)\n               return -1;\n            ++l_numLinks;\n         }\n      }\n   }\n   return l_numLinks;\n}\n\nstatic int ifaddrs_interpret_addrs(int p_socket,\n      NetlinkList *p_netlinkList,\n      struct ifaddrs **p_resultList, int p_numLinks)\n{\n   pid_t l_pid = getpid();\n   for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)\n   {\n      struct nlmsghdr *l_hdr = NULL;\n      unsigned int l_nlsize  = p_netlinkList->m_size;\n\n      for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);\n            l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))\n      {\n         if (     (pid_t)l_hdr->nlmsg_pid != l_pid \n               || (int)l_hdr->nlmsg_seq   != p_socket)\n            continue;\n\n         if (l_hdr->nlmsg_type == NLMSG_DONE)\n            break;\n\n         if (l_hdr->nlmsg_type == RTM_NEWADDR)\n         {\n            if (ifaddrs_interpret_addr(l_hdr, p_resultList, p_numLinks) == -1)\n               return -1;\n         }\n      }\n   }\n   return 0;\n}\n\nint getifaddrs(struct ifaddrs **ifap)\n{\n   int l_numLinks;\n   NetlinkList *l_linkResults;\n   NetlinkList *l_addrResults;\n   int l_socket   = 0;\n   int l_result   = 0;\n   if (!ifap)\n      return -1;\n\n   *ifap    = NULL;\n   l_socket = netlink_socket();\n\n   if (l_socket < 0)\n      return -1;\n\n   l_linkResults = ifaddrs_get_resultlist(l_socket, RTM_GETLINK);\n   if (!l_linkResults)\n   {\n      close(l_socket);\n      return -1;\n   }\n\n   l_addrResults = ifaddrs_get_resultlist(l_socket, RTM_GETADDR);\n   if (!l_addrResults)\n   {\n      close(l_socket);\n      ifaddr_free_result_list(l_linkResults);\n      return -1;\n   }\n\n   l_numLinks = ifaddrs_interpret_links(l_socket, l_linkResults, ifap);\n\n   if (     l_numLinks == -1\n         || ifaddrs_interpret_addrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)\n      l_result = -1;\n\n   ifaddr_free_result_list(l_linkResults);\n   ifaddr_free_result_list(l_addrResults);\n   close(l_socket);\n   return l_result;\n}\n\nvoid freeifaddrs(struct ifaddrs *ifa)\n{\n   struct ifaddrs *l_cur = NULL;\n\n   while (ifa)\n   {\n      l_cur = ifa;\n      ifa   = ifa->ifa_next;\n      free(l_cur);\n   }\n}\n"
  },
  {
    "path": "compat/compat_posix_string.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_posix_string.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <ctype.h>\n\n#include <compat/posix_string.h>\n\n#ifdef _WIN32\n\n#undef strcasecmp\n#undef strdup\n#undef isblank\n#undef strtok_r\n#include <ctype.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <compat/strl.h>\n\n#include <string.h>\n\nint retro_strcasecmp__(const char *a, const char *b)\n{\n   while (*a && *b)\n   {\n      int a_ = tolower(*a);\n      int b_ = tolower(*b);\n\n      if (a_ != b_)\n         return a_ - b_;\n\n      a++;\n      b++;\n   }\n\n   return tolower(*a) - tolower(*b);\n}\n\nchar *retro_strdup__(const char *orig)\n{\n   size_t _len = strlen(orig) + 1;\n   char *ret   = (char*)malloc(_len);\n   if (!ret)\n      return NULL;\n   memcpy(ret, orig, _len);\n   return ret;\n}\n\nint retro_isblank__(int c)\n{\n   return (c == ' ') || (c == '\\t');\n}\n\nchar *retro_strtok_r__(char *str, const char *delim, char **saveptr)\n{\n   char *first = NULL;\n   if (!saveptr || !delim)\n      return NULL;\n\n   if (str)\n      *saveptr = str;\n\n   do\n   {\n      char *ptr = NULL;\n      first = *saveptr;\n      while (*first && strchr(delim, *first))\n         *first++ = '\\0';\n\n      if (*first == '\\0')\n         return NULL;\n\n      ptr = first + 1;\n\n      while (*ptr && !strchr(delim, *ptr))\n         ptr++;\n\n      *saveptr = ptr + (*ptr ? 1 : 0);\n      *ptr     = '\\0';\n   } while (strlen(first) == 0);\n\n   return first;\n}\n#endif\n"
  },
  {
    "path": "compat/compat_snprintf.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_snprintf.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */\n#ifdef _MSC_VER\n\n#include <stdio.h>\n#include <stdarg.h>\n\n#if _MSC_VER < 1800\n#define va_copy(dst, src) ((dst) = (src))\n#endif\n\n#if _MSC_VER < 1300\n#define _vscprintf c89_vscprintf_retro__\n\nstatic int c89_vscprintf_retro__(const char *fmt, va_list pargs)\n{\n   int _len;\n   va_list argcopy;\n   va_copy(argcopy, pargs);\n   _len = vsnprintf(NULL, 0, fmt, argcopy);\n   va_end(argcopy);\n   return _len;\n}\n#endif\n\n/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */\n\nint c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)\n{\n   int _len = -1;\n   if (len != 0)\n   {\n#if (_MSC_VER <= 1310)\n      _len = _vsnprintf(s, len - 1, fmt, ap);\n#else\n      _len = _vsnprintf_s(s, len, len - 1, fmt, ap);\n#endif\n   }\n   if (_len == -1)\n       _len = _vscprintf(fmt, ap);\n   /* there was no room for a NULL, so truncate the last character */\n   if (_len == len && len)\n      s[len - 1] = '\\0';\n   return _len;\n}\n\nint c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)\n{\n   int _len;\n   va_list ap;\n   va_start(ap, fmt);\n   _len = c99_vsnprintf_retro__(s, len, fmt, ap);\n   va_end(ap);\n   return _len;\n}\n#endif\n"
  },
  {
    "path": "compat/compat_strcasestr.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_strcasestr.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <ctype.h>\n\n#include <compat/strcasestr.h>\n\n/* Pretty much strncasecmp. */\nstatic int casencmp(const char *a, const char *b, size_t n)\n{\n   size_t i;\n\n   for (i = 0; i < n; i++)\n   {\n      int a_lower = tolower(a[i]);\n      int b_lower = tolower(b[i]);\n      if (a_lower != b_lower)\n         return a_lower - b_lower;\n   }\n\n   return 0;\n}\n\nchar *strcasestr_retro__(const char *haystack, const char *needle)\n{\n   size_t _len  = strlen(needle);\n   size_t __len = strlen(haystack);\n   if (_len <= __len)\n   {\n      size_t i;\n      __len -= _len; /* offset */\n      for (i = 0; i <= __len; i++)\n         if (!casencmp(haystack + i, needle, _len))\n            return (char*)haystack + i;\n   }\n   return NULL;\n}\n"
  },
  {
    "path": "compat/compat_strl.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_strl.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <ctype.h>\n\n#include <compat/strl.h>\n\n/* Implementation of strlcpy()/strlcat() based on OpenBSD. */\n\n#if !(defined(__MACH__) && defined(__APPLE__))\nsize_t strlcpy(char *s, const char *in, size_t len)\n{\n    size_t _len = strlen(in);\n    if (len)\n    {\n        size_t __len = _len < len - 1 ? _len : len - 1;\n        memcpy(s, in, __len);\n        s[__len] = '\\0';\n    }\n    return _len;\n}\n\nsize_t strlcat(char *s, const char *source, size_t len)\n{\n   size_t _len = strlen(s);\n   s += _len;\n   if (_len > len)\n      len = 0;\n   else\n      len -= _len;\n   return _len + strlcpy(s, source, len);\n}\n#endif\n"
  },
  {
    "path": "compat/compat_strldup.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_strl.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <ctype.h>\n\n#include <compat/strl.h>\n\nchar *strldup(const char *s, size_t n)\n{\n   char *dst = (char*)malloc(sizeof(char) * (n + 1));\n   strlcpy(dst, s, n);\n   return dst;\n}\n"
  },
  {
    "path": "compat/compat_vscprintf.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_snprintf.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */\n#ifdef _MSC_VER\n\n#include <retro_common.h>\n\n#include <stdio.h>\n#include <stdarg.h>\n\n#if defined(_MSC_VER) && _MSC_VER < 1800\n#define va_copy(dst, src) ((dst) = (src))\n#endif\n\nint c89_vscprintf_retro__(const char *format, va_list pargs)\n{\n   int _len;\n   va_list argcopy;\n   va_copy(argcopy, pargs);\n   _len = vsnprintf(NULL, 0, format, argcopy);\n   va_end(argcopy);\n   return _len;\n}\n#endif\n"
  },
  {
    "path": "compat/fopen_utf8.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fopen_utf8.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <compat/fopen_utf8.h>\n#include <encodings/utf.h>\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <boolean.h>\n#if defined(__WINRT__)\n#include <stdint.h>\n#include <windows.h>\n#include <fileapifromapp.h>\n#include <io.h>\n#include <fcntl.h>\n#endif\n\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || (defined(_XBOX) && !defined(__WINRT__))\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n#endif\n\n#ifdef _WIN32\n#undef fopen\n\nvoid *fopen_utf8(const char * filename, const char * mode)\n{\n#if defined(LEGACY_WIN32)\n   char * filename_local = utf8_to_local_string_alloc(filename);\n   if (filename_local)\n   {\n      FILE *ret          = fopen(filename_local, mode);\n      free(filename_local);\n      return ret;\n   }\n#else\n   wchar_t * filename_w  = utf8_to_utf16_string_alloc(filename);\n   if (filename_w)\n   {\n      FILE    *ret       = NULL;\n#if defined(__WINRT__)\n      HANDLE   file_handle = INVALID_HANDLE_VALUE;\n      DWORD    desired_access = 0;\n      DWORD    creation_disposition = OPEN_EXISTING;\n      int      open_flags = O_BINARY;\n      int      fd = -1;\n      bool     append = mode && strchr(mode, 'a');\n      bool     write = mode && strchr(mode, 'w');\n      bool     plus = mode && strchr(mode, '+');\n      wchar_t *path = filename_w;\n\n      while (*path)\n      {\n         if (*path == L'/')\n            *path = L'\\\\';\n         path++;\n      }\n\n      if (mode && strchr(mode, 'r'))\n         desired_access |= GENERIC_READ;\n      if (write || append || plus)\n         desired_access |= GENERIC_WRITE;\n      if (plus)\n         desired_access |= GENERIC_READ;\n\n      if (append)\n         creation_disposition = OPEN_ALWAYS;\n      else if (write)\n         creation_disposition = CREATE_ALWAYS;\n\n      if (plus)\n         open_flags |= O_RDWR;\n      else if (append || write)\n         open_flags |= O_WRONLY;\n      else\n         open_flags |= O_RDONLY;\n\n      if (append)\n         open_flags |= O_APPEND;\n      if (write || append)\n         open_flags |= O_CREAT;\n      if (write)\n         open_flags |= O_TRUNC;\n\n      file_handle = CreateFile2FromAppW(filename_w, desired_access,\n            FILE_SHARE_READ | FILE_SHARE_WRITE,\n            creation_disposition, NULL);\n      if (file_handle != INVALID_HANDLE_VALUE)\n      {\n         fd = _open_osfhandle((intptr_t)file_handle, open_flags);\n         if (fd != -1)\n            ret = _fdopen(fd, mode);\n\n         if (!ret)\n         {\n            if (fd != -1)\n               _close(fd);\n            else\n               CloseHandle(file_handle);\n         }\n      }\n#else\n      wchar_t *mode_w    = utf8_to_utf16_string_alloc(mode);\n      if (mode_w)\n      {\n         ret             = _wfopen(filename_w, mode_w);\n         free(mode_w);\n      }\n#endif\n      free(filename_w);\n      return ret;\n   }\n#endif\n   return NULL;\n}\n#endif\n"
  },
  {
    "path": "crt/include/string.h",
    "content": "#ifndef __LIBRETRO_SDK_CRT_STRING_H_\n#define __LIBRETRO_SDK_CRT_STRING_H_\n\n#include <stdio.h>\n\nvoid *memcpy(void *dst, const void *src, size_t len);\n\nvoid *memset(void *b, int c, size_t len);\n\n#endif\n"
  },
  {
    "path": "crt/string.c",
    "content": "#ifdef _MSC_VER\n#include <cruntime.h>\n#endif\n#include <stdio.h>\n#include <string.h>\n\nvoid *memset(void *dst, int val, size_t count)\n{\n   void *start = dst;\n\n#if defined(_M_IA64) || defined (_M_AMD64) || defined(_M_ALPHA) || defined (_M_PPC)\n   extern void RtlFillMemory(void *, size_t count, char);\n\n   RtlFillMemory(dst, count, (char)val);\n#else\n   while (count--)\n   {\n      *(char*)dst = (char)val;\n      dst = (char*)dst + 1;\n   }\n#endif\n\n   return start;\n}\n\nvoid *memcpy(void *dst, const void *src, size_t len)\n{\n   size_t i;\n\n   for (i = 0; i < len; i++)\n      ((unsigned char *)dst)[i] = ((unsigned char *)src)[i];\n\n   return dst;\n}\n"
  },
  {
    "path": "dynamic/dylib.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (dylib.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n#include <stdio.h>\n#include <dynamic/dylib.h>\n#include <encodings/utf.h>\n#include <string/stdstring.h>\n#include <retro_miscellaneous.h>\n#include <file/file_path.h>\n\n#if defined(ORBIS)\n#include <orbis/libkernel.h>\n#endif\n\n#ifdef NEED_DYNAMIC\n\n#ifdef _WIN32\n#include <compat/posix_string.h>\n#include <windows.h>\n#else\n#if !defined(ORBIS)\n#include <dlfcn.h>\n#endif\n#endif\n\n/* Assume W-functions do not work below Win2K and Xbox platforms */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)\n\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n\n#endif\n\n#ifdef _WIN32\nstatic char last_dyn_err[512];\n\nstatic void set_dl_err(void)\n{\n   DWORD err = GetLastError();\n   if (FormatMessage(\n              FORMAT_MESSAGE_IGNORE_INSERTS\n            | FORMAT_MESSAGE_FROM_SYSTEM,\n            NULL, err,\n            MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),\n            last_dyn_err, sizeof(last_dyn_err) - 1,\n            NULL) == 0)\n      snprintf(last_dyn_err, sizeof(last_dyn_err) - 1,\n            \"unknown error %lu\", err);\n}\n#endif\n\n/**\n * dylib_load:\n * @path                         : Path to libretro core library.\n *\n * Platform independent dylib loading.\n *\n * @return Library handle on success, otherwise NULL.\n **/\ndylib_t dylib_load(const char *path)\n{\n#ifdef _WIN32\n#ifndef __WINRT__\n   int prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);\n#endif\n#ifdef __WINRT__\n   dylib_t lib;\n   /* On UWP, you can only load DLLs inside your install directory, using a special function that takes a relative path */\n   char relative_path_abbrev[PATH_MAX_LENGTH];\n   char *relative_path = relative_path_abbrev;\n   wchar_t *path_wide  = NULL;\n\n   relative_path_abbrev[0] = '\\0';\n\n   if (!path_is_absolute(path))\n      RARCH_WARN(\"Relative path in dylib_load! This is likely an attempt to load a system library that will fail.\\n\");\n\n   fill_pathname_abbreviate_special(relative_path_abbrev, path, sizeof(relative_path_abbrev));\n\n   /* Path to dylib_load is not inside app install directory.\n    * Loading will probably fail. */\n   if (relative_path[0] != ':' || !PATH_CHAR_IS_SLASH(relative_path[1])) { }\n   else\n      relative_path += 2;\n\n   path_wide = utf8_to_utf16_string_alloc(relative_path);\n   lib       = LoadPackagedLibrary(path_wide, 0);\n   free(path_wide);\n#elif defined(LEGACY_WIN32)\n   dylib_t lib        = LoadLibrary(path);\n#else\n   wchar_t *path_wide = utf8_to_utf16_string_alloc(path);\n   dylib_t lib        = LoadLibraryW(path_wide);\n   free(path_wide);\n#endif\n\n#ifndef __WINRT__\n   SetErrorMode(prevmode);\n#endif\n\n   if (!lib)\n   {\n      set_dl_err();\n      return NULL;\n   }\n   last_dyn_err[0] = 0;\n#elif defined(ORBIS)\n   int res;\n   dylib_t lib = (dylib_t)sceKernelLoadStartModule(path, 0, NULL, 0, NULL, &res);\n#elif defined(IOS) || defined(OSX)\n    dylib_t lib;\n    static const char fw_suffix[] = \".framework\";\n    if (string_ends_with(path, fw_suffix))\n    {\n        char fw_path[PATH_MAX_LENGTH];\n        const char *fw_name = path_basename(path);\n        size_t _len         = strlcpy(fw_path, path, sizeof(fw_path));\n        _len += strlcpy(fw_path + _len, \"/\", sizeof(fw_path) - _len);\n        /* Assume every framework binary is named for the framework. Not always\n         * a great assumption but correct enough for our uses. */\n        strlcpy(fw_path + _len, fw_name, strlen(fw_name) - STRLEN_CONST(fw_suffix) + 1);\n        lib = dlopen(fw_path, RTLD_LAZY | RTLD_LOCAL);\n    }\n    else\n        lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);\n#else\n   dylib_t lib = dlopen(path, RTLD_LAZY | RTLD_LOCAL);\n#endif\n   return lib;\n}\n\nchar *dylib_error(void)\n{\n#ifdef _WIN32\n   if (last_dyn_err[0])\n      return last_dyn_err;\n   return NULL;\n#else\n   return (char*)dlerror();\n#endif\n}\n\nfunction_t dylib_proc(dylib_t lib, const char *proc)\n{\n   function_t sym;\n\n#ifdef _WIN32\n   HMODULE mod = (HMODULE)lib;\n   if (!mod)\n   {\n#ifdef __WINRT__\n      /* GetModuleHandle is not available on UWP */\n      /* It's not possible to lookup symbols in current executable\n       * on UWP. */\n      DebugBreak();\n      return NULL;\n#else\n      mod = GetModuleHandle(NULL);\n#endif\n   }\n   if (!(sym = (function_t)GetProcAddress(mod, proc)))\n   {\n      set_dl_err();\n      return NULL;\n   }\n   last_dyn_err[0] = 0;\n#elif defined(ORBIS)\n   void *ptr_sym = NULL;\n   sym = NULL;\n\n   if (lib)\n   {\n     sceKernelDlsym((SceKernelModule)lib, proc, &ptr_sym);\n     memcpy(&sym, &ptr_sym, sizeof(void*));\n   }\n#else\n   void *ptr_sym = NULL;\n\n   if (lib)\n      ptr_sym = dlsym(lib, proc);\n   else\n   {\n      void *handle = dlopen(NULL, RTLD_LAZY);\n      if (handle)\n      {\n         ptr_sym = dlsym(handle, proc);\n         dlclose(handle);\n      }\n   }\n\n   /* Dirty hack to workaround the non-legality of\n    * (void*) -> fn-pointer casts. */\n   memcpy(&sym, &ptr_sym, sizeof(void*));\n#endif\n\n   return sym;\n}\n\n/**\n * dylib_close:\n * @lib                          : Library handle.\n *\n * Frees library handle.\n **/\nvoid dylib_close(dylib_t lib)\n{\n#ifdef _WIN32\n   if (!FreeLibrary((HMODULE)lib))\n      set_dl_err();\n   last_dyn_err[0] = 0;\n#elif defined(ORBIS)\n   int res;\n   sceKernelStopUnloadModule((SceKernelModule)lib, 0, NULL, 0, NULL, &res);\n#else\n#ifndef NO_DLCLOSE\n   dlclose(lib);\n#endif\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "encodings/encoding_base64.c",
    "content": "/*\n  https://github.com/superwills/NibbleAndAHalf\n  base64.h -- Fast base64 encoding and decoding.\n  version 1.0.0, April 17, 2013 143a\n  Copyright (C) 2013 William Sherif\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n  William Sherif\n  will.sherif@gmail.com\n  YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz\n\n\n  Modified for RetroArch formatting, logging, and header files.\n*/\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <encodings/base64.h>\n\nstatic const char* b64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n/* maps A=>0,B=>1.. */\nstatic const unsigned char unb64[]={\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,  62,   0,   0,   0,  63,  52,  53,\n 54,  55,  56,  57,  58,  59,  60,  61,   0,   0,\n  0,   0,   0,   0,   0,   0,   1,   2,   3,   4,\n  5,   6,   7,   8,   9,  10,  11,  12,  13,  14,\n 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,\n 25,   0,   0,   0,   0,   0,   0,  26,  27,  28,\n 29,  30,  31,  32,  33,  34,  35,  36,  37,  38,\n 39,  40,  41,  42,  43,  44,  45,  46,  47,  48,\n 49,  50,  51,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n  0,   0,   0,   0,   0,   0,\n}; /* This array has 256 elements */\n\n/*\n   Converts binary data of length=len to base64 characters.\n   Length of the resultant string is stored in flen\n   (you must pass pointer flen).\n*/\nchar* base64(const void* binaryData, int len, int *flen)\n{\n   char* res;\n   int byteNo; /* I need this after the loop */\n   const unsigned char* bin = (const unsigned char*) binaryData;\n   int rc                   = 0; /* result counter */\n   int modulusLen           = len % 3 ;\n   /* 2 gives 1 and 1 gives 2, but 0 gives 0. */\n   int pad                  = ((modulusLen&1)<<1) + ((modulusLen&2)>>1);\n\n   *flen                    = 4*(len + pad)/3;\n   if (!(res = (char*) malloc(*flen + 1))) /* and one for the NULL */\n      return 0;\n  \n   for (byteNo=0; byteNo <= len-3; byteNo+=3)\n   {\n      unsigned char BYTE0            = bin[byteNo];\n      unsigned char BYTE1            = bin[byteNo+1];\n      unsigned char BYTE2            = bin[byteNo+2];\n\n      res[rc++] = b64[BYTE0 >> 2];\n      res[rc++] = b64[((0x3&BYTE0)<<4) + (BYTE1 >> 4)];\n      res[rc++] = b64[((0x0f&BYTE1)<<2) + (BYTE2>>6)];\n      res[rc++] = b64[0x3f&BYTE2];\n   }\n  \n   if (pad==2)\n   {\n      res[rc++] = b64[bin[byteNo] >> 2];\n      res[rc++] = b64[(0x3&bin[byteNo])<<4];\n      res[rc++] = '=';\n      res[rc++] = '=';\n   }\n   else if (pad==1)\n   {\n      res[rc++] = b64[bin[byteNo] >> 2];\n      res[rc++] = b64[((0x3&bin[byteNo])<<4) + (bin[byteNo+1] >> 4)];\n      res[rc++] = b64[(0x0f&bin[byteNo+1])<<2];\n      res[rc++] = '=';\n   }\n  \n   res[rc]=0; /* NULL TERMINATOR! ;) */\n   return res;\n}\n\nunsigned char* unbase64(const char* ascii, int len, int *flen)\n{\n   int charNo;\n   unsigned char *bin;\n   const unsigned char *safeAsciiPtr = (const unsigned char*) ascii;\n   int cb                            = 0;\n   int pad                           = 0;\n\n   /* Valid base64 has length that is a non-zero multiple of 4.\n    * Shorter or misaligned inputs are malformed and have historically\n    * caused 1-byte heap overflows when pad > 0 (e.g. \"AB=\"). */\n   if (len < 4 || (len & 3) != 0)\n   {\n      *flen = 0;\n      return 0;\n   }\n\n   if (safeAsciiPtr[len-1]=='=')\n      ++pad;\n   if (safeAsciiPtr[len-2]=='=')\n      ++pad;\n  \n   *flen = 3*len/4 - pad;\n   if (!(bin = (unsigned char*)malloc(*flen)))\n      return 0;\n  \n   for (charNo=0; charNo <= len-4-pad; charNo+=4)\n   {\n      int A = unb64[safeAsciiPtr[charNo]];\n      int B = unb64[safeAsciiPtr[charNo+1]];\n      int C = unb64[safeAsciiPtr[charNo+2]];\n      int D = unb64[safeAsciiPtr[charNo+3]];\n    \n      bin[cb++] = (A<<2) | (B>>4);\n      bin[cb++] = (B<<4) | (C>>2);\n      bin[cb++] = (C<<6) | (D);\n   }\n  \n   if (pad==1)\n   {\n      int A = unb64[safeAsciiPtr[charNo]];\n      int B = unb64[safeAsciiPtr[charNo+1]];\n      int C = unb64[safeAsciiPtr[charNo+2]];\n    \n      bin[cb++] = (A<<2) | (B>>4);\n      bin[cb++] = (B<<4) | (C>>2);\n   }\n   else if (pad==2)\n   {\n      int A = unb64[safeAsciiPtr[charNo]];\n      int B = unb64[safeAsciiPtr[charNo+1]];\n    \n      bin[cb++] = (A<<2) | (B>>4);\n   }\n  \n   return bin;\n}\n\n"
  },
  {
    "path": "encodings/encoding_crc32.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (encoding_crc32.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stddef.h>\n#include <encodings/crc32.h>\n#include <stdlib.h>\n\n/*\n * Standard CRC-32 lookup table (slice 0).\n * Polynomial 0xEDB88320 (bit-reflected 0x04C11DB7),\n * compatible with zlib, gzip, PNG, etc.\n */\nstatic const uint32_t crc32_table[256] = {\n   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,\n   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,\n   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,\n   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,\n   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,\n   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,\n   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,\n   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,\n   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,\n   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,\n   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,\n   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,\n   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,\n   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,\n   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,\n   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,\n   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,\n   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,\n   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,\n   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,\n   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,\n   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,\n   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,\n   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,\n   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,\n   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,\n   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,\n   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,\n   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,\n   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,\n   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,\n   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,\n   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,\n   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,\n   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,\n   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,\n   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,\n   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,\n   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,\n   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,\n   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,\n   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,\n   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,\n   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,\n   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,\n   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,\n   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,\n   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,\n   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,\n   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,\n   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,\n   0x2d02ef8dL\n};\n\n#if __ARM_FEATURE_CRC32\n\n#ifdef _M_ARM64\n# include <arm64_neon.h>\n#else\n# include <arm_acle.h>\n#endif\n\nuint32_t encoding_crc32(uint32_t crc, const uint8_t *data, size_t len)\n{\n   crc = ~crc;\n   /* Align data if it is not aligned */\n   while (((uintptr_t)data & 7) && len > 0)\n   {\n      crc = __crc32b(crc, *(uint8_t *)data);\n      data++;\n      len--;\n   }\n   while (len >= 8)\n   {\n      crc = __crc32d(crc, *(uint64_t *)data);\n      data += 8;\n      len -= 8;\n   }\n   while (len > 0)\n   {\n      crc = __crc32b(crc, *(uint8_t *)data);\n      data++;\n      len--;\n   }\n   return ~crc;\n}\n\n#elif defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)\n\n/*\n * Slicing-by-8: processes 8 bytes per loop iteration using 8 parallel\n * table lookups and XORs. ~4-5x faster than the byte-at-a-time fallback\n * on x86 without requiring any SIMD or special instruction set extensions.\n *\n * Reference: \"High Octane CRC Generation with the Intel Slicing-by-8\n * Algorithm\", Intel Corporation.\n *\n * The 8 KiB table (crc32_slice8[8][256]) is generated at startup from\n * the base crc32_table[256] to avoid a massive static initializer.\n * The generation runs once and is guarded by a simple flag.\n */\n\nstatic uint32_t crc32_slice8[8][256];\nstatic int      crc32_slice8_ready;\n\nstatic void crc32_slice8_init(void)\n{\n   unsigned i;\n\n   /* Slice 0 is a copy of the standard table */\n   for (i = 0; i < 256; i++)\n      crc32_slice8[0][i] = crc32_table[i];\n\n   /* Build slices 1-7: each entry is one more byte of CRC iteration\n    * applied to the previous slice's entry. */\n   for (i = 0; i < 256; i++)\n   {\n      unsigned s;\n      uint32_t c = crc32_slice8[0][i];\n      for (s = 1; s < 8; s++)\n      {\n         c = crc32_slice8[0][c & 0xff] ^ (c >> 8);\n         crc32_slice8[s][i] = c;\n      }\n   }\n\n   crc32_slice8_ready = 1;\n}\n\nuint32_t encoding_crc32(uint32_t crc, const uint8_t *data, size_t len)\n{\n   if (!crc32_slice8_ready)\n      crc32_slice8_init();\n\n   crc = ~crc;\n\n   /* Process 8 bytes at a time */\n   while (len >= 8)\n   {\n      /* Read two 32-bit words (little-endian assumed on x86) */\n      uint32_t lo  = *(const uint32_t *)(data + 0) ^ crc;\n      uint32_t hi  = *(const uint32_t *)(data + 4);\n\n      crc = crc32_slice8[7][ lo        & 0xff]\n          ^ crc32_slice8[6][(lo >>  8) & 0xff]\n          ^ crc32_slice8[5][(lo >> 16) & 0xff]\n          ^ crc32_slice8[4][(lo >> 24)       ]\n          ^ crc32_slice8[3][ hi        & 0xff]\n          ^ crc32_slice8[2][(hi >>  8) & 0xff]\n          ^ crc32_slice8[1][(hi >> 16) & 0xff]\n          ^ crc32_slice8[0][(hi >> 24)       ];\n\n      data += 8;\n      len  -= 8;\n   }\n\n   /* Handle remaining bytes */\n   while (len--)\n      crc = crc32_table[(crc ^ (*data++)) & 0xff] ^ (crc >> 8);\n\n   return ~crc;\n}\n#else\nstatic uint32_t encoding_crc32_sw(uint32_t crc, const uint8_t *data, size_t len)\n{\n   crc = ~crc;\n   while (len--)\n      crc = crc32_table[(crc ^ (*data++)) & 0xff] ^ (crc >> 8);\n   return ~crc;\n}\n\nuint32_t encoding_crc32(uint32_t crc, const uint8_t *data, size_t len)\n{\n   return encoding_crc32_sw(crc, data, len);\n}\n#endif\n"
  },
  {
    "path": "encodings/encoding_utf.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (encoding_utf.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n\n#include <boolean.h>\n#include <compat/strl.h>\n#include <retro_inline.h>\n\n#include <encodings/utf.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#include <windows.h>\n#elif defined(_XBOX)\n#include <xtl.h>\n#endif\n\n#define UTF8_WALKBYTE(string) (*((*(string))++))\n\n/* Lookup table replaces leading_ones() bit-counting loop.\n * Index by high byte value >> 3 (32 entries) to get\n * the number of leading 1-bits for any byte.\n * Only values 0..7 are meaningful for UTF-8;\n * entries for invalid prefixes are set to 0xFF. */\nstatic const uint8_t utf8_lut[256] = {\n   /* 0x00..0x7F: 0 leading ones (ASCII) */\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n   /* 0x80..0xBF: 1 leading one (continuation byte) */\n   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n   1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\n   /* 0xC0..0xDF: 2 leading ones (2-byte sequence) */\n   2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,\n   2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,\n   /* 0xE0..0xEF: 3 leading ones (3-byte sequence) */\n   3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,\n   /* 0xF0..0xF7: 4 leading ones (4-byte sequence) */\n   4,4,4,4,4,4,4,4,\n   /* 0xF8..0xFB: 5 leading ones */\n   5,5,5,5,\n   /* 0xFC..0xFD: 6 leading ones */\n   6,6,\n   /* 0xFE..0xFF: 7+ leading ones (invalid) */\n   7,7\n};\n\n/**\n * utf8_conv_utf32:\n *\n * Simple implementation. Assumes the sequence is\n * properly synchronized and terminated.\n *\n * Optimized: replaced leading_ones() loop with LUT,\n * fast-path for ASCII, and unrolled continuation-byte reads.\n **/\nsize_t utf8_conv_utf32(uint32_t *out, size_t out_chars,\n      const char *in, size_t in_size)\n{\n   size_t ret = 0;\n   while (in_size && out_chars)\n   {\n      uint32_t c;\n      uint8_t first;\n      unsigned ones;\n\n      /* Fast path: batch ASCII characters */\n      while (in_size && out_chars && (uint8_t)*in < 0x80)\n      {\n         *out++ = (uint8_t)*in++;\n         in_size--;\n         out_chars--;\n         ret++;\n      }\n\n      if (!in_size || !out_chars)\n         break;\n\n      first = (uint8_t)*in++;\n      ones  = utf8_lut[first];\n\n      if (ones > 6 || ones < 2) /* Invalid or desync. */\n         break;\n\n      /* ones includes the lead byte; we already consumed it,\n       * but need (ones - 1) more continuation bytes */\n      if (ones > in_size)       /* Not enough data. */\n         break;\n\n      /* Decode based on sequence length to avoid inner loop */\n      c = first & ((1 << (7 - ones)) - 1);\n      switch (ones)\n      {\n         case 4:\n            c = (c << 6) | ((uint8_t)*in++ & 0x3F);\n            /* fall through */\n         case 3:\n            c = (c << 6) | ((uint8_t)*in++ & 0x3F);\n            /* fall through */\n         case 2:\n            c = (c << 6) | ((uint8_t)*in++ & 0x3F);\n            break;\n         default:\n         {\n            /* 5 or 6 byte sequences (ones == 5 or 6) */\n            unsigned i;\n            unsigned extra = ones - 1;\n            for (i = 0; i < extra; i++)\n               c = (c << 6) | ((uint8_t)*in++ & 0x3F);\n            break;\n         }\n      }\n\n      *out++   = c;\n      in_size -= ones;\n      out_chars--;\n      ret++;\n   }\n   return ret;\n}\n\n/**\n * utf16_conv_utf8:\n *\n * Leaf function.\n *\n * Optimized: separated counting-only path (out==NULL) from\n * encoding path to eliminate per-byte branch on `out`.\n * Added explicit fast-path for BMP 2-byte and 3-byte encodings.\n **/\nbool utf16_conv_utf8(uint8_t *out, size_t *out_chars,\n     const uint16_t *in, size_t in_size)\n{\n   size_t out_pos = 0;\n   size_t in_pos  = 0;\n\n   if (!out)\n   {\n      /* Counting-only pass: no stores, \n         no per-byte `if (out)` branches */\n      for (;;)\n      {\n         uint32_t value;\n         if (in_pos == in_size)\n         {\n            *out_chars = out_pos;\n            return true;\n         }\n         value = in[in_pos++];\n\n         if (value < 0x80)\n         {\n            out_pos++;\n            continue;\n         }\n\n         if (value >= 0xD800 && value < 0xE000)\n         {\n            uint32_t c2;\n            if (value >= 0xDC00 || in_pos == in_size)\n               break;\n            c2 = in[in_pos++];\n            if (c2 < 0xDC00 || c2 >= 0xE000)\n               break;\n            value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;\n         }\n\n         if (value < 0x800)\n            out_pos += 2;\n         else if (value < 0x10000)\n            out_pos += 3;\n         else\n            out_pos += 4;\n      }\n      *out_chars = out_pos;\n      return false;\n   }\n\n   /* Encoding pass */\n   for (;;)\n   {\n      uint32_t value;\n      if (in_pos == in_size)\n      {\n         *out_chars = out_pos;\n         return true;\n      }\n\n      /* Batch ASCII run: avoid per-char branch into multi-byte path */\n      while (in_pos < in_size && in[in_pos] < 0x80)\n         out[out_pos++] = (uint8_t)in[in_pos++];\n\n      if (in_pos == in_size)\n      {\n         *out_chars = out_pos;\n         return true;\n      }\n\n      value = in[in_pos++];\n\n      if (value >= 0xD800 && value < 0xE000)\n      {\n         uint32_t c2;\n         if (value >= 0xDC00 || in_pos == in_size)\n            break;\n         c2 = in[in_pos++];\n         if (c2 < 0xDC00 || c2 >= 0xE000)\n            break;\n         value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;\n      }\n\n      if (value < 0x800)\n      {\n         /* 2-byte sequence */\n         out[out_pos]     = (uint8_t)(0xC0 | (value >> 6));\n         out[out_pos + 1] = (uint8_t)(0x80 | (value & 0x3F));\n         out_pos += 2;\n      }\n      else if (value < 0x10000)\n      {\n         /* 3-byte sequence */\n         out[out_pos]     = (uint8_t)(0xE0 | (value >> 12));\n         out[out_pos + 1] = (uint8_t)(0x80 | ((value >> 6) & 0x3F));\n         out[out_pos + 2] = (uint8_t)(0x80 | (value & 0x3F));\n         out_pos += 3;\n      }\n      else\n      {\n         /* 4-byte sequence */\n         out[out_pos]     = (uint8_t)(0xF0 | (value >> 18));\n         out[out_pos + 1] = (uint8_t)(0x80 | ((value >> 12) & 0x3F));\n         out[out_pos + 2] = (uint8_t)(0x80 | ((value >> 6) & 0x3F));\n         out[out_pos + 3] = (uint8_t)(0x80 | (value & 0x3F));\n         out_pos += 4;\n      }\n   }\n\n   *out_chars = out_pos;\n   return false;\n}\n\n/**\n * utf8cpy:\n *\n * Acts mostly like strlcpy.\n *\n * Copies the given number of UTF-8 characters,\n * but at most @len bytes.\n *\n * Always NULL terminates. Does not copy half a character.\n * @s is assumed valid UTF-8.\n * Use only if @chars is considerably less than @len.\n *\n * @return Number of bytes.\n **/\nsize_t utf8cpy(char *s, size_t len, const char *in, size_t chars)\n{\n   size_t byte_count;\n   const uint8_t *sb     = (const uint8_t*)in;\n   const uint8_t *sb_org = sb;\n\n   if (!in)\n      return 0;\n\n   while (*sb && chars-- > 0)\n   {\n      /* Use LUT to skip entire character at once\n       * instead of byte-by-byte continuation check */\n      unsigned ones = utf8_lut[*sb];\n      if (ones < 2)\n         sb++;          /* ASCII or (invalid) standalone continuation */\n      else\n         sb += ones;    /* Skip full multi-byte character */\n   }\n\n   if ((size_t)(sb - sb_org) > len - 1)\n   {\n      sb = sb_org + len - 1;\n      while ((*sb & 0xC0) == 0x80)\n         sb--;\n   }\n\n   byte_count = (size_t)(sb - sb_org);\n   memcpy(s, sb_org, byte_count);\n   s[byte_count] = '\\0';\n   return byte_count;\n}\n\n/**\n * utf8skip:\n *\n * Leaf function.\n *\n * Optimized: use LUT to jump over entire multi-byte\n * characters instead of scanning continuation bytes.\n **/\nconst char *utf8skip(const char *str, size_t chars)\n{\n   const uint8_t *strb = (const uint8_t*)str;\n\n   if (!chars)\n      return str;\n\n   do\n   {\n      unsigned ones;\n      if (!*strb)\n         break;\n      ones = utf8_lut[*strb];\n      if (ones < 2)\n         strb++;\n      else\n      {\n         /* Verify we don't walk past a NUL inside a multi-byte seq */\n         unsigned i;\n         for (i = 0; i < ones && strb[i]; i++)\n            ;\n         strb += i;\n      }\n   } while (--chars);\n\n   return (const char*)strb;\n}\n\n/**\n * utf8len:\n *\n * Leaf function.\n *\n * Optimized: use LUT to skip entire multi-byte sequences\n * instead of testing each byte individually.\n **/\nsize_t utf8len(const char *string)\n{\n   size_t ret = 0;\n\n   if (!string)\n      return 0;\n\n   while (*string)\n   {\n      unsigned ones = utf8_lut[(uint8_t)*string];\n      ret++;\n      /* ASCII (ones==0) or continuation byte (ones==1, shouldn't\n       * appear at sequence start in valid UTF-8). Either way,\n       * count it and advance one byte. */\n      if (ones < 2)\n         string++;\n      else /* Multi-byte lead: count one character, skip `ones` bytes */\n         string += ones;\n   }\n   return ret;\n}\n\n/**\n * utf8_walk:\n *\n * Does not validate the input.\n *\n * Leaf function.\n *\n * @return Returns garbage if it's not UTF-8.\n **/\nuint32_t utf8_walk(const char **string)\n{\n   const uint8_t *s = (const uint8_t*)*string;\n   uint8_t first    = *s++;\n   uint32_t ret;\n\n   if (first < 0x80)\n   {\n      *string = (const char*)s;\n      return first;\n   }\n\n   /* Use LUT + switch to decode, matching utf8_conv_utf32 style */\n   ret = first & ((1 << (7 - utf8_lut[first])) - 1);\n   switch (utf8_lut[first])\n   {\n      case 4:\n         ret = (ret << 6) | (*s++ & 0x3F);\n         /* fall through */\n      case 3:\n         ret = (ret << 6) | (*s++ & 0x3F);\n         /* fall through */\n      case 2:\n         ret = (ret << 6) | (*s++ & 0x3F);\n         break;\n      default:\n         break;\n   }\n\n   *string = (const char*)s;\n   return ret;\n}\n\nstatic bool utf16_to_char(uint8_t **utf_data,\n      size_t *dest_len, const uint16_t *in)\n{\n   const uint16_t *p = in;\n   /* Find length in a single scan */\n   while (*p != 0)\n      p++;\n   {\n      size_t in_len = (size_t)(p - in);\n      utf16_conv_utf8(NULL, dest_len, in, in_len);\n      *dest_len  += 1;\n      if ((*utf_data = (uint8_t*)malloc(*dest_len)) != 0)\n         return utf16_conv_utf8(*utf_data, dest_len, in, in_len);\n   }\n   return false;\n}\n\n/**\n * utf16_to_char_string:\n **/\nbool utf16_to_char_string(const uint16_t *in, char *s, size_t len)\n{\n   size_t  _len        = 0;\n   uint8_t *utf16_data = NULL;\n   bool            ret = utf16_to_char(&utf16_data, &_len, in);\n   if (ret)\n   {\n      utf16_data[_len] = 0;\n      strlcpy(s, (const char*)utf16_data, len);\n   }\n   free(utf16_data);\n   utf16_data          = NULL;\n   return ret;\n}\n\n#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)\n/**\n * mb_to_mb_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nstatic char *mb_to_mb_string_alloc(const char *str,\n      enum CodePage cp_in, enum CodePage cp_out)\n{\n   wchar_t *path_buf_wide = NULL;\n   int path_buf_wide_len  = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);\n\n   /* Windows 95 will return 0 from these functions with\n    * a UTF8 codepage set without MSLU.\n    *\n    * From an unknown MSDN version (others omit this info):\n    *   - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:\n    *   Translate using UTF-8. When this is set, dwFlags must be zero.\n    *   - Windows 95: Under the Microsoft Layer for Unicode,\n    *   MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.\n    */\n\n   if (!path_buf_wide_len)\n      return strdup(str);\n\n   if ((path_buf_wide = (wchar_t*)\n      calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t))))\n   {\n      MultiByteToWideChar(cp_in, 0,\n            str, -1, path_buf_wide, path_buf_wide_len);\n\n      if (*path_buf_wide)\n      {\n         int path_buf_len = WideCharToMultiByte(cp_out, 0,\n               path_buf_wide, -1, NULL, 0, NULL, NULL);\n\n         if (path_buf_len)\n         {\n            char *path_buf = (char*)\n               calloc(path_buf_len + sizeof(char), sizeof(char));\n\n            if (path_buf)\n            {\n               WideCharToMultiByte(cp_out, 0,\n                     path_buf_wide, -1, path_buf,\n                     path_buf_len, NULL, NULL);\n\n               free(path_buf_wide);\n\n               if (*path_buf)\n                  return path_buf;\n\n               free(path_buf);\n               return NULL;\n            }\n         }\n         else\n         {\n            free(path_buf_wide);\n            return strdup(str);\n         }\n      }\n\n      free(path_buf_wide);\n   }\n\n   return NULL;\n}\n#endif\n\n/**\n * utf8_to_local_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nchar* utf8_to_local_string_alloc(const char *str)\n{\n   if (str && *str)\n#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)\n      return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);\n#else\n      return strdup(str); /* Assume string needs no modification if not on Windows */\n#endif\n   return NULL;\n}\n\n/**\n * local_to_utf8_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nchar *local_to_utf8_string_alloc(const char *str)\n{\n\tif (str && *str)\n#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)\n\t\treturn mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);\n#else\n      return strdup(str); /* Assume string needs no modification if not on Windows */\n#endif\n\treturn NULL;\n}\n\n/**\n * utf8_to_utf16_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nwchar_t *utf8_to_utf16_string_alloc(const char *str)\n{\n#ifdef _WIN32\n   int _len       = 0;\n#else\n   size_t _len    = 0;\n#endif\n   wchar_t *buf   = NULL;\n\n   if (!str || !*str)\n      return NULL;\n\n#ifdef _WIN32\n   if ((_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))\n   {\n      if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))\n         return NULL;\n\n      if ((MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, _len)) < 0)\n      {\n         free(buf);\n         return NULL;\n      }\n   }\n   else\n   {\n      /* Fallback to ANSI codepage instead */\n      if ((_len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)))\n      {\n         if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))\n            return NULL;\n\n         if ((MultiByteToWideChar(CP_ACP, 0, str, -1, buf, _len)) < 0)\n         {\n            free(buf);\n            return NULL;\n         }\n      }\n   }\n#else\n   /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */\n   if ((_len = mbstowcs(NULL, str, 0) + 1))\n   {\n      if (!(buf = (wchar_t*)calloc(_len, sizeof(wchar_t))))\n         return NULL;\n\n      if ((mbstowcs(buf, str, _len)) == (size_t)-1)\n      {\n         free(buf);\n         return NULL;\n      }\n   }\n#endif\n\n   return buf;\n}\n\n/**\n * utf16_to_utf8_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nchar *utf16_to_utf8_string_alloc(const wchar_t *str)\n{\n#ifdef _WIN32\n   int _len       = 0;\n#else\n   size_t _len    = 0;\n#endif\n   char *buf      = NULL;\n\n   if (!str || !*str)\n      return NULL;\n\n#ifdef _WIN32\n   {\n      UINT code_page = CP_UTF8;\n\n      /* fallback to ANSI codepage instead */\n      if (!(_len = WideCharToMultiByte(code_page,\n            0, str, -1, NULL, 0, NULL, NULL)))\n      {\n         code_page   = CP_ACP;\n         _len        = WideCharToMultiByte(code_page,\n               0, str, -1, NULL, 0, NULL, NULL);\n      }\n\n      if (!(buf = (char*)calloc(_len, sizeof(char))))\n         return NULL;\n\n      if (WideCharToMultiByte(code_page,\n            0, str, -1, buf, _len, NULL, NULL) < 0)\n      {\n         free(buf);\n         return NULL;\n      }\n   }\n#else\n   /* NOTE: For now, assume non-Windows platforms'\n    * locale is already UTF-8. */\n   if ((_len = wcstombs(NULL, str, 0) + 1))\n   {\n      if (!(buf = (char*)calloc(_len, sizeof(char))))\n         return NULL;\n\n      if (wcstombs(buf, str, _len) == (size_t)-1)\n      {\n         free(buf);\n         return NULL;\n      }\n   }\n#endif\n\n   return buf;\n}\n"
  },
  {
    "path": "features/features_cpu.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (features_cpu.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#if defined(_WIN32)\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\n#include <compat/strl.h>\n#include <streams/file_stream.h>\n#include <libretro.h>\n#include <features/features_cpu.h>\n#include <retro_timers.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#include <windows.h>\n#endif\n\n#ifdef __PSL1GHT__\n#include <lv2/systime.h>\n#endif\n\n#if defined(_XBOX360)\n#include <PPCIntrinsics.h>\n#elif !defined(__MACH__) && !defined(__FreeBSD__) && (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))\n#ifndef _PPU_INTRINSICS_H\n#include <ppu_intrinsics.h>\n#endif\n#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)\n/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */\n#include <time.h>\n#endif\n\n#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)\n#define CLOCK_MONOTONIC 2\n#endif\n\n#if defined(PSP)\n#include <pspkernel.h>\n#endif\n\n#if defined(PSP) || defined(__PSL1GHT__)\n#include <sys/time.h>\n#endif\n\n#if defined(PSP)\n#include <psprtc.h>\n#endif\n\n#if defined(VITA)\n#include <psp2/kernel/processmgr.h>\n#include <psp2/rtc.h>\n#endif\n\n#if defined(ORBIS)\n#include <orbis/libkernel.h>\n#endif\n\n#if defined(PS2)\n#include <ps2sdkapi.h>\n#endif\n\n#if !defined(__PSL1GHT__) && defined(__PS3__)\n#include <sys/sys_time.h>\n#endif\n\n#ifdef GEKKO\n#include <ogc/lwp_watchdog.h>\n#endif\n\n#ifdef WIIU\n#include <wiiu/os/time.h>\n#endif\n\n#if defined(HAVE_LIBNX)\n#include <switch.h>\n#elif defined(SWITCH)\n#include <libtransistor/types.h>\n#include <libtransistor/svc.h>\n#endif\n\n#if defined(_3DS)\n#include <3ds/svc.h>\n#include <3ds/os.h>\n#include <3ds/services/cfgu.h>\n#endif\n\n#if defined(WEBOS)\n#include <sys/stat.h>\n#endif\n\n/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */\n#ifdef __MACH__\n#include <sys/time.h>\n#include <AvailabilityMacros.h>\n\n#ifndef CLOCK_MONOTONIC\n#define CLOCK_MONOTONIC 0\n#endif\n\n#ifndef CLOCK_REALTIME\n#define CLOCK_REALTIME 0\n#endif\n\n/* clock_gettime() was added in iOS 10.0 / macOS 10.12 Sierra.\n * On deployment targets below those versions the symbol doesn't\n * exist in libSystem and the link fails, so fall back to a\n * gettimeofday() shim.  Gated on MIN_REQUIRED (deployment target)\n * rather than MAX_ALLOWED (SDK) because the binary needs to run on\n * the deployment target, and Apple weak-links clock_gettime when\n * targeting < 10.12 even from a newer SDK. */\n#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) \\\n       && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000) \\\n || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) \\\n       && MAC_OS_X_VERSION_MIN_REQUIRED < 101200)\n#define RA_NEEDS_CLOCK_GETTIME_SHIM 1\nstatic int ra_clock_gettime(int clk_ik, struct timespec *t)\n{\n   struct timeval now;\n   int rv     = gettimeofday(&now, NULL);\n   if (rv)\n      return rv;\n   t->tv_sec  = now.tv_sec;\n   t->tv_nsec = now.tv_usec * 1000;\n   return 0;\n}\n#endif\n#endif\n\n#if defined(__MACH__) && defined(RA_NEEDS_CLOCK_GETTIME_SHIM)\n#else\n#define ra_clock_gettime clock_gettime\n#endif\n\n#ifdef EMSCRIPTEN\n#include <emscripten.h>\n#endif\n\n#if defined(BSD) || defined(__APPLE__)\n#include <sys/sysctl.h>\n#endif\n\n#include <string.h>\n\nretro_perf_tick_t cpu_features_get_perf_counter(void)\n{\n   retro_perf_tick_t time_ticks = 0;\n#if defined(_WIN32)\n   long tv_sec, tv_usec;\n#if defined(_MSC_VER) && _MSC_VER <= 1200\n   static const unsigned __int64 epoch = 11644473600000000;\n#else\n   static const unsigned __int64 epoch = 11644473600000000ULL;\n#endif\n   FILETIME file_time;\n   SYSTEMTIME system_time;\n   ULARGE_INTEGER ularge;\n\n   GetSystemTime(&system_time);\n   SystemTimeToFileTime(&system_time, &file_time);\n   ularge.LowPart  = file_time.dwLowDateTime;\n   ularge.HighPart = file_time.dwHighDateTime;\n\n   tv_sec     = (long)((ularge.QuadPart - epoch) / 10000000L);\n   tv_usec    = (long)(system_time.wMilliseconds * 1000);\n   time_ticks = (1000000 * tv_sec + tv_usec);\n#elif defined(GEKKO)\n   time_ticks = gettime();\n#elif !defined(__MACH__) && !defined(__FreeBSD__) && (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))\n   time_ticks = __mftb();\n#elif (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0) || defined(__QNX__) || defined(ANDROID)\n   struct timespec tv;\n   if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)\n      time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +\n         (retro_perf_tick_t)tv.tv_nsec;\n\n#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)\n   __asm__ volatile (\"rdtsc\" : \"=A\" (time_ticks));\n#elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)\n   unsigned a, d;\n   __asm__ volatile (\"rdtsc\" : \"=a\" (a), \"=d\" (d));\n   time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);\n#elif defined(__ARM_ARCH_6__)\n   __asm__ volatile( \"mrc p15, 0, %0, c9, c13, 0\" : \"=r\"(time_ticks) );\n#elif defined(__aarch64__)\n   __asm__ volatile( \"mrs %0, cntvct_el0\" : \"=r\"(time_ticks) );\n#elif defined(PSP) || defined(VITA)\n   time_ticks = sceKernelGetSystemTimeWide();\n#elif defined(ORBIS)\n   sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);\n#elif defined(PS2)\n   time_ticks = ps2_clock();\n#elif defined(_3DS)\n   time_ticks = svcGetSystemTick();\n#elif defined(WIIU)\n   time_ticks = OSGetSystemTime();\n#elif defined(HAVE_LIBNX)\n   time_ticks = armGetSystemTick();\n#elif defined(EMSCRIPTEN)\n   time_ticks = emscripten_get_now() * 1000;\n#endif\n\n   return time_ticks;\n}\n\nretro_time_t cpu_features_get_time_usec(void)\n{\n#if defined(_WIN32)\n   static LARGE_INTEGER freq;\n   LARGE_INTEGER count;\n\n   /* Frequency is guaranteed to not change. */\n   if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))\n      return 0;\n\n   if (!QueryPerformanceCounter(&count))\n      return 0;\n   return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);\n#elif defined(__PSL1GHT__)\n   return sysGetSystemTime();\n#elif !defined(__PSL1GHT__) && defined(__PS3__)\n   return sys_time_get_system_time();\n#elif defined(GEKKO)\n   return ticks_to_microsecs(gettime());\n#elif defined(WIIU)\n   return ticks_to_us(OSGetSystemTime());\n#elif defined(SWITCH) || defined(HAVE_LIBNX)\n   return (svcGetSystemTick() * 10) / 192;\n#elif defined(_3DS)\n   return osGetTime() * 1000;\n#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)\n   struct timespec tv;\n   tv.tv_sec  = 0;\n   tv.tv_nsec = 0;\n   if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)\n      return 0;\n   return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;\n#elif defined(EMSCRIPTEN)\n   return emscripten_get_now() * 1000;\n#elif defined(PS2)\n   return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;\n#elif defined(VITA) || defined(PSP)\n   return sceKernelGetSystemTimeWide();\n#elif defined(DJGPP)\n   return uclock() * 1000000LL / UCLOCKS_PER_SEC;\n#elif defined(ORBIS)\n   return sceKernelGetProcessTime();\n#else\n#error \"Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue.\"\n#endif\n}\n\n#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)\n#define CPU_X86\n#endif\n\n#if defined(_MSC_VER) && !defined(_XBOX)\n#if (_MSC_VER > 1310)\n#include <intrin.h>\n#endif\n#endif\n\n#if defined(CPU_X86) && !defined(__MACH__)\n#include <limits.h>\nvoid x86_cpuid(int func, int32_t flags[4])\n{\n   /* On Android, we compile RetroArch with PIC, and we\n    * are not allowed to clobber the ebx register. */\n#ifdef __x86_64__\n#define REG_b \"rbx\"\n#define REG_S \"rsi\"\n#else\n#define REG_b \"ebx\"\n#define REG_S \"esi\"\n#endif\n\n#if defined(__GNUC__)\n   __asm__ volatile (\n         \"mov %%\" REG_b \", %%\" REG_S \"\\n\"\n         \"cpuid\\n\"\n         \"xchg %%\" REG_b \", %%\" REG_S \"\\n\"\n         : \"=a\"(flags[0]), \"=S\"(flags[1]), \"=c\"(flags[2]), \"=d\"(flags[3])\n         : \"a\"(func));\n#elif defined(_MSC_VER) && INT_MAX == 2147483647\n   __cpuid((int*)flags, func);\n#else\n#ifndef NDEBUG\n   printf(\"Unknown compiler. Cannot check CPUID with inline assembly.\\n\");\n#endif\n   memset(flags, 0, 4 * sizeof(int));\n#endif\n}\n\n/* Only runs on i686 and above. Needs to be conditionally run. */\nstatic uint64_t xgetbv_x86(uint32_t idx)\n{\n#if defined(__GNUC__)\n   uint32_t eax, edx;\n   __asm__ volatile (\n         /* Older GCC versions (Apple's GCC for example) do\n          * not understand xgetbv instruction.\n          * Stamp out the machine code directly.\n          */\n         \".byte 0x0f, 0x01, 0xd0\\n\"\n         : \"=a\"(eax), \"=d\"(edx) : \"c\"(idx));\n   return ((uint64_t)edx << 32) | eax;\n#elif _MSC_FULL_VER >= 160040219\n   /* Intrinsic only works on 2010 SP1 and above. */\n   return _xgetbv(idx);\n#else\n#ifndef NDEBUG\n   printf(\"Unknown compiler. Cannot check xgetbv bits.\\n\");\n#endif\n   return 0;\n#endif\n}\n#endif\n\n#if defined(__ARM_NEON__)\n#if defined(__arm__)\nstatic void arm_enable_runfast_mode(void)\n{\n   /* RunFast mode. Enables flush-to-zero and some\n    * floating point optimizations. */\n   static const unsigned x = 0x04086060;\n   static const unsigned y = 0x03000000;\n   int r;\n   __asm__ volatile(\n         \"fmrx\t%0, fpscr   \\n\\t\" /* r0 = FPSCR */\n         \"and\t%0, %0, %1  \\n\\t\" /* r0 = r0 & 0x04086060 */\n         \"orr\t%0, %0, %2  \\n\\t\" /* r0 = r0 | 0x03000000 */\n         \"fmxr\tfpscr, %0   \\n\\t\" /* FPSCR = r0 */\n         : \"=r\"(r)\n         : \"r\"(x), \"r\"(y)\n        );\n}\n#endif\n#endif\n\n#if defined(__linux__) && !defined(CPU_X86)\nstatic unsigned char check_arm_cpu_feature(const char* feature)\n{\n   char line[1024];\n   unsigned char status = 0;\n   RFILE *fp = filestream_open(\"/proc/cpuinfo\",\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n   if (!fp)\n      return 0;\n\n   while (filestream_gets(fp, line, sizeof(line)))\n   {\n      if (strncmp(line, \"Features\\t: \", 11))\n         continue;\n\n      if (strstr(line + 11, feature))\n         status = 1;\n\n      break;\n   }\n\n   filestream_close(fp);\n\n   return status;\n}\n\n#if !defined(_SC_NPROCESSORS_ONLN)\n/**\n * parse_decimal:\n *\n * Parse an decimal integer starting from 'input', but not going further\n * than 'limit'. Return the value into '*result'.\n *\n * NOTE: Does not skip over leading spaces, or deal with sign characters.\n * NOTE: Ignores overflows.\n *\n * The function returns NULL in case of error (bad format), or the new\n * position after the decimal number in case of success (which will always\n * be <= 'limit').\n *\n * Leaf function.\n **/\nstatic const char *parse_decimal(const char* input,\n      const char* limit, int* result)\n{\n    const char* p = input;\n    int       val = 0;\n\n    while (p < limit)\n    {\n        int d = (*p - '0');\n        if ((unsigned)d >= 10U)\n            break;\n        val = val*10 + d;\n        p++;\n    }\n    if (p == input)\n        return NULL;\n\n    *result = val;\n    return p;\n}\n\n/**\n * cpulist_parse:\n * Parse a textual list of cpus and store the result inside a CpuList object.\n * Input format is the following:\n * - comma-separated list of items (no spaces)\n * - each item is either a single decimal number (cpu index), or a range made\n *   of two numbers separated by a single dash (-). Ranges are inclusive.\n *\n * Examples:   0\n *             2,4-127,128-143\n *             0-1\n **/\nstatic void cpulist_parse(CpuList* list, char **buf, ssize_t len)\n{\n   const char* p   = (const char*)buf;\n   const char* end = p + len;\n\n   /* NOTE: the input line coming from sysfs typically contains a\n    * trailing newline, so take care of it in the code below\n    */\n   while (p < end && *p != '\\n')\n   {\n      int val, start_value, end_value;\n      /* Find the end of current item, and put it into 'q' */\n      const char *q = (const char*)memchr(p, ',', end-p);\n\n      if (!q)\n         q = end;\n\n      /* Get first value */\n      if (!(p = parse_decimal(p, q, &start_value)))\n         return;\n\n      end_value = start_value;\n\n      /* If we're not at the end of the item, expect a dash and\n       * and integer; extract end value.\n       */\n      if (p < q && *p == '-')\n      {\n         if (!(p = parse_decimal(p+1, q, &end_value)))\n            return;\n      }\n\n      /* Set bits CPU list bits */\n      for (val = start_value; val <= end_value; val++)\n      {\n         if ((unsigned)val < 32)\n            list->mask |= (uint32_t)(UINT32_C(1) << val);\n      }\n\n      /* Jump to next item */\n      p = q;\n      if (p < end)\n         p++;\n   }\n}\n\n/**\n * cpulist_read_from:\n *\n * Read a CPU list from one sysfs file\n **/\nstatic void cpulist_read_from(CpuList* list, const char* filename)\n{\n   ssize_t _len;\n   char *buf  = NULL;\n\n   list->mask = 0;\n\n   if (filestream_read_file(filename, (void**)&buf, &_len) != 1)\n      return;\n\n   cpulist_parse(list, &buf, _len);\n   if (buf)\n      free(buf);\n   buf = NULL;\n}\n#endif\n\n#endif\n\nunsigned cpu_features_get_core_amount(void)\n{\n#if defined(_WIN32) && !defined(_XBOX)\n   /* Win32 */\n   SYSTEM_INFO sysinfo;\n#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP\n   GetNativeSystemInfo(&sysinfo);\n#else\n   GetSystemInfo(&sysinfo);\n#endif\n   return sysinfo.dwNumberOfProcessors;\n#elif defined(GEKKO)\n   return 1;\n#elif defined(PSP) || defined(PS2)\n   return 1;\n#elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) && defined(__PS3__)\n   return 1; /* Only one PPU, SPUs don't really count */\n#elif defined(VITA)\n   return 4;\n#elif defined(HAVE_LIBNX) || defined(SWITCH)\n   return 4;\n#elif defined(_3DS)\n   u8 device_model = 0xFF;\n   CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/\n   switch (device_model)\n   {\n      case 0:\n      case 1:\n      case 3:\n         /*Old 3/2DS*/\n         return 2;\n\n      case 2:\n      case 4:\n      case 5:\n         /*New 3/2DS*/\n         return 4;\n\n      default:\n         /*Unknown Device Or Check Failed*/\n         break;\n   }\n   return 1;\n#elif defined(WIIU)\n   return 3;\n#elif defined(_SC_NPROCESSORS_ONLN)\n   /* Linux, most UNIX-likes. */\n   long ret = sysconf(_SC_NPROCESSORS_ONLN);\n   if (ret <= 0)\n      return (unsigned)1;\n   return (unsigned)ret;\n#elif defined(BSD) || defined(__APPLE__)\n   /* BSD */\n   /* Copypasta from stackoverflow, dunno if it works. */\n   int num_cpu = 0;\n   int mib[4];\n   size_t _len = sizeof(num_cpu);\n\n   mib[0] = CTL_HW;\n   mib[1] = HW_AVAILCPU;\n   sysctl(mib, 2, &num_cpu, &_len, NULL, 0);\n   if (num_cpu < 1)\n   {\n      mib[1] = HW_NCPU;\n      sysctl(mib, 2, &num_cpu, &_len, NULL, 0);\n      if (num_cpu < 1)\n         num_cpu = 1;\n   }\n   return num_cpu;\n#elif defined(__linux__)\n   CpuList  cpus_present[1];\n   CpuList  cpus_possible[1];\n   int amount = 0;\n\n   cpulist_read_from(cpus_present, \"/sys/devices/system/cpu/present\");\n   cpulist_read_from(cpus_possible, \"/sys/devices/system/cpu/possible\");\n\n   /* Compute the intersection of both sets to get the actual number of\n    * CPU cores that can be used on this device by the kernel.\n    */\n   cpus_present->mask &= cpus_possible->mask;\n   amount              = __builtin_popcount(cpus_present->mask);\n\n   if (amount == 0)\n      return 1;\n   return amount;\n#elif defined(_XBOX360)\n   return 3;\n#else\n   /* No idea, assume single core. */\n   return 1;\n#endif\n}\n\n/* According to http://en.wikipedia.org/wiki/CPUID */\n#define VENDOR_INTEL_b  0x756e6547\n#define VENDOR_INTEL_c  0x6c65746e\n#define VENDOR_INTEL_d  0x49656e69\n\nuint64_t cpu_features_get(void)\n{\n   uint64_t cpu        = 0;\n#if defined(CPU_X86) && !defined(__MACH__)\n   int vendor_is_intel = 0;\n   const int avx_flags = (1 << 27) | (1 << 28);\n#endif\n#if defined(__MACH__)\n   /* sysctlbyname() returns 0 (success) whenever the key exists, regardless\n    * of its value. On Intel Macs the hw.optional.* keys are always present\n    * but report 0 when the feature is unsupported (e.g. avx512f on pre-Skylake\n    * Xeon CPUs). We therefore have to read the value, not just the success\n    * code. */\n   int      _val        = 0;\n   size_t   _len        = sizeof(_val);\n   if (   sysctlbyname(\"hw.optional.floatingpoint\", &_val, &_len, NULL, 0) == 0\n       && _val)\n      cpu |= RETRO_SIMD_CMOV;\n\n#if defined(CPU_X86)\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.mmx\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_MMX | RETRO_SIMD_MMXEXT;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.sse\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_SSE;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.sse2\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_SSE2;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.sse3\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_SSE3;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.supplementalsse3\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_SSSE3;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.sse4_1\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_SSE4;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.sse4_2\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_SSE42;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.aes\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_AES;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.avx1_0\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_AVX;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.avx2_0\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_AVX2;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.avx512f\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_AVX512;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.altivec\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_VMX;\n#else\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.neon\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_NEON;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.neon_fp16\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_VFPV3;\n   _val = 0;\n   _len = sizeof(_val);\n   if (sysctlbyname(\"hw.optional.neon_hpfp\", &_val, &_len, NULL, 0) == 0 && _val)\n      cpu |= RETRO_SIMD_VFPV4;\n#endif\n#elif defined(_XBOX1)\n   cpu |= RETRO_SIMD_MMX | RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;\n#elif defined(CPU_X86)\n   unsigned max_flag   = 0;\n   int32_t flags[4];\n   int vendor_shuffle[3];\n   char vendor[13];\n   x86_cpuid(0, flags);\n   vendor_shuffle[0] = flags[1];\n   vendor_shuffle[1] = flags[3];\n   vendor_shuffle[2] = flags[2];\n\n   vendor[0]         = '\\0';\n   memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));\n\n   /* printf(\"[CPUID]: Vendor: %s\\n\", vendor); */\n\n   vendor_is_intel = (\n            flags[1] == VENDOR_INTEL_b \n         && flags[2] == VENDOR_INTEL_c\n         && flags[3] == VENDOR_INTEL_d);\n\n   max_flag = flags[0];\n   /* Does CPUID not support func = 1? (unlikely ...) */\n   if (max_flag < 1) \n      return 0;\n\n   x86_cpuid(1, flags);\n\n   if (flags[3] & (1 << 15))\n      cpu |= RETRO_SIMD_CMOV;\n\n   if (flags[3] & (1 << 23))\n      cpu |= RETRO_SIMD_MMX;\n\n   /* SSE also implies MMXEXT (according to FFmpeg source). */\n   if (flags[3] & (1 << 25))\n      cpu |= RETRO_SIMD_SSE | RETRO_SIMD_MMXEXT;\n\n   if (flags[3] & (1 << 26))\n      cpu |= RETRO_SIMD_SSE2;\n\n   if (flags[2] & (1 << 0))\n      cpu |= RETRO_SIMD_SSE3;\n\n   if (flags[2] & (1 << 9))\n      cpu |= RETRO_SIMD_SSSE3;\n\n   if (flags[2] & (1 << 19))\n      cpu |= RETRO_SIMD_SSE4;\n\n   if (flags[2] & (1 << 20))\n      cpu |= RETRO_SIMD_SSE42;\n\n   if ((flags[2] & (1 << 23)))\n      cpu |= RETRO_SIMD_POPCNT;\n\n   if (vendor_is_intel && (flags[2] & (1 << 22)))\n      cpu |= RETRO_SIMD_MOVBE;\n\n   if (flags[2] & (1 << 25))\n      cpu |= RETRO_SIMD_AES;\n\n   /* Must only perform xgetbv check if we have\n    * AVX CPU support (guaranteed to have at least i686). */\n   if (((flags[2] & avx_flags) == avx_flags)\n         && ((xgetbv_x86(0) & 0x6) == 0x6))\n      cpu |= RETRO_SIMD_AVX;\n\n   if (max_flag >= 7)\n   {\n      /* CPUID leaf 7 sub-leaf 0 requires ECX = 0.\n       * x86_cpuid() does not set ECX, so call cpuid directly. */\n      int32_t flags7[4];\n#if defined(__GNUC__)\n      __asm__ volatile (\n            \"mov %%\" REG_b \", %%\" REG_S \"\\n\"\n            \"cpuid\\n\"\n            \"xchg %%\" REG_b \", %%\" REG_S \"\\n\"\n            : \"=a\"(flags7[0]), \"=S\"(flags7[1]), \"=c\"(flags7[2]), \"=d\"(flags7[3])\n            : \"a\"(7), \"c\"(0));\n#elif defined(_MSC_VER) && INT_MAX == 2147483647\n#if _MSC_VER >= 1600\n      __cpuidex((int*)flags7, 7, 0);\n#else\n      {\n         int *p = (int*)flags7;\n         __asm {\n            mov eax, 7\n            xor ecx, ecx\n            cpuid\n            mov esi, p\n            mov [esi],      eax\n            mov [esi + 4],  ebx\n            mov [esi + 8],  ecx\n            mov [esi + 12], edx\n         }\n      }\n#endif\n#else\n      memset(flags7, 0, sizeof(flags7));\n#endif\n\n      if (flags7[1] & (1 << 5))\n         cpu |= RETRO_SIMD_AVX2;\n\n      /* AVX-512 Foundation detection.\n       * Requires CPUID leaf 7 sub-leaf 0 EBX bit 16 (AVX-512F),\n       * and OS support for saving ZMM state:\n       * xgetbv XCR0 bits 1,2 (SSE/AVX) and 5,6,7 (opmask, ZMM_Hi256, Hi16_ZMM). */\n      if ((flags7[1] & (1 << 16))\n            && ((xgetbv_x86(0) & 0xe6) == 0xe6))\n         cpu |= RETRO_SIMD_AVX512;\n   }\n\n   x86_cpuid(0x80000000, flags);\n   max_flag = flags[0];\n   if (max_flag >= 0x80000001u)\n   {\n      x86_cpuid(0x80000001, flags);\n      if (flags[3] & (1 << 23))\n         cpu |= RETRO_SIMD_MMX;\n      if (flags[3] & (1 << 22))\n         cpu |= RETRO_SIMD_MMXEXT;\n   }\n#elif defined(__linux__)\n   if (check_arm_cpu_feature(\"neon\"))\n   {\n      cpu |= RETRO_SIMD_NEON;\n#if defined(__ARM_NEON__) && defined(__arm__)\n      arm_enable_runfast_mode();\n#endif\n   }\n\n   if (check_arm_cpu_feature(\"vfpv3\"))\n      cpu |= RETRO_SIMD_VFPV3;\n\n   if (check_arm_cpu_feature(\"vfpv4\"))\n      cpu |= RETRO_SIMD_VFPV4;\n\n   if (check_arm_cpu_feature(\"asimd\"))\n   {\n      cpu |= RETRO_SIMD_ASIMD;\n#ifdef __ARM_NEON__\n      cpu |= RETRO_SIMD_NEON;\n#if defined(__arm__)\n      arm_enable_runfast_mode();\n#endif\n#endif\n   }\n#elif defined(__ARM_NEON__)\n   cpu |= RETRO_SIMD_NEON;\n#if defined(__arm__)\n   arm_enable_runfast_mode();\n#endif\n#elif defined(__ALTIVEC__)\n   cpu |= RETRO_SIMD_VMX;\n#elif defined(XBOX360)\n   cpu |= RETRO_SIMD_VMX128;\n#elif defined(PSP) || defined(PS2)\n   cpu |= RETRO_SIMD_VFPU;\n#elif defined(GEKKO)\n   cpu |= RETRO_SIMD_PS;\n#endif\n\n   return cpu;\n}\n\nvoid cpu_features_get_model_name(char *s, int len)\n{\n#if defined(CPU_X86) && !defined(__MACH__)\n   union {\n      int32_t i[4];\n      uint32_t u[4];\n      uint8_t s[16];\n   } flags;\n   int i, j;\n   int pos    = 0;\n   bool start = false;\n\n   if (!s)\n      return;\n\n   x86_cpuid(0x80000000, flags.i);\n\n   /* Check for additional cpuid attributes availability */\n   if (flags.u[0] < 0x80000004)\n      return;\n\n   for (i = 0; i < 3; i++)\n   {\n      memset(flags.i, 0, sizeof(flags.i));\n      x86_cpuid(0x80000002 + i, flags.i);\n\n      for (j = 0; j < (int)sizeof(flags.s); j++)\n      {\n         if (!start && flags.s[j] == ' ')\n            continue;\n\n         start = true;\n\n         if (pos == len - 1)\n         {\n            /* truncate if we ran out of room */\n            s[pos] = '\\0';\n            goto end;\n         }\n\n         s[pos++] = flags.s[j];\n      }\n   }\nend:\n   /* terminate our string */\n   if (pos < len)\n      s[pos] = '\\0';\n#elif defined(__MACH__)\n   if (!s)\n      return;\n   {\n      size_t __len = len;\n      sysctlbyname(\"machdep.cpu.brand_string\", s, &__len, NULL, 0);\n   }\n#elif defined(__linux__)\n   if (!s)\n      return;\n   {\n      char *model_name, line[128];\n      RFILE *fp = filestream_open(\"/proc/cpuinfo\",\n            RETRO_VFS_FILE_ACCESS_READ,\n            RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n      if (!fp)\n         return;\n\n      while (filestream_gets(fp, line, sizeof(line)))\n      {\n         if (strncmp(line, \"model name\", 10))\n            continue;\n\n         if ((model_name = strstr(line + 10, \": \")))\n         {\n            model_name += 2;\n            strlcpy(s, model_name, len);\n         }\n\n         break;\n      }\n\n      filestream_close(fp);\n\n#if defined(WEBOS)\n      struct stat st;\n      if (stat(\"/usr/bin/lscpu\", &st) == 0)\n      {\n         FILE *pipe = popen(\"/usr/bin/lscpu\", \"r\");\n         if (pipe)\n         {\n            char buf[256];\n\n            while (fgets(buf, sizeof(buf), pipe))\n            {\n               if (strncmp(buf, \"Model name:\", 11) == 0)\n               {\n                  const char *p = strchr(buf, ':');\n                  if (p)\n                  {\n                     size_t len2;\n                     p++; // skip ':'\n                     while (*p == ' ' || *p == '\\t')\n                        p++;\n                     len2 = strcspn(p, \"\\r\\n\");\n\n                     if (len2 > 0)\n                     {\n                        char *tmp = malloc(len2 + 1);\n                        if (tmp)\n                        {\n                           memcpy(tmp, p, len2);\n                           tmp[len2] = '\\0';\n\n                           if (s[0] != '\\0')\n                           {\n                              size_t oldlen  = strlen(s);\n                              char *combined = (char*)malloc(oldlen + len2 + 4);\n                              if (combined)\n                              {\n                                 memcpy(combined, s, oldlen);\n                                 combined[oldlen]     = ' ';\n                                 combined[oldlen + 1] = '(';\n                                 memcpy(combined + oldlen + 2, tmp, len2);\n                                 combined[oldlen + 2 + len2]     = ')';\n                                 combined[oldlen + 2 + len2 + 1] = '\\0';\n\n                                 strlcpy(s, combined, len);\n                                 free(combined);\n                              }\n                           }\n                           else\n                              strlcpy(s, tmp, len);\n                           free(tmp);\n                        }\n                     }\n                  }\n                  break;\n               }\n            }\n            pclose(pipe);\n         }\n      }\n#endif\n   }\n#endif\n}\n"
  },
  {
    "path": "file/archive_file.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_file.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <compat/strl.h>\n#include <file/archive_file.h>\n#include <file/file_path.h>\n#include <streams/file_stream.h>\n#include <retro_miscellaneous.h>\n#include <lists/string_list.h>\n#include <string/stdstring.h>\n\n#ifdef HAVE_MMAP\n#include <fcntl.h>\n#include <errno.h>\n#include <unistd.h>\n#include <sys/mman.h>\n#include <sys/stat.h>\n#endif\n\nstatic int file_archive_get_file_list_cb(\n      const char *path,\n      const char *valid_exts,\n      const uint8_t *cdata,\n      unsigned cmode,\n      uint32_t csize,\n      uint32_t size,\n      uint32_t checksum,\n      struct archive_extract_userdata *userdata)\n{\n   union string_list_elem_attr attr;\n   attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;\n\n   if (valid_exts)\n   {\n      size_t _len                  = strlen(path);\n      /* Checks if this entry is a directory or a file. */\n      char last_char               = path[_len - 1];\n      struct string_list ext_list  = {0};\n\n      /* Skip if directory. */\n      if (last_char == '/' || last_char == '\\\\' )\n         return 1;\n\n      string_list_initialize(&ext_list);\n      if (string_split_noalloc(&ext_list, valid_exts, \"|\"))\n      {\n         const char *file_ext = path_get_extension(path);\n\n         if (!file_ext)\n         {\n            string_list_deinitialize(&ext_list);\n            return 1;\n         }\n\n         if (!string_list_find_elem_prefix(&ext_list, \".\", file_ext))\n         {\n            /* keep iterating */\n            string_list_deinitialize(&ext_list);\n            return -1;\n         }\n      }\n\n      string_list_deinitialize(&ext_list);\n   }\n\n   return string_list_append(userdata->list, path, attr);\n}\n\nstatic int file_archive_extract_cb(const char *name, const char *valid_exts,\n      const uint8_t *cdata,\n      unsigned cmode, uint32_t csize, uint32_t size,\n      uint32_t checksum, struct archive_extract_userdata *userdata)\n{\n   const char *ext                   = path_get_extension(name);\n\n   /* Extract first file that matches our list. */\n   if (ext && string_list_find_elem(userdata->ext, ext))\n   {\n      char new_path[PATH_MAX_LENGTH];\n      const char *delim;\n\n      if ((delim = path_get_archive_delim(userdata->archive_path)))\n      {\n         if (!string_is_equal_noncase(\n                  userdata->current_file_path, delim + 1))\n           return 1; /* keep searching for the right file */\n      }\n\n      if (userdata->extraction_directory)\n         fill_pathname_join_special(new_path, userdata->extraction_directory,\n               path_basename(name), sizeof(new_path));\n      else\n         fill_pathname_resolve_relative(new_path, userdata->archive_path,\n               path_basename(name), sizeof(new_path));\n\n      if (file_archive_perform_mode(new_path,\n                valid_exts, cdata, cmode, csize, size,\n                checksum, userdata))\n      {\n         userdata->found_file = true;\n         userdata->first_extracted_file_path = strdup(new_path);\n      }\n\n      return 0;\n   }\n\n   return 1;\n}\n\nstatic int file_archive_parse_file_init(file_archive_transfer_t *state,\n      const char *file)\n{\n   char path[PATH_MAX_LENGTH];\n   char *last                 = NULL;\n\n   strlcpy(path, file, sizeof(path));\n\n   if ((last = (char*)path_get_archive_delim(path)))\n      *last  = '\\0';\n\n   if (!(state->backend = file_archive_get_file_backend(path)))\n      return -1;\n\n   /* Failed to open archive. */\n   if (!(state->archive_file = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE)))\n      return -1;\n\n   state->archive_size = filestream_get_size(state->archive_file);\n\n#ifdef HAVE_MMAP\n   if (state->archive_size <= (256*1024*1024))\n   {\n      state->archive_mmap_fd = open(path, O_RDONLY);\n      if (state->archive_mmap_fd)\n      {\n         state->archive_mmap_data = (uint8_t*)mmap(NULL,\n               (size_t)state->archive_size,\n               PROT_READ, MAP_SHARED, state->archive_mmap_fd, 0);\n\n         if (state->archive_mmap_data == (uint8_t*)MAP_FAILED)\n         {\n            close(state->archive_mmap_fd);\n            state->archive_mmap_fd = 0;\n            state->archive_mmap_data = NULL;\n         }\n      }\n   }\n#endif\n\n   state->step_current = 0;\n   state->step_total   = 0;\n\n   return state->backend->archive_parse_file_init(state, path);\n}\n\nvoid file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)\n{\n   if (!state || !state->archive_file)\n      return;\n\n   state->type = ARCHIVE_TRANSFER_DEINIT;\n   file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL);\n}\n\nint file_archive_parse_file_iterate(\n      file_archive_transfer_t *state,\n      bool *returnerr,\n      const char *file,\n      const char *valid_exts,\n      file_archive_file_cb file_cb,\n      struct archive_extract_userdata *userdata)\n{\n   if (!state)\n      return -1;\n\n   switch (state->type)\n   {\n      case ARCHIVE_TRANSFER_NONE:\n         break;\n      case ARCHIVE_TRANSFER_INIT:\n         if (file_archive_parse_file_init(state, file) == 0)\n         {\n            if (userdata)\n            {\n               userdata->transfer = state;\n               strlcpy(userdata->archive_path, file,\n                     sizeof(userdata->archive_path));\n            }\n            state->type = ARCHIVE_TRANSFER_ITERATE;\n         }\n         else\n            state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;\n         break;\n      case ARCHIVE_TRANSFER_ITERATE:\n         if (state->backend)\n         {\n            int ret = state->backend->archive_parse_file_iterate_step(\n                  state->context, valid_exts, userdata, file_cb);\n\n            if (ret == 1)\n               state->step_current++; /* found another file */\n            if (ret != 1)\n               state->type = ARCHIVE_TRANSFER_DEINIT;\n            if (ret == -1)\n               state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;\n\n            /* early return to prevent deinit from never firing */\n            return 0;\n         }\n         return -1;\n      case ARCHIVE_TRANSFER_DEINIT_ERROR:\n         *returnerr = false;\n      case ARCHIVE_TRANSFER_DEINIT:\n         if (state->context)\n         {\n            if (state->backend->archive_parse_file_free)\n               state->backend->archive_parse_file_free(state->context);\n            state->context = NULL;\n         }\n\n         if (state->archive_file)\n         {\n            filestream_close(state->archive_file);\n            state->archive_file = NULL;\n         }\n\n#ifdef HAVE_MMAP\n         if (state->archive_mmap_data)\n         {\n            munmap(state->archive_mmap_data, (size_t)state->archive_size);\n            close(state->archive_mmap_fd);\n            state->archive_mmap_fd = 0;\n            state->archive_mmap_data = NULL;\n         }\n#endif\n\n         if (userdata)\n            userdata->transfer = NULL;\n         break;\n   }\n\n   if (  state->type == ARCHIVE_TRANSFER_DEINIT ||\n         state->type == ARCHIVE_TRANSFER_DEINIT_ERROR)\n      return -1;\n\n   return 0;\n}\n\n/**\n * file_archive_walk:\n * @file                        : filename path of archive\n * @valid_exts                  : Valid extensions of archive to be parsed.\n *                                If NULL, allow all.\n * @file_cb                     : file_cb function pointer\n * @userdata                    : userdata to pass to file_cb function pointer.\n *\n * Low-level file parsing. Enumerates over all files and calls\n * file_cb with userdata.\n *\n * Returns: true (1) on success, otherwise false (0).\n **/\nstatic bool file_archive_walk(const char *file, const char *valid_exts,\n      file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)\n{\n   file_archive_transfer_t state;\n   bool returnerr          = true;\n\n   state.type              = ARCHIVE_TRANSFER_INIT;\n   state.archive_file      = NULL;\n#ifdef HAVE_MMAP\n   state.archive_mmap_fd   = 0;\n   state.archive_mmap_data = NULL;\n#endif\n   state.archive_size      = 0;\n   state.context           = NULL;\n   state.step_total        = 0;\n   state.step_current      = 0;\n   state.backend           = NULL;\n\n   for (;;)\n   {\n      if (file_archive_parse_file_iterate(&state, &returnerr, file,\n            valid_exts, file_cb, userdata) != 0)\n         break;\n   }\n\n   return returnerr;\n}\n\nint file_archive_parse_file_progress(file_archive_transfer_t *state)\n{\n   if (!state || state->step_total == 0)\n      return 0;\n\n   return (int)((state->step_current * 100) / (state->step_total));\n}\n\n/**\n * file_archive_extract_file:\n * @archive_path                : filename path to archive.\n * @valid_exts                  : valid extensions for the file.\n * @extraction_directory        : the directory to extract temporary\n *                                file to.\n *\n * Extract file from archive. If no file inside the archive is\n * specified, the first file found will be used.\n *\n * Returns : true (1) on success, otherwise false (0).\n **/\nbool file_archive_extract_file(\n      const char *archive_path,\n      const char *valid_exts,\n      const char *extraction_directory,\n      char *s, size_t len)\n{\n   struct archive_extract_userdata userdata;\n   struct string_list *list                 = string_split(valid_exts, \"|\");\n\n   userdata.archive_path[0]                 = '\\0';\n   userdata.current_file_path[0]            = '\\0';\n   userdata.first_extracted_file_path       = NULL;\n   userdata.extraction_directory            = extraction_directory;\n   userdata.ext                             = list;\n   userdata.list                            = NULL;\n   userdata.found_file                      = false;\n   userdata.list_only                       = false;\n   userdata.crc                             = 0;\n   userdata.transfer                        = NULL;\n   userdata.dec                             = NULL;\n\n   if (     list\n         && file_archive_walk(archive_path, valid_exts,\n            file_archive_extract_cb, &userdata)\n         && userdata.found_file\n      )\n   {\n      if (    userdata.first_extracted_file_path \n          && *userdata.first_extracted_file_path)\n         strlcpy(s, userdata.first_extracted_file_path, len);\n      return true;\n   }\n\n   if (userdata.first_extracted_file_path)\n      free(userdata.first_extracted_file_path);\n   if (list)\n      string_list_free(list);\n   return false;\n}\n\n/* Warning: 'list' must zero initialised before\n * calling this function, otherwise memory leaks/\n * undefined behaviour will occur */\nbool file_archive_get_file_list_noalloc(struct string_list *list,\n      const char *path,\n      const char *valid_exts)\n{\n   struct archive_extract_userdata userdata;\n\n   if (!list || !string_list_initialize(list))\n      return false;\n\n   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));\n   userdata.current_file_path[0]            = '\\0';\n   userdata.first_extracted_file_path       = NULL;\n   userdata.extraction_directory            = NULL;\n   userdata.ext                             = NULL;\n   userdata.list                            = list;\n   userdata.found_file                      = false;\n   userdata.list_only                       = true;\n   userdata.crc                             = 0;\n   userdata.transfer                        = NULL;\n   userdata.dec                             = NULL;\n\n   if (!file_archive_walk(path, valid_exts,\n            file_archive_get_file_list_cb, &userdata))\n      return false;\n   return true;\n}\n\n/**\n * file_archive_get_file_list:\n * @path                        : filename path of archive\n *\n * Returns: string listing of files from archive on success, otherwise NULL.\n **/\nstruct string_list *file_archive_get_file_list(const char *path,\n      const char *valid_exts)\n{\n   struct archive_extract_userdata userdata;\n\n   strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));\n   userdata.current_file_path[0]            = '\\0';\n   userdata.first_extracted_file_path       = NULL;\n   userdata.extraction_directory            = NULL;\n   userdata.ext                             = NULL;\n   userdata.list                            = string_list_new();\n   userdata.found_file                      = false;\n   userdata.list_only                       = true;\n   userdata.crc                             = 0;\n   userdata.transfer                        = NULL;\n   userdata.dec                             = NULL;\n\n   if (!userdata.list)\n      return NULL;\n   if (!file_archive_walk(path, valid_exts,\n         file_archive_get_file_list_cb, &userdata))\n   {\n      string_list_free(userdata.list);\n      return NULL;\n   }\n   return userdata.list;\n}\n\nbool file_archive_perform_mode(const char *path, const char *valid_exts,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,\n      uint32_t crc32, struct archive_extract_userdata *userdata)\n{\n   int ret;\n   file_archive_file_handle_t handle;\n\n   if (!userdata->transfer || !userdata->transfer->backend)\n      return false;\n\n   handle.data          = NULL;\n   handle.real_checksum = 0;\n\n   if (!userdata->transfer->backend->stream_decompress_data_to_file_init(\n            userdata->transfer->context, &handle, cdata, cmode, csize, size))\n      return false;\n\n   do\n   {\n      ret = userdata->transfer->backend->stream_decompress_data_to_file_iterate(\n               userdata->transfer->context, &handle);\n   }while (ret == 0);\n\n   if (ret == -1 || !filestream_write_file(path, handle.data, size))\n      return false;\n\n   return true;\n}\n\n/**\n * file_archive_filename_split:\n * @str              : filename to turn into a string list\n *\n * Creates a new string list based on filename @path, delimited by a hash (#).\n *\n * Returns: new string list if successful, otherwise NULL.\n */\nstatic struct string_list *file_archive_filename_split(const char *path)\n{\n   union string_list_elem_attr attr;\n   struct string_list *list = string_list_new();\n   const char *delim        = path_get_archive_delim(path);\n\n   attr.i = 0;\n\n   if (delim)\n   {\n      /* add archive path to list first */\n      if (!string_list_append_n(list, path, (unsigned)(delim - path), attr))\n      {\n         string_list_free(list);\n         return NULL;\n      }\n\n      /* now add the path within the archive */\n      delim++;\n\n      if (*delim)\n      {\n         if (!string_list_append(list, delim, attr))\n         {\n            string_list_free(list);\n            return NULL;\n         }\n      }\n   }\n   else\n   {\n      if (!string_list_append(list, path, attr))\n      {\n         string_list_free(list);\n         return NULL;\n      }\n   }\n\n   return list;\n}\n\n/* Generic compressed file loader.\n * Extracts to buf, unless optional_filename != 0\n * Then extracts to optional_filename and leaves buf alone.\n */\nint file_archive_compressed_read(\n      const char * path, void **buf,\n      const char* optional_filename, int64_t *len)\n{\n   const struct\n      file_archive_file_backend *backend = NULL;\n   struct string_list *str_list          = NULL;\n\n   /* Safety check.\n    * If optional_filename and optional_filename\n    * exists, we simply return 0,\n    * hoping that optional_filename is the\n    * same as requested.\n    */\n   if (optional_filename && path_is_valid(optional_filename))\n   {\n      *len = 0;\n      return 1;\n   }\n\n   str_list       = file_archive_filename_split(path);\n   /* We assure that there is something after the '#' symbol.\n    *\n    * This error condition happens for example, when\n    * path = /path/to/file.7z, or\n    * path = /path/to/file.7z#\n    */\n   if (str_list->size <= 1)\n   {\n      /* could not extract string and substring. */\n      string_list_free(str_list);\n      *len = 0;\n      return 0;\n   }\n\n   backend = file_archive_get_file_backend(str_list->elems[0].data);\n   *len    = backend->compressed_file_read(str_list->elems[0].data,\n         str_list->elems[1].data, buf, optional_filename);\n\n   string_list_free(str_list);\n\n   if (*len != -1)\n      return 1;\n\n   return 0;\n}\n\nconst struct file_archive_file_backend *file_archive_get_zlib_file_backend(void)\n{\n#ifdef HAVE_ZLIB\n   return &zlib_backend;\n#else\n   return NULL;\n#endif\n}\n\nconst struct file_archive_file_backend *file_archive_get_7z_file_backend(void)\n{\n#ifdef HAVE_7ZIP\n   return &sevenzip_backend;\n#else\n   return NULL;\n#endif\n}\n\nconst struct file_archive_file_backend *file_archive_get_zstd_file_backend(void)\n{\n#ifdef HAVE_ZSTD\n   return &zstd_backend;\n#else\n   return NULL;\n#endif\n}\n\nconst struct file_archive_file_backend* file_archive_get_file_backend(const char *path)\n{\n#if defined(HAVE_7ZIP) || defined(HAVE_ZLIB) || defined(HAVE_ZSTD)\n   char newpath[PATH_MAX_LENGTH];\n   const char *file_ext          = NULL;\n   char *last                    = NULL;\n\n   strlcpy(newpath, path, sizeof(newpath));\n\n   if ((last = (char*)path_get_archive_delim(newpath)))\n      *last  = '\\0';\n\n   file_ext  = path_get_extension(newpath);\n\n#ifdef HAVE_7ZIP\n   if (string_is_equal_noncase(file_ext, \"7z\"))\n      return &sevenzip_backend;\n#endif\n\n#ifdef HAVE_ZLIB\n   if (     string_is_equal_noncase(file_ext, \"zip\")\n         || string_is_equal_noncase(file_ext, \"apk\")\n      )\n      return &zlib_backend;\n#endif\n\n#ifdef HAVE_ZSTD\n   if (string_is_equal_noncase(file_ext, \"zst\"))\n      return &zstd_backend;\n#endif\n#endif\n\n   return NULL;\n}\n\n/**\n * file_archive_get_file_crc32:\n * @path                         : filename path of archive\n *\n * Returns: CRC32 of the specified file in the archive, otherwise 0.\n * If no path within the archive is specified, the first\n * file found inside is used.\n **/\nuint32_t file_archive_get_file_crc32(const char *path)\n{\n   uint64_t file_size;\n   return file_archive_get_file_crc32_and_size(path, &file_size);\n}\n\n/**\n * file_archive_get_file_crc32_and_size:\n * @path                         : filename path of archive\n * @size                         : size of the file inside the archive\n *\n * Returns: CRC32 of the specified file in the archive, otherwise 0.\n * If no path within the archive is specified, the first\n * file found inside is used.\n **/\nuint32_t file_archive_get_file_crc32_and_size(const char *path, uint64_t *size)\n{\n   file_archive_transfer_t state;\n   struct archive_extract_userdata userdata        = {0};\n   bool returnerr                                  = false;\n   const char *archive_path                        = NULL;\n   bool contains_compressed = path_contains_compressed_file(path);\n\n   if (contains_compressed)\n   {\n      archive_path = path_get_archive_delim(path);\n\n      /* move pointer right after the delimiter to give us the path */\n      if (archive_path)\n         archive_path += 1;\n   }\n\n   state.type              = ARCHIVE_TRANSFER_INIT;\n   state.archive_file      = NULL;\n#ifdef HAVE_MMAP\n   state.archive_mmap_fd   = 0;\n   state.archive_mmap_data = NULL;\n#endif\n   state.archive_size      = 0;\n   state.context           = NULL;\n   state.step_total        = 0;\n   state.step_current      = 0;\n   state.backend           = NULL;\n\n   /* Initialize and open archive first.\n      Sets next state type to ITERATE. */\n   file_archive_parse_file_iterate(&state,\n            &returnerr, path, NULL, NULL,\n            &userdata);\n\n   for (;;)\n   {\n      /* Now find the first file in the archive. */\n      if (state.type == ARCHIVE_TRANSFER_ITERATE)\n         file_archive_parse_file_iterate(&state,\n                  &returnerr, path, NULL, NULL,\n                  &userdata);\n\n      /* If no path specified within archive, stop after\n       * finding the first file.\n       */\n      if (!contains_compressed)\n         break;\n\n      /* Stop when the right file in the archive is found. */\n      if (archive_path)\n      {\n         if (string_is_equal(userdata.current_file_path, archive_path))\n            break;\n      }\n      else\n         break;\n   }\n\n   file_archive_parse_file_iterate_stop(&state);\n   *size = userdata.size;\n   return userdata.crc;\n}\n"
  },
  {
    "path": "file/archive_file_7z.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_file_sevenzip.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include <boolean.h>\n#include <file/archive_file.h>\n#include <streams/file_stream.h>\n#include <retro_miscellaneous.h>\n#include <encodings/utf.h>\n#include <encodings/crc32.h>\n#include <string/stdstring.h>\n#include <lists/string_list.h>\n#include <file/file_path.h>\n#include <compat/strl.h>\n#include <7zip/7z.h>\n#include <7zip/7zCrc.h>\n#include <7zip/7zFile.h>\n\n#define SEVENZIP_MAGIC \"7z\\xBC\\xAF\\x27\\x1C\"\n#define SEVENZIP_MAGIC_LEN 6\n#define SEVENZIP_LOOKTOREAD_BUF_SIZE (1 << 14)\n\n/* Assume W-functions do not work below Win2K and Xbox platforms */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n#endif\n\nstruct sevenzip_context_t\n{\n   uint8_t *output;\n   CFileInStream archiveStream;\n   CLookToRead2 lookStream;\n   ISzAlloc allocImp;\n   ISzAlloc allocTempImp;\n   CSzArEx db;\n   size_t temp_size;\n   uint32_t parse_index;\n   uint32_t decompress_index;\n   uint32_t packIndex;\n   uint32_t block_index;\n};\n\nstatic void *sevenzip_stream_alloc_impl(ISzAllocPtr p, size_t len)\n{\n   if (len == 0)\n      return 0;\n   return malloc(len);\n}\n\nstatic void sevenzip_stream_free_impl(ISzAllocPtr p, void *address)\n{\n   if (address)\n      free(address);\n}\n\nstatic void *sevenzip_stream_alloc_tmp_impl(ISzAllocPtr p, size_t len)\n{\n   if (len == 0)\n      return 0;\n   return malloc(len);\n}\n\nstatic void* sevenzip_stream_new(void)\n{\n   struct sevenzip_context_t *sevenzip_context =\n         (struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t));\n\n   /* NULL-check the calloc: the field writes below NULL-deref\n    * on OOM and the returned NULL is handled by the caller\n    * (sevenzip_parse_file_free at line ~112 NULL-tolerates). */\n   if (!sevenzip_context)\n      return NULL;\n\n   /* These are the allocation routines - currently using\n    * the non-standard 7zip choices. */\n   sevenzip_context->allocImp.Alloc     = sevenzip_stream_alloc_impl;\n   sevenzip_context->allocImp.Free      = sevenzip_stream_free_impl;\n   sevenzip_context->allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;\n   sevenzip_context->allocTempImp.Free  = sevenzip_stream_free_impl;\n   sevenzip_context->block_index        = 0xFFFFFFFF;\n   sevenzip_context->output             = NULL;\n\n   sevenzip_context->lookStream.bufSize = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);\n   sevenzip_context->lookStream.buf     = (Byte*)malloc(sevenzip_context->lookStream.bufSize);\n\n   if (!sevenzip_context->lookStream.buf)\n      sevenzip_context->lookStream.bufSize = 0;\n\n   return sevenzip_context;\n}\n\nstatic void sevenzip_parse_file_free(void *context)\n{\n   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;\n\n   if (!sevenzip_context)\n      return;\n\n   if (sevenzip_context->output)\n   {\n      IAlloc_Free(&sevenzip_context->allocImp, sevenzip_context->output);\n      sevenzip_context->output       = NULL;\n   }\n\n   SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp);\n   File_Close(&sevenzip_context->archiveStream.file);\n\n   if (sevenzip_context->lookStream.buf)\n      free(sevenzip_context->lookStream.buf);\n\n   free(sevenzip_context);\n}\n\n/* Extract the relative path (needle) from a 7z archive\n * (path) and allocate a buf for it to write it in.\n * If optional_outfile is set, extract to that instead\n * and don't allocate buffer.\n */\nstatic int64_t sevenzip_file_read(\n      const char *path,\n      const char *needle, void **buf,\n      const char *optional_outfile)\n{\n   CSzArEx db;\n   CFileInStream archiveStream;\n   CLookToRead2 lookStream;\n   ISzAlloc allocImp;\n   ISzAlloc allocTempImp;\n   uint8_t *output      = 0;\n   int64_t outsize      = -1;\n\n   /*These are the allocation routines.\n    * Currently using the non-standard 7zip choices. */\n   allocImp.Alloc       = sevenzip_stream_alloc_impl;\n   allocImp.Free        = sevenzip_stream_free_impl;\n   allocTempImp.Alloc   = sevenzip_stream_alloc_tmp_impl;\n   allocTempImp.Free    = sevenzip_stream_free_impl;\n\n   lookStream.bufSize   = SEVENZIP_LOOKTOREAD_BUF_SIZE * sizeof(Byte);\n   lookStream.buf       = (Byte*)malloc(lookStream.bufSize);\n\n   if (!lookStream.buf)\n      lookStream.bufSize = 0;\n\n#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)\n   if (path && *path)\n   {\n      wchar_t *path_w = utf8_to_utf16_string_alloc(path);\n      if (path_w)\n      {\n         /* Could not open 7zip archive? */\n         if (InFile_OpenW(&archiveStream.file, path_w))\n         {\n            free(path_w);\n            return -1;\n         }\n         free(path_w);\n      }\n   }\n#else\n   /* Could not open 7zip archive? */\n   if (InFile_Open(&archiveStream.file, path))\n      return -1;\n#endif\n\n   FileInStream_CreateVTable(&archiveStream);\n   LookToRead2_CreateVTable(&lookStream, false);\n   lookStream.realStream = &archiveStream.vt;\n   LookToRead2_Init(&lookStream);\n   CrcGenerateTable();\n\n   memset(&db, 0, sizeof(db));\n\n   SzArEx_Init(&db);\n\n   if (SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp) == SZ_OK)\n   {\n      uint32_t i;\n      bool file_found      = false;\n      uint16_t *temp       = NULL;\n      size_t temp_size     = 0;\n      uint32_t block_index   = 0xFFFFFFFF;\n      SRes res             = SZ_OK;\n\n      for (i = 0; i < db.NumFiles; i++)\n      {\n         size_t _len;\n         char infile[PATH_MAX_LENGTH];\n         size_t offset                = 0;\n         size_t outSizeProcessed      = 0;\n\n         /* We skip over everything which is not a directory.\n          * FIXME: Why continue then if IsDir is true?*/\n         if (SzArEx_IsDir(&db, i))\n            continue;\n\n         _len = SzArEx_GetFileNameUtf16(&db, i, NULL);\n\n         if (_len > temp_size)\n         {\n            if (temp)\n               free(temp);\n            temp_size = _len;\n            temp      = (uint16_t *)malloc(temp_size * sizeof(temp[0]));\n\n            if (temp == 0)\n            {\n               res = SZ_ERROR_MEM;\n               break;\n            }\n         }\n\n         SzArEx_GetFileNameUtf16(&db, i, temp);\n         res       = SZ_ERROR_FAIL;\n         infile[0] = '\\0';\n\n         if (temp)\n            res = utf16_to_char_string(temp, infile, sizeof(infile))\n               ? SZ_OK : SZ_ERROR_FAIL;\n\n         if (string_is_equal(infile, needle))\n         {\n            size_t output_size   = 0;\n\n            /* C LZMA SDK does not support chunked extraction - see here:\n             * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/\n             * */\n            file_found = true;\n            res = SzArEx_Extract(&db, &lookStream.vt, i, &block_index,\n                  &output, &output_size, &offset, &outSizeProcessed,\n                  &allocImp, &allocTempImp);\n\n            if (res != SZ_OK)\n               break; /* This goes to the error section. */\n\n            outsize = (int64_t)outSizeProcessed;\n\n            if (optional_outfile)\n            {\n               const void *ptr = (const void*)(output + offset);\n\n               if (!filestream_write_file(optional_outfile, ptr, outsize))\n               {\n                  res        = SZ_OK;\n                  file_found = true;\n                  outsize    = -1;\n               }\n            }\n            else\n            {\n               /*We could either use the 7Zip allocated buffer,\n                * or create our own and use it.\n                * We would however need to realloc anyways, because RetroArch\n                * expects a \\0 at the end, therefore we allocate new,\n                * copy and free the old one. */\n               /* NULL-check the malloc before the NUL-termination\n                * write and the memcpy below dereference '*buf'.  On\n                * OOM mark the extraction failed and break out of the\n                * file-search loop; the '!(file_found && res == SZ_OK)'\n                * branch further down then forces outsize = -1 and\n                * the teardown runs. */\n               if (!(*buf = malloc((size_t)(outsize + 1))))\n               {\n                  res     = SZ_ERROR_MEM;\n                  outsize = -1;\n                  break;\n               }\n               ((char*)(*buf))[outsize] = '\\0';\n               memcpy(*buf, output + offset, outsize);\n            }\n            break;\n         }\n      }\n\n      if (temp)\n         free(temp);\n      IAlloc_Free(&allocImp, output);\n\n      if (!(file_found && res == SZ_OK))\n      {\n         /* Error handling\n          *\n          * Failed to open compressed file inside 7zip archive.\n          */\n\n         outsize    = -1;\n      }\n   }\n\n   SzArEx_Free(&db, &allocImp);\n   File_Close(&archiveStream.file);\n\n   if (lookStream.buf)\n      free(lookStream.buf);\n\n   return outsize;\n}\n\nstatic bool sevenzip_stream_decompress_data_to_file_init(\n      void *context, file_archive_file_handle_t *handle,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)\n{\n   struct sevenzip_context_t *sevenzip_context =\n         (struct sevenzip_context_t*)context;\n\n   if (!sevenzip_context)\n      return false;\n\n   sevenzip_context->decompress_index = (uint32_t)(size_t)cdata;\n\n   return true;\n}\n\nstatic int sevenzip_stream_decompress_data_to_file_iterate(\n      void *context, file_archive_file_handle_t *handle)\n{\n   struct sevenzip_context_t *sevenzip_context =\n         (struct sevenzip_context_t*)context;\n\n   SRes res                = SZ_ERROR_FAIL;\n   size_t output_size      = 0;\n   size_t offset           = 0;\n   size_t outSizeProcessed = 0;\n\n   res = SzArEx_Extract(&sevenzip_context->db,\n         &sevenzip_context->lookStream.vt, sevenzip_context->decompress_index,\n         &sevenzip_context->block_index, &sevenzip_context->output,\n         &output_size, &offset, &outSizeProcessed,\n         &sevenzip_context->allocImp, &sevenzip_context->allocTempImp);\n\n   if (res != SZ_OK)\n      return 0;\n\n   if (handle)\n      handle->data = sevenzip_context->output + offset;\n\n   return 1;\n}\n\nstatic int sevenzip_parse_file_init(file_archive_transfer_t *state,\n      const char *file)\n{\n   uint8_t magic_buf[SEVENZIP_MAGIC_LEN];\n   struct sevenzip_context_t *sevenzip_context = NULL;\n\n   if (state->archive_size < SEVENZIP_MAGIC_LEN)\n      goto error;\n\n   filestream_seek(state->archive_file, 0, SEEK_SET);\n   if (filestream_read(state->archive_file, magic_buf, SEVENZIP_MAGIC_LEN) != SEVENZIP_MAGIC_LEN)\n      goto error;\n\n   if (memcmp(magic_buf, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN) != 0)\n      goto error;\n\n   sevenzip_context = (struct sevenzip_context_t*)sevenzip_stream_new();\n   state->context = sevenzip_context;\n\n#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)\n   if (file && *file)\n   {\n      wchar_t *file_w = utf8_to_utf16_string_alloc(file);\n\n      if (file_w)\n      {\n         /* could not open 7zip archive? */\n         if (InFile_OpenW(&sevenzip_context->archiveStream.file, file_w))\n         {\n            free(file_w);\n            goto error;\n         }\n\n         free(file_w);\n      }\n   }\n#else\n   /* could not open 7zip archive? */\n   if (InFile_Open(&sevenzip_context->archiveStream.file, file))\n      goto error;\n#endif\n\n   FileInStream_CreateVTable(&sevenzip_context->archiveStream);\n   LookToRead2_CreateVTable(&sevenzip_context->lookStream, false);\n   sevenzip_context->lookStream.realStream = &sevenzip_context->archiveStream.vt;\n   LookToRead2_Init(&sevenzip_context->lookStream);\n   CrcGenerateTable();\n   SzArEx_Init(&sevenzip_context->db);\n\n   if (SzArEx_Open(&sevenzip_context->db, &sevenzip_context->lookStream.vt,\n         &sevenzip_context->allocImp, &sevenzip_context->allocTempImp) != SZ_OK)\n      goto error;\n\n   state->step_total = sevenzip_context->db.NumFiles;\n\n   return 0;\n\nerror:\n   if (sevenzip_context)\n      sevenzip_parse_file_free(sevenzip_context);\n   state->context = NULL;\n   return -1;\n}\n\nstatic int sevenzip_parse_file_iterate_step_internal(\n      struct sevenzip_context_t *sevenzip_context,\n      char *s,\n      const uint8_t **cdata,\n      unsigned *cmode,\n      uint32_t *size,\n      uint32_t *csize,\n      uint32_t *checksum,\n      unsigned *payback,\n      struct archive_extract_userdata *userdata)\n{\n   if (sevenzip_context->parse_index < sevenzip_context->db.NumFiles)\n   {\n      size_t _len = SzArEx_GetFileNameUtf16(&sevenzip_context->db,\n            sevenzip_context->parse_index, NULL);\n      uint64_t compressed_size = 0;\n\n      if (sevenzip_context->packIndex < sevenzip_context->db.db.NumPackStreams)\n      {\n         compressed_size = sevenzip_context->db.db.PackPositions[sevenzip_context->packIndex + 1] -\n               sevenzip_context->db.db.PackPositions[sevenzip_context->packIndex];\n\n         sevenzip_context->packIndex++;\n      }\n\n      if (   (_len < PATH_MAX_LENGTH)\n          && !SzArEx_IsDir(&sevenzip_context->db, sevenzip_context->parse_index))\n      {\n         SRes res       = SZ_ERROR_FAIL;\n         uint16_t *temp = (uint16_t*)malloc(_len * sizeof(uint16_t));\n\n         if (!temp)\n            return -1;\n\n         SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->parse_index,\n               temp);\n\n         if (temp)\n         {\n            res  = utf16_to_char_string(temp, s, PATH_MAX_LENGTH)\n               ? SZ_OK : SZ_ERROR_FAIL;\n            free(temp);\n         }\n\n         if (res != SZ_OK)\n            return -1;\n\n         *cmode    = 0; /* unused for 7zip */\n         *checksum = sevenzip_context->db.CRCs.Vals[sevenzip_context->parse_index];\n         *size     = (uint32_t)SzArEx_GetFileSize(&sevenzip_context->db, sevenzip_context->parse_index);\n         *csize    = (uint32_t)compressed_size;\n\n         *cdata    = (uint8_t *)(size_t)sevenzip_context->parse_index;\n      }\n   }\n   else\n      return 0;\n\n   *payback = 1;\n\n   return 1;\n}\n\nstatic int sevenzip_parse_file_iterate_step(void *context,\n      const char *valid_exts,\n      struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)\n{\n   const uint8_t *cdata = NULL;\n   uint32_t checksum    = 0;\n   uint32_t size        = 0;\n   uint32_t csize       = 0;\n   unsigned cmode       = 0;\n   unsigned payload     = 0;\n   struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;\n   int ret;\n\n   userdata->current_file_path[0] = '\\0';\n\n   ret = sevenzip_parse_file_iterate_step_internal(sevenzip_context,\n         userdata->current_file_path,\n         &cdata, &cmode, &size, &csize,\n         &checksum, &payload, userdata);\n\n   if (ret != 1)\n      return ret;\n\n   userdata->crc                 = checksum;\n   userdata->size                = size;\n\n   if (file_cb && !file_cb(userdata->current_file_path, valid_exts,\n            cdata, cmode,\n            csize, size, checksum, userdata))\n      return 0;\n\n   sevenzip_context->parse_index += payload;\n\n   return 1;\n}\n\nstatic uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,\n      const uint8_t *data, size_t len)\n{\n   return encoding_crc32(crc, data, len);\n}\n\nconst struct file_archive_file_backend sevenzip_backend = {\n   sevenzip_parse_file_init,\n   sevenzip_parse_file_iterate_step,\n   sevenzip_parse_file_free,\n   sevenzip_stream_decompress_data_to_file_init,\n   sevenzip_stream_decompress_data_to_file_iterate,\n   sevenzip_stream_crc32_calculate,\n   sevenzip_file_read,\n   \"7z\"\n};\n"
  },
  {
    "path": "file/archive_file_zlib.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_file_zlib.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <file/archive_file.h>\n#include <streams/file_stream.h>\n#include <retro_inline.h>\n#include <retro_miscellaneous.h>\n#include <encodings/crc32.h>\n\n#include <zlib.h>\n\n#ifdef HAVE_ZSTD\n#include <zstd.h>\n#endif\n\n#ifndef CENTRAL_FILE_HEADER_SIGNATURE\n#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50\n#endif\n\n#ifndef END_OF_CENTRAL_DIR_SIGNATURE\n#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50\n#endif\n\n#define _READ_CHUNK_SIZE   (128*1024)   /* Read 128KiB compressed chunks */\n\nenum file_archive_compression_mode\n{\n   ZIP_MODE_STORED   = 0,\n   ZIP_MODE_DEFLATED = 8,\n   ZIP_MODE_ZSTD     = 93\n};\n\ntypedef struct\n{\n   struct file_archive_transfer *state;\n   uint8_t *directory;\n   uint8_t *directory_entry;\n   uint8_t *directory_end;\n   uint64_t fdoffset;\n   uint32_t boffset, csize, usize;\n   unsigned cmode;\n   z_stream *zstream;\n   uint8_t *tmpbuf;\n   uint8_t *decompressed_data;\n} zip_context_t;\n\nstatic INLINE uint32_t read_le(const uint8_t *data, size_t len)\n{\n   unsigned i;\n   uint32_t val = 0;\n   len *= 8;\n   for (i = 0; i < len; i += 8)\n      val |= (uint32_t)*data++ << i;\n   return val;\n}\n\nstatic void zip_context_free_stream(\n      zip_context_t *zip_context, bool keep_decompressed)\n{\n   if (zip_context->zstream)\n   {\n      inflateEnd(zip_context->zstream);\n      free(zip_context->zstream);\n      zip_context->fdoffset = 0;\n      zip_context->csize = 0;\n      zip_context->usize = 0;\n      zip_context->zstream = NULL;\n   }\n   if (zip_context->tmpbuf)\n   {\n      free(zip_context->tmpbuf);\n      zip_context->tmpbuf = NULL;\n   }\n   if (zip_context->decompressed_data && !keep_decompressed)\n   {\n      free(zip_context->decompressed_data);\n      zip_context->decompressed_data = NULL;\n   }\n}\n\nstatic bool zlib_stream_decompress_data_to_file_init(\n      void *context, file_archive_file_handle_t *handle,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)\n{\n   int64_t offsetData;\n   uint8_t *local_header;\n   uint32_t offsetNL, offsetEL;\n   uint8_t local_header_buf[4];\n   zip_context_t *zip_context = (zip_context_t *)context;\n   struct file_archive_transfer *state = zip_context->state;\n\n   /* free previous data and stream if left unfinished */\n   zip_context_free_stream(zip_context, false);\n\n   /* seek past most of the local directory header */\n#ifdef HAVE_MMAP\n   if (state->archive_mmap_data)\n      local_header = state->archive_mmap_data + (size_t)cdata + 26;\n   else\n#endif\n   {\n      filestream_seek(state->archive_file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);\n      if (filestream_read(state->archive_file, local_header_buf, 4) != 4)\n      {\n         zip_context_free_stream(zip_context, false);\n         return false;\n      }\n      local_header = local_header_buf;\n   }\n\n   offsetNL = read_le(local_header,     2); /* file name length */\n   offsetEL = read_le(local_header + 2, 2); /* extra field length */\n   offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;\n\n   zip_context->fdoffset              = offsetData;\n   zip_context->usize                 = size;\n   zip_context->csize                 = csize;\n   zip_context->boffset               = 0;\n   zip_context->cmode                 = cmode;\n   zip_context->decompressed_data     = (uint8_t*)malloc(size);\n   zip_context->zstream               = NULL;\n   zip_context->tmpbuf                = NULL;\n\n   /* NULL-check the decompressed_data malloc: subsequent\n    * consumers (zip_context_iterate, and line 155 below where\n    * zstream->next_out = decompressed_data seeds the inflate\n    * output) unconditionally dereference it.  On OOM fail the\n    * whole context setup via zip_context_free_stream which is\n    * NULL-safe for both zstream and tmpbuf. */\n   if (!zip_context->decompressed_data)\n   {\n      zip_context_free_stream(zip_context, false);\n      return false;\n   }\n\n   if (cmode == ZIP_MODE_DEFLATED)\n   {\n      /* Initialize the zlib inflate machinery */\n      zip_context->zstream            = (z_stream*)malloc(sizeof(z_stream));\n      zip_context->tmpbuf             = (uint8_t*)malloc(_READ_CHUNK_SIZE);\n\n      /* NULL-check both mallocs: the zstream->next_in etc.\n       * field writes below NULL-deref on OOM for zstream, and\n       * inflate() later reads from tmpbuf.  Fail the context\n       * setup on either failure. */\n      if (!zip_context->zstream || !zip_context->tmpbuf)\n      {\n         zip_context_free_stream(zip_context, false);\n         return false;\n      }\n\n      zip_context->zstream->next_in   = NULL;\n      zip_context->zstream->avail_in  = 0;\n      zip_context->zstream->total_in  = 0;\n      zip_context->zstream->next_out  = zip_context->decompressed_data;\n      zip_context->zstream->avail_out = size;\n      zip_context->zstream->total_out = 0;\n\n      zip_context->zstream->zalloc    = NULL;\n      zip_context->zstream->zfree     = NULL;\n      zip_context->zstream->opaque    = NULL;\n\n      if (inflateInit2(zip_context->zstream, -MAX_WBITS) != Z_OK)\n      {\n         free(zip_context->zstream);\n         zip_context->zstream = NULL;\n         zip_context_free_stream(zip_context, false);\n         return false;\n      }\n   }\n#ifdef HAVE_ZSTD\n   else if (cmode == ZIP_MODE_ZSTD)\n   {\n      /* Allocate a buffer to read compressed data into;\n       * decompression is done in one shot during iterate */\n      zip_context->tmpbuf = (uint8_t*)malloc(csize);\n      if (!zip_context->tmpbuf)\n      {\n         zip_context_free_stream(zip_context, false);\n         return false;\n      }\n   }\n#endif\n\n   return true;\n}\n\nstatic int zlib_stream_decompress_data_to_file_iterate(\n      void *context, file_archive_file_handle_t *handle)\n{\n   int64_t rd;\n   zip_context_t *zip_context = (zip_context_t *)context;\n   struct file_archive_transfer *state = zip_context->state;\n\n   if (zip_context->cmode == ZIP_MODE_STORED)\n   {\n#ifdef HAVE_MMAP\n      /* Simply copy the data to the output buffer */\n      if (zip_context->state->archive_mmap_data)\n         memcpy(zip_context->decompressed_data,\n               zip_context->state->archive_mmap_data + (size_t)zip_context->fdoffset,\n               zip_context->usize);\n      else\n#endif\n      {\n         /* Read the entire file to memory */\n         filestream_seek(state->archive_file, zip_context->fdoffset, RETRO_VFS_SEEK_POSITION_START);\n         if (filestream_read(state->archive_file,\n                             zip_context->decompressed_data,\n                             zip_context->usize) < 0)\n            return -1;\n      }\n\n      handle->data = zip_context->decompressed_data;\n      return 1;\n   }\n   else if (zip_context->cmode == ZIP_MODE_DEFLATED)\n   {\n      uint8_t *dptr;\n      int to_read = MIN(zip_context->csize - zip_context->boffset, _READ_CHUNK_SIZE);\n      /* File was uncompressed or decompression finished before */\n      if (!zip_context->zstream)\n         return 1;\n\n#ifdef HAVE_MMAP\n      if (state->archive_mmap_data)\n      {\n         /* Decompress from the mapped file */\n         dptr = state->archive_mmap_data + (size_t)zip_context->fdoffset + zip_context->boffset;\n         rd   = to_read;\n      }\n      else\n#endif\n      {\n         /* Read some compressed data from file to the temp buffer */\n         filestream_seek(state->archive_file,\n               zip_context->fdoffset + zip_context->boffset,\n               RETRO_VFS_SEEK_POSITION_START);\n         rd = filestream_read(state->archive_file, zip_context->tmpbuf, to_read);\n         if (rd < 0)\n            return -1;\n         dptr = zip_context->tmpbuf;\n      }\n\n      zip_context->boffset           += rd;\n      zip_context->zstream->next_in   = dptr;\n      zip_context->zstream->avail_in  = (uInt)rd;\n\n      if (inflate(zip_context->zstream, 0) < 0)\n         return -1;\n\n      if (zip_context->boffset >= zip_context->csize)\n      {\n         inflateEnd(zip_context->zstream);\n         free(zip_context->zstream);\n         zip_context->zstream = NULL;\n\n         handle->data = zip_context->decompressed_data;\n         return 1;\n      }\n\n      return 0;   /* still more data to process */\n   }\n#ifdef HAVE_ZSTD\n   else if (zip_context->cmode == ZIP_MODE_ZSTD)\n   {\n      size_t result;\n\n#ifdef HAVE_MMAP\n      if (state->archive_mmap_data)\n      {\n         result = ZSTD_decompress(\n               zip_context->decompressed_data, zip_context->usize,\n               state->archive_mmap_data + (size_t)zip_context->fdoffset,\n               zip_context->csize);\n      }\n      else\n#endif\n      {\n         /* Read all compressed data, then decompress */\n         filestream_seek(state->archive_file,\n               zip_context->fdoffset,\n               RETRO_VFS_SEEK_POSITION_START);\n         if (filestream_read(state->archive_file,\n                  zip_context->tmpbuf, zip_context->csize) < 0)\n            return -1;\n\n         result = ZSTD_decompress(\n               zip_context->decompressed_data, zip_context->usize,\n               zip_context->tmpbuf, zip_context->csize);\n      }\n\n      if (ZSTD_isError(result))\n         return -1;\n\n      free(zip_context->tmpbuf);\n      zip_context->tmpbuf = NULL;\n\n      handle->data = zip_context->decompressed_data;\n      return 1;\n   }\n#endif\n\n   /* No idea what kind of compression this is */\n   return -1;\n}\n\nstatic uint32_t zlib_stream_crc32_calculate(uint32_t crc,\n      const uint8_t *data, size_t len)\n{\n   return encoding_crc32(crc, data, len);\n}\n\nstatic bool zip_file_decompressed_handle(\n      file_archive_transfer_t *transfer,\n      file_archive_file_handle_t* handle,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize,\n      uint32_t size, uint32_t crc32)\n{\n   int ret   = 0;\n\n   transfer->backend = &zlib_backend;\n\n   if (!transfer->backend->stream_decompress_data_to_file_init(\n            transfer->context, handle, cdata, cmode, csize, size))\n      return false;\n\n   do\n   {\n      ret = transfer->backend->stream_decompress_data_to_file_iterate(\n            transfer->context, handle);\n      if (ret < 0)\n         return false;\n   }while (ret == 0);\n\n   return true;\n}\n\ntypedef struct\n{\n   char *opt_file;\n   char *needle;\n   void **buf;\n   size_t size;\n   bool found;\n} decomp_state_t;\n\n/* Extract the relative path (needle) from a\n * ZIP archive (path) and allocate a buffer for it to write it in.\n *\n * optional_outfile if not NULL will be used to extract the file to.\n * buf will be 0 then.\n */\n\nstatic int zip_file_decompressed(\n      const char *name, const char *valid_exts,\n      const uint8_t *cdata, unsigned cmode,\n      uint32_t csize, uint32_t size,\n      uint32_t crc32, struct archive_extract_userdata *userdata)\n{\n   decomp_state_t* decomp_state = (decomp_state_t*)userdata->cb_data;\n   size_t name_len              = name ? strlen(name) : 0;\n   char last_char;\n   /* Reject empty or NULL name -- strlen-1 on empty would read\n    * name[SIZE_MAX].  Malformed archives can have 0-length filename\n    * entries. */\n   if (name_len == 0)\n      return 1;\n   last_char = name[name_len - 1];\n   /* Ignore directories. */\n   if (last_char == '/' || last_char == '\\\\')\n      return 1;\n\n   if (strstr(name, decomp_state->needle))\n   {\n      file_archive_file_handle_t handle = {0};\n\n      if (zip_file_decompressed_handle(userdata->transfer,\n               &handle, cdata, cmode, csize, size, crc32))\n      {\n         if (decomp_state->opt_file != 0)\n         {\n            /* Called in case core has need_fullpath enabled. */\n            bool success = filestream_write_file(decomp_state->opt_file, handle.data, size);\n\n            /* Note: Do not free handle.data here - this\n             * will be done when stream is deinitialised */\n            handle.data = NULL;\n\n            decomp_state->size = 0;\n\n            if (!success)\n               return -1;\n         }\n         else\n         {\n            /* Called in case core has need_fullpath disabled.\n             * Will move decompressed content directly into\n             * RetroArch's ROM buffer. */\n            zip_context_t *zip_context = (zip_context_t *)userdata->transfer->context;\n\n            decomp_state->size = 0;\n            *decomp_state->buf             = handle.data;\n            decomp_state->size             = size;\n            /* We keep the data, prevent its deallocation during free */\n            zip_context->decompressed_data = NULL;\n            handle.data = NULL;\n         }\n      }\n\n      decomp_state->found = true;\n   }\n\n   return 1;\n}\n\nstatic int64_t zip_file_read(\n      const char *path,\n      const char *needle, void **buf,\n      const char *optional_outfile)\n{\n   file_archive_transfer_t state            = {0};\n   decomp_state_t decomp                    = {0};\n   struct archive_extract_userdata userdata = {0};\n   int ret                                  = 0;\n\n   if (needle)\n      decomp.needle          = strdup(needle);\n   if (optional_outfile)\n      decomp.opt_file        = strdup(optional_outfile);\n\n   /* NULL-check strdups: zip_file_decompressed (line ~396)\n    * calls strstr(name, decomp_state->needle) which NULL-derefs\n    * if needle was requested but strdup failed.  Bail out of\n    * the extraction; caller treats -1 as 'not found / failed'.\n    * Free whatever strdup succeeded to avoid a leak on\n    * partial-success OOM. */\n   if ((needle && !decomp.needle) ||\n       (optional_outfile && !decomp.opt_file))\n   {\n      free(decomp.needle);\n      free(decomp.opt_file);\n      return -1;\n   }\n\n   state.type                = ARCHIVE_TRANSFER_INIT;\n   userdata.transfer         = &state;\n   userdata.cb_data          = &decomp;\n   decomp.buf                = buf;\n\n   do\n   {\n      bool returnerr = true;\n      ret = file_archive_parse_file_iterate(&state, &returnerr, path,\n            \"\", zip_file_decompressed, &userdata);\n      if (!returnerr)\n         break;\n   }while (ret == 0 && !decomp.found);\n\n   file_archive_parse_file_iterate_stop(&state);\n\n   if (decomp.opt_file)\n      free(decomp.opt_file);\n   if (decomp.needle)\n      free(decomp.needle);\n\n   if (!decomp.found)\n      return -1;\n\n   return (int64_t)decomp.size;\n}\n\nstatic int zip_parse_file_init(file_archive_transfer_t *state,\n      const char *file)\n{\n   uint8_t footer_buf[1024];\n   uint8_t *footer = footer_buf;\n   int64_t read_pos = state->archive_size;\n   int64_t read_block = MIN(read_pos, (ssize_t)sizeof(footer_buf));\n   int64_t directory_size, directory_offset;\n   zip_context_t *zip_context = NULL;\n\n   /* Minimal ZIP file size is 22 bytes */\n   if (read_block < 22)\n      return -1;\n\n   /* Find the end of central directory record by scanning\n    * the file from the end towards the beginning.\n    */\n   for (;;)\n   {\n      if (--footer < footer_buf)\n      {\n         if (read_pos <= 0)\n            return -1; /* reached beginning of file */\n\n         /* Read 21 bytes of overlaps except on the first block. */\n         if (read_pos == state->archive_size)\n            read_pos = read_pos - read_block;\n         else\n            read_pos = MAX(read_pos - read_block + 21, 0);\n\n         /* Seek to read_pos and read read_block bytes. */\n         filestream_seek(state->archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);\n         if (filestream_read(state->archive_file, footer_buf, read_block) != read_block)\n            return -1;\n\n         footer = footer_buf + read_block - 22;\n      }\n      if (read_le(footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)\n      {\n         unsigned comment_len = read_le(footer + 20, 2);\n         if (read_pos + (footer - footer_buf) + 22 + comment_len == state->archive_size)\n            break; /* found it! */\n      }\n   }\n\n   /* Read directory info and do basic sanity checks. */\n   directory_size   = read_le(footer + 12, 4);\n   directory_offset = read_le(footer + 16, 4);\n   if (directory_size > state->archive_size\n         || directory_offset > state->archive_size)\n      return -1;\n\n   /* Combined sanity check: the directory must fit entirely within\n    * the archive.  Without this, offset + size could wrap or point\n    * past EOF, producing a large bogus allocation and a short read. */\n   if ((int64_t)directory_offset + (int64_t)directory_size > state->archive_size)\n      return -1;\n\n   /* Reject sizes that would overflow the allocation on 32-bit hosts.\n    * size_t is 32-bit on 3DS / Vita / PSP / Wii / Wii U, where a\n    * directory_size near UINT32_MAX would wrap\n    *     sizeof(zip_context_t) + (size_t)directory_size\n    * to a tiny value, after which directory_end runs off the end of\n    * the allocation. */\n   if ((size_t)directory_size > SIZE_MAX - sizeof(zip_context_t))\n      return -1;\n\n   /* This is a ZIP file, allocate one block of memory for both the\n    * context and the entire directory, then read the directory.\n    */\n   zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);\n   if (!zip_context)\n      return -1;\n   zip_context->state             = state;\n   zip_context->directory         = (uint8_t*)(zip_context + 1);\n   zip_context->directory_entry   = zip_context->directory;\n   zip_context->directory_end     = zip_context->directory + (size_t)directory_size;\n   zip_context->zstream           = NULL;\n   zip_context->tmpbuf            = NULL;\n   zip_context->decompressed_data = NULL;\n\n   filestream_seek(state->archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);\n   if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size)\n   {\n      free(zip_context);\n      return -1;\n   }\n\n   state->context = zip_context;\n   state->step_total = read_le(footer + 10, 2); /* total entries */;\n\n   return 0;\n}\n\nstatic int zip_parse_file_iterate_step_internal(\n      zip_context_t * zip_context, char *filename,\n      const uint8_t **cdata,\n      unsigned *cmode, uint32_t *size, uint32_t *csize,\n      uint32_t *checksum, unsigned *payback)\n{\n   uint8_t *entry = zip_context->directory_entry;\n   uint32_t signature, namelength, extralength, commentlength, offset;\n\n   if (entry < zip_context->directory || entry >= zip_context->directory_end)\n      return 0;\n\n   /* Central-directory fixed header is 46 bytes (highest-offset read\n    * is at +42..+45).  Reject a truncated trailing entry before any\n    * out-of-bounds read. */\n   if ((size_t)(zip_context->directory_end - entry) < 46)\n      return -1;\n\n   signature = read_le(zip_context->directory_entry + 0, 4);\n\n   if (signature != CENTRAL_FILE_HEADER_SIGNATURE)\n      return 0;\n\n   *cmode         = read_le(zip_context->directory_entry + 10, 2); /* compression mode, 0 = store, 8 = deflate */\n   *checksum      = read_le(zip_context->directory_entry + 16, 4); /* CRC32 */\n   *csize         = read_le(zip_context->directory_entry + 20, 4); /* compressed size */\n   *size          = read_le(zip_context->directory_entry + 24, 4); /* uncompressed size */\n\n   namelength     = read_le(zip_context->directory_entry + 28, 2); /* file name length */\n   extralength    = read_le(zip_context->directory_entry + 30, 2); /* extra field length */\n   commentlength  = read_le(zip_context->directory_entry + 32, 2); /* file comment length */\n\n   if (namelength >= PATH_MAX_LENGTH)\n      return -1;\n\n   /* Variable-length fields (name, extra, comment) follow the 46-byte\n    * fixed header.  Reject if the declared sizes would run past the\n    * end of the directory block. */\n   if ((size_t)(zip_context->directory_end - entry)\n         < (size_t)46 + namelength + extralength + commentlength)\n      return -1;\n\n   memcpy(filename, zip_context->directory_entry + 46, namelength); /* file name */\n   filename[namelength] = '\\0';\n\n   offset   = read_le(zip_context->directory_entry + 42, 4); /* relative offset of local file header */\n\n   *cdata   = (uint8_t*)(size_t)offset; /* store file offset in data pointer */\n\n   *payback = 46 + namelength + extralength + commentlength;\n\n   return 1;\n}\n\nstatic int zip_parse_file_iterate_step(void *context,\n      const char *valid_exts, struct archive_extract_userdata *userdata,\n      file_archive_file_cb file_cb)\n{\n   zip_context_t *zip_context = (zip_context_t *)context;\n   const uint8_t *cdata       = NULL;\n   uint32_t checksum          = 0;\n   uint32_t size              = 0;\n   uint32_t csize             = 0;\n   unsigned cmode             = 0;\n   unsigned payload           = 0;\n   int ret                    = zip_parse_file_iterate_step_internal(zip_context,\n         userdata->current_file_path, &cdata, &cmode, &size, &csize, &checksum, &payload);\n\n   if (ret != 1)\n      return ret;\n\n   userdata->crc  = checksum;\n   userdata->size = size;\n\n   if (file_cb && !file_cb(userdata->current_file_path, valid_exts, cdata, cmode,\n            csize, size, checksum, userdata))\n      return 0;\n\n   zip_context->directory_entry += payload;\n\n   return 1;\n}\n\nstatic void zip_parse_file_free(void *context)\n{\n   zip_context_t *zip_context = (zip_context_t *)context;\n   zip_context_free_stream(zip_context, false);\n   free(zip_context);\n}\n\nconst struct file_archive_file_backend zlib_backend = {\n   zip_parse_file_init,\n   zip_parse_file_iterate_step,\n   zip_parse_file_free,\n   zlib_stream_decompress_data_to_file_init,\n   zlib_stream_decompress_data_to_file_iterate,\n   zlib_stream_crc32_calculate,\n   zip_file_read,\n   \"zlib\"\n};\n"
  },
  {
    "path": "file/archive_file_zstd.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_file_zstd.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#include <boolean.h>\n#include <file/archive_file.h>\n#include <streams/file_stream.h>\n#include <retro_miscellaneous.h>\n#include <encodings/crc32.h>\n#include <string/stdstring.h>\n#include <file/file_path.h>\n#include <compat/strl.h>\n\n#include <zstd.h>\n\n#define ZSTD_MAGIC         \"\\x28\\xB5\\x2F\\xFD\"\n#define ZSTD_MAGIC_LEN     4\n\nstruct zstd_file_context\n{\n   uint8_t *decompressed_data;\n   char inner_filename[PATH_MAX_LENGTH];\n   char archive_path[PATH_MAX_LENGTH];\n   int64_t archive_size;\n   uint32_t decompressed_size;\n   bool parsed;\n};\n\n/* Derive the inner filename from the .zst path by stripping the .zst extension */\nstatic void zstd_derive_inner_filename(const char *path, char *s, size_t len)\n{\n   const char *base = path_basename(path);\n   const char *ext;\n\n   strlcpy(s, base, len);\n   ext = strrchr(s, '.');\n   if (ext && string_is_equal_noncase(ext, \".zst\"))\n      ((char*)ext)[0] = '\\0';\n}\n\nstatic int zstd_parse_file_init(file_archive_transfer_t *state,\n      const char *file)\n{\n   uint8_t magic_buf[ZSTD_MAGIC_LEN];\n   struct zstd_file_context *ctx = NULL;\n\n   if (state->archive_size < ZSTD_MAGIC_LEN)\n      goto error;\n\n   filestream_seek(state->archive_file, 0, SEEK_SET);\n   if (filestream_read(state->archive_file, magic_buf, ZSTD_MAGIC_LEN)\n         != ZSTD_MAGIC_LEN)\n      goto error;\n\n   if (memcmp(magic_buf, ZSTD_MAGIC, ZSTD_MAGIC_LEN) != 0)\n      goto error;\n\n   ctx = (struct zstd_file_context*)calloc(1, sizeof(*ctx));\n   if (!ctx)\n      goto error;\n\n   zstd_derive_inner_filename(file, ctx->inner_filename,\n         sizeof(ctx->inner_filename));\n   strlcpy(ctx->archive_path, file, sizeof(ctx->archive_path));\n   ctx->archive_size = state->archive_size;\n\n   state->context    = ctx;\n   state->step_total = 1;\n\n   return 0;\n\nerror:\n   if (ctx)\n      free(ctx);\n   state->context = NULL;\n   return -1;\n}\n\nstatic int zstd_parse_file_iterate_step(void *context,\n      const char *valid_exts,\n      struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)\n{\n   struct zstd_file_context *ctx = (struct zstd_file_context*)context;\n   file_archive_transfer_t *state;\n   unsigned long long content_size;\n\n   if (!ctx || ctx->parsed)\n      return 0;\n\n   ctx->parsed = true;\n   state       = userdata->transfer;\n\n   /* Read the frame header to get decompressed size */\n   filestream_seek(state->archive_file, 0, SEEK_SET);\n\n#ifdef HAVE_MMAP\n   if (state->archive_mmap_data)\n   {\n      content_size = ZSTD_getFrameContentSize(\n            state->archive_mmap_data, (size_t)state->archive_size);\n   }\n   else\n#endif\n   {\n      /* Only need to read the header; ZSTD_frameHeaderSize_max is 18 */\n      uint8_t header_buf[18];\n      int64_t to_read = state->archive_size < 18\n                       ? state->archive_size : 18;\n      if (filestream_read(state->archive_file, header_buf, to_read) != to_read)\n         return -1;\n      content_size = ZSTD_getFrameContentSize(header_buf, (size_t)to_read);\n   }\n\n   if (  content_size == ZSTD_CONTENTSIZE_UNKNOWN\n      || content_size == ZSTD_CONTENTSIZE_ERROR)\n      return -1;\n\n   /* decompressed_size is a uint32_t and feeds a later malloc; reject\n    * values that would truncate to a smaller size and mismatch the\n    * actual ZSTD_decompress output length. */\n   if (content_size > UINT32_MAX)\n      return -1;\n\n   ctx->decompressed_size = (uint32_t)content_size;\n\n   strlcpy(userdata->current_file_path, ctx->inner_filename,\n         sizeof(userdata->current_file_path));\n\n   userdata->crc  = 0;\n   userdata->size = (uint64_t)content_size;\n\n   if (file_cb && !file_cb(ctx->inner_filename, valid_exts,\n            NULL, 0,\n            (uint32_t)state->archive_size, (uint32_t)content_size,\n            0, userdata))\n      return 0;\n\n   return 1;\n}\n\nstatic void zstd_parse_file_free(void *context)\n{\n   struct zstd_file_context *ctx = (struct zstd_file_context*)context;\n   if (!ctx)\n      return;\n   if (ctx->decompressed_data)\n      free(ctx->decompressed_data);\n   free(ctx);\n}\n\nstatic bool zstd_stream_decompress_data_to_file_init(\n      void *context, file_archive_file_handle_t *handle,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)\n{\n   struct zstd_file_context *ctx = (struct zstd_file_context*)context;\n   if (!ctx)\n      return false;\n   return true;\n}\n\nstatic int zstd_stream_decompress_data_to_file_iterate(\n      void *context, file_archive_file_handle_t *handle)\n{\n   struct zstd_file_context *ctx = (struct zstd_file_context*)context;\n   void *compressed_data = NULL;\n   size_t result;\n   RFILE *file;\n\n   if (!ctx || !handle)\n      return -1;\n\n   if (ctx->decompressed_data)\n   {\n      handle->data = ctx->decompressed_data;\n      return 1;\n   }\n\n   /* Read the entire compressed file */\n   file = filestream_open(ctx->archive_path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   if (!file)\n      return -1;\n\n   compressed_data = malloc((size_t)ctx->archive_size);\n   if (!compressed_data)\n   {\n      filestream_close(file);\n      return -1;\n   }\n\n   if (filestream_read(file, compressed_data, ctx->archive_size)\n         != ctx->archive_size)\n   {\n      free(compressed_data);\n      filestream_close(file);\n      return -1;\n   }\n   filestream_close(file);\n\n   ctx->decompressed_data = (uint8_t*)malloc(ctx->decompressed_size);\n   if (!ctx->decompressed_data)\n   {\n      free(compressed_data);\n      return -1;\n   }\n\n   result = ZSTD_decompress(ctx->decompressed_data, ctx->decompressed_size,\n         compressed_data, (size_t)ctx->archive_size);\n   free(compressed_data);\n\n   if (ZSTD_isError(result))\n   {\n      free(ctx->decompressed_data);\n      ctx->decompressed_data = NULL;\n      return -1;\n   }\n\n   handle->data = ctx->decompressed_data;\n   return 1;\n}\n\n/* Extract the file from a .zst archive (single-file container).\n * If needle doesn't match the derived inner filename, returns -1.\n * If optional_outfile is set, writes to that file instead of buf. */\nstatic int64_t zstd_file_read(\n      const char *path,\n      const char *needle, void **buf,\n      const char *optional_outfile)\n{\n   char inner_name[PATH_MAX_LENGTH];\n   int64_t file_size;\n   void *compressed_data    = NULL;\n   uint8_t *decompressed    = NULL;\n   unsigned long long content_size;\n   size_t result;\n   RFILE *file;\n\n   zstd_derive_inner_filename(path, inner_name, sizeof(inner_name));\n\n   if (!string_is_equal(inner_name, needle))\n      return -1;\n\n   file = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   if (!file)\n      return -1;\n\n   file_size = filestream_get_size(file);\n   if (file_size <= 0)\n   {\n      filestream_close(file);\n      return -1;\n   }\n\n   compressed_data = malloc((size_t)file_size);\n   if (!compressed_data)\n   {\n      filestream_close(file);\n      return -1;\n   }\n\n   if (filestream_read(file, compressed_data, (int64_t)file_size) != file_size)\n   {\n      free(compressed_data);\n      filestream_close(file);\n      return -1;\n   }\n\n   filestream_close(file);\n\n   content_size = ZSTD_getFrameContentSize(compressed_data, (size_t)file_size);\n   if (  content_size == ZSTD_CONTENTSIZE_UNKNOWN\n      || content_size == ZSTD_CONTENTSIZE_ERROR)\n   {\n      free(compressed_data);\n      return -1;\n   }\n\n   /* Reject sizes that would overflow the \"+1\" NUL-byte allocation or\n    * truncate when cast to size_t on 32-bit hosts.  Without this guard\n    * content_size = 0xFFFFFFFF on a 32-bit host wraps the +1 to zero,\n    * malloc(0) may return a non-NULL pointer, and the following\n    * ZSTD_decompress writes 4 GiB into it. */\n   if (content_size >= SIZE_MAX)\n   {\n      free(compressed_data);\n      return -1;\n   }\n\n   decompressed = (uint8_t*)malloc((size_t)(content_size + 1));\n   if (!decompressed)\n   {\n      free(compressed_data);\n      return -1;\n   }\n\n   result = ZSTD_decompress(decompressed, (size_t)content_size,\n         compressed_data, (size_t)file_size);\n   free(compressed_data);\n\n   if (ZSTD_isError(result))\n   {\n      free(decompressed);\n      return -1;\n   }\n\n   if (optional_outfile)\n   {\n      if (!filestream_write_file(optional_outfile, decompressed, (int64_t)result))\n      {\n         free(decompressed);\n         return -1;\n      }\n      free(decompressed);\n   }\n   else\n   {\n      decompressed[result] = '\\0';\n      *buf = decompressed;\n   }\n\n   return (int64_t)result;\n}\n\nstatic uint32_t zstd_stream_crc32_calculate(uint32_t crc,\n      const uint8_t *data, size_t len)\n{\n   return encoding_crc32(crc, data, len);\n}\n\nconst struct file_archive_file_backend zstd_backend = {\n   zstd_parse_file_init,\n   zstd_parse_file_iterate_step,\n   zstd_parse_file_free,\n   zstd_stream_decompress_data_to_file_init,\n   zstd_stream_decompress_data_to_file_iterate,\n   zstd_stream_crc32_calculate,\n   zstd_file_read,\n   \"zstd\"\n};\n"
  },
  {
    "path": "file/config_file.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (config_file.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <ctype.h>\n#include <errno.h>\n#include <limits.h>\n\n#include <retro_miscellaneous.h>\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n#include <compat/fopen_utf8.h>\n#include <compat/msvc.h>\n#include <file/config_file.h>\n#include <file/file_path.h>\n#include <streams/file_stream.h>\n#include <array/rhmap.h>\n\n#define MAX_INCLUDE_DEPTH 16\n\nstruct config_include_list\n{\n   char *path;\n   struct config_include_list *next;\n};\n\n/* Forward declaration */\nstatic bool config_file_parse_line(config_file_t *conf,\n      struct config_entry_list *list, char *line, config_file_cb_t *cb);\n\nstatic int config_file_sort_compare_func(struct config_entry_list *a,\n      struct config_entry_list *b)\n{\n   if (a && b)\n   {\n      if (a->key)\n      {\n         if (b->key)\n            return strcasecmp(a->key, b->key);\n         return 1;\n      }\n      else if (b->key)\n         return -1;\n   }\n\n   return 0;\n}\n\n/* https://stackoverflow.com/questions/7685/merge-sort-a-linked-list */\nstatic struct config_entry_list* config_file_merge_sort_linked_list(\n         struct config_entry_list *list, int (*compare)(\n         struct config_entry_list *one,struct config_entry_list *two))\n{\n   struct config_entry_list\n         *right  = list,\n         *temp   = list,\n         *last   = list,\n         *result = 0,\n         *next   = 0,\n         *tail   = 0;\n\n   /* Trivial case. */\n   if (!list || !list->next)\n      return list;\n\n   /* Find halfway through the list (by running two pointers,\n    * one at twice the speed of the other). */\n   while (temp && temp->next)\n   {\n      last     = right;\n      right    = right->next;\n      temp     = temp->next->next;\n   }\n\n   /* Break the list in two. (prev pointers are broken here,\n    * but we fix later) */\n   last->next  = 0;\n\n   /* Recurse on the two smaller lists: */\n   list        = config_file_merge_sort_linked_list(list, compare);\n   right       = config_file_merge_sort_linked_list(right, compare);\n\n   /* Merge: */\n   while (list || right)\n   {\n      /* Take from empty lists, or compare: */\n      if (!right)\n      {\n         next  = list;\n         list  = list->next;\n      }\n      else if (!list)\n      {\n         next  = right;\n         right = right->next;\n      }\n      else if (compare(list, right) < 0)\n      {\n         next  = list;\n         list  = list->next;\n      }\n      else\n      {\n         next  = right;\n         right = right->next;\n      }\n\n      if (!result)\n         result     = next;\n      else\n         tail->next = next;\n\n      tail          = next;\n   }\n\n   return result;\n}\n\n/**\n * config_file_strip_comment:\n *\n * Searches input string for a comment ('#') entry\n * > If first character is '#', then entire line is\n *   a comment and may correspond to a directive\n *   (command action - e.g. include sub-config file).\n *   In this case, 'str' is set to NUL and the comment\n *   itself (everything after the '#' character) is\n *   returned\n * > If a '#' character is found inside a string literal\n *   value, then it does not correspond to a comment and\n *   is ignored. In this case, 'str' is left untouched\n *   and NULL is returned\n * > If a '#' character is found anywhere else, then the\n *   comment text is a suffix of the input string and\n *   has no programmatic value. In this case, the comment\n *   is removed from the end of 'str' and NULL is returned\n **/\nstatic char *config_file_strip_comment(char *str)\n{\n   /* Search for a comment (#) character */\n   char *comment = strchr(str, '#');\n\n   if (comment)\n   {\n      char *literal_start = NULL;\n\n      /* Check whether entire line is a comment\n       * > First character == '#' */\n      if (str == comment)\n      {\n         /* Set 'str' to NUL and return comment\n          * for processing at a higher level */\n         *str = '\\0';\n         return ++comment;\n      }\n\n      /* Comment character occurs at an offset:\n       * Search for the start of a string literal value */\n      literal_start = strchr(str, '\\\"');\n\n      /* Check whether string literal start occurs\n       * *before* the comment character */\n      if (literal_start && (literal_start < comment))\n      {\n         /* Search for the end of the string literal\n          * value */\n         char *literal_end = strchr(literal_start + 1, '\\\"');\n\n         /* Check whether string literal end occurs\n          * *after* the comment character\n          * > If this is the case, ignore the comment\n          * > Leave 'str' untouched and return NULL */\n         if (literal_end && (literal_end > comment))\n            return NULL;\n      }\n\n      /* If we reach this point, then a comment\n       * exists outside of a string literal\n       * > Trim the entire comment from the end\n       *   of 'str' */\n      *comment = '\\0';\n   }\n\n   return NULL;\n}\n\nstatic char *config_file_extract_value(char *line)\n{\n   while (*line == ' ' || *line == '\\t' || *line == '\\r' || *line == '\\n')\n      line++;\n\n   /* Note: From this point on, an empty value\n    * string is valid - and in this case, strldup(\"\", sizeof(\"\"))\n    * will be returned (see Note 2)\n    * > If we instead return NULL, the the entry\n    *   is ignored completely - which means we cannot\n    *   track *changes* in entry value */\n\n   /* If first character is (\"), we have a full string\n    * literal */\n   if (*line == '\"')\n   {\n      size_t idx  = 0;\n      char *value = NULL;\n      /* Skip to next character */\n      line++;\n\n      /* If this a (\"), then value string is empty */\n      if (*line != '\"')\n      {\n         /* Find the next (\") character */\n         while (line[idx] && (line[idx] != '\\\"'))\n            idx++;\n\n         line[idx] = '\\0';\n         if ((value = line) && *value)\n            return strdup(value);\n      }\n   }\n   /* This is not a string literal - just read\n    * until the next space is found\n    * > Note: Skip this if line is empty */\n   else if (*line != '\\0')\n   {\n      size_t idx  = 0;\n      char *value = NULL;\n      /* Find next space character */\n      while (line[idx] && isgraph((unsigned char)line[idx]))\n         idx++;\n\n      line[idx] = '\\0';\n      if ((value = line) && *value)\n         return strdup(value);\n   }\n\n   /* Note 2: Return an empty string.\n    * calloc gives us a NUL-terminated empty string in one call. */\n   return (char*)calloc(1, 1);\n}\n\n/* Move semantics? */\nstatic void config_file_add_child_list(config_file_t *parent,\n      config_file_t *child)\n{\n   struct config_entry_list *list = child->entries;\n   bool merge_hash_map            = false;\n\n   /* set list readonly */\n   while (list)\n   {\n      list->readonly = true;\n      list           = list->next;\n   }\n\n   if (parent->entries)\n   {\n      /* Use tracked tail instead of walking the list */\n      if (parent->tail)\n         parent->tail->next = child->entries;\n      else\n      {\n         struct config_entry_list *head = parent->entries;\n         while (head->next)\n            head = head->next;\n         head->next        = child->entries;\n      }\n\n      merge_hash_map    = true;\n   }\n   else\n      parent->entries   = child->entries;\n\n   /* Rebase tail. */\n   if (parent->entries)\n   {\n      struct config_entry_list *head =\n         (struct config_entry_list*)parent->entries;\n\n      while (head->next)\n         head = head->next;\n      parent->tail = head;\n   }\n   else\n      parent->tail = NULL;\n\n   /* Update hash map */\n   if (merge_hash_map)\n   {\n      size_t i;\n      size_t cap;\n\n      /* We are merging two lists - if any child entry\n       * (key) is not present in the parent list, add it\n       * to the parent hash map */\n      for (i = 0, cap = RHMAP_CAP(child->entries_map); i != cap; i++)\n      {\n         uint32_t child_hash   = RHMAP_KEY(child->entries_map, i);\n         const char *child_key = RHMAP_KEY_STR(child->entries_map, i);\n\n         if (child_hash &&\n             child_key &&\n             !RHMAP_HAS_FULL(parent->entries_map, child_hash, child_key))\n         {\n            struct config_entry_list *entry = child->entries_map[i];\n\n            if (entry)\n               RHMAP_SET_FULL(parent->entries_map, child_hash, child_key, entry);\n         }\n      }\n\n      /* Child entries map is no longer required,\n       * so free it now */\n      RHMAP_FREE(child->entries_map);\n   }\n   else\n   {\n      /* If parent list was originally empty,\n       * take map from child list */\n      RHMAP_FREE(parent->entries_map);\n      parent->entries_map = child->entries_map;\n      child->entries_map  = NULL;\n   }\n\n   child->entries = NULL;\n}\n\nstatic void config_file_get_realpath(char *s, size_t len,\n      char *path, const char *config_path)\n{\n#if !defined(_WIN32) && !defined(__PSL1GHT__) && !defined(__PS3__)\n   if (*path == '~')\n   {\n      const char *home = getenv(\"HOME\");\n      if (home)\n      {\n         size_t _len = strlcpy(s, home,     len);\n         strlcpy(s + _len, path + 1, len - _len);\n      }\n      else\n         strlcpy(s, path + 1, len);\n   }\n   else\n#endif\n   {\n      if (config_path && *config_path)\n         fill_pathname_resolve_relative(s, config_path,\n            path, len);\n   }\n}\n\nstatic void config_file_add_sub_conf(config_file_t *conf, char *path,\n      char *s, size_t len, config_file_cb_t *cb)\n{\n   struct config_include_list *head = conf->includes;\n   struct config_include_list *node = (struct config_include_list*)\n      malloc(sizeof(*node));\n\n   if (node)\n   {\n      node->next        = NULL;\n      /* Add include list */\n      if (!(node->path = strdup(path)))\n      {\n         free(node);\n         goto realpath;\n      }\n\n      if (head)\n      {\n         while (head->next)\n            head        = head->next;\n\n         head->next     = node;\n      }\n      else\n         conf->includes = node;\n   }\n\nrealpath:\n   config_file_get_realpath(s, len, path,\n         conf->path);\n}\n\nsize_t config_file_add_reference(config_file_t *conf, char *path)\n{\n   size_t _len;\n   /* It is expected that the conf has it's path already set */\n   char short_path[NAME_MAX_LENGTH];\n   if (!conf->references)\n   {\n      conf->references       = (struct path_linked_list*)malloc(sizeof(*conf->references));\n      /* NULL-check: the next two field writes NULL-deref on OOM,\n       * and the subsequent path_linked_list_add_path call would\n       * walk ->next through a NULL head.  On OOM bail before\n       * filling short_path - fill_pathname_abbreviated_or_\n       * relative returns the computed length regardless of\n       * whether references was successfully allocated, so\n       * compute-and-return a valid length is also an option, but\n       * returning 0 signals 'no reference added' cleanly and\n       * matches the state (no reference) that persists. */\n      if (!conf->references)\n         return 0;\n      conf->references->next = NULL;\n      conf->references->path = NULL;\n   }\n   _len = fill_pathname_abbreviated_or_relative(short_path, conf->path, path, sizeof(short_path));\n   path_linked_list_add_path(conf->references, short_path);\n   return _len;\n}\n\nstatic int config_file_load_internal(\n      struct config_file *conf,\n      const char *path, unsigned depth, config_file_cb_t *cb)\n{\n   RFILE         *file = NULL;\n   char      *new_path = strdup(path);\n   if (!new_path)\n      return 1;\n   if (!(file = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE)))\n   {\n      free(new_path);\n      return 1;\n   }\n\n   conf->path          = new_path;\n   conf->include_depth = depth;\n   while (!filestream_eof(file))\n   {\n      struct config_entry_list *list = NULL;\n      char *line                     = filestream_getline(file);\n      if (!line)\n         continue;\n      if (line[0] == '\\0')\n      {\n         free(line);\n         continue;\n      }\n\n      if (!(list = (struct config_entry_list*)malloc(sizeof(*list))))\n      {\n         free(line);\n         filestream_close(file);\n         free(conf->path);\n         conf->path = NULL;\n         return -1;\n      }\n\n      list->readonly  = false;\n      list->key       = NULL;\n      list->value     = NULL;\n      list->next      = NULL;\n\n      if (config_file_parse_line(conf, list, line, cb))\n      {\n         if (conf->entries)\n            conf->tail->next = list;\n         else\n            conf->entries    = list;\n\n         conf->tail = list;\n\n         if (list->key)\n         {\n            /* Only add entry to the map if an entry\n             * with the specified value does not\n             * already exist */\n            uint32_t hash = rhmap_hash_string(list->key);\n\n            if (!RHMAP_HAS_FULL(conf->entries_map, hash, list->key))\n            {\n               RHMAP_SET_FULL(conf->entries_map, hash, list->key, list);\n\n               if (cb && list->value)\n                  cb->config_file_new_entry_cb(list->key, list->value);\n            }\n         }\n      }\n      else\n         free(list);\n\n      free(line);\n   }\n\n   filestream_close(file);\n\n   return 0;\n}\n\nstatic bool config_file_parse_line(config_file_t *conf,\n      struct config_entry_list *list, char *line, config_file_cb_t *cb)\n{\n   size_t idx            = 0;\n   char *key             = NULL;\n   /* Remove any comment text */\n   char *comment         = config_file_strip_comment(line);\n   /* Check whether entire line is a comment */\n   if (comment)\n   {\n      char *path           = NULL;\n      size_t clen          = strlen(comment);\n      bool include_found   = clen >= 8  && !memcmp(comment, \"include \",   8);\n      bool reference_found = clen >= 10 && !memcmp(comment, \"reference \", 10);\n      /* All comments except those starting with the include or\n       * reference directive are ignored */\n      if (!include_found && !reference_found)\n         return false;\n      /* Starting a line with an 'include' directive\n       * appends a sub-config file */\n      if (include_found)\n      {\n         config_file_t sub_conf;\n         char real_path[PATH_MAX_LENGTH];\n         char *include_line = comment + (sizeof(\"include \")-1);\n         if (*include_line == '\\0')\n            return false;\n         if (!(path = config_file_extract_value(include_line)))\n            return false;\n         if (     *path == '\\0'\n               || conf->include_depth >= MAX_INCLUDE_DEPTH)\n         {\n            free(path);\n            return false;\n         }\n         config_file_add_sub_conf(conf, path,\n            real_path, sizeof(real_path), cb);\n         config_file_initialize(&sub_conf);\n         switch (config_file_load_internal(&sub_conf, real_path,\n            conf->include_depth + 1, cb))\n         {\n            case 0:\n               /* Pilfer internal list. */\n               config_file_add_child_list(conf, &sub_conf);\n               /* fall-through to deinitialize */\n            case -1:\n               config_file_deinitialize(&sub_conf);\n               break;\n            case 1:\n            default:\n               break;\n         }\n      }\n      /* Starting a line with an 'reference' directive\n       * sets the reference path */\n      if (reference_found)\n      {\n         char *reference_line = comment + (sizeof(\"reference \")-1);\n         if (*reference_line == '\\0')\n            return false;\n         if (!(path = config_file_extract_value(reference_line)))\n            return false;\n         config_file_add_reference(conf, path);\n         if (!path)\n            return false;\n      }\n      free(path);\n      return true;\n   }\n   /* Skip to first non-space character */\n   while (*line == ' ' || *line == '\\t' || *line == '\\r' || *line == '\\n')\n      line++;\n   /* Measure key length first (up to next non-graph char),\n    * then copy once - avoids malloc+realloc growth pattern */\n   {\n      const char *key_start = line;\n      while (isgraph((unsigned char)*line))\n         line++;\n      idx = (size_t)(line - key_start);\n      if (idx == 0)\n         return false;\n      if (!(key = (char*)malloc(idx + 1)))\n         return false;\n      memcpy(key, key_start, idx);\n      key[idx] = '\\0';\n   }\n   /* Add key and value entries to list */\n   list->key     = key;\n   /* An entry without a value is invalid */\n   while (*line == ' ' || *line == '\\t' || *line == '\\r' || *line == '\\n')\n      line++;\n   /* If we don't have an equal sign here,\n    * we've got an invalid string. */\n   if (*line != '=')\n   {\n      list->value = NULL;\n      list->key   = NULL;\n      free(key);\n      return false;\n   }\n   line++;\n   if (!(list->value   = config_file_extract_value(line)))\n   {\n      list->key   = NULL;\n      free(key);\n      return false;\n   }\n   return true;\n}\n\nstatic int config_file_from_string_internal(\n      struct config_file *conf,\n      char *from_string,\n      const char *path)\n{\n   char *line                     = from_string;\n   if (path && *path)\n      conf->path                  = strdup(path);\n   if (!line || !*line)\n      return 0;\n   while (*line)\n   {\n      struct config_entry_list *list = NULL;\n      char *next                     = strchr(line, '\\n');\n      if (next)\n         *next = '\\0';\n      /* Parse current line */\n      if (*line)\n      {\n         list = (struct config_entry_list*)\n               malloc(sizeof(*list));\n         if (!list)\n            return -1;\n         list->readonly  = false;\n         list->key       = NULL;\n         list->value     = NULL;\n         list->next      = NULL;\n         if (config_file_parse_line(conf, list, line, NULL))\n         {\n            if (conf->entries)\n               conf->tail->next = list;\n            else\n               conf->entries    = list;\n            conf->tail          = list;\n            if (list->key)\n            {\n               /* Only add entry to the map if an entry\n                * with the specified value does not\n                * already exist */\n               uint32_t hash = rhmap_hash_string(list->key);\n               if (!RHMAP_HAS_FULL(conf->entries_map, hash, list->key))\n                  RHMAP_SET_FULL(conf->entries_map, hash, list->key, list);\n            }\n         }\n         else\n            free(list);\n      }\n      /* Advance to next line */\n      if (next)\n         line = next + 1;\n      else\n         break;\n   }\n   return 0;\n}\n\nbool config_file_deinitialize(config_file_t *conf)\n{\n   struct config_include_list *inc_tmp = NULL;\n   struct config_entry_list *tmp       = NULL;\n\n   if (!conf)\n      return false;\n\n   tmp = conf->entries;\n   while (tmp)\n   {\n      struct config_entry_list *hold = NULL;\n      if (tmp->key)\n         free(tmp->key);\n      if (tmp->value)\n         free(tmp->value);\n\n      tmp->value = NULL;\n      tmp->key   = NULL;\n\n      hold       = tmp;\n      tmp        = tmp->next;\n\n      if (hold)\n         free(hold);\n   }\n\n   inc_tmp = (struct config_include_list*)conf->includes;\n   while (inc_tmp)\n   {\n      struct config_include_list *hold = NULL;\n      if (inc_tmp->path)\n         free(inc_tmp->path);\n      hold    = (struct config_include_list*)inc_tmp;\n      inc_tmp = inc_tmp->next;\n      if (hold)\n         free(hold);\n   }\n\n   path_linked_list_free(conf->references);\n\n   if (conf->path)\n      free(conf->path);\n\n   RHMAP_FREE(conf->entries_map);\n\n   /* NULL out all pointer fields so that a caller who reuses the\n    * struct after deinitialize() -- or who accidentally calls\n    * deinitialize() twice -- does not chase dangling pointers.  The\n    * free() calls above leave every listed field pointing at freed\n    * memory; without these NULLs any subsequent config_* call on\n    * this struct is undefined behaviour.  config_file_free() frees\n    * the struct itself immediately after this, so for that path the\n    * NULLs are redundant but harmless; config_file_deinitialize()\n    * is a public API callable on its own. */\n   conf->entries     = NULL;\n   conf->tail        = NULL;\n   conf->last        = NULL;\n   conf->includes    = NULL;\n   conf->references  = NULL;\n   conf->path        = NULL;\n   /* entries_map is cleared by RHMAP_FREE */\n\n   return true;\n}\n\n/**\n * config_file_free:\n *\n * Frees config file.\n **/\nvoid config_file_free(config_file_t *conf)\n{\n   if (config_file_deinitialize(conf))\n      free(conf);\n}\n\n/**\n * config_append_file:\n *\n * Loads a new config, and appends its data to @conf.\n * The key-value pairs of the new config file takes priority over the old.\n **/\nbool config_append_file(config_file_t *conf, const char *path)\n{\n   size_t i, cap;\n   config_file_t *new_conf = config_file_new_from_path_to_string(path);\n\n   if (!new_conf)\n      return false;\n\n   /* Update hash map */\n   for (i = 0, cap = RHMAP_CAP(new_conf->entries_map); i != cap; i++)\n   {\n      uint32_t new_hash   = RHMAP_KEY(new_conf->entries_map, i);\n      const char *new_key = RHMAP_KEY_STR(new_conf->entries_map, i);\n\n      if (new_hash && new_key)\n      {\n         struct config_entry_list *entry = new_conf->entries_map[i];\n\n         if (entry)\n            RHMAP_SET_FULL(conf->entries_map, new_hash, new_key, entry);\n      }\n   }\n\n   if (new_conf->tail)\n   {\n      new_conf->tail->next = conf->entries;\n      conf->entries        = new_conf->entries; /* Pilfer. */\n      new_conf->entries    = NULL;\n   }\n\n   config_file_free(new_conf);\n   return true;\n}\n\n/**\n * config_file_new_from_string:\n *\n * Load a config file from a string.\n *\n * NOTE: This will modify @from_string.\n * Pass a copy of source string if original\n * contents must be preserved\n **/\nconfig_file_t *config_file_new_from_string(char *from_string,\n      const char *path)\n{\n   struct config_file *conf      = config_file_new_alloc();\n   if (     conf\n         && config_file_from_string_internal(\n            conf, from_string, path) != -1)\n      return conf;\n   if (conf)\n      config_file_free(conf);\n   return NULL;\n}\n\nconfig_file_t *config_file_new_from_path_to_string(const char *path)\n{\n   if (path_is_valid(path))\n   {\n      uint8_t *ret_buf                 = NULL;\n      int64_t length                   = 0;\n      if (filestream_read_file(path, (void**)&ret_buf, &length))\n      {\n         config_file_t *conf           = NULL;\n         /* Note: 'ret_buf' is not used outside this\n          * function - we do not care that it will be\n          * modified by config_file_new_from_string() */\n         if (length >= 0)\n            conf = config_file_new_from_string((char*)ret_buf, path);\n\n         if ((void*)ret_buf)\n            free((void*)ret_buf);\n\n         return conf;\n      }\n   }\n\n   return NULL;\n}\n\n/**\n * config_file_new_with_callback:\n *\n * Loads a config file.\n * If @path is NULL, will create an empty config file.\n * Includes cb callbacks  to run custom code during config file processing.\n *\n * @return Returns NULL if file doesn't exist.\n **/\nconfig_file_t *config_file_new_with_callback(\n      const char *path, config_file_cb_t *cb)\n{\n   int ret                  = 0;\n   struct config_file *conf = config_file_new_alloc();\n   if (!path || !*path)\n      return conf;\n   if ((ret = config_file_load_internal(conf, path, 0, cb)) == -1)\n   {\n      config_file_free(conf);\n      return NULL;\n   }\n   else if (ret == 1)\n   {\n      free(conf);\n      return NULL;\n   }\n   return conf;\n}\n\n/**\n * config_file_new:\n *\n * Loads a config file.\n * If @path is NULL, will create an empty config file.\n *\n * @return Returns NULL if file doesn't exist.\n **/\nconfig_file_t *config_file_new(const char *path)\n{\n   int ret                  = 0;\n   struct config_file *conf = config_file_new_alloc();\n   if (!path || !*path)\n      return conf;\n   if ((ret = config_file_load_internal(conf, path, 0, NULL)) == -1)\n   {\n      config_file_free(conf);\n      return NULL;\n   }\n   else if (ret == 1)\n   {\n      free(conf);\n      return NULL;\n   }\n   return conf;\n}\n\n/**\n * config_file_initialize:\n *\n * Leaf function.\n **/\nvoid config_file_initialize(struct config_file *conf)\n{\n   if (!conf)\n      return;\n\n   conf->path                     = NULL;\n   conf->entries_map              = NULL;\n   conf->entries                  = NULL;\n   conf->tail                     = NULL;\n   conf->last                     = NULL;\n   conf->references               = NULL;\n   conf->includes                 = NULL;\n   conf->include_depth            = 0;\n   conf->flags                    = 0;\n}\n\nconfig_file_t *config_file_new_alloc(void)\n{\n   struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));\n   if (!conf)\n      return NULL;\n   config_file_initialize(conf);\n   return conf;\n}\n\n/**\n * config_get_entry_internal:\n *\n * Leaf function.\n **/\nstatic struct config_entry_list *config_get_entry_internal(\n      const config_file_t *conf,\n      const char *key, struct config_entry_list **prev)\n{\n   struct config_entry_list *entry = RHMAP_GET_STR(conf->entries_map, key);\n\n   if (entry)\n      return entry;\n\n   if (prev)\n   {\n      struct config_entry_list *previous = *prev;\n      for (entry = conf->entries; entry; entry = entry->next)\n         previous = entry;\n\n      *prev = previous;\n   }\n\n   return NULL;\n}\n\nstruct config_entry_list *config_get_entry(\n      const config_file_t *conf, const char *key)\n{\n   return RHMAP_GET_STR(conf->entries_map, key);\n}\n\n/**\n * config_get_double:\n *\n * Extracts a double from config file.\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_double(config_file_t *conf, const char *key, double *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (!entry)\n      return false;\n\n   *in = strtod(entry->value, NULL);\n   return true;\n}\n\n/**\n * config_get_float:\n *\n * Extracts a float from config file.\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_float(config_file_t *conf, const char *key, float *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (!entry)\n      return false;\n\n   /* strtof() is C99/POSIX. Just use the more portable kind. */\n   *in = (float)strtod(entry->value, NULL);\n   return true;\n}\n\nbool config_get_int(config_file_t *conf, const char *key, int *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (entry)\n   {\n      long  val;\n      char *end = NULL;\n      errno = 0;\n      val   = strtol(entry->value, &end, 0);\n\n      if (errno != 0 || end == entry->value || *end != '\\0')\n         return false;\n\n      if (val < INT_MIN || val > INT_MAX)\n         return false;\n\n      *in = (int)val;\n      return true;\n   }\n\n   return false;\n}\n\nbool config_get_size_t(config_file_t *conf, const char *key, size_t *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (entry)\n   { \n      unsigned long val;\n      char *end = NULL;\n      errno = 0;\n      val   = (unsigned long)strtoul(entry->value, &end, 0);\n\n      if (errno != 0 || end == entry->value || *end != '\\0')\n         return false;\n\n#if (SIZE_MAX < ULONG_MAX)\n      if (val > SIZE_MAX)\n         return false;\n#endif\n\n      *in = (size_t)val;\n      return true;\n   }\n\n   return false;\n}\n\n#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L\nbool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (entry)\n   {\n      uint64_t val;\n      char    *end = NULL;\n      errno = 0;\n      val   = (uint64_t)strtoull(entry->value, &end, 0);\n\n      if (errno != 0 || end == entry->value || *end != '\\0')\n         return false;\n\n      *in = val;\n      return true;\n   }\n   return false;\n}\n#endif\n\nbool config_get_uint(config_file_t *conf, const char *key, unsigned *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (entry)\n   {\n      unsigned long  val;\n      char          *end = NULL;\n      errno = 0;\n      val   = strtoul(entry->value, &end, 0);\n\n      if (errno != 0 || end == entry->value || *end != '\\0')\n         return false;\n\n      if (val > UINT_MAX)\n         return false;\n\n      *in = (unsigned)val;\n      return true;\n   }\n\n   return false;\n}\n\nbool config_get_hex(config_file_t *conf, const char *key, unsigned *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (entry)\n   {\n      unsigned long  val;\n      char          *end = NULL;\n      errno = 0;\n      val   = strtoul(entry->value, &end, 16);\n\n      if (errno != 0 || end == entry->value || *end != '\\0')\n         return false;\n\n      if (val > UINT_MAX)\n         return false;\n\n      *in = (unsigned)val;\n      return true;\n   }\n\n   return false;\n}\n\n/**\n * config_get_char:\n *\n * Extracts a single char from config file.\n * If value consists of several chars, this is an error.\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_char(config_file_t *conf, const char *key, char *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n\n   if (entry)\n   {\n      if (entry->value[0] && entry->value[1])\n         return false;\n\n      *in = *entry->value;\n      return true;\n   }\n\n   return false;\n}\n\n/**\n * config_get_string:\n *\n * Extracts an allocated string in *in. This must be free()-d if\n * this function succeeds.\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_string(config_file_t *conf, const char *key, char **str)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n   char *dup;\n\n   if (!entry || !entry->value)\n      return false;\n\n   /* strdup can fail; pre-patch the function claimed success with\n    * *str possibly left as NULL or uninitialised garbage.  Callers\n    * that don't defensively zero *str ahead of the call end up\n    * dereferencing a stale pointer. */\n   if (!(dup = strdup(entry->value)))\n      return false;\n\n   *str = dup;\n   return true;\n}\n\n/**\n  * config_get_config_path:\n  *\n  * Extracts a string to a preallocated buffer.\n  * Avoid memory allocation.\n  **/\nsize_t config_get_config_path(config_file_t *conf, char *s, size_t len)\n{\n   if (conf)\n      return strlcpy(s, conf->path, len);\n   return 0;\n}\n\nbool config_get_array(config_file_t *conf, const char *key,\n      char *s, size_t len)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n   if (entry)\n      return strlcpy(s, entry->value, len) < len;\n   return false;\n}\n\nbool config_get_path(config_file_t *conf, const char *key,\n      char *s, size_t len)\n{\n#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)\n   return config_get_array(conf, key, s, len);\n#else\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n   if (entry)\n   {\n      fill_pathname_expand_special(s, entry->value, len);\n      return true;\n   }\n   return false;\n#endif\n}\n\n/**\n * config_get_bool:\n *\n * Extracts a boolean from config.\n * Valid boolean true are \"true\" and \"1\". Valid false are \"false\" and \"0\".\n * Other values will be treated as an error.\n *\n * @return true if preconditions are true, otherwise false.\n **/\nbool config_get_bool(config_file_t *conf, const char *key, bool *in)\n{\n   const struct config_entry_list *entry = config_get_entry(conf, key);\n   if (!entry)\n      return false;\n   if      (\n         entry->value[0] == '1'\n      && entry->value[1] == '\\0'\n         )\n      *in = true;\n   else if (\n         entry->value[0] == 't'\n      && entry->value[1] == 'r'\n      && entry->value[2] == 'u'\n      && entry->value[3] == 'e'\n      && entry->value[4] == '\\0'\n         )\n      *in = true;\n   else if (\n         entry->value[0] == '0'\n      && entry->value[1] == '\\0'\n         )\n      *in = false;\n   else if (\n         entry->value[0] == 'f'\n      && entry->value[1] == 'a'\n      && entry->value[2] == 'l'\n      && entry->value[3] == 's'\n      && entry->value[4] == 'e'\n      && entry->value[5] == '\\0'\n         )\n      *in = false;\n   else\n      return false;\n   return true;\n}\n\nvoid config_set_string(config_file_t *conf, const char *key, const char *val)\n{\n   struct config_entry_list *last  = NULL;\n   struct config_entry_list *entry = NULL;\n   if (!conf || !key || !val)\n      return;\n   last                            = conf->entries;\n   if (conf->flags & CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES)\n   {\n      if (conf->last)\n         last                      = conf->last;\n   }\n   else\n   {\n      if ((entry = config_get_entry_internal(conf, key, &last)))\n      {\n         if (entry->value)\n         {\n            if (strcmp(entry->value, val) == 0)\n               return;\n            free(entry->value);\n         }\n         entry->value    = strdup(val);\n         entry->readonly = false;\n         conf->flags    |= CONF_FILE_FLG_MODIFIED;\n         return;\n      }\n   }\n   if (!(entry = (struct config_entry_list*)malloc(sizeof(*entry))))\n      return;\n   entry->readonly  = false;\n   entry->next      = NULL;\n   entry->key       = strdup(key);\n   entry->value     = strdup(val);\n   /* If either strdup failed, don't insert a half-initialised entry\n    * into the list or hash map -- RHMAP_SET_STR with a NULL key\n    * is undefined, and subsequent config_get_string/config_set_*\n    * calls on this key would chase a NULL key. */\n   if (!entry->key || !entry->value)\n   {\n      free(entry->key);\n      free(entry->value);\n      free(entry);\n      return;\n   }\n   conf->flags     |= CONF_FILE_FLG_MODIFIED;\n   if (last)\n      last->next    = entry;\n   else\n      conf->entries = entry;\n   conf->last       = entry;\n   RHMAP_SET_STR(conf->entries_map, entry->key, entry);\n}\n\nvoid config_unset(config_file_t *conf, const char *key)\n{\n   struct config_entry_list *last  = NULL;\n   struct config_entry_list *entry = NULL;\n\n   if (!conf || !key)\n      return;\n\n   last  = conf->entries;\n\n   if (!(entry = config_get_entry_internal(conf, key, &last)))\n      return;\n\n   (void)RHMAP_DEL_STR(conf->entries_map, entry->key);\n\n   if (entry->key)\n      free(entry->key);\n\n   if (entry->value)\n      free(entry->value);\n\n   entry->key     = NULL;\n   entry->value   = NULL;\n   conf->flags   |= CONF_FILE_FLG_MODIFIED;\n}\n\nvoid config_set_path(config_file_t *conf, const char *entry, const char *val)\n{\n#if defined(RARCH_CONSOLE) || !defined(RARCH_INTERNAL)\n   config_set_string(conf, entry, val);\n#else\n   char buf[PATH_MAX_LENGTH];\n   fill_pathname_abbreviate_special(buf, val, sizeof(buf));\n   config_set_string(conf, entry, buf);\n#endif\n}\n\nsize_t config_set_double(config_file_t *conf, const char *key, double val)\n{\n   char buf[320];\n#ifdef __cplusplus\n   size_t _len = snprintf(buf, sizeof(buf), \"%f\", (float)val);\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L\n   size_t _len = snprintf(buf, sizeof(buf), \"%lf\", val);\n#else\n   size_t _len = snprintf(buf, sizeof(buf), \"%f\", (float)val);\n#endif\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\nsize_t config_set_float(config_file_t *conf, const char *key, float val)\n{\n   char buf[64];\n   size_t _len = snprintf(buf, sizeof(buf), \"%f\", val);\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\nsize_t config_set_int(config_file_t *conf, const char *key, int val)\n{\n   char buf[16];\n   size_t _len = snprintf(buf, sizeof(buf), \"%d\", val);\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\nsize_t config_set_uint(config_file_t *conf, const char *key, unsigned int val)\n{\n   char buf[16];\n   size_t _len = snprintf(buf, sizeof(buf), \"%u\", val);\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\nsize_t config_set_hex(config_file_t *conf, const char *key, unsigned val)\n{\n   char buf[16];\n   size_t _len = snprintf(buf, sizeof(buf), \"%x\", val);\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\nsize_t config_set_uint64(config_file_t *conf, const char *key, uint64_t val)\n{\n   char buf[32];\n   size_t _len = snprintf(buf, sizeof(buf), \"%\" PRIu64, val);\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\nsize_t config_set_char(config_file_t *conf, const char *key, char val)\n{\n   char buf[2];\n   size_t _len = snprintf(buf, sizeof(buf), \"%c\", val);\n   config_set_string(conf, key, buf);\n   return _len;\n}\n\n/**\n * config_file_write:\n *\n * Write the current config to a file.\n **/\nbool config_file_write(config_file_t *conf, const char *path, bool sort)\n{\n   if (!conf)\n      return false;\n   if (conf->flags & CONF_FILE_FLG_MODIFIED)\n   {\n      if (!path || !*path)\n         config_file_dump(conf, stdout, sort);\n      else\n      {\n         char buf[0x4000];\n         FILE *file = (FILE*)fopen_utf8(path, \"wb\");\n         if (!file)\n            return false;\n         setvbuf(file, buf, _IOFBF, sizeof(buf));\n         config_file_dump(conf, file, sort);\n         if (file != stdout)\n            fclose(file);\n         conf->flags &= ~CONF_FILE_FLG_MODIFIED;\n      }\n   }\n   return true;\n}\n\n/**\n * config_file_dump:\n *\n * Dump the current config to an already opened file.\n * Does not close the file.\n **/\nvoid config_file_dump(config_file_t *conf, FILE *file, bool sort)\n{\n   struct config_entry_list       *list = NULL;\n   struct config_include_list *includes = conf->includes;\n   struct path_linked_list *ref_tmp = conf->references;\n\n   while (ref_tmp)\n   {\n      pathname_make_slashes_portable(ref_tmp->path);\n      fprintf(file, \"#reference \\\"%s\\\"\\n\", ref_tmp->path);\n      ref_tmp = ref_tmp->next;\n   }\n\n   if (sort)\n      list = config_file_merge_sort_linked_list(\n            (struct config_entry_list*)conf->entries,\n            config_file_sort_compare_func);\n   else\n      list = (struct config_entry_list*)conf->entries;\n\n   conf->entries = list;\n\n   while (list)\n   {\n      if (!list->readonly && list->key)\n         fprintf(file, \"%s = \\\"%s\\\"\\n\", list->key, list->value);\n      list = list->next;\n   }\n\n   /* Config files are read from the top down - if\n    * duplicate entries are found then the topmost\n    * one in the list takes precedence. This means\n    * '#include' directives must go *after* individual\n    * config entries, otherwise they will override\n    * any custom-set values */\n   while (includes)\n   {\n      fprintf(file, \"#include \\\"%s\\\"\\n\", includes->path);\n      includes = includes->next;\n   }\n}\n\n/**\n * config_get_entry_list_head:\n *\n * Leaf function.\n **/\nbool config_get_entry_list_head(config_file_t *conf,\n      struct config_file_entry *entry)\n{\n   const struct config_entry_list *head = conf->entries;\n\n   if (!head)\n      return false;\n\n   entry->key   = head->key;\n   entry->value = head->value;\n   entry->next  = head->next;\n   return true;\n}\n\n/**\n * config_get_entry_list_next:\n *\n * Leaf function.\n **/\nbool config_get_entry_list_next(struct config_file_entry *entry)\n{\n   const struct config_entry_list *next = entry->next;\n\n   if (!next)\n      return false;\n\n   entry->key   = next->key;\n   entry->value = next->value;\n   entry->next  = next->next;\n   return true;\n}\n"
  },
  {
    "path": "file/config_file_userdata.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (config_file_userdata.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <file/file_path.h>\n\n#include <file/config_file_userdata.h>\n\nint config_userdata_get_float(void *userdata, const char *key_str,\n      float *value, float default_value)\n{\n   char key[256];\n   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;\n   *value = default_value;\n   fill_pathname_join_delim(key, usr->prefix[0], key_str, '_', sizeof(key));\n   if (config_get_float(usr->conf, key, value))\n      return 1;\n   fill_pathname_join_delim(key, usr->prefix[1], key_str, '_', sizeof(key));\n   if (config_get_float(usr->conf, key, value))\n      return 1;\n   return 0;\n}\n\nint config_userdata_get_int(void *userdata, const char *key_str,\n      int *value, int default_value)\n{\n   char key[256];\n   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;\n   *value = default_value;\n   fill_pathname_join_delim(key, usr->prefix[0], key_str, '_', sizeof(key));\n   if (config_get_int(usr->conf, key, value))\n      return 1;\n   fill_pathname_join_delim(key, usr->prefix[1], key_str, '_', sizeof(key));\n   if (config_get_int(usr->conf, key, value))\n      return 1;\n   return 0;\n}\n\nint config_userdata_get_hex(void *userdata, const char *key_str,\n      unsigned *value, unsigned default_value)\n{\n   char key[256];\n   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;\n   *value = default_value;\n   fill_pathname_join_delim(key, usr->prefix[0], key_str, '_', sizeof(key));\n   if (config_get_hex(usr->conf, key, value))\n      return 1;\n   fill_pathname_join_delim(key, usr->prefix[1], key_str, '_', sizeof(key));\n   if (config_get_hex(usr->conf, key, value))\n      return 1;\n   return 0;\n}\n\nint config_userdata_get_float_array(void *userdata, const char *key_str,\n      float **values, unsigned *out_num_values,\n      const float *default_values, unsigned num_default_values)\n{\n   char key[2][256];\n   char *str = NULL;\n   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;\n   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));\n   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));\n   if (     config_get_string(usr->conf, key[0], &str)\n         || config_get_string(usr->conf, key[1], &str))\n   {\n      unsigned count = 0;\n      const char *p = str;\n      char *tok, *end;\n      float *arr;\n\n      /* Count tokens */\n      while (*p)\n      {\n         while (*p == ' ')\n            p++;\n         if (!*p)\n            break;\n         count++;\n         while (*p && *p != ' ')\n            p++;\n      }\n\n      if (count == 0)\n      {\n         free(str);\n         goto use_defaults;\n      }\n\n      arr = (float*)calloc(count, sizeof(float));\n      if (!arr)\n      {\n         free(str);\n         *values         = NULL;\n         *out_num_values = 0;\n         return 0;\n      }\n\n      /* Parse tokens */\n      count = 0;\n      tok   = str;\n      while (*tok)\n      {\n         while (*tok == ' ')\n            tok++;\n         if (!*tok)\n            break;\n         arr[count++] = (float)strtod(tok, &end);\n         tok = end;\n      }\n\n      *values         = arr;\n      *out_num_values = count;\n      free(str);\n      return 1;\n   }\n\nuse_defaults:\n   if (num_default_values > 0 && default_values)\n   {\n      float *arr = (float*)calloc(num_default_values, sizeof(float));\n      if (!arr)\n      {\n         *values         = NULL;\n         *out_num_values = 0;\n         return 0;\n      }\n      memcpy(arr, default_values, sizeof(float) * num_default_values);\n      *values         = arr;\n      *out_num_values = num_default_values;\n   }\n   else\n   {\n      *values         = NULL;\n      *out_num_values = 0;\n   }\n   return 0;\n}\n\nint config_userdata_get_int_array(void *userdata, const char *key_str,\n      int **values, unsigned *out_num_values,\n      const int *default_values, unsigned num_default_values)\n{\n   char key[2][256];\n   char *str = NULL;\n   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;\n   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));\n   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));\n   if (     config_get_string(usr->conf, key[0], &str)\n         || config_get_string(usr->conf, key[1], &str))\n   {\n      unsigned i, count = 0;\n      const char *p = str;\n\n      /* First pass: count tokens */\n      while (*p)\n      {\n         while (*p == ' ')\n            p++;\n         if (!*p)\n            break;\n         count++;\n         while (*p && *p != ' ')\n            p++;\n      }\n\n      if (count == 0)\n      {\n         free(str);\n         *values         = NULL;\n         *out_num_values = 0;\n         return 1;\n      }\n\n      *values = (int*)calloc(count, sizeof(int));\n      if (!*values)\n      {\n         free(str);\n         *out_num_values = 0;\n         return 1;\n      }\n\n      /* Second pass: parse integers */\n      p = str;\n      i = 0;\n      while (*p && i < count)\n      {\n         char *end;\n         while (*p == ' ')\n            p++;\n         if (!*p)\n            break;\n         (*values)[i++] = (int)strtol(p, &end, 0);\n         p = end;\n      }\n\n      *out_num_values = count;\n      free(str);\n      return 1;\n   }\n\n   *values = (int*)calloc(num_default_values, sizeof(int));\n   if (*values)\n      memcpy(*values, default_values, sizeof(int) * num_default_values);\n   *out_num_values = *values ? num_default_values : 0;\n   return 0;\n}\n\nint config_userdata_get_string(void *userdata, const char *key_str,\n      char **output, const char *default_output)\n{\n   char key[2][256];\n   char *str = NULL;\n   struct config_file_userdata *usr = (struct config_file_userdata*)userdata;\n   fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));\n   fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));\n   if (     config_get_string(usr->conf, key[0], &str)\n         || config_get_string(usr->conf, key[1], &str))\n   {\n      *output = str;\n      return 1;\n   }\n   *output = strdup(default_output);\n   return 0;\n}\n\nvoid config_userdata_free(void *ptr)\n{\n   if (ptr)\n      free(ptr);\n}\n"
  },
  {
    "path": "file/file_path.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_path.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n#include <locale.h>\n#include <ctype.h>\n\n#include <sys/stat.h>\n\n#include <boolean.h>\n#include <file/file_path.h>\n#include <retro_miscellaneous.h>\n#include <time/rtime.h>\n\n/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */\n#ifdef __APPLE__\n#include <CoreFoundation/CoreFoundation.h>\n#endif\n#ifdef __HAIKU__\n#include <kernel/image.h>\n#endif\n#ifndef __MACH__\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n#endif\n#include <encodings/utf.h>\n\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h> /* stat() is defined here */\n#endif\n\n#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)\n#ifdef __WINRT__\n#include <uwp/uwp_func.h>\n#endif\n#endif\n\n/* Assume W-functions do not work below Win2K and Xbox platforms */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)\n\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n\n#endif\n\n/* Time format strings with AM-PM designation require special\n * handling due to platform dependence */\nsize_t strftime_am_pm(char *s, size_t len, const char* format,\n      const void *ptr)\n{\n   size_t _len              = 0;\n#if !(defined(__linux__) && !defined(ANDROID))\n   char *local              = NULL;\n#endif\n   const struct tm *timeptr = (const struct tm*)ptr;\n   setlocale(LC_TIME, \"\");\n   _len = strftime(s, len, format, timeptr);\n#if !(defined(__linux__) && !defined(ANDROID))\n   if ((local = local_to_utf8_string_alloc(s)))\n   {\n      if (local[0] != '\\0')\n         _len = strlcpy(s, local, len);\n      free(local);\n      local = NULL;\n   }\n#endif\n   return _len;\n}\n\n/**\n * Create a new linked list with one node in it\n * The path on this node will be set to NULL\n**/\nstruct path_linked_list* path_linked_list_new(void)\n{\n   struct path_linked_list* paths_list =\n      (struct path_linked_list*)malloc(sizeof(*paths_list));\n   if (!paths_list)\n      return NULL;\n   paths_list->next = NULL;\n   paths_list->path = NULL;\n   return paths_list;\n}\n\n/**\n * path_linked_list_free:\n *\n * Free the entire linked list\n **/\nvoid path_linked_list_free(struct path_linked_list *in_path_llist)\n{\n   struct path_linked_list *node_tmp = in_path_llist;\n   while (node_tmp)\n   {\n      struct path_linked_list *hold = node_tmp;\n      node_tmp = node_tmp->next;\n      free(hold->path); /* free(NULL) is safe per C89 */\n      free(hold);\n   }\n}\n\n/**\n * path_linked_list_add_path:\n *\n * Add a node to the linked list with this path\n * If the first node's path if it's not yet set the path\n * on this node instead\n**/\nvoid path_linked_list_add_path(struct path_linked_list *in_path_llist,\n      char *path)\n{\n   /* If the first item does not have a path this is\n      a list which has just been created, so we just fill\n      the path for the first item\n   */\n   if (!in_path_llist->path)\n      in_path_llist->path = strdup(path);\n   else\n   {\n      struct path_linked_list *node =\n         (struct path_linked_list*)malloc(sizeof(*node));\n\n      if (node)\n      {\n         struct path_linked_list *tail = in_path_llist;\n\n         node->next = NULL;\n         node->path = strdup(path);\n\n         while (tail->next)\n            tail = tail->next;\n         tail->next = node;\n      }\n   }\n}\n\n/**\n * path_get_archive_delim:\n * @path               : path\n *\n * Find delimiter of an archive file. Only the first '#'\n * after a compression extension is considered.\n *\n * @return pointer to the delimiter in the path if it contains\n * a path inside a compressed file, otherwise NULL.\n **/\nconst char *path_get_archive_delim(const char *path)\n{\n   /* Find delimiter position\n    * > Since filenames may contain '#' characters,\n    *   must loop until we find the first '#' that\n    *   is directly *after* a compression extension */\n   const char *delim = strchr(path, '#');\n\n   while (delim)\n   {\n      long d = (long)(delim - path);\n      /* Check whether this is a known archive type */\n      if (d > 3)\n      {\n         char c3 = delim[-3] | 0x20;\n         char c2 = delim[-2] | 0x20;\n         char c1 = delim[-1] | 0x20;\n\n         /* Check \".7z\" */\n         if (delim[-3] == '.' && delim[-2] == '7' && c1 == 'z')\n            return delim;\n\n         if (d > 4)\n         {\n            char c4 = delim[-4];\n\n            if (c4 == '.')\n            {\n               /* Check \".zip\" or \".zst\" */\n               if (c3 == 'z')\n               {\n                  if (c2 == 'i' && c1 == 'p')\n                     return delim;\n                  if (c2 == 's' && c1 == 't')\n                     return delim;\n               }\n               /* Check \".apk\" */\n               else if (c3 == 'a' && c2 == 'p' && c1 == 'k')\n                  return delim;\n            }\n         }\n      }\n\n      delim++;\n      delim = strchr(delim, '#');\n   }\n\n   return NULL;\n}\n\n/**\n * path_get_extension:\n * @path               : path\n *\n * Gets extension of file. Only '.'s\n * after the last slash are considered.\n *\n * @return extension part from the path.\n **/\nconst char *path_get_extension(const char *path)\n{\n   const char *ext;\n   if (  path\n       && (ext = strrchr(path_basename(path), '.'))\n       && ext[1] != '\\0')\n      return ext + 1;\n   return \"\";\n}\n\n/**\n * path_get_extension_mutable:\n * @path               : path\n *\n * Specialized version of path_get_extension(). Return\n * value is mutable.\n *\n * Gets extension of file. Only '.'s\n * after the last slash are considered.\n *\n * @return extension part from the path.\n **/\nchar *path_get_extension_mutable(const char *path)\n{\n   char *ext = NULL;\n   if (    path && *path != '\\0'\n       && ((ext = (char*)strrchr(path_basename(path), '.'))))\n      return ext;\n   return NULL;\n}\n\n/**\n * path_remove_extension:\n * @s                  : path\n *\n * Mutates path by removing its extension. Removes all\n * text after and including the last '.'.\n * Only '.'s after the last slash are considered.\n *\n * @return\n * 1) If path has an extension, returns path with the\n *    extension removed.\n * 2) If there is no extension, returns NULL.\n * 3) If path is empty or NULL, returns NULL\n **/\nchar *path_remove_extension(char *s)\n{\n   char *last = path_get_extension_mutable(s);\n   if (!last)\n      return NULL;\n   if (*last)\n      *last = '\\0';\n   return s;\n}\n\n/**\n * path_is_compressed_file:\n * @path               : path\n *\n * Checks if path is a compressed file.\n *\n * @return true if path is a compressed file, otherwise false.\n **/\nbool path_is_compressed_file(const char *path)\n{\n   const char *ext = path_get_extension(path);\n   if (!ext)\n      return false;\n   switch (tolower((unsigned char)ext[0]))\n   {\n      case '7':\n         return ext[1] == 'z' && ext[2] == '\\0';\n      case 'a':\n         return tolower((unsigned char)ext[1]) == 'p'\n             && tolower((unsigned char)ext[2]) == 'k'\n             && ext[3] == '\\0';\n      case 'z':\n         switch (tolower((unsigned char)ext[1]))\n         {\n            case 'i':\n               return tolower((unsigned char)ext[2]) == 'p'\n                   && ext[3] == '\\0';\n            case 's':\n               return tolower((unsigned char)ext[2]) == 't'\n                   && ext[3] == '\\0';\n         }\n         break;\n   }\n   return false;\n}\n\n/**\n * fill_pathname:\n * @s                  : output path\n * @in_path            : input  path\n * @replace            : what to replace\n * @len                : buffer size of output path\n *\n * FIXME: Verify\n *\n * Replaces filename extension with 'replace' and outputs result to @s.\n * The extension here is considered to be the string from the last '.'\n * to the end.\n *\n * Only '.'s after the last slash are considered as extensions.\n * If no '.' is present, in_path and replace will simply be concatenated.\n * 'len' is buffer size of 's'.\n * E.g.: in_path = \"/foo/bar/baz/boo.c\", replace = \".asm\" =>\n * s = \"/foo/bar/baz/boo.asm\"\n * E.g.: in_path = \"/foo/bar/baz/boo.c\", replace = \"\"     =>\n * s = \"/foo/bar/baz/boo\"\n *\n * @return Length of the string copied into @out\n */\nsize_t fill_pathname(char *s, const char *in_path,\n      const char *replace, size_t len)\n{\n   char *tok   = NULL;\n   size_t _len = strlcpy(s, in_path, len);\n   if (_len >= len)\n      _len = (len > 0) ? len - 1 : 0;\n   if ((tok = (char*)strrchr(path_basename(s), '.')))\n   {\n      *tok = '\\0'; _len = tok - s;\n   }\n   _len += strlcpy(s + _len, replace,  len - _len);\n   return _len;\n}\n\n\n/**\n * find_last_slash:\n * @str                : path\n * @size               : size of path\n *\n * Find last slash in path. Tries to find\n * a backslash as used for Windows paths,\n * otherwise checks for a regular slash.\n\n * @return pointer to last slash/backslash found in @str.\n **/\nchar *find_last_slash(const char *str)\n{\n#ifdef _WIN32\n   char *s1 = strrchr(str, '/');\n   char *s2 = strrchr(str, '\\\\');\n   if (!s1)\n      return s2;\n   if (!s2)\n      return s1;\n   return (s2 > s1) ? s2 : s1;\n#else\n   return strrchr(str, '/');\n#endif\n}\n\n/**\n * fill_pathname_slash:\n * @s                  : path\n * @len                : size of @s\n *\n * Assumes path is a directory. Appends a slash\n * if not already there.\n **/\nsize_t fill_pathname_slash(char *s, size_t len)\n{\n   size_t _len         = strlen(s);\n   char *last_slash    = find_last_slash(s);\n   if (!last_slash)\n   {\n      if (_len + 2 <= len)\n      {\n         s[  _len]     = PATH_DEFAULT_SLASH_C();\n         s[++_len]     = '\\0';\n      }\n   }\n   else if (last_slash != (s + _len - 1))\n   {\n      /* Try to preserve slash type. */\n      if (_len + 2 <= len)\n      {\n         s[  _len]     = last_slash[0];\n         s[++_len]     = '\\0';\n      }\n   }\n   return _len;\n}\n\n/**\n * fill_pathname_dir:\n * @s                  : input directory path\n * @in_basename        : input basename to be appended to @s\n * @replace            : replacement to be appended to @in_basename\n * @size               : size of buffer\n *\n * Appends basename of 'in_basename', to 's', along with 'replace'.\n * Basename of in_basename is the string after the last '/' or '\\\\',\n * i.e the filename without directories.\n *\n * If in_basename has no '/' or '\\\\', the whole 'in_basename' will be used.\n * 'size' is buffer size of 's'.\n *\n * E.g..: s = \"/tmp/some_dir\", in_basename = \"/some_content/foo.c\",\n * replace = \".asm\" => s = \"/tmp/some_dir/foo.c.asm\"\n **/\nsize_t fill_pathname_dir(char *s, const char *in_basename,\n      const char *replace, size_t len)\n{\n   size_t _len  = fill_pathname_slash(s, len);\n   _len        += strlcpy(s + _len, path_basename(in_basename), len - _len);\n   _len        += strlcpy(s + _len, replace, len - _len);\n   return _len;\n}\n\n/**\n * fill_pathname_base:\n * @s                  : output path\n * @in_path            : input path\n * @len                : size of output path\n *\n * Copies basename of @in_path into @s.\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_base(char *s, const char *in_path, size_t len)\n{\n   const char     *ptr = path_basename(in_path);\n   if (ptr)\n      return strlcpy(s, ptr, len);\n   return strlcpy(s, in_path, len);\n}\n\n/**\n * fill_pathname_basedir:\n * @s                  : output directory\n * @in_path            : input path\n * @len                : size of output directory\n *\n * Copies base directory of @in_path into @s.\n * If in_path is a path without any slashes (relative current directory),\n * @s will get path \"./\".\n *\n * @return Length of the string copied in @s\n **/\nsize_t fill_pathname_basedir(char *s, const char *in_path, size_t len)\n{\n   if (s != in_path)\n      strlcpy(s, in_path, len);\n   return path_basedir(s);\n}\n\n/**\n * fill_pathname_parent_dir_name:\n * @s                  : output string\n * @in_dir             : input directory\n * @len                : size of @s\n *\n * Copies only the parent directory name of @in_dir into @s.\n * The two buffers must not overlap. Removes trailing '/'.\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_parent_dir_name(char *s,\n   const char *in_dir, size_t len)\n{\n   const char *end, *parent_end;\n\n   if (len)\n      s[0] = '\\0';\n\n   end = in_dir + strlen(in_dir);\n\n   /* Skip trailing slash */\n   if (end > in_dir && (end[-1] == '/' || end[-1] == '\\\\'))\n      --end;\n\n   /* Find slash before the last component  \n    * (the filename/deepest dir) */\n   parent_end = end;\n   while (parent_end > in_dir \n         && parent_end[-1] != '/' && parent_end[-1] != '\\\\')\n      --parent_end;\n\n   /* parent_end now points past the slash that ends the parent dir.\n    * Move back over that slash, then find the start of the parent \n    * name. */\n   if (parent_end > in_dir)\n   {\n      const char *parent_start;\n      --parent_end; /* skip the slash itself */\n      parent_start = parent_end;\n      while (parent_start > in_dir \n            && parent_start[-1] != '/' \n            && parent_start[-1] != '\\\\')\n         --parent_start;\n\n      if (parent_end > parent_start)\n         return strlcpy(s, parent_start,\n               (size_t)(parent_end - parent_start + 1) < len\n               ? (size_t)(parent_end - parent_start + 1)\n               : len);\n   }\n   return 0;\n}\n\n/**\n * fill_pathname_parent_dir:\n * @s                  : output directory\n * @in_dir             : input directory\n * @len                : size of @s\n *\n * Copies parent directory of @in_dir into @s.\n * Assumes @in_dir is a directory. Keeps trailing '/'.\n * If the path was already at the root directory,\n * @s will be an empty string.\n **/\nsize_t fill_pathname_parent_dir(char *s,\n      const char *in_dir, size_t len)\n{\n   size_t _len = 0;\n   if (s == in_dir)\n      _len = strlen(s);\n   else\n      _len = strlcpy(s, in_dir, len);\n   return path_parent_dir(s, _len);\n}\n\n/**\n * fill_dated_filename:\n * @s                  : output filename\n * @ext                : extension of output filename\n * @len                : buffer size of output filename\n *\n * Creates a 'dated' filename prefixed by 'retroarch', and\n * concatenates extension (@ext) to it.\n *\n * E.g.:\n * s = \"retroarch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}\"\n **/\nsize_t fill_dated_filename(char *s,\n      const char *ext, size_t len)\n{\n   size_t _len;\n   struct tm tm_;\n   time_t cur_time = time(NULL);\n   rtime_localtime(&cur_time, &tm_);\n   _len  = strftime(s, len,\n         \"retroarch-%y%m%d-%H%M%S\", &tm_);\n   _len += strlcpy(s + _len, ext, len - _len);\n   return _len;\n}\n\n/**\n * fill_str_dated_filename:\n * @s                  : output filename\n * @in_str             : input string\n * @ext                : extension of output filename\n * @len                : buffer size of output filename\n *\n * Creates a 'dated' filename prefixed by the string @in_str, and\n * concatenates extension (@ext) to it.\n *\n * E.g.:\n * s = \"RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}\"\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_str_dated_filename(char *s,\n      const char *in_str, const char *ext, size_t len)\n{\n   struct tm tm_;\n   size_t _len     = 0;\n   time_t cur_time = time(NULL);\n   rtime_localtime(&cur_time, &tm_);\n   _len      = strlcpy(s, in_str, len);\n   if (!ext || ext[0] == '\\0')\n      _len += strftime(s + _len, len - _len, \"-%y%m%d-%H%M%S\", &tm_);\n   else\n   {\n      _len  += strftime(s + _len, len - _len, \"-%y%m%d-%H%M%S.\", &tm_);\n      _len  += strlcpy(s + _len, ext,    len - _len);\n   }\n   return _len;\n}\n\n/**\n * path_basedir:\n * @s                  : path\n *\n * Extracts base directory by mutating path.\n * Keeps trailing '/'.\n *\n * @return The new size of @s\n **/\nsize_t path_basedir(char *s)\n{\n   char *last_slash = NULL;\n   if (!s || s[0] == '\\0' || s[1] == '\\0')\n      return (s && s[0] != '\\0') ? 1 : 0;\n   last_slash       = find_last_slash(s);\n   if (last_slash)\n   {\n      last_slash[1] = '\\0';\n      return last_slash + 1 - s;\n   }\n   s[0]             = '.';\n   s[1]             = PATH_DEFAULT_SLASH_C();\n   s[2]             = '\\0';\n   return 2;\n}\n\n/**\n * path_parent_dir:\n * @s                  : path\n * @len                : length of @path\n *\n * Extracts parent directory by mutating path.\n * Assumes that @s is a directory. Keeps trailing '/'.\n * If the path was already at the root directory, returns empty string\n *\n * @return The new size of @s\n **/\nsize_t path_parent_dir(char *s, size_t len)\n{\n   if (!s)\n      return 0;\n\n   if (len && PATH_CHAR_IS_SLASH(s[len - 1]))\n   {\n      char *last_slash;\n      bool was_absolute = path_is_absolute(s);\n\n      s[len - 1]        = '\\0';\n      last_slash        = find_last_slash(s);\n\n      if (was_absolute && !last_slash)\n      {\n         /* We removed the only slash from what used \n          * to be an absolute path.\n          *\n          * On Linux, this goes from \"/\" to an empty string \n          * and everything works fine, but on Windows, we went \n          * from C:\\ to C:, which is not a valid path and that later\n          * gets erroneously treated as a relative one by path_basedir \n          * and returns \"./\".\n          * What we really wanted is an empty string. */\n         s[0] = '\\0';\n         return 0;\n      }\n   }\n   return path_basedir(s);\n}\n\n/**\n * path_basename:\n * @path               : path\n *\n * Get basename from @path.\n *\n * @return basename from path.\n **/\nconst char *path_basename(const char *path)\n{\n   /* We cut either at the first compression-related hash,\n    * or we cut at the last slash */\n   const char *ptr       = NULL;\n   char *last_slash      = find_last_slash(path);\n   return ((ptr = path_get_archive_delim(path)) || (ptr = last_slash))\n      ? (ptr + 1) : path;\n}\n\n/* Specialized version */\n/**\n * path_basename_nocompression:\n * @path               : path\n *\n * Specialized version of path_basename().\n * Get basename from @path.\n *\n * @return basename from path.\n **/\nconst char *path_basename_nocompression(const char *path)\n{\n   /* We cut at the last slash */\n   char *last_slash = find_last_slash(path);\n   return (last_slash) ? (last_slash + 1) : path;\n}\n\n/**\n * path_is_absolute:\n * @path               : path\n *\n * Checks if @path is an absolute path or a relative path.\n *\n * @return true if path is absolute, false if path is relative.\n **/\nbool path_is_absolute(const char *path)\n{\n   if (path && *path != '\\0')\n   {\n      if (path[0] == '/')\n         return true;\n#if defined(_WIN32)\n      if (path[0] == '\\\\' && path[1] == '\\\\')\n         return true;\n      if (path[0] && (path[1] == ':') && (path[2] == '/' || path[2] == '\\\\'))\n         return true;\n#elif defined(__wiiu__) || defined(VITA)\n      {\n         const char *sep = strchr(path, ':');\n         if (sep && sep[1] == '/')\n            return true;\n      }\n#endif\n   }\n   return false;\n}\n\n/**\n * path_resolve_realpath:\n * @s                  : input and output buffer for path\n * @len                : size of @s\n * @resolve_symlinks   : whether to resolve symlinks or not\n *\n * Resolves use of \".\", \"..\", multiple slashes etc in absolute paths.\n *\n * Relative paths are rebased on the current working dir.\n *\n * @return @s if successful, NULL otherwise.\n * Note: Not implemented on consoles\n * Note: Symlinks are only resolved on Unix-likes\n * Note: The current working dir might not be what you expect,\n *       e.g. on Android it is \"/\"\n *       Use of fill_pathname_resolve_relative() should be preferred\n **/\nchar *path_resolve_realpath(char *s, size_t len, bool resolve_symlinks)\n{\n#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)\n#ifdef _WIN32\n   char *ret         = NULL;\n   wchar_t *rel_path = utf8_to_utf16_string_alloc(s);\n   if (rel_path)\n   {\n      wchar_t abs_path[PATH_MAX_LENGTH];\n      if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH))\n      {\n         char *tmp = utf16_to_utf8_string_alloc(abs_path);\n         if (tmp)\n         {\n            strlcpy(s, tmp, len);\n            free(tmp);\n            ret = s;\n         }\n      }\n      free(rel_path);\n   }\n   return ret;\n#else\n   char tmp[PATH_MAX_LENGTH];\n   size_t t;\n   char *p;\n   const char *next;\n   const char *buf_end;\n   if (resolve_symlinks)\n   {\n      strlcpy(tmp, s, sizeof(tmp));\n      if (!realpath(tmp, s))\n      {\n         strlcpy(s, tmp, len);\n         return NULL;\n      }\n      return s;\n   }\n   t       = 0;\n   if (!path_is_absolute(s))\n   {\n      size_t _len;\n      size_t s_len;\n      if (!getcwd(tmp, PATH_MAX_LENGTH - 1))\n         return NULL;\n      _len  = strlen(tmp);\n      t    += _len;\n      if (tmp[_len - 1] != '/')\n         tmp[t++] = '/';\n      if (!s || *s == '\\0')\n      {\n         tmp[t] = '\\0';\n         strlcpy(s, tmp, len);\n         return s;\n      }\n      s_len = strlen(s);\n      if (t + s_len >= PATH_MAX_LENGTH)\n         return NULL;\n      buf_end = s + s_len;\n      p = s;\n   }\n   else\n   {\n      /* Leave one byte for the eventual '\\0' terminator. */\n      for (p = s; *p == '/' && t < PATH_MAX_LENGTH - 1; p++)\n         tmp[t++] = '/';\n      if (*p == '/')           /* still more slashes -> input too long */\n         return NULL;\n      buf_end = p + strlen(p);\n   }\n   do\n   {\n      if (!(next = strchr(p, '/')))\n         next = buf_end;\n      if (next - p == 2 && p[0] == '.' && p[1] == '.')\n      {\n         p = (char *)next + 1;\n         if (t == 1 || tmp[t - 2] == '/')\n            return NULL;\n         t -= 2;\n         while (tmp[t] != '/')\n            t--;\n         t++;\n      }\n      else if (next - p == 1 && p[0] == '.')\n         p = (char *)next + 1;\n      else if (next - p == 0)\n         p += 1;\n      else\n      {\n         if (t + (next - p) + 1 > PATH_MAX_LENGTH - 1)\n            return NULL;\n         while (p <= next)\n            tmp[t++] = *p++;\n      }\n   } while (next < buf_end);\n   tmp[t] = '\\0';\n   strlcpy(s, tmp, len);\n   return s;\n#endif\n#endif\n   return NULL;\n}\n\n/**\n * path_relative_to:\n * @s                  : buffer to write the relative path to\n * @path               : path to be expressed relatively\n * @base               : base directory to start out on\n * @len                : size of @s\n *\n * Turns @path into a path relative to @base and writes it to @s.\n *\n * @base is assumed to be a base directory, i.e. a path ending with '/' or '\\'.\n * Both @path and @base are assumed to be absolute paths without \".\" or \"..\".\n *\n * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg\n *\n * @return Length of the string copied into @s\n **/\nsize_t path_relative_to(char *s,\n      const char *path, const char *base, size_t len)\n{\n   size_t i, j;\n   size_t _len;\n   const char *trimmed_path, *trimmed_base;\n\n#ifdef _WIN32\n   /* For different drives, return absolute path */\n   if (\n            path\n         && base\n         && path[0] != '\\0'\n         && path[1] != '\\0'\n         && base[0] != '\\0'\n         && base[1] != '\\0'\n         && path[1] == ':'\n         && base[1] == ':'\n         && path[0] != base[0])\n      return strlcpy(s, path, len);\n#endif\n\n   /* Trim common beginning - recognize both slash types */\n   for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)\n      if (PATH_CHAR_IS_SLASH(path[i]))\n         j = i + 1;\n\n   trimmed_path = path + j;\n   trimmed_base = base + i;\n\n   /* Each segment of base turns into \"..\" */\n   _len = 0;\n   for (i = 0; trimmed_base[i]; i++)\n   {\n      if (PATH_CHAR_IS_SLASH(trimmed_base[i]))\n      {\n         if (_len + 3 < len)\n         {\n            s[_len++] = '.';\n            s[_len++] = '.';\n            s[_len++] = PATH_DEFAULT_SLASH_C();\n         }\n      }\n   }\n   s[_len] = '\\0';\n\n   _len += strlcpy(s + _len, trimmed_path, len - _len);\n   return _len;\n}\n\n/**\n * fill_pathname_resolve_relative:\n * @s                  : output path\n * @in_refpath         : input reference path\n * @in_path            : input path\n * @len                : size of @s\n *\n * Joins basedir of @in_refpath together with @in_path.\n * If @in_path is an absolute path, s = in_path.\n * E.g.: in_refpath = \"/foo/bar/baz.a\", in_path = \"foobar.cg\",\n * s = \"/foo/bar/foobar.cg\".\n **/\nvoid fill_pathname_resolve_relative(char *s,\n      const char *in_refpath, const char *in_path, size_t len)\n{\n   size_t _len;\n   if (path_is_absolute(in_path))\n   {\n      strlcpy(s, in_path, len);\n      return;\n   }\n\n   _len = fill_pathname_basedir(s, in_refpath, len);\n   strlcpy(s + _len, in_path, len - _len);\n   path_resolve_realpath(s, len, false);\n}\n\n/**\n * fill_pathname_join:\n * @s                  : output path\n * @dir                : directory\n * @path               : path\n * @len                : size of output path\n *\n * Joins a directory (@dir) and path (@path) together.\n * Makes sure not to get  two consecutive slashes\n * between directory and path.\n *\n * Deprecated. Use fill_pathname_join_special() instead\n * if you can ensure @dir and @s won't overlap.\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_join(char *s, const char *dir,\n      const char *path, size_t len)\n{\n   size_t _len = 0;\n   if (s != dir)\n      _len = strlcpy(s, dir, len);\n   if (*s)\n      _len = fill_pathname_slash(s, len);\n   _len   += strlcpy(s + _len, path, len - _len);\n   return _len;\n}\n\n/**\n * fill_pathname_join_special:\n * @s                  : output path\n * @dir                : directory. Cannot be identical to @s\n * @path               : path\n * @len                : size of @s\n *\n * Specialized version of fill_pathname_join.\n * Unlike fill_pathname_join(),\n * @dir and @s CANNOT be identical.\n *\n * Joins a directory (@dir) and path (@path) together.\n * Makes sure not to get  two consecutive slashes\n * between directory and path.\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_join_special(char *s,\n      const char *dir, const char *path, size_t len)\n{\n   size_t _len = strlcpy(s, dir, len);\n\n   if (*s)\n      _len = fill_pathname_slash(s, len);\n\n   _len += strlcpy(s + _len, path, len - _len);\n   return _len;\n}\n\nsize_t fill_pathname_join_special_ext(char *s,\n      const char *dir,  const char *path,\n      const char *last, const char *ext,\n      size_t len)\n{\n   size_t _len = fill_pathname_join(s, dir, path, len);\n   if (*s)\n      _len     = fill_pathname_slash(s, len);\n   _len       += strlcpy(s + _len, last, len - _len);\n   _len       += strlcpy(s + _len, ext,  len - _len);\n   return _len;\n}\n\n/**\n * fill_pathname_join_delim:\n * @s                  : output path\n * @dir                : directory\n * @path               : path\n * @delim              : delimiter\n * @len                : size of output path\n *\n * Joins a directory (@dir) and path (@path) together\n * using the given delimiter (@delim).\n **/\nsize_t fill_pathname_join_delim(char *s, const char *dir,\n      const char *path, const char delim, size_t len)\n{\n   size_t _len;\n   /* Behavior of strlcpy is undefined if dst and src overlap */\n   if (s == dir)\n      _len     = strlen(dir);\n   else\n      _len     = strlcpy(s, dir, len);\n   if (len - _len < 2)\n      return _len;\n   s[_len++]   = delim;\n   s[_len  ]   = '\\0';\n   if (path)\n      _len    += strlcpy(s + _len, path, len - _len);\n   return _len;\n}\n\nsize_t fill_pathname_expand_special(char *s, const char *in_path, size_t len)\n{\n#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)\n   if (in_path[0] == '~' || in_path[0] == ':')\n   {\n      char app_dir[DIR_MAX_LENGTH];\n\n      if (in_path[0] == '~')\n         fill_pathname_home_dir(app_dir, sizeof(app_dir));\n      else\n      {\n         app_dir[0] = '\\0';\n         fill_pathname_application_dir(app_dir, sizeof(app_dir));\n      }\n\n      if (*app_dir)\n      {\n         size_t _len  = strlcpy(s, app_dir, len);\n\n         s           += _len;\n         len         -= _len;\n\n         if (!PATH_CHAR_IS_SLASH(s[-1]))\n         {\n            _len      = strlcpy(s, PATH_DEFAULT_SLASH(), len);\n\n            s        += _len;\n            len      -= _len;\n         }\n\n         in_path += 2;\n      }\n   }\n#endif\n   return strlcpy(s, in_path, len);\n}\n\nsize_t fill_pathname_abbreviate_special(char *s,\n      const char *in_path, size_t len)\n{\n#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)\n   unsigned i;\n   const char *candidates[3];\n   const char *notations[3];\n   size_t cand_len[3];\n   char application_dir[DIR_MAX_LENGTH];\n   char home_dir[DIR_MAX_LENGTH];\n   application_dir[0] = '\\0';\n   candidates[0] = application_dir;\n   candidates[1] = home_dir;\n   candidates[2] = NULL;\n   notations [0] = \":\";\n   notations [1] = \"~\";\n   notations [2] = NULL;\n   cand_len[0] = fill_pathname_application_dir(application_dir, sizeof(application_dir));\n   cand_len[1] = fill_pathname_home_dir(home_dir, sizeof(home_dir));\n   cand_len[2] = 0;\n   for (i = 0; candidates[i]; i++)\n   {\n      if (  cand_len[i] > 0\n          && !strncmp(in_path, candidates[i], cand_len[i]))\n      {\n         size_t _len     = strlcpy(s, notations[i], len);\n         if (_len >= len)\n            return _len;\n         s              += _len;\n         len            -= _len;\n         in_path        += cand_len[i];\n         if (!PATH_CHAR_IS_SLASH(*in_path))\n         {\n            size_t sl    = strlcpy(s, PATH_DEFAULT_SLASH(), len);\n            if (sl >= len)\n               return _len + sl;\n            s           += sl;\n            len         -= sl;\n         }\n         break;\n      }\n   }\n#endif\n   return strlcpy(s, in_path, len);\n}\n\n/**\n * sanitize_path_part:\n *\n * @path_part               : directory or filename\n * @len                     : length of path_part\n *\n * Takes single part of a path eg. single filename\n * or directory, and removes any special chars that are\n * unavailable.\n *\n * @returns newly allocated string that has been sanitized.\n * Caller is responsible for freeing the returned string.\n **/\nchar *sanitize_path_part(const char *path_part, size_t len)\n{\n   size_t i;\n   size_t j = 0;\n   char *tmp = NULL;\n\n   if (!path_part || *path_part == '\\0')\n      return NULL;\n\n   tmp = (char *)malloc((len + 1) * sizeof(char));\n   if (!tmp)\n      return NULL;\n\n   for (i = 0; path_part[i] != '\\0'; i++)\n   {\n      char c = path_part[i];\n      /* Skip filesystem-unsafe characters */\n      switch (c)\n      {\n         case '<':\n         case '>':\n         case ':':\n         case '\"':\n         case '/':\n         case '\\\\':\n         case '|':\n         case '?':\n         case '*':\n            break;\n         default:\n            tmp[j++] = c;\n            break;\n      }\n   }\n\n   tmp[j] = '\\0';\n\n   return tmp;\n}\n\n/**\n * pathname_conform_slashes_to_os:\n *\n * @s                  : path\n *\n * Leaf function.\n *\n * Changes the slashes to the correct kind for the OS\n * So forward slash on linux and backslash on Windows\n **/\nvoid pathname_conform_slashes_to_os(char *s)\n{\n   /* Conform slashes to OS standard \n    * so we get proper matching */\n   char *p;\n   for (p = s; *p; p++)\n      if (*p == '/' || *p == '\\\\')\n         *p = PATH_DEFAULT_SLASH_C();\n}\n\n/**\n * pathname_make_slashes_portable:\n * @s                  : path\n *\n * Leaf function.\n *\n * Change all slashes to forward so they are more\n * portable between Windows and Linux\n **/\nvoid pathname_make_slashes_portable(char *s)\n{\n   /* Conform slashes to OS standard \n    * so we get proper matching */\n   char *p;\n   for (p = s; *p; p++)\n      if (*p == '/' || *p == '\\\\')\n         *p = '/';\n}\n\n/**\n * get_pathname_num_slashes:\n * @in_path            : input path\n *\n * Leaf function.\n *\n * Get the number of slashes in a path.\n *\n * @return number of slashes found in @in_path.\n **/\nstatic int get_pathname_num_slashes(const char *in_path)\n{\n   int num_slashes = 0;\n   const char *p;\n   for (p = in_path; *p != '\\0'; p++)\n   {\n      if (PATH_CHAR_IS_SLASH(*p))\n         num_slashes++;\n   }\n   return num_slashes;\n}\n\n/**\n * fill_pathname_abbreviated_or_relative:\n *\n * Fills the supplied path with either the abbreviated path or\n * the relative path, which ever one has less \n * depth / number of slashes\n *\n * If lengths of abbreviated and relative paths are the same,\n * the relative path will be used\n * @in_path can be an absolute, relative or abbreviated path\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_abbreviated_or_relative(char *s,\n      const char *in_refpath, const char *in_path, size_t len)\n{\n   size_t _len;\n   char buf_a[PATH_MAX_LENGTH];\n   char buf_b[PATH_MAX_LENGTH];\n\n   strlcpy(buf_a, in_path,    sizeof(buf_a));\n   strlcpy(buf_b, in_refpath, sizeof(buf_b));\n\n   pathname_conform_slashes_to_os(buf_a);\n   pathname_conform_slashes_to_os(buf_b);\n\n   /* Expand paths which start with :\\ to an absolute path.\n    * Write into s (used as scratch for the absolute path). */\n   s[0] = '\\0';\n   fill_pathname_expand_special(s, buf_a, len);\n\n   /* Get the absolute path if it is not already */\n   if (!path_is_absolute(s))\n      fill_pathname_resolve_relative(s, buf_b, buf_a, len);\n   pathname_conform_slashes_to_os(s);\n\n   /* s now holds the absolute path, buf_a is free.\n    * Compute the relative path into buf_a. */\n   path_relative_to(buf_a, s, buf_b, sizeof(buf_a));\n\n   /* buf_b is now also free. Save the absolute path there so we can\n    * pass non-overlapping pointers to fill_pathname_abbreviate_special. */\n   strlcpy(buf_b, s, sizeof(buf_b));\n   _len = fill_pathname_abbreviate_special(s, buf_b, len);\n\n   /* Use the shortest path, preferring the relative path */\n   if (     get_pathname_num_slashes(buf_a)\n         <= get_pathname_num_slashes(s))\n      return strlcpy(s, buf_a, len);\n   return _len;\n}\n\n/**\n * path_basedir:\n * @s                  : path\n *\n * Extracts base directory by mutating path.\n * Keeps trailing '/'.\n **/\nvoid path_basedir_wrapper(char *s)\n{\n   char *last_slash = NULL;\n   if (!s || s[0] == '\\0' || s[1] == '\\0')\n      return;\n#ifdef HAVE_COMPRESSION\n   /* We want to find the directory with the archive in basedir. */\n   if ((last_slash  = (char*)path_get_archive_delim(s)))\n      *last_slash   = '\\0';\n#endif\n   last_slash       = find_last_slash(s);\n   if (!last_slash)\n   {\n      s[0]          = '.';\n      s[1]          = PATH_DEFAULT_SLASH_C();\n      s[2]          = '\\0';\n   }\n   else\n      last_slash[1] = '\\0';\n}\n\n#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)\nsize_t fill_pathname_application_path(char *s, size_t len)\n{\n   if (len)\n   {\n#if defined(_WIN32)\n#ifdef LEGACY_WIN32\n      DWORD ret = GetModuleFileNameA(NULL, s, len);\n#else\n      wchar_t wstr[PATH_MAX_LENGTH] = {0};\n      DWORD ret = GetModuleFileNameW(NULL, wstr, ARRAY_SIZE(wstr));\n      if (*wstr)\n      {\n         char *str = utf16_to_utf8_string_alloc(wstr);\n         if (str)\n         {\n            strlcpy(s, str, len);\n            free(str);\n         }\n      }\n#endif\n      s[ret] = '\\0';\n      return ret;\n#elif defined(__APPLE__)\n      CFBundleRef bundle = CFBundleGetMainBundle();\n      if (bundle)\n      {\n         size_t rv               = 0;\n         CFURLRef bundle_url     = CFBundleCopyBundleURL(bundle);\n         CFStringRef bundle_path = CFURLCopyPath(bundle_url);\n         CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8);\n#ifdef HAVE_COCOATOUCH\n         {\n            /* This needs to be done so that the path becomes\n             * /private/var/... and this\n             * is used consistently throughout for the \n             * iOS bundle path */\n            char resolved_bundle_dir_buf[DIR_MAX_LENGTH] = {0};\n            if (realpath(s, resolved_bundle_dir_buf))\n            {\n               size_t _len = strlcpy(s, resolved_bundle_dir_buf, len - 1);\n               s[  _len]   = '/';\n               s[++_len]   = '\\0';\n               rv          = _len;\n            }\n         }\n#else\n         rv = CFStringGetLength(bundle_path);\n#endif\n\n         CFRelease(bundle_path);\n         CFRelease(bundle_url);\n         return rv;\n      }\n#elif defined(__HAIKU__)\n      image_info info;\n      int32_t cookie = 0;\n      while (get_next_image_info(0, &cookie, &info) == B_OK)\n      {\n         if (info.type == B_APP_IMAGE)\n            return strlcpy(s, info.name, len);\n      }\n#elif defined(__QNX__)\n      char *buff  = (char*)malloc(len);\n      size_t _len = 0;\n      /* NULL-check the malloc: _cmdname writes through its\n       * buffer argument (populates with the command path),\n       * NULL-derefs on OOM.  Leave s as it was set by the\n       * caller (empty or previous value) and return 0 -\n       * callers treat 0 as 'unable to resolve own path' and\n       * fall back to argv[0] or similar. */\n      if (!buff)\n         return 0;\n      if (_cmdname(buff))\n         _len = strlcpy(s, buff, len);\n      free(buff);\n      return _len;\n#else\n      size_t i;\n      static const char *exts[] = { \"exe\", \"file\", \"path/a.out\" };\n      char link_path[255];\n      pid_t pid   = getpid();\n      size_t _len = snprintf(link_path, sizeof(link_path), \"/proc/%u/\",\n            (unsigned)pid);\n\n      *s           = '\\0';\n\n      /* Linux, BSD and Solaris paths. Not standardized. */\n      for (i = 0; i < ARRAY_SIZE(exts); i++)\n      {\n         ssize_t ret;\n         strlcpy(link_path + _len, exts[i], sizeof(link_path) - _len);\n\n         if ((ret = readlink(link_path, s, len - 1)) >= 0)\n         {\n            s[ret] = '\\0';\n            return ret;\n         }\n      }\n#endif\n   }\n   return 0;\n}\n\nsize_t fill_pathname_application_dir(char *s, size_t len)\n{\n#ifdef __WINRT__\n   return strlcpy(s, uwp_dir_install, len);\n#else\n   fill_pathname_application_path(s, len);\n   return path_basedir(s);\n#endif\n}\n\nsize_t fill_pathname_home_dir(char *s, size_t len)\n{\n#ifdef __WINRT__\n   const char *home = uwp_dir_data;\n#else\n   const char *home = getenv(\"HOME\");\n#endif\n   if (home)\n      return strlcpy(s, home, len);\n   *s = 0;\n   return 0;\n}\n#endif\n\nbool is_path_accessible_using_standard_io(const char *path)\n{\n#ifdef __WINRT__\n   return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;\n#else\n   return true;\n#endif\n}\n"
  },
  {
    "path": "file/file_path_io.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_path_io.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n#include <sys/stat.h>\n\n#include <boolean.h>\n#include <file/file_path.h>\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n#include <retro_miscellaneous.h>\n#define VFS_FRONTEND\n#include <vfs/vfs_implementation.h>\n\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h> /* stat() is defined here */\n#endif\n\n/* TODO/FIXME - globals */\nstatic retro_vfs_stat_t path_stat32_cb = retro_vfs_stat_impl;\nstatic retro_vfs_stat_64_t path_stat64_cb = retro_vfs_stat_64_impl;\nstatic retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;\n\nvoid path_vfs_init(const struct retro_vfs_interface_info* vfs_info)\n{\n   const struct retro_vfs_interface* \n      vfs_iface           = vfs_info->iface;\n\n   path_stat32_cb         = retro_vfs_stat_impl;\n   path_stat64_cb         = retro_vfs_stat_64_impl;\n   path_mkdir_cb          = retro_vfs_mkdir_impl;\n\n   if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)\n      return;\n\n   path_stat32_cb         = vfs_iface->stat;\n   path_mkdir_cb          = vfs_iface->mkdir;\n\n   if (vfs_info->required_interface_version >= STAT64_REQUIRED_VFS_VERSION)\n      path_stat64_cb = vfs_iface->stat_64;\n   else\n      path_stat64_cb = NULL;\n}\n\nint path_stat(const char *path)\n{\n   /* Use 64‑bit stat if available, else fallback */\n   return path_stat64_cb ? path_stat64_cb(path, NULL) : path_stat32_cb(path, NULL);\n}\n\n/**\n * path_is_directory:\n * @path               : path\n *\n * Checks if path is a directory.\n *\n * @return true if path is a directory, otherwise false.\n */\nbool path_is_directory(const char *path)\n{\n   if (path_stat64_cb)\n      return (path_stat64_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;\n   return (path_stat32_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;\n}\n\nbool path_is_character_special(const char *path)\n{\n   if (path_stat64_cb)\n      return (path_stat64_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;\n   return (path_stat32_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;\n}\n\nbool path_is_valid(const char *path)\n{\n   if (path_stat64_cb)\n      return (path_stat64_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;\n   return (path_stat32_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;\n}\n\nint64_t path_get_size(const char *path)\n{\n   int64_t filesize = 0;\n   int32_t filesize32 = 0;\n\n   if (path_stat64_cb && path_stat64_cb(path, &filesize) != 0)\n      return filesize;\n\n   /* Fallback: 32-bit stat */\n   if (path_stat32_cb && path_stat32_cb(path, &filesize32) != 0)\n      return (int64_t)filesize32;\n\n   return -1;\n}\n\n/**\n * path_mkdir:\n * @dir                : directory\n *\n * Create directory on filesystem.\n * \n * Recursive function.\n *\n * @return true if directory could be created, otherwise false.\n **/\nbool path_mkdir(const char *dir)\n{\n   bool norecurse     = false;\n   char     *basedir  = NULL;\n\n   if (!(dir && *dir))\n      return false;\n\n   /* Use heap. Real chance of stack \n    * overflow if we recurse too hard. */\n   if (!(basedir = strdup(dir)))\n      return false;\n\n   path_parent_dir(basedir, strlen(basedir));\n\n   if (!*basedir || !strcmp(basedir, dir))\n   {\n      free(basedir);\n      return false;\n   }\n\n   if (     path_is_directory(basedir)\n         || path_mkdir(basedir))\n      norecurse = true;\n\n   free(basedir);\n\n   if (norecurse)\n   {\n      int ret = path_mkdir_cb(dir);\n\n      /* Don't treat this as an error. */\n      if (ret == -2 && path_is_directory(dir))\n         return true;\n      else if (ret == 0)\n         return true;\n   }\n   return false;\n}\n"
  },
  {
    "path": "file/nbio/nbio_intf.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nbio_intf.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <file/nbio.h>\n\nextern nbio_intf_t nbio_linux;\nextern nbio_intf_t nbio_mmap_unix;\nextern nbio_intf_t nbio_mmap_win32;\nextern nbio_intf_t nbio_stdio;\n\n#ifndef _XBOX\n#if defined(_WIN32)\n#if defined(_MSC_VER) && _MSC_VER >= 1500\n\n#ifndef HAVE_MMAP_WIN32\n#define HAVE_MMAP_WIN32\n#endif\n\n#elif !defined(_MSC_VER)\n\n#ifndef HAVE_MMAP_WIN32\n#define HAVE_MMAP_WIN32\n#endif\n#endif\n#endif\n\n#endif\n\n/* Disabled: the Linux AIO backend calls io_setup/io_destroy per\n * file handle, adding ~35us of kernel overhead per open+close.\n * For the small-file burst pattern used by menu icon loading\n * (40+ files of 4-64KB), this makes it ~2x slower than stdio.\n * Fall through to nbio_stdio on Linux until the AIO backend\n * shares a single context across handles. */\n#if 0 /* was: defined(__linux__) */\nstatic nbio_intf_t *internal_nbio = &nbio_linux;\n#elif defined(HAVE_MMAP) && defined(BSD)\nstatic nbio_intf_t *internal_nbio = &nbio_mmap_unix;\n#elif defined(HAVE_MMAP_WIN32)\nstatic nbio_intf_t *internal_nbio = &nbio_mmap_win32;\n#else\nstatic nbio_intf_t *internal_nbio = &nbio_stdio;\n#endif\n\nvoid *nbio_open(const char * filename, unsigned mode)\n{\n   return internal_nbio->open(filename, mode);\n}\n\nvoid nbio_begin_read(void *data)\n{\n   internal_nbio->begin_read(data);\n}\n\nvoid nbio_begin_write(void *data)\n{\n   internal_nbio->begin_write(data);\n}\n\nbool nbio_iterate(void *data)\n{\n   return internal_nbio->iterate(data);\n}\n\nvoid nbio_resize(void *data, size_t len)\n{\n   internal_nbio->resize(data, len);\n}\n\nvoid *nbio_get_ptr(void *data, size_t* len)\n{\n   return internal_nbio->get_ptr(data, len);\n}\n\nvoid nbio_cancel(void *data)\n{\n   internal_nbio->cancel(data);\n}\n\nvoid nbio_free(void *data)\n{\n   internal_nbio->free(data);\n}\n\nvoid nbio_set_chunk_size(void *data, size_t chunk_size)\n{\n   if (internal_nbio->set_chunk_size)\n      internal_nbio->set_chunk_size(data, chunk_size);\n}\n\nint nbio_get_fd(void *data)\n{\n   if (internal_nbio->get_fd)\n      return internal_nbio->get_fd(data);\n   return -1;\n}\n\nbool nbio_get_progress(void *data, size_t *completed, size_t *total)\n{\n   if (internal_nbio->get_progress)\n      return internal_nbio->get_progress(data, completed, total);\n   if (completed) *completed = 0;\n   if (total)     *total     = 0;\n   return false;\n}\n\nvoid *nbio_load_entire(void *data, size_t *len)\n{\n   /* Fast path: backend provides a direct implementation */\n   if (internal_nbio->load_entire)\n      return internal_nbio->load_entire(data, len);\n\n   /* Fallback: use the iterate loop */\n   internal_nbio->begin_read(data);\n   while (!internal_nbio->iterate(data));\n   return internal_nbio->get_ptr(data, len);\n}\n"
  },
  {
    "path": "file/nbio/nbio_linux.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nbio_linux.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <file/nbio.h>\n\n#if defined(__linux__)\n\n#ifndef _GNU_SOURCE\n#define _GNU_SOURCE\n#endif\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#include <time.h>\n\n#include <unistd.h>\n#include <fcntl.h>\n#include <sys/syscall.h>\n#include <linux/aio_abi.h>\n\nstruct nbio_linux_t\n{\n   void* ptr;\n   aio_context_t ctx;\n   struct iocb cb;\n   size_t len;\n   int fd;\n   bool busy;\n};\n\n/* there's also a Unix AIO thingy, but it's not in glibc\n * and we don't want more dependencies */\n\nstatic int io_setup(unsigned nr, aio_context_t * ctxp)\n{\n   return syscall(__NR_io_setup, nr, ctxp);\n}\n\nstatic int io_destroy(aio_context_t ctx)\n{\n   return syscall(__NR_io_destroy, ctx);\n}\n\nstatic int io_submit(aio_context_t ctx, long nr, struct iocb ** cbp)\n{\n   return syscall(__NR_io_submit, ctx, nr, cbp);\n}\n\nstatic int io_cancel(aio_context_t ctx, struct iocb * iocb, struct io_event * result)\n{\n   return syscall(__NR_io_cancel, ctx, iocb, result);\n}\n\nstatic int io_getevents(aio_context_t ctx, long min_nr, long nr,\n      struct io_event * events, struct timespec * timeout)\n{\n   return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);\n}\n\nstatic void nbio_begin_op(struct nbio_linux_t* handle, uint16_t op)\n{\n   struct iocb * cbp         = &handle->cb;\n\n   memset(&handle->cb, 0, sizeof(handle->cb));\n\n   handle->cb.aio_fildes     = handle->fd;\n   handle->cb.aio_lio_opcode = op;\n\n   handle->cb.aio_buf        = (uint64_t)(uintptr_t)handle->ptr;\n   handle->cb.aio_offset     = 0;\n   handle->cb.aio_nbytes     = handle->len;\n\n   if (io_submit(handle->ctx, 1, &cbp) != 1)\n      abort();\n\n   handle->busy = true;\n}\n\nstatic void *nbio_linux_open(const char * filename, unsigned mode)\n{\n   static const int o_flags[]  =   { O_RDONLY, O_RDWR|O_CREAT|O_TRUNC, O_RDWR, O_RDONLY, O_RDWR|O_CREAT|O_TRUNC };\n\n   aio_context_t ctx           = 0;\n   struct nbio_linux_t* handle = NULL;\n   int fd                      = open(filename, o_flags[mode]|O_CLOEXEC, 0644);\n   if (fd < 0)\n      return NULL;\n\n   if (io_setup(128, &ctx) < 0)\n   {\n      close(fd);\n      return NULL;\n   }\n\n   handle       = (struct nbio_linux_t*)malloc(sizeof(struct nbio_linux_t));\n   /* NULL-check the handle malloc: the next five lines dereferenced\n    * 'handle' unconditionally, so OOM segfaulted.  On failure we\n    * also have to unwind the fd we open()'d above and the aio\n    * context we io_setup()'d - both are resources that would be\n    * owned by the handle had it been allocated. */\n   if (!handle)\n   {\n      io_destroy(ctx);\n      close(fd);\n      return NULL;\n   }\n   handle->fd   = fd;\n   handle->ctx  = ctx;\n   handle->len  = lseek(fd, 0, SEEK_END);\n   handle->ptr  = malloc(handle->len);\n   /* Same pattern for the data buffer.  Subsequent begin_read /\n    * begin_write / iterate paths all assume handle->ptr is a valid\n    * buffer of handle->len bytes; passing a NULL through them\n    * would crash in the iocb setup.  Unwind everything we got. */\n   if (!handle->ptr)\n   {\n      free(handle);\n      io_destroy(ctx);\n      close(fd);\n      return NULL;\n   }\n   handle->busy = false;\n\n   return handle;\n}\n\nstatic void nbio_linux_begin_read(void *data)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (handle)\n      nbio_begin_op(handle, IOCB_CMD_PREAD);\n}\n\nstatic void nbio_linux_begin_write(void *data)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (handle)\n      nbio_begin_op(handle, IOCB_CMD_PWRITE);\n}\n\nstatic bool nbio_linux_iterate(void *data)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (!handle)\n      return false;\n   if (handle->busy)\n   {\n      struct io_event ev;\n      if (io_getevents(handle->ctx, 0, 1, &ev, NULL) == 1)\n         handle->busy = false;\n   }\n   return !handle->busy;\n}\n\nstatic void nbio_linux_resize(void *data, size_t len)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   void *new_ptr;\n   if (!handle)\n      return;\n\n   /* This works perfectly fine if this check is removed, but it\n    * won't work on other nbio implementations */\n   /* therefore, it's blocked so nobody accidentally relies on it */\n   if (len < handle->len)\n      abort();\n\n   if (ftruncate(handle->fd, len) != 0)\n      abort(); /* this one returns void and I can't find any other way\n                  for it to report failure */\n\n   /* Attempt the realloc BEFORE committing the new length.  If it\n    * fails, the old pointer and its old size are still valid; the\n    * caller can retry or abandon.  Matches the sibling pattern in\n    * nbio_stdio_resize - the pre-patch form\n    *\n    *    handle->ptr = realloc(handle->ptr, len);\n    *    handle->len = len;\n    *\n    * set handle->ptr to NULL on OOM (leaking the old buffer) and\n    * then claimed the new length, so subsequent get_ptr()/read/write\n    * walked a NULL pointer assuming len bytes. */\n   if (!(new_ptr = realloc(handle->ptr, len)))\n      return;\n\n   handle->ptr = new_ptr;\n   handle->len = len;\n}\n\nstatic void *nbio_linux_get_ptr(void *data, size_t* len)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (!handle)\n      return NULL;\n   if (len)\n      *len = handle->len;\n   if (!handle->busy)\n      return handle->ptr;\n   return NULL;\n}\n\nstatic void nbio_linux_cancel(void *data)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (!handle)\n      return;\n\n   if (handle->busy)\n   {\n      struct io_event ev;\n      io_cancel(handle->ctx, &handle->cb, &ev);\n      handle->busy = false;\n   }\n}\n\nstatic void nbio_linux_free(void *data)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (!handle)\n      return;\n\n   io_destroy(handle->ctx);\n   close(handle->fd);\n   free(handle->ptr);\n   free(handle);\n}\n\nstatic int nbio_linux_get_fd(void *data)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (handle)\n      return handle->fd;\n   return -1;\n}\n\nstatic bool nbio_linux_get_progress(void *data,\n      size_t *completed, size_t *total)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (!handle)\n   {\n      if (completed) *completed = 0;\n      if (total)     *total     = 0;\n      return false;\n   }\n   /* Linux AIO is all-or-nothing: either busy (0 done) or complete */\n   if (completed) *completed = handle->busy ? 0 : handle->len;\n   if (total)     *total     = handle->len;\n   return handle->busy;\n}\n\nstatic void *nbio_linux_load_entire(void *data, size_t *len)\n{\n   struct nbio_linux_t* handle = (struct nbio_linux_t*)data;\n   if (!handle)\n      return NULL;\n\n   /* Submit the read if not already in flight */\n   if (!handle->busy)\n      nbio_begin_op(handle, IOCB_CMD_PREAD);\n\n   /* Blocking wait: min_nr=1 means the kernel won't return\n    * until the I/O is complete — one syscall, no poll loop. */\n   if (handle->busy)\n   {\n      struct io_event ev;\n      while (io_getevents(handle->ctx, 1, 1, &ev, NULL) != 1);\n      handle->busy = false;\n   }\n\n   if (len)\n      *len = handle->len;\n   return handle->ptr;\n}\n\nnbio_intf_t nbio_linux = {\n   nbio_linux_open,\n   nbio_linux_begin_read,\n   nbio_linux_begin_write,\n   nbio_linux_iterate,\n   nbio_linux_resize,\n   nbio_linux_get_ptr,\n   nbio_linux_cancel,\n   nbio_linux_free,\n   NULL, /* set_chunk_size - linux AIO submits entire read at once */\n   nbio_linux_get_fd,\n   nbio_linux_get_progress,\n   nbio_linux_load_entire,\n   \"nbio_linux\",\n};\n#else\nnbio_intf_t nbio_linux = {\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL, /* set_chunk_size */\n   NULL, /* get_fd */\n   NULL, /* get_progress */\n   NULL, /* load_entire */\n   \"nbio_linux\",\n};\n\n#endif\n"
  },
  {
    "path": "file/nbio/nbio_stdio.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nbio_stdio.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#if defined(WIIU)\n#include <malloc.h>\n#endif\n\n#include <file/nbio.h>\n#include <encodings/utf.h>\n\n/* Assume W-functions do not work below Win2K and Xbox platforms */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)\n\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n\n#endif\n\n#if defined(_WIN32)\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n#define ATLEAST_VC2005\n#endif\n#endif\n\n#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)\n#ifndef HAVE_64BIT_OFFSETS\n#define HAVE_64BIT_OFFSETS\n#endif\n#endif\n\n/* Default chunk size for non-blocking I/O iterations (bytes).\n * Callers may override per-handle via nbio_set_chunk_size(). */\n#define NBIO_DEFAULT_CHUNK_SIZE 65536\n\nstruct nbio_stdio_t\n{\n   FILE* f;\n   void* data;\n   size_t progress;\n   size_t len;\n   size_t chunk_size;\n   /*\n    * possible values:\n    * NBIO_READ, NBIO_WRITE - obvious\n    * -1 - currently doing nothing\n    * -2 - the pointer was reallocated since the last operation\n    */\n   signed char op;\n   signed char mode;\n};\n\n#if !defined(_WIN32) || defined(LEGACY_WIN32)\nstatic const char    *stdio_modes[] = { \"rb\", \"wb\", \"r+b\", \"rb\", \"wb\", \"r+b\" };\n#else\nstatic const wchar_t *stdio_modes[] = { L\"rb\", L\"wb\", L\"r+b\", L\"rb\", L\"wb\", L\"r+b\" };\n#endif\n\nstatic int64_t fseek_wrap(FILE *f, int64_t offset, int origin)\n{\n#ifdef ATLEAST_VC2005\n   /* VC2005 and up have a special 64-bit fseek */\n   return _fseeki64(f, offset, origin);\n#elif defined(HAVE_64BIT_OFFSETS)\n   return fseeko(f, (off_t)offset, origin);\n#else\n   return fseek(f, (long)offset, origin);\n#endif\n}\n\nstatic int64_t ftell_wrap(FILE *f)\n{\n#ifdef ATLEAST_VC2005\n   /* VC2005 and up have a special 64-bit ftell */\n   return _ftelli64(f);\n#elif defined(HAVE_64BIT_OFFSETS)\n   return ftello(f);\n#else\n   return ftell(f);\n#endif\n}\n\nstatic void *nbio_stdio_open(const char * filename, unsigned mode)\n{\n   void *buf                   = NULL;\n   struct nbio_stdio_t* handle = NULL;\n   int64_t len                 = 0;\n#if !defined(_WIN32) || defined(LEGACY_WIN32)\n   FILE* f                     = fopen(filename, stdio_modes[mode]);\n#else\n   wchar_t *filename_wide      = utf8_to_utf16_string_alloc(filename);\n   FILE* f                     = _wfopen(filename_wide, stdio_modes[mode]);\n\n   if (filename_wide)\n      free(filename_wide);\n#endif\n   if (!f)\n      return NULL;\n\n   handle = (struct nbio_stdio_t*)malloc(sizeof(struct nbio_stdio_t));\n\n   if (!handle)\n   {\n      fclose(f);\n      return NULL;\n   }\n\n   handle->f = f;\n\n   switch (mode)\n   {\n      case NBIO_WRITE:\n      case BIO_WRITE:\n         break;\n      default:\n         fseek_wrap(handle->f, 0, SEEK_END);\n         len = ftell_wrap(handle->f);\n         break;\n   }\n\n   handle->mode          = mode;\n\n#if defined(WIIU)\n   /* hit the aligned-buffer fast path on Wii U */\n   if (len)\n      buf                = memalign(0x40, (size_t)len);\n#else\n   if (len)\n      buf                = malloc((size_t)len);\n#endif\n\n   if (len && !buf)\n   {\n      free(handle);\n      fclose(f);\n      return NULL;\n   }\n\n   handle->data          = buf;\n   handle->len           = len;\n   handle->progress      = handle->len;\n   handle->chunk_size    = NBIO_DEFAULT_CHUNK_SIZE;\n   handle->op            = -2;\n\n   return handle;\n}\n\nstatic void nbio_stdio_begin_read(void *data)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return;\n\n   if (handle->op >= 0)\n      abort();\n\n   fseek_wrap(handle->f, 0, SEEK_SET);\n\n   handle->op       = NBIO_READ;\n   handle->progress = 0;\n}\n\nstatic void nbio_stdio_begin_write(void *data)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return;\n\n   if (handle->op >= 0)\n      abort();\n\n   fseek_wrap(handle->f, 0, SEEK_SET);\n   handle->op = NBIO_WRITE;\n   handle->progress = 0;\n}\n\nstatic bool nbio_stdio_iterate(void *data)\n{\n   size_t amount               = 0;\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n\n   if (!handle)\n      return false;\n\n   amount = handle->chunk_size;\n\n   if (amount > handle->len - handle->progress)\n      amount = handle->len - handle->progress;\n\n   switch (handle->op)\n   {\n      case NBIO_READ:\n         if (handle->mode == BIO_READ)\n         {\n            amount = handle->len;\n            fread((char*)handle->data, 1, amount, handle->f);\n         }\n         else\n            fread((char*)handle->data + handle->progress, 1, amount, handle->f);\n         break;\n      case NBIO_WRITE:\n         if (handle->mode == BIO_WRITE)\n         {\n            size_t written = 0;\n            amount = handle->len;\n            written = fwrite((char*)handle->data, 1, amount, handle->f);\n            if (written != amount)\n               return false;\n         }\n         else\n            fwrite((char*)handle->data + handle->progress, 1, amount, handle->f);\n         break;\n   }\n\n   handle->progress += amount;\n\n   if (handle->progress == handle->len)\n      handle->op = -1;\n   return (handle->op < 0);\n}\n\nstatic void nbio_stdio_resize(void *data, size_t len)\n{\n   void *new_data              = NULL;\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return;\n\n   if (handle->op >= 0)\n      abort();\n   if (len < handle->len)\n      abort();\n\n   /* Attempt the realloc BEFORE committing the new length.  If it\n    * fails, the old pointer and its old size are still valid; the\n    * caller can retry or abandon.  Pre-patch we wrote handle->len\n    * = len first, then on realloc failure the handle claimed it\n    * owned a larger buffer than it actually did -- subsequent\n    * fread/fwrite iterate up to handle->len and walk off the end. */\n   if (!(new_data = realloc(handle->data, len)))\n      return;\n\n   handle->data     = new_data;\n   handle->len      = len;\n   handle->progress = len;\n   handle->op       = -1;\n}\n\nstatic void *nbio_stdio_get_ptr(void *data, size_t* len)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return NULL;\n   if (len)\n      *len = handle->len;\n   if (handle->op == -1)\n      return handle->data;\n   return NULL;\n}\n\nstatic void nbio_stdio_cancel(void *data)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return;\n\n   handle->op = -1;\n   handle->progress = handle->len;\n}\n\nstatic void nbio_stdio_free(void *data)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return;\n   if (handle->op >= 0)\n      abort();\n   fclose(handle->f);\n   free(handle->data);\n\n   handle->f    = NULL;\n   handle->data = NULL;\n   free(handle);\n}\n\nstatic void nbio_stdio_set_chunk_size(void *data, size_t chunk_size)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n      return;\n   handle->chunk_size = (chunk_size > 0) ? chunk_size : NBIO_DEFAULT_CHUNK_SIZE;\n}\n\nstatic int nbio_stdio_get_fd(void *data)\n{\n#if !defined(_WIN32) || defined(LEGACY_WIN32)\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (handle && handle->f)\n      return fileno(handle->f);\n#endif\n   return -1;\n}\n\nstatic bool nbio_stdio_get_progress(void *data,\n      size_t *completed, size_t *total)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle)\n   {\n      if (completed) *completed = 0;\n      if (total)     *total     = 0;\n      return false;\n   }\n   if (completed) *completed = handle->progress;\n   if (total)     *total     = handle->len;\n   return (handle->op >= 0);\n}\n\nstatic void *nbio_stdio_load_entire(void *data, size_t *len)\n{\n   struct nbio_stdio_t *handle = (struct nbio_stdio_t*)data;\n   if (!handle || !handle->f)\n      return NULL;\n\n   fseek_wrap(handle->f, 0, SEEK_SET);\n\n   /* Single fread of the entire file */\n   if (handle->len > 0)\n      fread((char*)handle->data, 1, handle->len, handle->f);\n\n   handle->progress = handle->len;\n   handle->op       = -1;\n\n   if (len)\n      *len = handle->len;\n   return handle->data;\n}\n\nnbio_intf_t nbio_stdio = {\n   nbio_stdio_open,\n   nbio_stdio_begin_read,\n   nbio_stdio_begin_write,\n   nbio_stdio_iterate,\n   nbio_stdio_resize,\n   nbio_stdio_get_ptr,\n   nbio_stdio_cancel,\n   nbio_stdio_free,\n   nbio_stdio_set_chunk_size,\n   nbio_stdio_get_fd,\n   nbio_stdio_get_progress,\n   nbio_stdio_load_entire,\n   \"nbio_stdio\",\n};\n"
  },
  {
    "path": "file/nbio/nbio_unixmmap.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nbio_unixmmap.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <file/nbio.h>\n\n#if defined(HAVE_MMAP) && defined(BSD)\n\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n#include <fcntl.h>\n#include <sys/mman.h>\n\n#ifdef __APPLE__\n\n#ifndef O_CLOEXEC\n#define O_CLOEXEC 0x1000000\n#endif\n\n#else\n\n#ifndef O_CLOEXEC\n#define O_CLOEXEC 0\n#endif\n\n#endif\n\nstruct nbio_mmap_unix_t\n{\n   void* ptr;\n   size_t len;\n   int fd;\n   int map_flags;\n};\n\nstatic void *nbio_mmap_unix_open(const char * filename, unsigned mode)\n{\n   static const int o_flags[] =   { O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC, O_RDWR,               O_RDONLY,  O_RDWR|O_CREAT|O_TRUNC };\n   static const int map_flags[] = { PROT_READ, PROT_WRITE|PROT_READ,   PROT_WRITE|PROT_READ, PROT_READ, PROT_WRITE|PROT_READ   };\n\n   size_t _len;\n   void* ptr                       = NULL;\n   struct nbio_mmap_unix_t* handle = NULL;\n   int fd                          = open(filename, o_flags[mode]|O_CLOEXEC, 0644);\n   if (fd < 0)\n      return NULL;\n\n   _len = lseek(fd, 0, SEEK_END);\n   if (_len != 0)\n      ptr = mmap(NULL, _len, map_flags[mode], MAP_SHARED, fd, 0);\n\n   if (ptr == MAP_FAILED)\n   {\n      close(fd);\n      return NULL;\n   }\n\n   handle            = malloc(sizeof(struct nbio_mmap_unix_t));\n   /* NULL-check the handle malloc: the four field writes below\n    * would segfault on OOM.  On failure munmap the region and\n    * close the fd we acquired above - both were destined to be\n    * owned by the handle and will leak otherwise. */\n   if (!handle)\n   {\n      if (_len != 0)\n         munmap(ptr, _len);\n      close(fd);\n      return NULL;\n   }\n   handle->fd        = fd;\n   handle->map_flags = map_flags[mode];\n   handle->len       = _len;\n   handle->ptr       = ptr;\n\n   /* For read-only mappings the fd is no longer needed once mmap has\n    * succeeded — the mapping remains valid after close(). Release it\n    * immediately so that loading many small files (e.g. hundreds of\n    * menu thumbnails via the async task queue) doesn't exhaust\n    * RLIMIT_NOFILE and cause unrelated fopen() calls to fail. The\n    * resize path (write mode) still needs the fd for ftruncate, so\n    * only close for read-only modes. */\n   if (o_flags[mode] == O_RDONLY)\n   {\n      close(fd);\n      handle->fd = -1;\n   }\n   return handle;\n}\n\nstatic void nbio_mmap_unix_begin_read(void *data)\n{\n   /* not needed */\n}\n\nstatic void nbio_mmap_unix_begin_write(void *data)\n{\n   /* not needed */\n}\n\nstatic bool nbio_mmap_unix_iterate(void *data)\n{\n   return true; /* not needed */\n}\n\nstatic void nbio_mmap_unix_resize(void *data, size_t len)\n{\n   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;\n   if (!handle)\n      return;\n   if (len < handle->len)\n   {\n      /* this works perfectly fine if this check is removed, but it\n       * won't work on other nbio implementations */\n      /* therefore, it's blocked so nobody accidentally relies on it */\n      abort();\n   }\n\n   if (ftruncate(handle->fd, len) != 0)\n      abort(); /* this one returns void and I can't find any other\n                  way for it to report failure */\n\n   munmap(handle->ptr, handle->len);\n\n   handle->ptr = mmap(NULL, len, handle->map_flags, MAP_SHARED, handle->fd, 0);\n   handle->len = len;\n\n   if (handle->ptr == MAP_FAILED)\n      abort();\n}\n\nstatic void *nbio_mmap_unix_get_ptr(void *data, size_t *len)\n{\n   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;\n   if (!handle)\n      return NULL;\n   if (len)\n      *len = handle->len;\n   return handle->ptr;\n}\n\nstatic void nbio_mmap_unix_cancel(void *data)\n{\n   /* not needed */\n}\n\nstatic void nbio_mmap_unix_free(void *data)\n{\n   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;\n   if (!handle)\n      return;\n   if (handle->fd >= 0)\n      close(handle->fd);\n   munmap(handle->ptr, handle->len);\n   free(handle);\n}\n\nstatic int nbio_mmap_unix_get_fd(void *data)\n{\n   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;\n   if (handle)\n      return handle->fd;\n   return -1;\n}\n\nstatic bool nbio_mmap_unix_get_progress(void *data,\n      size_t *completed, size_t *total)\n{\n   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;\n   if (!handle)\n   {\n      if (completed) *completed = 0;\n      if (total)     *total     = 0;\n      return false;\n   }\n   /* mmap is always \"complete\" — pages fault on demand */\n   if (completed) *completed = handle->len;\n   if (total)     *total     = handle->len;\n   return false;\n}\n\nstatic void *nbio_mmap_unix_load_entire(void *data, size_t *len)\n{\n   /* mmap: data is already mapped — just return the pointer.\n    * No begin_read/iterate ceremony needed. */\n   struct nbio_mmap_unix_t* handle = (struct nbio_mmap_unix_t*)data;\n   if (!handle)\n      return NULL;\n   if (len)\n      *len = handle->len;\n   return handle->ptr;\n}\n\nnbio_intf_t nbio_mmap_unix = {\n   nbio_mmap_unix_open,\n   nbio_mmap_unix_begin_read,\n   nbio_mmap_unix_begin_write,\n   nbio_mmap_unix_iterate,\n   nbio_mmap_unix_resize,\n   nbio_mmap_unix_get_ptr,\n   nbio_mmap_unix_cancel,\n   nbio_mmap_unix_free,\n   NULL, /* set_chunk_size - mmap doesn't chunk */\n   nbio_mmap_unix_get_fd,\n   nbio_mmap_unix_get_progress,\n   nbio_mmap_unix_load_entire,\n   \"nbio_mmap_unix\",\n};\n#else\nnbio_intf_t nbio_mmap_unix = {\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL, /* set_chunk_size */\n   NULL, /* get_fd */\n   NULL, /* get_progress */\n   NULL, /* load_entire */\n   \"nbio_mmap_unix\",\n};\n\n#endif\n"
  },
  {
    "path": "file/nbio/nbio_windowsmmap.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nbio_windowsmmap.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <file/nbio.h>\n\n#if defined(_WIN32)\n#if defined(_MSC_VER) && _MSC_VER >= 1500\n\n#ifndef HAVE_MMAP_WIN32\n#define HAVE_MMAP_WIN32\n#endif\n\n#elif !defined(_MSC_VER)\n\n#ifndef HAVE_MMAP_WIN32\n#define HAVE_MMAP_WIN32\n#endif\n#endif\n\n#endif\n\n#if defined(HAVE_MMAP_WIN32)\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <encodings/utf.h>\n\n#include <windows.h>\n\n/* Assume W-functions do not work below Win2K and Xbox platforms */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)\n\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n\n#endif\n\n#ifndef FILE_SHARE_ALL\n#define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)\n#endif\n\nstruct nbio_mmap_win32_t\n{\n   HANDLE file;\n   void* ptr;\n   size_t len;\n   bool is_write;\n};\n\nstatic void *nbio_mmap_win32_open(const char * filename, unsigned mode)\n{\n   static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS };\n   HANDLE mem;\n#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500\n   LARGE_INTEGER len;\n#else\n   SIZE_T len;\n#endif\n   struct nbio_mmap_win32_t* handle  = NULL;\n   void* ptr                         = NULL;\n   bool is_write                     = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE);\n   DWORD access                      = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ);\n#if !defined(_WIN32) || defined(LEGACY_WIN32)\n   HANDLE file                       = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);\n#else\n   wchar_t *filename_wide            = utf8_to_utf16_string_alloc(filename);\n#ifdef __WINRT__\n   HANDLE file                       = CreateFile2(filename_wide, access, FILE_SHARE_ALL, dispositions[mode], NULL);\n#else\n   HANDLE file                       = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);\n#endif\n\n   if (filename_wide)\n      free(filename_wide);\n#endif\n\n   if (file == INVALID_HANDLE_VALUE)\n      return NULL;\n\n#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500\n   /* GetFileSizeEx is new for Windows 2000 */\n   GetFileSizeEx(file, &len);\n   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);\n   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart);\n#else\n   GetFileSize(file, &len);\n   mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);\n   ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);\n#endif\n\n   CloseHandle(mem);\n\n   handle           = (struct nbio_mmap_win32_t*)malloc(sizeof(struct nbio_mmap_win32_t));\n   /* NULL-check the handle malloc: the field writes below would\n    * segfault on OOM.  On failure unmap the view and close the\n    * file handle - both are resources destined to be owned by\n    * the handle and will leak otherwise. */\n   if (!handle)\n   {\n      if (ptr)\n         UnmapViewOfFile(ptr);\n      CloseHandle(file);\n      return NULL;\n   }\n\n   handle->file     = file;\n   handle->is_write = is_write;\n#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500\n   handle->len      = len.QuadPart;\n#else\n   handle->len      = len;\n#endif\n   handle->ptr      = ptr;\n\n   return handle;\n}\n\nstatic void nbio_mmap_win32_begin_read(void *data)\n{\n   /* not needed */\n}\n\nstatic void nbio_mmap_win32_begin_write(void *data)\n{\n   /* not needed */\n}\n\nstatic bool nbio_mmap_win32_iterate(void *data)\n{\n   /* not needed */\n   return true;\n}\n\nstatic void nbio_mmap_win32_resize(void *data, size_t len)\n{\n#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500\n   LARGE_INTEGER len_li;\n#else\n   SIZE_T len_li;\n#endif\n   HANDLE mem;\n   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;\n\n   if (!handle)\n      return;\n\n   if (len < handle->len)\n   {\n      /* this works perfectly fine if this check is removed,\n       * but it won't work on other nbio implementations */\n      /* therefore, it's blocked so nobody accidentally\n       * relies on it. */\n      abort();\n   }\n\n#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500\n   /* SetFilePointerEx is new for Windows 2000 */\n   len_li.QuadPart = len;\n   SetFilePointerEx(handle->file, len_li, NULL, FILE_BEGIN);\n#else\n   len_li = len;\n   SetFilePointer(handle->file, len_li, NULL, FILE_BEGIN);\n#endif\n\n   if (!SetEndOfFile(handle->file))\n      abort(); /* this one returns void and I can't find any other way for it to report failure */\n   handle->len = len;\n\n   UnmapViewOfFile(handle->ptr);\n   mem = CreateFileMapping(handle->file, NULL, handle->is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);\n   handle->ptr = MapViewOfFile(mem, handle->is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);\n   CloseHandle(mem);\n\n   if (!handle->ptr)\n      abort();\n}\n\nstatic void *nbio_mmap_win32_get_ptr(void *data, size_t* len)\n{\n   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;\n   if (!handle)\n      return NULL;\n   if (len)\n      *len = handle->len;\n   return handle->ptr;\n}\n\nstatic void nbio_mmap_win32_cancel(void *data)\n{\n   /* not needed */\n}\n\nstatic void nbio_mmap_win32_free(void *data)\n{\n   struct nbio_mmap_win32_t* handle  = (struct nbio_mmap_win32_t*)data;\n   if (!handle)\n      return;\n   CloseHandle(handle->file);\n   UnmapViewOfFile(handle->ptr);\n   free(handle);\n}\n\nstatic void *nbio_mmap_win32_load_entire(void *data, size_t *len)\n{\n   /* mmap: data is already mapped — just return the pointer. */\n   struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;\n   if (!handle)\n      return NULL;\n   if (len)\n      *len = handle->len;\n   return handle->ptr;\n}\n\nnbio_intf_t nbio_mmap_win32 = {\n   nbio_mmap_win32_open,\n   nbio_mmap_win32_begin_read,\n   nbio_mmap_win32_begin_write,\n   nbio_mmap_win32_iterate,\n   nbio_mmap_win32_resize,\n   nbio_mmap_win32_get_ptr,\n   nbio_mmap_win32_cancel,\n   nbio_mmap_win32_free,\n   NULL, /* set_chunk_size - mmap doesn't chunk */\n   NULL, /* get_fd - win32 uses HANDLE, not fd */\n   NULL, /* get_progress - mmap is instant */\n   nbio_mmap_win32_load_entire,\n   \"nbio_mmap_win32\",\n};\n#else\nnbio_intf_t nbio_mmap_win32 = {\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL,\n   NULL, /* set_chunk_size */\n   NULL, /* get_fd */\n   NULL, /* get_progress */\n   NULL, /* load_entire */\n   \"nbio_mmap_win32\",\n};\n\n#endif\n"
  },
  {
    "path": "file/retro_dirent.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_dirent.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_common.h>\n\n#include <boolean.h>\n#include <retro_dirent.h>\n#define VFS_FRONTEND\n#include <vfs/vfs_implementation.h>\n\n/* TODO/FIXME - static globals */\nstatic retro_vfs_opendir_t dirent_opendir_cb                 = NULL;\nstatic retro_vfs_readdir_t dirent_readdir_cb                 = NULL;\nstatic retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;\nstatic retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb     = NULL;\nstatic retro_vfs_closedir_t dirent_closedir_cb               = NULL;\n\nvoid dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)\n{\n   const struct retro_vfs_interface* vfs_iface;\n\n   dirent_opendir_cb         = NULL;\n   dirent_readdir_cb         = NULL;\n   dirent_dirent_get_name_cb = NULL;\n   dirent_dirent_is_dir_cb   = NULL;\n   dirent_closedir_cb        = NULL;\n\n   vfs_iface                 = vfs_info->iface;\n\n   if (\n             vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION\n         || !vfs_iface)\n      return;\n\n   dirent_opendir_cb         = vfs_iface->opendir;\n   dirent_readdir_cb         = vfs_iface->readdir;\n   dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;\n   dirent_dirent_is_dir_cb   = vfs_iface->dirent_is_dir;\n   dirent_closedir_cb        = vfs_iface->closedir;\n}\n\nstruct RDIR *retro_opendir_include_hidden(\n      const char *name, bool include_hidden)\n{\n   if (dirent_opendir_cb)\n      return (struct RDIR *)dirent_opendir_cb(name, include_hidden);\n   return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);\n}\n\nstruct RDIR *retro_opendir(const char *name)\n{\n   return retro_opendir_include_hidden(name, false);\n}\n\nbool retro_dirent_error(struct RDIR *rdir)\n{\n   /* Left for compatibility */\n   return false;\n}\n\nint retro_readdir(struct RDIR *rdir)\n{\n   if (dirent_readdir_cb)\n      return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);\n   return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);\n}\n\nconst char *retro_dirent_get_name(struct RDIR *rdir)\n{\n   if (dirent_dirent_get_name_cb)\n      return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);\n   return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);\n}\n\n/**\n *\n * retro_dirent_is_dir:\n * @rdir         : pointer to the directory entry.\n * @unused       : deprecated, included for compatibility reasons, pass NULL\n *\n * Is the directory listing entry a directory?\n *\n * Returns: true if directory listing entry is\n * a directory, false if not.\n */\nbool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)\n{\n   if (dirent_dirent_is_dir_cb)\n      return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);\n   return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);\n}\n\nvoid retro_closedir(struct RDIR *rdir)\n{\n   if (dirent_closedir_cb)\n      dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);\n   else\n      retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);\n}\n"
  },
  {
    "path": "formats/bmp/rbmp.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rbmp.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Modified version of stb_image's BMP sources. */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <stddef.h> /* ptrdiff_t on osx */\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h> /* INT_MAX */\n\n#include <retro_inline.h>\n\n#include <formats/image.h>\n#include <formats/rbmp.h>\n\n/* truncate int to byte without warnings */\n#define RBMP_BYTECAST(x)  ((unsigned char) ((x) & 255))\n\ntypedef struct\n{\n   unsigned char *img_buffer;\n   unsigned char *img_buffer_end;\n   unsigned char *img_buffer_original;\n   int img_n;\n   int img_out_n;\n   int buflen;\n   uint32_t img_x;\n   uint32_t img_y;\n   unsigned char buffer_start[128];\n} rbmp_context;\n\nstruct rbmp\n{\n   uint8_t *buff_data;\n   uint32_t *output_image;\n};\n\nstatic INLINE unsigned char rbmp_get8(rbmp_context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n\n   return 0;\n}\n\nstatic void rbmp_skip(rbmp_context *s, int n)\n{\n   ptrdiff_t remaining;\n   if (n < 0)\n   {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   /* Clamp to remaining input to avoid pointer arithmetic beyond\n    * img_buffer_end (UB per C99).  Subsequent rbmp_get8 calls\n    * check \"buffer < buffer_end\" and parse as EOF. */\n   remaining = s->img_buffer_end - s->img_buffer;\n   if ((ptrdiff_t)n > remaining)\n      s->img_buffer = s->img_buffer_end;\n   else\n      s->img_buffer += n;\n}\n\nstatic int rbmp_get16le(rbmp_context *s)\n{\n   return rbmp_get8(s) + (rbmp_get8(s) << 8);\n}\n\n#define RBMP_GET32LE(s) (rbmp_get16le(s) + (rbmp_get16le(s) << 16))\n\n/* Microsoft/Windows BMP image */\n\n/* returns 0..31 for the highest set bit */\nstatic int rbmp_high_bit(unsigned int z)\n{\n   int n=0;\n   if (z == 0)\n      return -1;\n\n   if (z >= 0x10000)\n   {\n      n  += 16;\n      z >>= 16;\n   }\n   if (z >= 0x00100)\n   {\n      n  +=  8;\n      z >>=  8;\n   }\n   if (z >= 0x00010)\n   {\n      n  +=  4;\n      z >>=  4;\n   }\n   if (z >= 0x00004)\n   {\n      n  +=  2;\n      z >>=  2;\n   }\n   if (z >= 0x00002)\n      n +=  1;\n   return n;\n}\n\nstatic int rbmp_bitcount(unsigned int a)\n{\n   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); /* max 2 */\n   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); /* max 4 */\n   a = (a + (a >> 4)) & 0x0f0f0f0f; /* max 8 per 4, now 8 bits */\n   a = (a + (a >> 8));              /* max 16 per 8 bits */\n   a = (a + (a >> 16));             /* max 32 per 8 bits */\n   return a & 0xff;\n}\n\nstatic int rbmp_shiftsigned(int v, int shift, int bits)\n{\n   int ret;\n   int z = bits;\n\n   if (shift < 0)\n      v <<= -shift;\n   else\n      v >>= shift;\n\n   ret = v;\n\n   while (z < 8)\n   {\n      ret += v >> z;\n      z   += bits;\n   }\n   return ret;\n}\n\nstatic uint32_t *rbmp_bmp_load(rbmp_context *s, unsigned *x, unsigned *y,\n      int *comp, bool supports_rgba)\n{\n   uint32_t *output;\n   int bpp, flip_vertically, pad, offset, hsz;\n   int psize=0,i,j,width;\n   unsigned int mr=0,mg=0,mb=0,ma=0;\n\n   /* Corrupt BMP? */\n   if (rbmp_get8(s) != 'B' || rbmp_get8(s) != 'M')\n      return 0;\n\n   /* discard filesize */\n   rbmp_get16le(s);\n   rbmp_get16le(s);\n   /* discard reserved */\n   rbmp_get16le(s);\n   rbmp_get16le(s);\n\n   offset = (uint32_t)RBMP_GET32LE(s);\n   hsz    = (uint32_t)RBMP_GET32LE(s);\n\n   /* BMP type not supported? */\n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)\n      return 0;\n\n   if (hsz == 12)\n   {\n      s->img_x = rbmp_get16le(s);\n      s->img_y = rbmp_get16le(s);\n   }\n   else\n   {\n      s->img_x = (uint32_t)RBMP_GET32LE(s);\n      s->img_y = (uint32_t)RBMP_GET32LE(s);\n   }\n\n   /* Bad BMP? */\n   if (rbmp_get16le(s) != 1)\n      return 0;\n\n   bpp = rbmp_get16le(s);\n\n   /* BMP 1-bit type not supported? */\n   if (bpp == 1)\n      return 0;\n\n   /* img_y can legitimately be a negative int (top-down BMP).\n    * Pre-patch the code did abs((int)s->img_y) -- if the uint32\n    * happened to be 0x80000000, the cast to int is INT_MIN and\n    * abs(INT_MIN) is undefined behaviour.  Detect that case and\n    * treat as bottom-up zero-height (rejected by the overflow\n    * guard below). */\n   if (s->img_y == 0x80000000u)\n      return 0;\n   flip_vertically = ((int) s->img_y) > 0;\n   s->img_y        = (uint32_t)abs((int) s->img_y);\n\n   if (hsz == 12)\n   {\n      if (bpp < 24)\n         psize = (offset - 14 - 24) / 3;\n   }\n   else\n   {\n      int compress = (uint32_t)RBMP_GET32LE(s);\n\n      /* BMP RLE type not supported? */\n      if (compress == 1 || compress == 2)\n         return 0;\n\n      /* discard sizeof */\n      rbmp_get16le(s);\n      rbmp_get16le(s);\n      /* discard hres */\n      rbmp_get16le(s);\n      rbmp_get16le(s);\n      /* discard vres */\n      rbmp_get16le(s);\n      rbmp_get16le(s);\n      /* discard colors used */\n      rbmp_get16le(s);\n      rbmp_get16le(s);\n      /* discard max important */\n      rbmp_get16le(s);\n      rbmp_get16le(s);\n\n      if (hsz == 40 || hsz == 56)\n      {\n         if (hsz == 56)\n         {\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n         }\n         if (bpp == 16 || bpp == 32)\n         {\n            switch (compress)\n            {\n               case 0:\n                  break;\n               case 3:\n                  mr = (uint32_t)RBMP_GET32LE(s);\n                  mg = (uint32_t)RBMP_GET32LE(s);\n                  mb = (uint32_t)RBMP_GET32LE(s);\n                  /* not documented, but generated by\n                   * Photoshop and handled by MS Paint */\n                  /* Bad BMP ?*/\n                  if (mr == mg && mg == mb)\n                     return 0;\n                  break;\n               default:\n                  break;\n            }\n\n            /* Bad BMP? */\n            return 0;\n         }\n      }\n      else\n      {\n         mr = (uint32_t)RBMP_GET32LE(s);\n         mg = (uint32_t)RBMP_GET32LE(s);\n         mb = (uint32_t)RBMP_GET32LE(s);\n         ma = (uint32_t)RBMP_GET32LE(s);\n         /* Discard color space */\n         rbmp_get16le(s);\n         rbmp_get16le(s);\n         for (i = 0; i < 12; ++i)\n         {\n            /* Discard color space parameters */\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n         }\n         if (hsz == 124)\n         {\n            /* Discard rendering intent */\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            /* Discard offset of profile data */\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            /* Discard size of profile data */\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n            /* Discard reserved */\n            rbmp_get16le(s);\n            rbmp_get16le(s);\n         }\n      }\n      if (bpp < 16)\n         psize = (offset - 14 - hsz) >> 2;\n   }\n   s->img_n = ma ? 4 : 3;\n\n   /* Always output as uint32 (4 bytes per pixel).\n    *\n    * Pre-patch this multiplied two uint32_t dimensions at uint32_t\n    * width, so img_x * img_y silently wrapped on 32-bit -- e.g.\n    * 0x10001 * 0x10000 = 0x100010000 wraps to 0x10000, and the\n    * subsequent malloc returned a 256 KiB buffer that the pixel\n    * decode loop wrote off the end of (4 GiB+ of writes).  Do\n    * the multiplication in size_t with an explicit ceiling:\n    * 0x4000 x 0x4000 = 256 M pixels = 1 GiB of decoded RGBA is\n    * far beyond any realistic libretro asset, and rejecting at\n    * that ceiling blocks the overflow case AND avoids giving a\n    * malicious BMP a direct route to a multi-GiB allocation\n    * attempt. */\n   if (s->img_x == 0 || s->img_y == 0)\n      return 0;\n   if (s->img_x > 0x4000u || s->img_y > 0x4000u)\n      return 0;\n   output = (uint32_t*)malloc(\n         (size_t)s->img_x * (size_t)s->img_y * sizeof(uint32_t));\n   if (!output)\n      return 0;\n\n   if (bpp < 16)\n   {\n      /* Palette mode: pre-convert palette to uint32 in target byte order */\n      uint32_t pal32[256];\n\n      if (psize == 0 || psize > 256)\n      {\n         free(output);\n         return 0;\n      }\n\n      for (i = 0; i < psize; ++i)\n      {\n         unsigned char b = rbmp_get8(s);\n         unsigned char g = rbmp_get8(s);\n         unsigned char r = rbmp_get8(s);\n         if (hsz != 12)\n            rbmp_get8(s);\n         if (supports_rgba)\n            pal32[i] = 0xFF000000u | ((uint32_t)b << 16) | ((uint32_t)g << 8) | r;\n         else\n            pal32[i] = 0xFF000000u | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;\n      }\n\n      rbmp_skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));\n      if (bpp == 4)\n         width = (s->img_x + 1) >> 1;\n      else if (bpp == 8)\n         width = s->img_x;\n      else\n      {\n         free(output);\n         return 0;\n      }\n\n      pad = (-width)&3;\n      for (j = 0; j < (int)s->img_y; ++j)\n      {\n         int dst_row = flip_vertically ? (int)(s->img_y - 1 - j) : j;\n         /* Use size_t for the row-stride offset.  dst_row *\n          * s->img_x in signed-int could overflow for a legitimate\n          * 2 GiB BMP (e.g. 46341 x 46341).  Post-patch the\n          * pointer math matches the size_t-based allocation. */\n         uint32_t *dst = output + (size_t)dst_row * (size_t)s->img_x;\n         int col = 0;\n\n         for (i = 0; i < (int)s->img_x; i += 2)\n         {\n            int v  = rbmp_get8(s);\n            int v2 = 0;\n            if (bpp == 4)\n            {\n               v2  = v & 15;\n               v >>= 4;\n            }\n            dst[col++] = pal32[v];\n\n            if (i + 1 == (int)s->img_x)\n               break;\n\n            v = (bpp == 8) ? rbmp_get8(s) : v2;\n            dst[col++] = pal32[v];\n         }\n         rbmp_skip(s, pad);\n      }\n   }\n   else\n   {\n      int rshift = 0;\n      int gshift = 0;\n      int bshift = 0;\n      int ashift = 0;\n      int rcount = 0;\n      int gcount = 0;\n      int bcount = 0;\n      int acount = 0;\n      int easy   = 0;\n\n      rbmp_skip(s, offset - 14 - hsz);\n\n      if (bpp == 24)\n         width = 3 * s->img_x;\n      else if (bpp == 16)\n         width = 2 * s->img_x;\n      else /* bpp = 32 and pad = 0 */\n         width = 0;\n\n      pad = (-width) & 3;\n\n      switch (bpp)\n      {\n         case 24:\n            easy = 1;\n            break;\n         case 32:\n            if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)\n               easy = 2;\n            break;\n         default:\n            break;\n      }\n\n      if (!easy)\n      {\n         /* Corrupt BMP? */\n         if (!mr || !mg || !mb)\n         {\n            free(output);\n            return 0;\n         }\n\n         rshift = rbmp_high_bit(mr)-7;\n         rcount = rbmp_bitcount(mr);\n         gshift = rbmp_high_bit(mg)-7;\n         gcount = rbmp_bitcount(mg);\n         bshift = rbmp_high_bit(mb)-7;\n         bcount = rbmp_bitcount(mb);\n         ashift = rbmp_high_bit(ma)-7;\n         acount = rbmp_bitcount(ma);\n      }\n\n      for (j = 0; j < (int)s->img_y; ++j)\n      {\n         int dst_row = flip_vertically ? (int)(s->img_y - 1 - j) : j;\n         uint32_t *dst = output + dst_row * s->img_x;\n\n         if (easy)\n         {\n            if (easy == 2)\n            {\n               /* 32bpp BGRA — can read directly */\n               if (!supports_rgba)\n               {\n                  /* BMP bytes [B,G,R,A] = uint32 ARGB on LE — memcpy */\n                  int bytes_needed = s->img_x * 4;\n                  if (s->img_buffer + bytes_needed <= s->img_buffer_end)\n                  {\n                     memcpy(dst, s->img_buffer, bytes_needed);\n                     s->img_buffer += bytes_needed;\n                  }\n               }\n               else\n               {\n                  /* Need ABGR — swap R and B during read */\n                  for (i = 0; i < (int)s->img_x; ++i)\n                  {\n                     unsigned char b = rbmp_get8(s);\n                     unsigned char g = rbmp_get8(s);\n                     unsigned char r = rbmp_get8(s);\n                     unsigned char a = rbmp_get8(s);\n                     dst[i] = ((uint32_t)a << 24) | ((uint32_t)b << 16)\n                            | ((uint32_t)g << 8)  | (uint32_t)r;\n                  }\n               }\n            }\n            else\n            {\n               /* 24bpp BGR */\n               if (!supports_rgba)\n               {\n                  /* Need ARGB */\n                  for (i = 0; i < (int)s->img_x; ++i)\n                  {\n                     unsigned char b = rbmp_get8(s);\n                     unsigned char g = rbmp_get8(s);\n                     unsigned char r = rbmp_get8(s);\n                     dst[i] = 0xFF000000u | ((uint32_t)r << 16)\n                            | ((uint32_t)g << 8)  | (uint32_t)b;\n                  }\n               }\n               else\n               {\n                  /* Need ABGR */\n                  for (i = 0; i < (int)s->img_x; ++i)\n                  {\n                     unsigned char b = rbmp_get8(s);\n                     unsigned char g = rbmp_get8(s);\n                     unsigned char r = rbmp_get8(s);\n                     dst[i] = 0xFF000000u | ((uint32_t)b << 16)\n                            | ((uint32_t)g << 8)  | (uint32_t)r;\n                  }\n               }\n            }\n         }\n         else\n         {\n            /* Bitmask mode (16bpp or non-standard 32bpp) */\n            for (i = 0; i < (int)s->img_x; ++i)\n            {\n               unsigned char r, g, b, a;\n               uint32_t v = (bpp == 16)\n                  ? (uint32_t)rbmp_get16le(s)\n                  : (uint32_t)RBMP_GET32LE(s);\n               r = RBMP_BYTECAST(rbmp_shiftsigned(v & mr, rshift, rcount));\n               g = RBMP_BYTECAST(rbmp_shiftsigned(v & mg, gshift, gcount));\n               b = RBMP_BYTECAST(rbmp_shiftsigned(v & mb, bshift, bcount));\n               a = ma ? RBMP_BYTECAST(rbmp_shiftsigned(v & ma, ashift, acount)) : 255;\n\n               if (supports_rgba)\n                  dst[i] = ((uint32_t)a << 24) | ((uint32_t)b << 16)\n                         | ((uint32_t)g << 8)  | (uint32_t)r;\n               else\n                  dst[i] = ((uint32_t)a << 24) | ((uint32_t)r << 16)\n                         | ((uint32_t)g << 8)  | (uint32_t)b;\n            }\n         }\n         rbmp_skip(s, pad);\n      }\n   }\n\n   *x = s->img_x;\n   *y = s->img_y;\n\n   if (comp)\n      *comp = s->img_n;\n\n   return output;\n}\n\nstatic uint32_t *rbmp_load_from_memory(unsigned char const *buffer, int len,\n      unsigned *x, unsigned *y, int *comp, bool supports_rgba)\n{\n   rbmp_context s;\n\n   s.img_buffer          = (unsigned char*)buffer;\n   s.img_buffer_original = (unsigned char*)buffer;\n   s.img_buffer_end      = (unsigned char*)buffer+len;\n\n   return rbmp_bmp_load(&s, x, y, comp, supports_rgba);\n}\n\nint rbmp_process_image(rbmp_t *rbmp, void **buf_data,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba)\n{\n   int comp;\n\n   if (!rbmp)\n      return IMAGE_PROCESS_ERROR;\n\n   rbmp->output_image   = rbmp_load_from_memory(rbmp->buff_data,\n                           (int)size, width, height, &comp, supports_rgba);\n   *buf_data             = rbmp->output_image;\n\n   if (!rbmp->output_image)\n      return IMAGE_PROCESS_ERROR;\n\n   return IMAGE_PROCESS_END;\n}\n\nbool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data)\n{\n   if (!rbmp)\n      return false;\n\n   rbmp->buff_data = (uint8_t*)data;\n\n   return true;\n}\n\nvoid rbmp_free(rbmp_t *rbmp)\n{\n   if (!rbmp)\n      return;\n\n   free(rbmp);\n}\n\nrbmp_t *rbmp_alloc(void)\n{\n   rbmp_t *rbmp = (rbmp_t*)calloc(1, sizeof(*rbmp));\n   if (!rbmp)\n      return NULL;\n   return rbmp;\n}\n"
  },
  {
    "path": "formats/bmp/rbmp_encode.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rbmp_encode.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <streams/file_stream.h>\n#include <formats/rbmp.h>\n\nvoid form_bmp_header(uint8_t *header,\n      unsigned width, unsigned height,\n      bool is32bpp)\n{\n   unsigned line_size  = (width * (is32bpp?4:3) + 3) & ~3;\n   unsigned size       = line_size * height + 54;\n   unsigned size_array = line_size * height;\n\n   /* Generic BMP stuff. */\n   /* signature */\n   header[0] = 'B';\n   header[1] = 'M';\n   /* file size */\n   header[2] = (uint8_t)(size >> 0);\n   header[3] = (uint8_t)(size >> 8);\n   header[4] = (uint8_t)(size >> 16);\n   header[5] = (uint8_t)(size >> 24);\n   /* reserved */\n   header[6] = 0;\n   header[7] = 0;\n   header[8] = 0;\n   header[9] = 0;\n   /* offset */\n   header[10] = 54;\n   header[11] = 0;\n   header[12] = 0;\n   header[13] = 0;\n   /* DIB size */\n   header[14] = 40;\n   header[15] = 0;\n   header[16] = 0;\n   header[17] = 0;\n   /* Width */\n   header[18] = (uint8_t)(width >> 0);\n   header[19] = (uint8_t)(width >> 8);\n   header[20] = (uint8_t)(width >> 16);\n   header[21] = (uint8_t)(width >> 24);\n   /* Height */\n   header[22] = (uint8_t)(height >> 0);\n   header[23] = (uint8_t)(height >> 8);\n   header[24] = (uint8_t)(height >> 16);\n   header[25] = (uint8_t)(height >> 24);\n   /* Color planes */\n   header[26] = 1;\n   header[27] = 0;\n   /* Bits per pixel */\n   header[28] = is32bpp ? 32 : 24;\n   header[29] = 0;\n   /* Compression method */\n   header[30] = 0;\n   header[31] = 0;\n   header[32] = 0;\n   header[33] = 0;\n   /* Image data size */\n   header[34] = (uint8_t)(size_array >> 0);\n   header[35] = (uint8_t)(size_array >> 8);\n   header[36] = (uint8_t)(size_array >> 16);\n   header[37] = (uint8_t)(size_array >> 24);\n   /* Horizontal resolution */\n   header[38] = 19;\n   header[39] = 11;\n   header[40] = 0;\n   header[41] = 0;\n   /* Vertical resolution */\n   header[42] = 19;\n   header[43] = 11;\n   header[44] = 0;\n   header[45] = 0;\n   /* Palette size */\n   header[46] = 0;\n   header[47] = 0;\n   header[48] = 0;\n   header[49] = 0;\n   /* Important color count */\n   header[50] = 0;\n   header[51] = 0;\n   header[52] = 0;\n   header[53] = 0;\n}\n\nstatic bool write_header_bmp(RFILE *file, unsigned width, unsigned height, bool is32bpp)\n{\n   uint8_t header[54];\n   form_bmp_header(header, width, height, is32bpp);\n   return filestream_write(file, header, sizeof(header)) == sizeof(header);\n}\n\nstatic void dump_line_565_to_24(uint8_t *line, const uint16_t *src, unsigned width)\n{\n   unsigned i;\n\n   for (i = 0; i < width; i++)\n   {\n      uint16_t pixel = *src++;\n      uint8_t b = (pixel >>  0) & 0x1f;\n      uint8_t g = (pixel >>  5) & 0x3f;\n      uint8_t r = (pixel >> 11) & 0x1f;\n      *line++   = (b << 3) | (b >> 2);\n      *line++   = (g << 2) | (g >> 4);\n      *line++   = (r << 3) | (r >> 2);\n   }\n}\n\nstatic void dump_line_32_to_24(uint8_t *line, const uint32_t *src, unsigned width)\n{\n   unsigned i;\n\n   for (i = 0; i < width; i++)\n   {\n      uint32_t pixel = *src++;\n      *line++ = (pixel >>  0) & 0xff;\n      *line++ = (pixel >>  8) & 0xff;\n      *line++ = (pixel >> 16) & 0xff;\n   }\n}\n\nstatic void dump_content(RFILE *file, const void *frame,\n      int width, int height, int pitch, enum rbmp_source_type type)\n{\n   int j;\n   size_t line_size;\n   uint8_t *line       = NULL;\n   int bytes_per_pixel = (type==RBMP_SOURCE_TYPE_ARGB8888?4:3);\n   union\n   {\n      const uint8_t *u8;\n      const uint16_t *u16;\n      const uint32_t *u32;\n   } u;\n\n   u.u8      = (const uint8_t*)frame;\n   line_size = (width * bytes_per_pixel + 3) & ~3;\n\n   switch (type)\n   {\n      case RBMP_SOURCE_TYPE_BGR24:\n         {\n            /* BGR24 byte order input matches output. Can directly copy, but... need to make sure we pad it. */\n            uint32_t zeros = 0;\n            int padding    = (int)(line_size-pitch);\n            for (j = 0; j < height; j++, u.u8 += pitch)\n            {\n               filestream_write(file, u.u8, pitch);\n               if (padding != 0)\n                  filestream_write(file, &zeros, padding);\n            }\n         }\n         break;\n      case RBMP_SOURCE_TYPE_ARGB8888:\n         /* ARGB8888 byte order input matches output. Can directly copy. */\n         for (j = 0; j < height; j++, u.u8 += pitch)\n            filestream_write(file, u.u8, line_size);\n         return;\n      default:\n         break;\n   }\n\n   /* allocate line buffer, and initialize the final four bytes to zero, for deterministic padding */\n   if (!(line = (uint8_t*)malloc(line_size)))\n      return;\n   *(uint32_t*)(line + line_size - 4) = 0;\n\n   switch (type)\n   {\n      case RBMP_SOURCE_TYPE_XRGB888:\n         for (j = 0; j < height; j++, u.u8 += pitch)\n         {\n            dump_line_32_to_24(line, u.u32, width);\n            filestream_write(file, line, line_size);\n         }\n         break;\n      case RBMP_SOURCE_TYPE_RGB565:\n         for (j = 0; j < height; j++, u.u8 += pitch)\n         {\n            dump_line_565_to_24(line, u.u16, width);\n            filestream_write(file, line, line_size);\n         }\n         break;\n      default:\n         break;\n   }\n\n   /* Free allocated line buffer */\n   free(line);\n}\n\nbool rbmp_save_image(\n      const char *filename,\n      const void *frame,\n      unsigned width, unsigned height,\n      unsigned pitch, enum rbmp_source_type type)\n{\n   bool ret    = false;\n   RFILE *file = filestream_open(filename,\n         RETRO_VFS_FILE_ACCESS_WRITE,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   if (!file)\n      return false;\n\n   ret = write_header_bmp(file, width, height, type==RBMP_SOURCE_TYPE_ARGB8888);\n\n   if (ret)\n      dump_content(file, frame, width, height, pitch, type);\n\n   filestream_close(file);\n\n   return ret;\n}\n"
  },
  {
    "path": "formats/cdfs/cdfs.c",
    "content": "#include <formats/cdfs.h>\n\n#include <retro_miscellaneous.h>\n#include <compat/strl.h>\n#include <file/file_path.h>\n#include <string/stdstring.h>\n\n#ifdef HAVE_CHD\n#include <streams/chd_stream.h>\n#endif\n\nstatic void cdfs_determine_sector_size(cdfs_track_t* track)\n{\n   uint8_t buffer[32];\n   const int toc_sector = 16;\n\n   /* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.\n    *\n    *   MODE1/2048 - CDROM Mode1 Data (cooked) [no header, no footer]\n    *   MODE1/2352 - CDROM Mode1 Data (raw)    [16 byte header, 288 byte footer]\n    *   MODE2/2336 - CDROM-XA Mode2 Data       [8 byte header, 280 byte footer]\n    *   MODE2/2352 - CDROM-XA Mode2 Data       [24 byte header, 280 byte footer]\n    *\n    * Note that MODE is actually a property on each sector and can change between 1 and 2 depending on how much error\n    * correction the author desired. To support that, the data format must be \"/2352\" to include the full header and\n    * data without error correction information, at which point the CUE sheet information becomes just a hint.\n    */\n\n   /* The boot record or primary volume descriptor is always at sector 16 and will contain a \"CD001\" marker */\n   intfstream_seek(track->stream, toc_sector * 2352 + track->first_sector_offset, SEEK_SET);\n   if (intfstream_read(track->stream, &buffer, sizeof(buffer)) != (int64_t)sizeof(buffer))\n      return;\n\n   /* if this is a CDROM-XA data source, the \"CD001\" tag will be 25 bytes into the sector */\n   if (  buffer[25] == 0x43\n      && buffer[26] == 0x44\n      && buffer[27] == 0x30\n      && buffer[28] == 0x30\n      && buffer[29] == 0x31)\n   {\n      track->stream_sector_size        = 2352;\n      track->stream_sector_header_size = 24;\n   }\n   /* otherwise it should be 17 bytes into the sector */\n   else if (buffer[17] == 0x43\n      &&    buffer[18] == 0x44\n      &&    buffer[19] == 0x30\n      &&    buffer[20] == 0x30\n      &&    buffer[21] == 0x31)\n   {\n      track->stream_sector_size = 2352;\n      track->stream_sector_header_size = 16;\n   }\n   else\n   {\n      /* 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 */\n      if (\n            buffer[ 0] == 0\n         && buffer[ 1] == 0xFF\n         && buffer[ 2] == 0xFF\n         && buffer[ 3] == 0xFF\n         && buffer[ 4] == 0xFF\n         && buffer[ 5] == 0xFF\n         && buffer[ 6] == 0xFF\n         && buffer[ 7] == 0xFF\n         && buffer[ 8] == 0xFF\n         && buffer[ 9] == 0xFF\n         && buffer[10] == 0xFF\n         && buffer[11] == 0)\n      {\n         /* if we didn't find a CD001 tag, this format may predate ISO-9660 */\n\n         /* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */\n         track->stream_sector_size        = 2352;\n         track->stream_sector_header_size = 16;\n      }\n   }\n}\n\nstatic void cdfs_determine_sector_size_from_file_size(cdfs_track_t* track)\n{\n   /* attempt to determine stream_sector_size from file size */\n   size_t _len = intfstream_get_size(track->stream);\n\n   if ((_len % 2352) == 0)\n   {\n      /* raw tracks use all 2352 bytes and have a 24 byte header */\n      track->stream_sector_size        = 2352;\n      track->stream_sector_header_size = 24;\n   }\n   else if ((_len % 2048) == 0)\n   {\n      /* cooked tracks eliminate all header/footer data */\n      track->stream_sector_size        = 2048;\n      track->stream_sector_header_size = 0;\n   }\n   else if ((_len % 2336) == 0)\n   {\n      /* MODE 2 format without 16-byte sync data */\n      track->stream_sector_size        = 2336;\n      track->stream_sector_header_size = 8;\n   }\n}\n\nstatic void cdfs_seek_track_sector(cdfs_track_t* track, unsigned int sector)\n{\n   intfstream_seek(track->stream,\n           sector * track->stream_sector_size\n         + track->stream_sector_header_size\n         + track->first_sector_offset, SEEK_SET);\n}\n\nvoid cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)\n{\n   /* only allowed if open_file was called with a NULL path */\n   if (file->first_sector == 0)\n   {\n      if (file->current_sector != (int)sector)\n      {\n         file->current_sector      = (int)sector;\n         file->sector_buffer_valid = 0;\n      }\n\n      file->pos                    = sector * 2048;\n      file->current_sector_offset  = 0;\n   }\n}\n\nuint32_t cdfs_get_num_sectors(cdfs_file_t* file)\n{\n   uint32_t frame_size = intfstream_get_frame_size(file->track->stream);\n   if (frame_size == 0)\n   {\n      frame_size = file->track->stream_sector_size;\n      if (frame_size == 0)\n         frame_size = 1; /* prevent divide by 0 error if sector size is unknown */\n   }\n   return (uint32_t)(intfstream_get_size(file->track->stream) / frame_size);\n}\n\nuint32_t cdfs_get_first_sector(cdfs_file_t* file)\n{\n   return file->track->first_sector_index;\n}\n\nstatic int cdfs_find_file(cdfs_file_t* file, const char* path)\n{\n   size_t path_length;\n   int sector;\n   uint8_t buffer[2048], *tmp;\n   const char* slash = strrchr(path, '\\\\');\n\n   if (slash)\n   {\n      /* navigate the path to the directory record for the file */\n      const int dir_length = (int)(slash - path);\n      memcpy(buffer, path, dir_length);\n      buffer[dir_length] = '\\0';\n\n      sector = cdfs_find_file(file, (const char*)buffer);\n      if (sector < 0)\n         return sector;\n\n      path += dir_length + 1;\n   }\n   else\n   {\n      int offset;\n\n      /* find the CD information (always 16 frames in) */\n      cdfs_seek_track_sector(file->track, 16);\n      intfstream_read(file->track->stream, buffer, sizeof(buffer));\n\n      /* the directory_record starts at 156 bytes into the sector.\n       * the sector containing the root directory contents is a\n       * 3 byte value that is 2 bytes into the directory_record. */\n      offset = 156 + 2;\n      sector = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16);\n   }\n\n   /* process the contents of the directory */\n   cdfs_seek_track_sector(file->track, sector);\n   intfstream_read(file->track->stream, buffer, sizeof(buffer));\n\n   path_length = strlen(path);\n   tmp         = buffer;\n\n   /* The directory record layout (ECMA-119 §9.1) is:\n    *   byte  0:  record length (1 byte; 0 = end of records)\n    *   byte  1:  extended-attr length\n    *   bytes 2-9: location-of-extent (LE+BE) -- we use bytes 2..4\n    *   bytes 10-17: data length (LE+BE) -- we use bytes 10..13\n    *   ...\n    *   byte 32:  filename length\n    *   bytes 33..32+filename_length: filename\n    *\n    * Pre-this-patch the read at tmp[33 + path_length] and the\n    * subsequent reads at tmp[2..4]/tmp[10..13] could run off the\n    * end of the 2048-byte stack buffer when a malformed disc\n    * image had a record positioned (or chained via the\n    * tmp += tmp[0] advance) so that tmp + 33 + path_length lay\n    * past buffer + sizeof(buffer).  An attacker who can place a\n    * crafted sector at the directory offset gets:\n    *  - a 1-byte info-leak from adjacent stack via the\n    *    tmp[33 + path_length] comparison vs ';' / '\\0';\n    *  - filename-length bytes leaked via strncasecmp's\n    *    short-circuit timing;\n    *  - up to 4 bytes of attacker-influenced stack data feeding\n    *    `sector` (tmp[2..4]) and `file->size` (tmp[10..13]),\n    *    redirecting the next intfstream_read.\n    *\n    * The advance \"tmp += tmp[0]\" itself can land tmp anywhere\n    * up to 255 bytes ahead.  The guard tmp < buffer + sizeof\n    * only catches the case where the loop body re-runs; it does\n    * not protect against a single iteration whose body reads\n    * past the buffer.\n    *\n    * Tighten the guard so the entire record (header through the\n    * byte at offset 33 + path_length) must fit, and require the\n    * record's claimed length to be at least large enough to\n    * cover the filename comparison. */\n   while (   tmp < buffer + sizeof(buffer)\n          && (size_t)(tmp - buffer) + 33 + path_length < sizeof(buffer))\n   {\n      /* The first byte of the record is the length of\n       * the record - if 0, we reached the end of the data */\n      if (!*tmp)\n         break;\n\n      /* Reject records whose claimed length cannot accommodate\n       * the filename comparison below.  A legitimate ECMA-119\n       * directory record has length >= 33 + filename_length\n       * + 1 (the version-separator byte). */\n      if (tmp[0] < 33 + path_length + 1)\n         break;\n\n      /* filename is 33 bytes into the record and\n       * the format is \"FILENAME;version\" or \"DIRECTORY\" */\n      if (        (tmp[33 + path_length] == ';'\n               || (tmp[33 + path_length] == '\\0'))\n               &&  strncasecmp((const char*)(tmp + 33), path, path_length) == 0)\n      {\n         /* the file size is in bytes 10-13 of the record */\n         file->size =\n              (tmp[10])\n            | (tmp[11] << 8)\n            | (tmp[12] << 16)\n            | (tmp[13] << 24);\n\n         /* the file contents are in the sector identified\n          * in bytes 2-4 of the record */\n         sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);\n         return sector;\n      }\n\n      /* the first byte of the record is the length of the record */\n      tmp += tmp[0];\n   }\n\n   return -1;\n}\n\nint cdfs_open_file(cdfs_file_t* file, cdfs_track_t* track, const char* path)\n{\n   if (!file || !track)\n      return 0;\n\n   memset(file, 0, sizeof(*file));\n\n   file->track          = track;\n   file->current_sector = -1;\n   file->first_sector   = -1;\n\n   if (path)\n      file->first_sector = cdfs_find_file(file, path);\n   else if (file->track->stream_sector_size)\n   {\n      file->first_sector = 0;\n      file->size         = (unsigned int)((intfstream_get_size(\n               file->track->stream) / file->track->stream_sector_size)\n         * 2048);\n      return 1;\n   }\n\n   return (file->first_sector >= 0);\n}\n\nint64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)\n{\n   int bytes_read = 0;\n\n   if (!file || file->first_sector < 0 || !buffer)\n      return 0;\n\n   if (len > file->size - file->pos)\n      len = file->size - file->pos;\n\n   if (len == 0)\n      return 0;\n\n   if (file->sector_buffer_valid)\n   {\n      size_t remaining = 2048 - file->current_sector_offset;\n      if (remaining > 0)\n      {\n         if (remaining >= len)\n         {\n            memcpy(buffer,\n                  &file->sector_buffer[file->current_sector_offset],\n                  (size_t)len);\n            file->current_sector_offset += len;\n            return len;\n         }\n\n         memcpy(buffer,\n               &file->sector_buffer[file->current_sector_offset], remaining);\n         buffer      = (char*)buffer + remaining;\n         bytes_read += remaining;\n         len        -= remaining;\n\n         file->current_sector_offset += remaining;\n      }\n\n      ++file->current_sector;\n      file->current_sector_offset = 0;\n      file->sector_buffer_valid   = 0;\n   }\n   else if (file->current_sector < file->first_sector)\n   {\n      file->current_sector        = file->first_sector;\n      file->current_sector_offset = 0;\n   }\n\n   while (len >= 2048)\n   {\n      cdfs_seek_track_sector(file->track, file->current_sector);\n      intfstream_read(file->track->stream, buffer, 2048);\n\n      buffer      = (char*)buffer + 2048;\n      bytes_read += 2048;\n\n      ++file->current_sector;\n\n      len        -= 2048;\n   }\n\n   if (len > 0)\n   {\n      cdfs_seek_track_sector(file->track, file->current_sector);\n      intfstream_read(file->track->stream, file->sector_buffer, 2048);\n      memcpy(buffer, file->sector_buffer, (size_t)len);\n      file->current_sector_offset = (unsigned int)len;\n      file->sector_buffer_valid   = 1;\n\n      bytes_read += len;\n   }\n\n   file->pos += bytes_read;\n   return bytes_read;\n}\n\nvoid cdfs_close_file(cdfs_file_t* file)\n{\n   /* Not really anything to do here, just\n    * clear out the first_sector so\n    * read() won't do anything */\n   if (file)\n      file->first_sector = -1;\n}\n\nint64_t cdfs_get_size(cdfs_file_t* file)\n{\n   if (!file || file->first_sector < 0)\n      return 0;\n   return file->size;\n}\n\nint64_t cdfs_tell(cdfs_file_t* file)\n{\n   if (!file || file->first_sector < 0)\n      return -1;\n   return file->pos;\n}\n\nint64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)\n{\n   int64_t new_pos;\n   int new_sector;\n\n   if (!file || file->first_sector < 0)\n      return -1;\n\n   switch (whence)\n   {\n      case SEEK_SET:\n         new_pos = offset;\n         break;\n\n      case SEEK_CUR:\n         new_pos = file->pos + offset;\n         break;\n\n      case SEEK_END:\n         new_pos = file->size - offset;\n         break;\n\n      default:\n         return -1;\n   }\n\n   if (new_pos < 0)\n      return -1;\n   else if (new_pos > file->size)\n      return -1;\n\n   file->pos = (unsigned int)new_pos;\n   file->current_sector_offset = file->pos % 2048;\n\n   new_sector = file->pos / 2048;\n   if (new_sector != file->current_sector)\n   {\n      file->current_sector      = new_sector;\n      file->sector_buffer_valid = false;\n   }\n\n   return 0;\n}\n\nstatic void cdfs_skip_spaces(const char** ptr)\n{\n   while (**ptr && (**ptr == ' ' || **ptr == '\\t'))\n      ++(*ptr);\n}\n\nstatic cdfs_track_t* cdfs_wrap_stream(\n      intfstream_t* stream,\n      unsigned first_sector_offset,\n      unsigned first_sector_index)\n{\n   cdfs_track_t* track = NULL;\n\n   if (!stream)\n      return NULL;\n\n   track                      = (cdfs_track_t*)\n      calloc(1, sizeof(*track));\n   track->stream              = stream;\n   track->first_sector_offset = first_sector_offset;\n   track->first_sector_index  = first_sector_index;\n\n   cdfs_determine_sector_size(track);\n\n   return track;\n}\n\nstatic cdfs_track_t* cdfs_open_cue_track(\n      const char* path, unsigned int track_index)\n{\n   char* cue                                = NULL;\n   const char* line                         = NULL;\n   int found_track                          = 0;\n   char current_track_path[PATH_MAX_LENGTH] = {0};\n   char track_path[PATH_MAX_LENGTH]         = {0};\n   unsigned int sector_size                 = 0;\n   unsigned int previous_sector_size        = 0;\n   unsigned int previous_index_sector_offset= 0;\n   unsigned int track_offset                = 0;\n   intfstream_t *cue_stream                 = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   int64_t stream_size                      = intfstream_get_size(cue_stream);\n   char *cue_contents                       = (char*)malloc((size_t)(stream_size + 1));\n   cdfs_track_t* track                      = NULL;\n\n   if (!cue_contents)\n   {\n      intfstream_close(cue_stream);\n      free(cue_stream);\n      return NULL;\n   }\n\n   intfstream_read(cue_stream, cue_contents, stream_size);\n   intfstream_close(cue_stream);\n   free(cue_stream);\n\n   cue_contents[stream_size] = '\\0';\n\n   cue = cue_contents;\n   while (*cue)\n   {\n      cdfs_skip_spaces((const char**)&cue);\n      line = cue;\n\n      while (*cue && *cue != '\\n')\n         ++cue;\n      if (*cue)\n         *cue++ = '\\0';\n\n      if (!strncasecmp(line, \"FILE\", 4))\n      {\n         const char *file = line + 4;\n         cdfs_skip_spaces(&file);\n\n         if (file[0])\n         {\n            const char *file_end = cue - 1;\n            while (file_end > file && *file_end != ' ' && *file_end != '\\t')\n               --file_end;\n\n            if (     file[0]      == '\"'\n                  && file_end[-1] == '\"')\n            {\n               ++file;\n               --file_end;\n            }\n\n            if (file_end - file < PATH_MAX_LENGTH)\n            {\n               memcpy(current_track_path, file, file_end - file);\n               current_track_path[file_end - file] = '\\0';\n            }\n            else\n            {\n               memcpy(current_track_path, file, PATH_MAX_LENGTH - 1);\n               current_track_path[PATH_MAX_LENGTH - 1] = '\\0';\n            }\n         }\n\n         previous_sector_size = 0;\n         previous_index_sector_offset = 0;\n         track_offset = 0;\n      }\n      else if (!strncasecmp(line, \"TRACK\", 5))\n      {\n         char *ptr             = NULL;\n         unsigned track_number = 0;\n         const char *track     = line + 5;\n         cdfs_skip_spaces(&track);\n\n         track_number = (unsigned)strtol(track, &ptr, 10);\n         while (*track && *track != ' ' && *track != '\\n')\n            ++track;\n\n         previous_sector_size = sector_size;\n\n         cdfs_skip_spaces(&track);\n\n         if (!strncasecmp(track, \"MODE\", 4))\n         {\n            /* track_index = 0 means find the first data track */\n            if (!track_index || track_index == track_number)\n               found_track = track_number;\n\n            sector_size = atoi(track + 6);\n         }\n         else /* assume AUDIO */\n            sector_size = 2352;\n      }\n      else if (!strncasecmp(line, \"INDEX\", 5))\n      {\n         unsigned sector_offset;\n         unsigned min = 0, sec = 0, frame = 0;\n         unsigned index_number = 0;\n         const char *index     = line + 5;\n\n         cdfs_skip_spaces(&index);\n         index_number = (unsigned)strtol(index, NULL, 10);\n         while (*index && *index != ' ' && *index != '\\n')\n            ++index;\n         cdfs_skip_spaces(&index);\n\n         {\n            char *end;\n            min   = (unsigned)strtol(index, &end, 10);\n            if (*end == ':')\n               ++end;\n            sec   = (unsigned)strtol(end, &end, 10);\n            if (*end == ':')\n               ++end;\n            frame = (unsigned)strtol(end, NULL, 10);\n         }\n         sector_offset                 = ((min * 60) + sec) * 75 + frame;\n         sector_offset                -= previous_index_sector_offset;\n         track_offset                 += sector_offset * previous_sector_size;\n         previous_sector_size          = sector_size;\n         previous_index_sector_offset += sector_offset;\n\n         if (found_track && index_number == 1)\n         {\n            if (     strchr(current_track_path, '/')\n                  || strchr(current_track_path, '\\\\'))\n               strlcpy(track_path, current_track_path, sizeof(track_path));\n            else\n            {\n               fill_pathname_basedir(track_path, path, sizeof(track_path));\n               strlcat(track_path, current_track_path, sizeof(track_path));\n            }\n\n            break;\n         }\n      }\n   }\n\n   free(cue_contents);\n\n   if (!*track_path)\n      return NULL;\n\n   /* NOTE: previous_index_sector_offset will only be valid if all tracks are in the same BIN file.\n    * Otherwise, we need to determine how many tracks are in each previous BIN file, which is not\n    * stored in the CUE file. This will affect cdfs_get_first_sector, which luckily isn't used much. */\n   track = cdfs_wrap_stream(intfstream_open_file(\n            track_path, RETRO_VFS_FILE_ACCESS_READ,\n            RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset, previous_index_sector_offset);\n\n   if (track && track->stream_sector_size == 0)\n   {\n      track->stream_sector_size = sector_size;\n\n      if (sector_size == 2352)\n         track->stream_sector_header_size = 16;\n      else if (sector_size == 2336)\n         track->stream_sector_header_size = 8;\n   }\n\n   return track;\n}\n\n#ifdef HAVE_CHD\nstatic cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index)\n{\n   cdfs_track_t *track;\n   intfstream_t *intf_stream = intfstream_open_chd_track(path,\n         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE,\n         track_index);\n   if (!intf_stream)\n      return NULL;\n\n   track = cdfs_wrap_stream(intf_stream,\n         intfstream_get_offset_to_start(intf_stream),\n         intfstream_get_first_sector(intf_stream));\n\n   if (track && track->stream_sector_header_size == 0)\n   {\n      track->stream_sector_size = intfstream_get_frame_size(intf_stream);\n\n      if (track->stream_sector_size == 2352)\n         track->stream_sector_header_size = 16;\n      else if (track->stream_sector_size == 2336)\n         track->stream_sector_header_size = 8;\n   }\n\n   return track;\n}\n#endif\n\nstruct cdfs_track_t* cdfs_open_track(const char* path,\n      unsigned int track_index)\n{\n   const char* ext = path_get_extension(path);\n\n   if (string_is_equal_noncase(ext, \"cue\"))\n      return cdfs_open_cue_track(path, track_index);\n\n#ifdef HAVE_CHD\n   if (string_is_equal_noncase(ext, \"chd\"))\n      return cdfs_open_chd_track(path, track_index);\n#endif\n\n   /* if opening track 1, try opening as a raw track */\n   if (track_index == 1)\n      return cdfs_open_raw_track(path);\n\n   /* unsupported file type */\n   return NULL;\n}\n\nstruct cdfs_track_t* cdfs_open_data_track(const char* path)\n{\n   const char* ext = path_get_extension(path);\n\n   if (string_is_equal_noncase(ext, \"cue\"))\n      return cdfs_open_cue_track(path, 0);\n\n#ifdef HAVE_CHD\n   if (string_is_equal_noncase(ext, \"chd\"))\n      return cdfs_open_chd_track(path, CHDSTREAM_TRACK_PRIMARY);\n#endif\n\n   /* unsupported file type - try opening as a raw track */\n   return cdfs_open_raw_track(path);\n}\n\ncdfs_track_t* cdfs_open_raw_track(const char* path)\n{\n   const char *ext     = path_get_extension(path);\n   cdfs_track_t *track = NULL;\n\n   if (     string_is_equal_noncase(ext, \"bin\")\n         || string_is_equal_noncase(ext, \"iso\"))\n   {\n      intfstream_t* file = intfstream_open_file(path,\n         RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n      track = cdfs_wrap_stream(file, 0, 0);\n      if (track && track->stream_sector_size == 0)\n      {\n         cdfs_determine_sector_size_from_file_size(track);\n         if (track->stream_sector_size == 0)\n         {\n            cdfs_close_track(track);\n            track = NULL;\n         }\n      }\n   }\n\n   return track;\n}\n\nvoid cdfs_close_track(cdfs_track_t* track)\n{\n   if (track)\n   {\n      if (track->stream)\n      {\n         intfstream_close(track->stream);\n         free(track->stream);\n      }\n\n      free(track);\n   }\n}\n"
  },
  {
    "path": "formats/image_texture.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (image_texture.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stddef.h>\n\n#include <boolean.h>\n#include <formats/image.h>\n#include <file/nbio.h>\n\nenum image_type_enum image_texture_get_type(const char *path)\n{\n   /* We are comparing against a fixed list of file\n    * extensions, the longest (jpeg) being 4 characters\n    * in length. We therefore only need to extract the first\n    * 5 characters from the extension of the input path\n    * to correctly validate a match */\n   size_t len;\n   const char *ext = NULL;\n   if (!path || *path == '\\0')\n      return IMAGE_TYPE_NONE;\n\n   ext = strrchr(path, '.');\n   if (!ext || (*(++ext) == '\\0'))\n      return IMAGE_TYPE_NONE;\n\n   len = strlen(ext);\n\n   /* All supported extensions are 3 or 4 characters */\n   if (len < 3 || len > 4)\n      return IMAGE_TYPE_NONE;\n\n   /* Compare with inline lowering — avoids copy + tolower pass */\n   switch (len)\n   {\n      case 3:\n#ifdef HAVE_RPNG\n         if ((ext[0] | 0x20) == 'p' &&\n             (ext[1] | 0x20) == 'n' &&\n             (ext[2] | 0x20) == 'g')\n            return IMAGE_TYPE_PNG;\n#endif\n#ifdef HAVE_RJPEG\n         if ((ext[0] | 0x20) == 'j' &&\n             (ext[1] | 0x20) == 'p' &&\n             (ext[2] | 0x20) == 'g')\n            return IMAGE_TYPE_JPEG;\n#endif\n#ifdef HAVE_RBMP\n         if ((ext[0] | 0x20) == 'b' &&\n             (ext[1] | 0x20) == 'm' &&\n             (ext[2] | 0x20) == 'p')\n            return IMAGE_TYPE_BMP;\n#endif\n#ifdef HAVE_RTGA\n         if ((ext[0] | 0x20) == 't' &&\n             (ext[1] | 0x20) == 'g' &&\n             (ext[2] | 0x20) == 'a')\n            return IMAGE_TYPE_TGA;\n#endif\n         break;\n\n      case 4:\n#ifdef HAVE_RJPEG\n         if ((ext[0] | 0x20) == 'j' &&\n             (ext[1] | 0x20) == 'p' &&\n             (ext[2] | 0x20) == 'e' &&\n             (ext[3] | 0x20) == 'g')\n            return IMAGE_TYPE_JPEG;\n#endif\n#ifdef HAVE_RWEBP\n         if ((ext[0] | 0x20) == 'w' &&\n             (ext[1] | 0x20) == 'e' &&\n             (ext[2] | 0x20) == 'b' &&\n             (ext[3] | 0x20) == 'p')\n            return IMAGE_TYPE_WEBP;\n#endif\n         break;\n   }\n\n   return IMAGE_TYPE_NONE;\n}\n\nstatic bool image_texture_load_internal(\n      enum image_type_enum type,\n      void *ptr,\n      size_t len,\n      struct texture_image *out_img)\n{\n   int ret;\n   void *img    = image_transfer_new(type);\n\n   if (!img)\n      return false;\n\n   image_transfer_set_buffer_ptr(img, type, (uint8_t*)ptr, len);\n\n   if (!image_transfer_start(img, type))\n   {\n      image_transfer_free(img, type);\n      return false;\n   }\n\n   while (image_transfer_iterate(img, type));\n\n   if (!image_transfer_is_valid(img, type))\n   {\n      image_transfer_free(img, type);\n      return false;\n   }\n\n   do\n   {\n      ret = image_transfer_process(img, type,\n            (uint32_t**)&out_img->pixels, len, &out_img->width,\n            &out_img->height, out_img->supports_rgba);\n   } while (ret == IMAGE_PROCESS_NEXT);\n\n   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)\n   {\n      image_transfer_free(img, type);\n      return false;\n   }\n\n   image_transfer_free(img, type);\n   return true;\n}\n\nvoid image_texture_free(struct texture_image *img)\n{\n   if (!img)\n      return;\n\n   if (img->pixels)\n      free(img->pixels);\n   img->width  = 0;\n   img->height = 0;\n   img->pixels = NULL;\n}\n\nbool image_texture_load_buffer(struct texture_image *out_img,\n   enum image_type_enum type, void *buffer, size_t buffer_len)\n{\n   if (type != IMAGE_TYPE_NONE)\n   {\n      if (image_texture_load_internal(\n         type, buffer, buffer_len, out_img))\n         return true;\n   }\n\n   out_img->supports_rgba = false;\n   out_img->pixels = NULL;\n   out_img->width = 0;\n   out_img->height = 0;\n\n   return false;\n}\n\nbool image_texture_load(struct texture_image *out_img,\n      const char *path)\n{\n   enum image_type_enum type  = image_texture_get_type(path);\n\n   if (type != IMAGE_TYPE_NONE)\n   {\n      struct nbio_t *handle = (struct nbio_t*)\n         nbio_open(path, NBIO_READ);\n      if (handle)\n      {\n         void *ptr       = NULL;\n         size_t file_len = 0;\n\n         /* Fast path: collapses begin_read + iterate-loop + get_ptr\n          * into a single call. For mmap this is zero-copy (instant),\n          * for AIO a single blocking syscall, for stdio one fread. */\n         if ((ptr = nbio_load_entire(handle, &file_len)))\n         {\n            if (image_texture_load_internal(\n                     type,\n                     ptr, file_len, out_img))\n            {\n               nbio_free(handle);\n               return true;\n            }\n         }\n         nbio_free(handle);\n      }\n   }\n\n   out_img->supports_rgba = false;\n   out_img->pixels        = NULL;\n   out_img->width         = 0;\n   out_img->height        = 0;\n\n   return false;\n}\n"
  },
  {
    "path": "formats/image_transfer.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (image_transfer.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include <boolean.h>\n\n#ifdef HAVE_RPNG\n#include <formats/rpng.h>\n#endif\n#ifdef HAVE_RJPEG\n#include <formats/rjpeg.h>\n#endif\n#ifdef HAVE_RTGA\n#include <formats/rtga.h>\n#endif\n#ifdef HAVE_RBMP\n#include <formats/rbmp.h>\n#endif\n#ifdef HAVE_RWEBP\n#include <formats/rwebp.h>\n#endif\n\n#include <formats/image.h>\n\nvoid image_transfer_free(void *data, enum image_type_enum type)\n{\n   switch (type)\n   {\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         rtga_free((rtga_t*)data);\n#endif\n         break;\n      case IMAGE_TYPE_PNG:\n         {\n#ifdef HAVE_RPNG\n            rpng_t *rpng = (rpng_t*)data;\n            if (rpng)\n               rpng_free(rpng);\n#endif\n         }\n         break;\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         rjpeg_free((rjpeg_t*)data);\n#endif\n         break;\n      case IMAGE_TYPE_BMP:\n#ifdef HAVE_RBMP\n         rbmp_free((rbmp_t*)data);\n#endif\n         break;\n      case IMAGE_TYPE_WEBP:\n#ifdef HAVE_RWEBP\n         rwebp_free((rwebp_t*)data);\n#endif\n         break;\n      case IMAGE_TYPE_NONE:\n         break;\n   }\n}\n\nvoid *image_transfer_new(enum image_type_enum type)\n{\n   switch (type)\n   {\n      case IMAGE_TYPE_PNG:\n#ifdef HAVE_RPNG\n         return rpng_alloc();\n#else\n         break;\n#endif\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         return rjpeg_alloc();\n#else\n         break;\n#endif\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         return rtga_alloc();\n#else\n         break;\n#endif\n      case IMAGE_TYPE_BMP:\n#ifdef HAVE_RBMP\n         return rbmp_alloc();\n#else\n         break;\n#endif\n      case IMAGE_TYPE_WEBP:\n#ifdef HAVE_RWEBP\n         return rwebp_alloc();\n#else\n         break;\n#endif\n      default:\n         break;\n   }\n\n   return NULL;\n}\n\nbool image_transfer_start(void *data, enum image_type_enum type)\n{\n\n   switch (type)\n   {\n      case IMAGE_TYPE_PNG:\n#ifdef HAVE_RPNG\n         if (!rpng_start((rpng_t*)data))\n            break;\n         return true;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         if (!rjpeg_start((rjpeg_t*)data))\n            break;\n         return true;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         return true;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_BMP:\n         return true;\n      case IMAGE_TYPE_WEBP:\n         return true;\n      case IMAGE_TYPE_NONE:\n         break;\n   }\n\n   return false;\n}\n\nbool image_transfer_is_valid(\n      void *data,\n      enum image_type_enum type)\n{\n   switch (type)\n   {\n      case IMAGE_TYPE_PNG:\n#ifdef HAVE_RPNG\n         return rpng_is_valid((rpng_t*)data);\n#else\n         break;\n#endif\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         return rjpeg_is_valid((rjpeg_t*)data);\n#else\n         break;\n#endif\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         return true;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_BMP:\n         return true;\n      case IMAGE_TYPE_WEBP:\n         return true;\n      case IMAGE_TYPE_NONE:\n         break;\n   }\n\n   return false;\n}\n\nvoid image_transfer_set_buffer_ptr(\n      void *data,\n      enum image_type_enum type,\n      void *ptr,\n      size_t len)\n{\n   switch (type)\n   {\n      case IMAGE_TYPE_PNG:\n#ifdef HAVE_RPNG\n         rpng_set_buf_ptr((rpng_t*)data, (uint8_t*)ptr, len);\n#endif\n         break;\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         rjpeg_set_buf_ptr((rjpeg_t*)data, (uint8_t*)ptr, len);\n#endif\n         break;\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         rtga_set_buf_ptr((rtga_t*)data, (uint8_t*)ptr);\n#endif\n         break;\n      case IMAGE_TYPE_BMP:\n#ifdef HAVE_RBMP\n         rbmp_set_buf_ptr((rbmp_t*)data, (uint8_t*)ptr);\n#endif\n         break;\n      case IMAGE_TYPE_WEBP:\n#ifdef HAVE_RWEBP\n         rwebp_set_buf_ptr((rwebp_t*)data, (uint8_t*)ptr, len);\n#endif\n         break;\n      case IMAGE_TYPE_NONE:\n         break;\n   }\n}\n\nint image_transfer_process(\n      void *data,\n      enum image_type_enum type,\n      uint32_t **buf, size_t len,\n      unsigned *width, unsigned *height,\n      bool supports_rgba)\n{\n   int ret = 0;\n\n   switch (type)\n   {\n      case IMAGE_TYPE_PNG:\n#ifdef HAVE_RPNG\n         ret = rpng_process_image(\n               (rpng_t*)data,\n               (void**)buf, len, width, height, supports_rgba);\n         break;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         ret = rjpeg_process_image((rjpeg_t*)data,\n               (void**)buf, len, width, height, supports_rgba);\n         break;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         ret = rtga_process_image((rtga_t*)data,\n               (void**)buf, len, width, height, supports_rgba);\n         break;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_BMP:\n#ifdef HAVE_RBMP\n         ret = rbmp_process_image((rbmp_t*)data,\n               (void**)buf, len, width, height, supports_rgba);\n         break;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_WEBP:\n#ifdef HAVE_RWEBP\n         ret = rwebp_process_image((rwebp_t*)data,\n               (void**)buf, len, width, height, supports_rgba);\n         break;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_NONE:\n         break;\n   }\n\n#ifdef GEKKO\n   /* Convert from linear ARGB to the Wii's tiled texture format.\n    * Applied once when decoding finishes (IMAGE_PROCESS_END),\n    * not during intermediate iterations. */\n   if (ret == IMAGE_PROCESS_END && *buf && *width && *height)\n   {\n      unsigned tmp_pitch, width2, i;\n      const uint16_t *src = NULL;\n      uint16_t *dst       = NULL;\n      /* (size_t) casts on width and height: pre-patch the uint32\n       * multiplication width * height * 4 wrapped on 32-bit Wii\n       * (Gekko is a 32-bit PowerPC) for any image with\n       * width*height > 2^30, the malloc returned an undersized\n       * buffer, and the memcpy below ran off the end.  This file\n       * is reached only after rpng/rjpeg has already accepted the\n       * image; on 32-bit (which is where this matters) those\n       * decoders cap dimensions at 0x4000 which closes the\n       * primitive at the source.  The casts here keep the\n       * arithmetic safe regardless of upstream caps and on any\n       * platform where image_transfer.c is compiled, including\n       * future 64-bit Wii-class targets. */\n      void *tmp           = malloc(\n            (size_t)(*width) * (size_t)(*height) * sizeof(uint32_t));\n\n      if (!tmp)\n         return IMAGE_PROCESS_ERROR;\n\n      memcpy(tmp, *buf,\n            (size_t)(*width) * (size_t)(*height) * sizeof(uint32_t));\n      tmp_pitch = ((*width) * sizeof(uint32_t)) >> 1;\n\n      *width  &= ~3;\n      *height &= ~3;\n      width2   = (*width) << 1;\n      src      = (const uint16_t*)tmp;\n      dst      = (uint16_t*)*buf;\n\n      for (i = 0; i < *height; i += 4, dst += 4 * width2)\n      {\n#define GX_BLIT_LINE_32(off) \\\n         { \\\n            unsigned x; \\\n            const uint16_t *tmp_src = src; \\\n            uint16_t       *tmp_dst = dst; \\\n            for (x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \\\n            { \\\n               tmp_dst[  0 + off] = tmp_src[0]; \\\n               tmp_dst[ 16 + off] = tmp_src[1]; \\\n               tmp_dst[  1 + off] = tmp_src[2]; \\\n               tmp_dst[ 17 + off] = tmp_src[3]; \\\n               tmp_dst[  2 + off] = tmp_src[4]; \\\n               tmp_dst[ 18 + off] = tmp_src[5]; \\\n               tmp_dst[  3 + off] = tmp_src[6]; \\\n               tmp_dst[ 19 + off] = tmp_src[7]; \\\n            } \\\n            src += tmp_pitch; \\\n         }\n         GX_BLIT_LINE_32(0)\n         GX_BLIT_LINE_32(4)\n         GX_BLIT_LINE_32(8)\n         GX_BLIT_LINE_32(12)\n#undef GX_BLIT_LINE_32\n      }\n\n      free(tmp);\n   }\n#endif\n\n   return ret;\n}\n\nbool image_transfer_iterate(void *data, enum image_type_enum type)\n{\n\n   switch (type)\n   {\n      case IMAGE_TYPE_PNG:\n#ifdef HAVE_RPNG\n         if (!rpng_iterate_image((rpng_t*)data))\n            return false;\n#endif\n         break;\n      case IMAGE_TYPE_JPEG:\n#ifdef HAVE_RJPEG\n         if (!rjpeg_iterate_image((rjpeg_t*)data))\n            return false;\n#endif\n         break;\n      case IMAGE_TYPE_TGA:\n#ifdef HAVE_RTGA\n         return false;\n#else\n         break;\n#endif\n      case IMAGE_TYPE_BMP:\n         return false;\n      case IMAGE_TYPE_WEBP:\n         return false;\n      case IMAGE_TYPE_NONE:\n         return false;\n   }\n\n   return true;\n}\n"
  },
  {
    "path": "formats/jpeg/rjpeg.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rjpeg.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Modified version of stb_image's JPEG sources. */\n\n#include <stdint.h>\n#include <stdarg.h>\n#include <stddef.h> /* ptrdiff_t on osx */\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_inline.h>\n#include <boolean.h>\n#include <formats/image.h>\n#include <formats/rjpeg.h>\n#include <features/features_cpu.h>\n\nenum\n{\n   RJPEG_DEFAULT = 0, /* only used for req_comp */\n   RJPEG_GREY,\n   RJPEG_GREY_ALPHA,\n   RJPEG_RGB,\n   RJPEG_RGB_ALPHA\n};\n\nenum\n{\n   RJPEG_SCAN_LOAD = 0,\n   RJPEG_SCAN_TYPE,\n   RJPEG_SCAN_HEADER\n};\n\ntypedef uint8_t *(*rjpeg_resample_row_func)(uint8_t *out, uint8_t *in0, uint8_t *in1,\n                                    int w, int hs);\n\ntypedef struct\n{\n   rjpeg_resample_row_func resample;\n   uint8_t *line0;\n   uint8_t *line1;\n   int hs,vs;   /* expansion factor in each axis */\n   int w_lores; /* horizontal pixels pre-expansion */\n   int ystep;   /* how far through vertical expansion we are */\n   int ypos;    /* which pre-expansion row we're on */\n} rjpeg_resample;\n\nenum rjpeg_phase\n{\n   RJPEG_PHASE_DECODE = 0,\n   RJPEG_PHASE_RESAMPLE\n};\n\n/* Iterative decode states -- mirrors how rpng walks chunks.\n * The entropy decode (the hot path) is broken into MCU-row\n * batches so the caller can yield between rows. */\nenum rjpeg_iter_state\n{\n   RJPEG_ITER_PARSE_HEADER = 0,  /* SOI + markers before first SOS       */\n   RJPEG_ITER_ENTROPY_ROWS,      /* MCU-row-at-a-time entropy decode      */\n   RJPEG_ITER_PROG_SCAN,         /* progressive: one scan per iteration   */\n   RJPEG_ITER_FINISH_PROG,       /* progressive: dequant+IDCT after scans */\n   RJPEG_ITER_DONE,              /* all decoding finished                 */\n   RJPEG_ITER_ERROR               /* unrecoverable error                   */\n};\n\n/* Forward declaration -- full definition appears later in the file */\nstruct rjpeg_jpeg_s;\n\nstruct rjpeg_process\n{\n   struct rjpeg_jpeg_s  *j;            /* heap-allocated decode state           */\n   uint8_t          *output;       /* output pixel buffer (n * w * h)       */\n   rjpeg_resample    res_comp[4];  /* per-component resample state          */\n   uint8_t          *coutput[4];   /* per-component line pointers           */\n   unsigned          cur_row;      /* current output row during resample    */\n   int               n;            /* output components (always 4)          */\n   int               decode_n;     /* components to actually decode         */\n   enum rjpeg_phase  phase;\n};\n\nstruct rjpeg\n{\n   struct rjpeg_process   *process;\n   uint8_t                *buff_data;\n   size_t                  buff_len;       /* set by set_buf_ptr caller (image_transfer) */\n\n   /* Iterative decode state --\n    * NULL until rjpeg_start() allocates it. */\n   struct rjpeg_jpeg_s    *iter_j;\n   enum rjpeg_iter_state   iter_state;\n   int                     iter_mcu_row;   /* current MCU row during entropy  */\n   int                     iter_marker;    /* pending marker between scans    */\n   bool                    iter_started;   /* rjpeg_start() was called        */\n\n   /* Progressive finish-phase tracking (RJPEG_ITER_FINISH_PROG) */\n   int                     iter_finish_comp;  /* current component index       */\n   int                     iter_finish_row;   /* current block-row within comp */\n\n   /* Fused iterate+resample state: when iterating baseline interleaved,\n    * the resample for MCU-row N runs after MCU-row N+1's entropy decode.\n    * This overlaps the two phases and avoids the serial\n    * entropy→done→resample pipeline. */\n   rjpeg_resample          iter_res[4];       /* per-component resample state  */\n   uint8_t                *iter_output;       /* RGBA8888 output buffer        */\n   unsigned                iter_out_row;      /* next output row to resample   */\n   int                     iter_resample_ready; /* 1 = resample state inited   */\n\n   /* Output byte order selector. Latched from the rjpeg_process_image\n    * parameter and consulted by the resample+colorconvert callsites.\n    * false -> BGRA (ARGB32 on LE); true -> RGBA (ABGR32 on LE). */\n   bool                    supports_rgba;\n};\n\n#ifdef _MSC_VER\n#define RJPEG_HAS_LROTL\n#endif\n\n#ifdef RJPEG_HAS_LROTL\n   #define RJPEG_LROT(x,y)  _lrotl(x,y)\n#else\n   #define RJPEG_LROT(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))\n#endif\n\n/* x86/x64 detection */\n#if defined(__x86_64__) || defined(_M_X64)\n#define RJPEG_X64_TARGET\n#elif defined(__i386) || defined(_M_IX86)\n#define RJPEG_X86_TARGET\n#endif\n\n#if defined(__GNUC__) && (defined(RJPEG_X86_TARGET) || defined(RJPEG_X64_TARGET)) && !defined(__SSE2__) && !defined(RJPEG_NO_SIMD)\n/* NOTE: not clear do we actually need this for the 64-bit path?\n * gcc doesn't support sse2 intrinsics unless you compile with -msse2,\n * (but compiling with -msse2 allows the compiler to use SSE2 everywhere;\n * this is just broken and gcc are jerks for not fixing it properly\n * http://www.virtualdub.org/blog/pivot/entry.php?id=363 )\n */\n#define RJPEG_NO_SIMD\n#endif\n\n#if defined(__MINGW32__) && defined(RJPEG_X86_TARGET) && !defined(RJPEG_MINGW_ENABLE_SSE2) && !defined(RJPEG_NO_SIMD)\n/* Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid RJPEG_X64_TARGET\n *\n * 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the\n * Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.\n * As a result, enabling SSE2 on 32-bit MinGW is dangerous when not\n * simultaneously enabling \"-mstackrealign\".\n *\n * See https://github.com/nothings/stb/issues/81 for more information.\n *\n * So default to no SSE2 on 32-bit MinGW. If you've read this far and added\n * -mstackrealign to your build settings, feel free to #define RJPEG_MINGW_ENABLE_SSE2.\n */\n#define RJPEG_NO_SIMD\n#endif\n\n#if defined(__SSE2__)\n#include <emmintrin.h>\n\n#ifdef _MSC_VER\n#define RJPEG_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n#else\n#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n\n#endif\n\n/* Auto-detect NEON support */\n#if !defined(RJPEG_NO_SIMD) && !defined(RJPEG_NEON) \\\n   && (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(HAVE_NEON))\n#define RJPEG_NEON\n#endif\n\n/* ARM NEON */\n#if defined(RJPEG_NO_SIMD) && defined(RJPEG_NEON)\n#undef RJPEG_NEON\n#endif\n\n#ifdef RJPEG_NEON\n#include <arm_neon.h>\n/* assume GCC or Clang on ARM targets */\n#define RJPEG_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n\n#ifndef RJPEG_SIMD_ALIGN\n#define RJPEG_SIMD_ALIGN(type, name) type name\n#endif\n\n/* rjpeg_context has been folded into rjpeg_jpeg (struct rjpeg_jpeg_s).\n * The I/O primitives below take rjpeg_jpeg* directly. */\ntypedef struct rjpeg_jpeg_s rjpeg_jpeg;\n\n\n/* I/O primitives moved after struct definition — see below */\n\n\n/* huffman decoding acceleration */\n#define FAST_BITS   9  /* larger handles more cases; smaller stomps less cache */\n\ntypedef struct\n{\n   unsigned int maxcode[18];\n   int    delta[17];   /* old 'firstsymbol' - old 'firstcode' */\n   /* weirdly, repacking this into AoS is a 10% speed loss, instead of a win */\n   uint16_t code[256];\n   uint8_t  fast[1 << FAST_BITS];\n   uint8_t  values[256];\n   uint8_t  size[257];\n} rjpeg_huffman;\n\nstruct rjpeg_jpeg_s\n{\n   /* Embedded context (was separately allocated rjpeg_jpeg).\n    * Eliminating the j-> double indirection saves ~50K pointer\n    * chases per 1080p frame in the hot entropy decode path. */\n   uint8_t *img_buffer;\n   uint8_t *img_buffer_original;\n   uint8_t *img_buffer_end;\n   int      img_n;\n   int      img_out_n;\n   uint32_t img_x;\n   uint32_t img_y;\n   uint8_t  buffer_start[128];\n\n   /* kernels */\n   void (*idct_block_kernel)(uint8_t *out, int out_stride, short data[64]);\n   void (*dequant_idct_block_kernel)(uint8_t *out, int out_stride,\n         short data[64], uint8_t *dequant);\n   void (*YCbCr_to_RGB_kernel)(uint8_t *out, const uint8_t *y, const uint8_t *pcb,\n         const uint8_t *pcr, int count, int step, bool supports_rgba);\n   uint8_t *(*resample_row_hv_2_kernel)(uint8_t *out, uint8_t *in_near,\n         uint8_t *in_far, int w, int hs);\n   /* Fused chroma upsample (hv_2) + YCbCr->RGBA8888.\n    * Eliminates the linebuf write+read round-trip by keeping upsampled\n    * chroma in SIMD registers and feeding directly to color math.\n    * Output byte order (BGRA vs RGBA) is selected by supports_rgba.\n    * NULL = not available; use separate resample + colorconvert. */\n   void (*upsample_YCbCr_to_BGRA_kernel)(uint8_t *out, const uint8_t *y_row,\n         uint8_t *cb_near, uint8_t *cb_far,\n         uint8_t *cr_near, uint8_t *cr_far,\n         int chroma_w, int out_w, bool supports_rgba);\n\n   /* definition of jpeg image component */\n   struct\n   {\n      uint8_t *data;\n      void *raw_data, *raw_coeff;\n      uint8_t *linebuf;\n      short   *coeff;            /* progressive only */\n      int id;\n      int h,v;\n      int tq;\n      int hd,ha;\n      int dc_pred;\n\n      int x,y,w2,h2;\n      int      coeff_w;          /* number of 8x8 coefficient blocks */\n      int      coeff_h;          /* number of 8x8 coefficient blocks */\n   } img_comp[4];\n\n   /* Single arena allocation for all component buffers.\n    * When non-NULL, raw_data/raw_coeff/linebuf point into this\n    * arena and must NOT be individually freed. */\n   void  *comp_arena;\n   size_t comp_arena_size;\n\n   /* sizes for components, interleaved MCUs */\n   int img_h_max, img_v_max;\n   int img_mcu_x, img_mcu_y;\n   int img_mcu_w, img_mcu_h;\n\n   int            code_bits;     /* number of valid bits */\n   int            nomore;        /* flag if we saw a marker so must stop */\n   int            progressive;\n   int            spec_start;\n   int            spec_end;\n   int            succ_high;\n   int            succ_low;\n   int            eob_run;\n   int scan_n, order[4];\n   int restart_interval, todo;\n   uint32_t       code_buffer;   /* jpeg entropy-coded buffer */\n   rjpeg_huffman huff_dc[4];     /* unsigned int alignment */\n   rjpeg_huffman huff_ac[4];     /* unsigned int alignment */\n   int16_t fast_ac[4][1 << FAST_BITS];\n   unsigned char  marker;        /* marker seen while filling entropy buffer */\n   uint8_t dequant[4][64];\n};\n\nstatic INLINE uint8_t rjpeg_get8(rjpeg_jpeg *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n\n   return 0;\n}\n\n#define RJPEG_AT_EOF(s)     ((s)->img_buffer >= (s)->img_buffer_end)\n\n/* Fast 16-bit big-endian read: single bounds check for 2 bytes.\n * The old RJPEG_GET16BE called rjpeg_get8 twice (2 bounds checks).\n * At EOF, returns partial or zero like the original. */\nstatic INLINE uint32_t rjpeg_get16be(rjpeg_jpeg *s)\n{\n   uint32_t hi;\n   if (s->img_buffer + 1 < s->img_buffer_end)\n   {\n      hi = s->img_buffer[0];\n      s->img_buffer += 2;\n      return (hi << 8) | s->img_buffer[-1];\n   }\n   /* Fallback for last byte or empty */\n   hi = rjpeg_get8(s);\n   return (hi << 8) | rjpeg_get8(s);\n}\n\n#define RJPEG_GET16BE(s)    rjpeg_get16be((s))\n\n/* Unchecked byte read: caller guarantees img_buffer < img_buffer_end.\n * Used in bulk parsing loops after a segment-length bounds check. */\nstatic INLINE uint8_t rjpeg_get8_fast(rjpeg_jpeg *s)\n{\n   return *s->img_buffer++;\n}\n\n/* Skip n bytes, clamping to end of buffer */\nstatic INLINE void rjpeg_skip(rjpeg_jpeg *s, int n)\n{\n   if (s->img_buffer + n > s->img_buffer_end)\n      s->img_buffer = s->img_buffer_end;\n   else\n      s->img_buffer += n;\n}\n\n#define RJPEG_F2F(x)  ((int) (((x) * 4096 + 0.5)))\n#define RJPEG_FSH(x)  ((x) << 12)\n\n#define RJPEG_MARKER_NONE  0xff\n/* if there's a pending marker from the entropy stream, return that\n * otherwise, fetch from the stream and get a marker. if there's no\n * marker, return 0xff, which is never a valid marker value\n */\n\n/* in each scan, we'll have scan_n components, and the order\n * of the components is specified by order[]\n */\n#define RJPEG_RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)\n\n#define JPEG_MARKER           0xFF\n#define JPEG_MARKER_SOI       0xD8\n#define JPEG_MARKER_SOS       0xDA\n#define JPEG_MARKER_EOI       0xD9\n#define JPEG_MARKER_APP1      0xE1\n#define JPEG_MARKER_APP2      0xE2\n\n/* use comparisons since in some cases we handle more than one case (e.g. SOF) */\n#define RJPEG_SOF(x)               ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)\n\n#define RJPEG_SOF_PROGRESSIVE(x)   ((x) == 0xc2)\n#define RJPEG_DIV4(x)              ((uint8_t) ((x) >> 2))\n#define RJPEG_DIV16(x)             ((uint8_t) ((x) >> 4))\n\nstatic int rjpeg_build_huffman(rjpeg_huffman *h, int *count)\n{\n   int i,j,k = 0,code;\n\n   /* build size list for each symbol (from JPEG spec) */\n   for (i = 0; i < 16; ++i)\n      for (j = 0; j < count[i]; ++j)\n         h->size[k++] = (uint8_t) (i+1);\n\n   h->size[k] = 0;\n   /* compute actual symbols (from jpeg spec) */\n   code       = 0;\n   k          = 0;\n\n   for (j = 1; j <= 16; ++j)\n   {\n      /* compute delta to add to code to compute symbol id */\n      h->delta[j] = k - code;\n      if (h->size[k] == j)\n      {\n         while (h->size[k] == j)\n            h->code[k++] = (uint16_t) (code++);\n\n         /* Bad code lengths, corrupt JPEG? */\n         if (code-1 >= (1 << j))\n            return 0;\n      }\n      /* compute largest code + 1 for this size, preshifted as needed later */\n      h->maxcode[j] = code << (16-j);\n      code <<= 1;\n   }\n   h->maxcode[j] = 0xffffffff;\n\n   /* build non-spec acceleration table; 255 is flag for not-accelerated */\n   memset(h->fast, 255, 1 << FAST_BITS);\n   for (i = 0; i < k; ++i)\n   {\n      int s = h->size[i];\n      if (s <= FAST_BITS)\n      {\n         int c = h->code[i] << (FAST_BITS-s);\n         int m = 1 << (FAST_BITS-s);\n         for (j = 0; j < m; ++j)\n            h->fast[c+j] = (uint8_t) i;\n      }\n   }\n   return 1;\n}\n\n/* build a table that decodes both magnitude and value of small ACs in\n * one go. */\nstatic void rjpeg_build_fast_ac(int16_t *fast_ac, rjpeg_huffman *h)\n{\n   int i;\n\n   for (i = 0; i < (1 << FAST_BITS); ++i)\n   {\n      uint8_t fast = h->fast[i];\n\n      fast_ac[i] = 0;\n\n      if (fast < 255)\n      {\n         int rs      = h->values[fast];\n         int run     = (rs >> 4) & 15;\n         int magbits = rs & 15;\n         int len     = h->size[fast];\n\n         if (magbits && len + magbits <= FAST_BITS)\n         {\n            /* magnitude code followed by receive_extend code */\n            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);\n            int m = 1 << (magbits - 1);\n            if (k < m)\n               k += (~0U << magbits) + 1;\n\n            /* if the result is small enough, we can fit it in fast_ac table */\n            if (k >= -128 && k <= 127)\n               fast_ac[i] = (int16_t) ((k << 8) + (run << 4) + (len + magbits));\n         }\n      }\n   }\n}\n\n/* -----------------------------------------------------------------------\n * Bulk bitstream fill\n *\n * The original grow_buffer_unsafe reads one byte at a time via\n * rjpeg_get8(), branching on 0xFF for each byte.  Since this function\n * is called on every Huffman symbol (up to 63× per 8×8 block), the\n * per-byte overhead dominates small-block decode time.\n *\n * This replacement reads up to 4 bytes in a single memory access when\n * it's safe (≥4 bytes remaining in the buffer), scans the loaded word\n * for 0xFF marker prefixes, and inserts all clean bytes at once.  The\n * 0xFF00 \"byte-stuff\" escape is handled inline.\n *\n * When fewer than 4 bytes remain or a marker is encountered, we fall\n * back to the safe byte-at-a-time path.\n *\n * Invariant: on entry, code_bits ≤ 24 (room for at least 1 byte).\n *            on exit,  code_bits > 24  OR nomore == 1.\n * ----------------------------------------------------------------------- */\n\nstatic void rjpeg_grow_buffer_unsafe(rjpeg_jpeg *j)\n{\n   rjpeg_jpeg *s = j;\n\n   if (j->nomore)\n   {\n      /* Already hit a marker — pad with zeros */\n      while (j->code_bits <= 24)\n         j->code_bits += 8;\n      return;\n   }\n\n   /* Fast path: bulk-read when ≥4 bytes remain in the buffer.\n    * This avoids per-byte function call overhead and lets us\n    * scan for 0xFF with simple comparisons on loaded bytes. */\n   while (j->code_bits <= 24)\n   {\n      ptrdiff_t remaining = s->img_buffer_end - s->img_buffer;\n\n      if (remaining >= 4)\n      {\n         /* Load 4 bytes.  We scan for 0xFF from left to right,\n          * consuming clean bytes and stopping at the first marker\n          * prefix.  Most JPEG data has no 0xFF bytes in the entropy\n          * stream (they're escaped as 0xFF00), so the common case\n          * consumes all 4 bytes with no marker. */\n         uint8_t b0 = s->img_buffer[0];\n         uint8_t b1 = s->img_buffer[1];\n         uint8_t b2 = s->img_buffer[2];\n         uint8_t b3 = s->img_buffer[3];\n\n         /* Check each byte for 0xFF.  The compiler will branch-predict\n          * these as not-taken since 0xFF is rare in entropy data. */\n         if (b0 == 0xFF)\n            goto handle_ff_at_0;\n         j->code_buffer |= (uint32_t)b0 << (24 - j->code_bits);\n         j->code_bits   += 8;\n         if (j->code_bits > 24)\n         {\n            s->img_buffer += 1;\n            return;\n         }\n\n         if (b1 == 0xFF)\n            goto handle_ff_at_1;\n         j->code_buffer |= (uint32_t)b1 << (24 - j->code_bits);\n         j->code_bits   += 8;\n         if (j->code_bits > 24)\n         {\n            s->img_buffer += 2;\n            return;\n         }\n\n         if (b2 == 0xFF)\n            goto handle_ff_at_2;\n         j->code_buffer |= (uint32_t)b2 << (24 - j->code_bits);\n         j->code_bits   += 8;\n         if (j->code_bits > 24)\n         {\n            s->img_buffer += 3;\n            return;\n         }\n\n         if (b3 == 0xFF)\n            goto handle_ff_at_3;\n         j->code_buffer |= (uint32_t)b3 << (24 - j->code_bits);\n         j->code_bits   += 8;\n         s->img_buffer  += 4;\n\n         return;\n\n         /* 0xFF handling: consume the bytes before the 0xFF, then\n          * check the byte after 0xFF.  If it's 0x00, that's a\n          * byte-stuffed 0xFF data byte.  If non-zero, it's a real\n          * marker — set j->marker and stop. */\nhandle_ff_at_0:\n         s->img_buffer += 1;\n         goto handle_ff;\nhandle_ff_at_1:\n         s->img_buffer += 2;\n         goto handle_ff;\nhandle_ff_at_2:\n         s->img_buffer += 3;\n         goto handle_ff;\nhandle_ff_at_3:\n         s->img_buffer += 4;\n         /* fall through */\nhandle_ff:\n         {\n            /* s->img_buffer now points past the 0xFF byte.\n             * Read the byte after the 0xFF. */\n            if (s->img_buffer < s->img_buffer_end)\n            {\n               uint8_t c = *s->img_buffer++;\n               if (c != 0)\n               {\n                  /* Real marker found */\n                  j->marker = c;\n                  j->nomore = 1;\n                  /* Pad remaining bits with zeros */\n                  while (j->code_bits <= 24)\n                     j->code_bits += 8;\n                  return;\n               }\n               /* Byte-stuff: 0xFF00 means literal 0xFF data byte */\n               j->code_buffer |= (uint32_t)0xFF << (24 - j->code_bits);\n               j->code_bits   += 8;\n               if (j->code_bits > 24)\n                  return;\n               /* Need more bytes — loop back to top */\n               continue;\n            }\n            else\n            {\n               /* EOF right after 0xFF — treat as end */\n               j->nomore = 1;\n               while (j->code_bits <= 24)\n                  j->code_bits += 8;\n               return;\n            }\n         }\n      }\n      else\n      {\n         /* Fewer than 4 bytes remain: byte-at-a-time fallback */\n         int b = rjpeg_get8(s);\n         if (b == 0xFF)\n         {\n            int c = rjpeg_get8(s);\n            if (c != 0)\n            {\n               j->marker = (unsigned char)c;\n               j->nomore = 1;\n               return;\n            }\n         }\n         j->code_buffer |= (uint32_t)b << (24 - j->code_bits);\n         j->code_bits   += 8;\n      }\n   }\n}\n\n/* (1 << n) - 1 */\nstatic uint32_t rjpeg_bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};\n\n/* decode a JPEG huffman value from the bitstream */\nstatic INLINE int rjpeg_jpeg_huff_decode(rjpeg_jpeg *j, rjpeg_huffman *h)\n{\n   unsigned int temp;\n   int c,k;\n\n   if (j->code_bits < 16)\n      rjpeg_grow_buffer_unsafe(j);\n\n   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   k = h->fast[c];\n\n   if (k < 255)\n   {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n\n   if (k == 17)\n   {\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   c = ((j->code_buffer >> (32 - k)) & rjpeg_bmask[k]) + h->delta[k];\n\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n/* _nocheck variant: caller guarantees code_bits >= 16.\n * Used from decode_block where grow_buffer was just called. */\nstatic INLINE int rjpeg_jpeg_huff_decode_nocheck(rjpeg_jpeg *j,\n      rjpeg_huffman *h)\n{\n   unsigned int temp;\n   int c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   int k = h->fast[c];\n\n   if (k < 255)\n   {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n\n   if (k == 17)\n   {\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   c = ((j->code_buffer >> (32 - k)) & rjpeg_bmask[k]) + h->delta[k];\n\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n/* bias[n] = (-1<<n) + 1 */\nstatic int const rjpeg_jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};\n\n/* combined JPEG 'receive' and JPEG 'extend', since baseline\n * always extends everything it receives. */\nstatic INLINE int rjpeg_extend_receive(rjpeg_jpeg *j, int n)\n{\n   unsigned int k;\n   int sgn;\n   if (j->code_bits < n)\n      rjpeg_grow_buffer_unsafe(j);\n\n   sgn             = (int32_t)j->code_buffer >> 31;\n   k               = RJPEG_LROT(j->code_buffer, n);\n   j->code_buffer  = k & ~rjpeg_bmask[n];\n   k              &= rjpeg_bmask[n];\n   j->code_bits   -= n;\n   return k + (rjpeg_jbias[n] & ~sgn);\n}\n\n/* get some unsigned bits */\nstatic INLINE int rjpeg_jpeg_get_bits(rjpeg_jpeg *j, int n)\n{\n   unsigned int k;\n   if (j->code_bits < n)\n      rjpeg_grow_buffer_unsafe(j);\n   k              = RJPEG_LROT(j->code_buffer, n);\n   j->code_buffer = k & ~rjpeg_bmask[n];\n   k             &= rjpeg_bmask[n];\n   j->code_bits  -= n;\n   return k;\n}\n\nstatic INLINE int rjpeg_jpeg_get_bit(rjpeg_jpeg *j)\n{\n   unsigned int k;\n   if (j->code_bits < 1)\n      rjpeg_grow_buffer_unsafe(j);\n\n   k                = j->code_buffer;\n   j->code_buffer <<= 1;\n   --j->code_bits;\n   return k & 0x80000000;\n}\n\n/* given a value that's at position X in the zigzag stream,\n * where does it appear in the 8x8 matrix coded as row-major? */\nstatic uint8_t rjpeg_jpeg_dezigzag[64+15] =\n{\n    0,  1,  8, 16,  9,  2,  3, 10,\n   17, 24, 32, 25, 18, 11,  4,  5,\n   12, 19, 26, 33, 40, 48, 41, 34,\n   27, 20, 13,  6,  7, 14, 21, 28,\n   35, 42, 49, 56, 57, 50, 43, 36,\n   29, 22, 15, 23, 30, 37, 44, 51,\n   58, 59, 52, 45, 38, 31, 39, 46,\n   53, 60, 61, 54, 47, 55, 62, 63,\n   /* let corrupt input sample past end */\n   63, 63, 63, 63, 63, 63, 63, 63,\n   63, 63, 63, 63, 63, 63, 63\n};\n\n/* decode one 64-entry block--\n *\n * Deferred zero-fill: the caller is responsible for ensuring data[0..63]\n * are zero on entry (done once at the start of the MCU row, then maintained\n * by zeroing only the positions written after each IDCT).  This avoids\n * a full memset(data,0,128) per block — saving ~1.3M zero-writes/frame\n * at 1080p since ~40% of blocks are DC-only and never touch positions 1-63.\n *\n * Returns the zigzag index k at which decoding stopped (1 for DC-only,\n * up to 64 for a full block, 0 on error).  The caller uses this to\n * clean up: zero data[dezigzag[1..k-1]] after IDCT consumes the block.\n */\nstatic INLINE int rjpeg_jpeg_decode_block(\n      rjpeg_jpeg *j, short data[64],\n      rjpeg_huffman *hdc,\n      rjpeg_huffman *hac,\n      int16_t *fac,\n      int b,\n      uint8_t *dequant)\n{\n   int dc,k;\n   int t;\n   int diff      = 0;\n\n   if (j->code_bits < 16)\n      rjpeg_grow_buffer_unsafe(j);\n   t = rjpeg_jpeg_huff_decode_nocheck(j, hdc);\n\n   if (t < 0)\n      return 0;\n\n   if (t)\n      diff                = rjpeg_extend_receive(j, t);\n   dc                     = j->img_comp[b].dc_pred + diff;\n   j->img_comp[b].dc_pred = dc;\n   data[0]                = (short) (dc * dequant[0]);\n\n   k                      = 1;\n   do\n   {\n      unsigned int zig;\n      int c,r,s;\n      /* Single grow_buffer per AC iteration: guarantees >= 16 bits.\n       * The fast_ac path consumes at most 16 bits (FAST_BITS=9 + 7\n       * for the coefficient). The slow path's huff_decode_nocheck\n       * consumes at most 16 bits, then extend_receive_nocheck\n       * consumes at most 10 bits (max AC category). We check once\n       * here; both paths skip their internal checks. */\n      if (j->code_bits < 16)\n         rjpeg_grow_buffer_unsafe(j);\n      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n      r = fac[c];\n      if (r)\n      {\n         k               += (r >> 4) & 15;\n         s                = r & 15;\n         if (k > 63)\n            return 0;\n         j->code_buffer <<= s;\n         j->code_bits    -= s;\n         zig              = rjpeg_jpeg_dezigzag[k++];\n         data[zig]        = (short) ((r >> 8) * dequant[zig]);\n      }\n      else\n      {\n         int rs = rjpeg_jpeg_huff_decode_nocheck(j, hac);\n\n         if (rs < 0)\n            return 0;\n\n         s = rs & 15;\n         r = rs >> 4;\n         if (s == 0)\n         {\n            if (rs != 0xf0)\n               break;\n            k += 16;\n         }\n         else\n         {\n            k += r;\n            if (k > 63)\n               return 0;\n            zig = rjpeg_jpeg_dezigzag[k++];\n            data[zig] = (short) (rjpeg_extend_receive(j,s) * dequant[zig]);\n         }\n      }\n   } while (k < 64);\n   return k;\n}\n\n/* Clean up the data[] buffer after IDCT by zeroing only the positions\n * that decode_block wrote to.  data[0] (DC) is always written and always\n * needs zeroing.  AC positions are at dezigzag[1..k_end-1].\n * For DC-only blocks (k_end==1), only data[0] is zeroed — no loop. */\nstatic INLINE void rjpeg_block_cleanup(short data[64], int k_end)\n{\n   int k;\n   data[0] = 0;\n   for (k = 1; k < k_end; ++k)\n      data[rjpeg_jpeg_dezigzag[k]] = 0;\n}\n\nstatic int rjpeg_jpeg_decode_block_prog_dc(\n      rjpeg_jpeg *j,\n      short data[64],\n      rjpeg_huffman *hdc,\n      int b)\n{\n   /* Can't merge DC and AC. Corrupt JPEG? */\n   if (j->spec_end != 0)\n      return 0;\n\n   if (j->code_bits < 16)\n      rjpeg_grow_buffer_unsafe(j);\n\n   if (j->succ_high == 0)\n   {\n      int t;\n      int dc;\n      int diff = 0;\n\n      /* first scan for DC coefficient, must be first */\n      memset(data,0,64*sizeof(data[0])); /* 0 all the ac values now */\n      t       = rjpeg_jpeg_huff_decode(j, hdc);\n      if (t)\n         diff = rjpeg_extend_receive(j, t);\n\n      dc      = j->img_comp[b].dc_pred + diff;\n      j->img_comp[b].dc_pred = dc;\n      data[0] = (short) (dc << j->succ_low);\n   }\n   else\n   {\n      /* refinement scan for DC coefficient */\n      if (rjpeg_jpeg_get_bit(j))\n         data[0] += (short) (1 << j->succ_low);\n   }\n   return 1;\n}\n\nstatic int rjpeg_jpeg_decode_block_prog_ac(\n      rjpeg_jpeg *j,\n      short data[64],\n      rjpeg_huffman *hac,\n      int16_t *fac)\n{\n   int k;\n\n   /* Can't merge DC and AC. Corrupt JPEG? */\n   if (j->spec_start == 0)\n      return 0;\n\n   if (j->succ_high == 0)\n   {\n      int shift = j->succ_low;\n\n      if (j->eob_run)\n      {\n         --j->eob_run;\n         return 1;\n      }\n\n      k = j->spec_start;\n      do\n      {\n         unsigned int zig;\n         int c,r,s;\n         if (j->code_bits < 16)\n            rjpeg_grow_buffer_unsafe(j);\n         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n         r = fac[c];\n         if (r)\n         {\n            /* fast-AC path */\n            k               += (r >> 4) & 15; /* run */\n            s                = r & 15; /* combined length */\n            j->code_buffer <<= s;\n            j->code_bits    -= s;\n            zig              = rjpeg_jpeg_dezigzag[k++];\n            data[zig]        = (short) ((r >> 8) << shift);\n         }\n         else\n         {\n            int rs = rjpeg_jpeg_huff_decode(j, hac);\n\n            /* Bad huffman code. Corrupt JPEG? */\n            if (rs < 0)\n               return 0;\n\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0)\n            {\n               if (r < 15)\n               {\n                  j->eob_run = (1 << r);\n                  if (r)\n                     j->eob_run += rjpeg_jpeg_get_bits(j, r);\n                  --j->eob_run;\n                  break;\n               }\n               k += 16;\n            }\n            else\n            {\n               k         += r;\n               zig        = rjpeg_jpeg_dezigzag[k++];\n               data[zig]  = (short) (rjpeg_extend_receive(j,s) << shift);\n            }\n         }\n      } while (k <= j->spec_end);\n   }\n   else\n   {\n      /* refinement scan for these AC coefficients */\n\n      short bit = (short) (1 << j->succ_low);\n\n      if (j->eob_run)\n      {\n         --j->eob_run;\n         for (k = j->spec_start; k <= j->spec_end; ++k)\n         {\n            short *p = &data[rjpeg_jpeg_dezigzag[k]];\n            if (*p != 0)\n               if (rjpeg_jpeg_get_bit(j))\n                  if ((*p & bit) == 0)\n                  {\n                     if (*p > 0)\n                        *p += bit;\n                     else\n                        *p -= bit;\n                  }\n         }\n      }\n      else\n      {\n         k = j->spec_start;\n         do\n         {\n            int r,s;\n            int rs = rjpeg_jpeg_huff_decode(j, hac);\n\n            /* Bad huffman code. Corrupt JPEG? */\n            if (rs < 0)\n               return 0;\n\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0)\n            {\n               if (r < 15)\n               {\n                  j->eob_run = (1 << r) - 1;\n                  if (r)\n                     j->eob_run += rjpeg_jpeg_get_bits(j, r);\n                  r = 64; /* force end of block */\n               }\n               else\n               {\n                  /* r=15 s=0 should write 16 0s, so we just do\n                   * a run of 15 0s and then write s (which is 0),\n                   * so we don't have to do anything special here */\n               }\n            }\n            else\n            {\n               /* Bad huffman code. Corrupt JPEG? */\n               if (s != 1)\n                  return 0;\n\n               /* sign bit */\n               if (rjpeg_jpeg_get_bit(j))\n                  s = bit;\n               else\n                  s = -bit;\n            }\n\n            /* advance by r */\n            while (k <= j->spec_end)\n            {\n               short *p = &data[rjpeg_jpeg_dezigzag[k++]];\n               if (*p != 0)\n               {\n                  if (rjpeg_jpeg_get_bit(j))\n                     if ((*p & bit) == 0)\n                     {\n                        if (*p > 0)\n                           *p += bit;\n                        else\n                           *p -= bit;\n                     }\n               }\n               else\n               {\n                  if (r == 0)\n                  {\n                     *p = (short) s;\n                     break;\n                  }\n                  --r;\n               }\n            }\n         } while (k <= j->spec_end);\n      }\n   }\n   return 1;\n}\n\n/* take a -128..127 value and rjpeg_clamp it and convert to 0..255 */\nstatic INLINE uint8_t rjpeg_clamp(int x)\n{\n   /* trick to use a single test to catch both cases */\n   if ((unsigned int) x > 255)\n      return (x < 0) ? 0 : 255;\n   return (uint8_t) x;\n}\n\n/* derived from jidctint -- DCT_ISLOW */\n#define RJPEG_IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \\\n   int t0,t1,p4,p5,x0,x1,x2,x3; \\\n   int p2 = s2;                                \\\n   int p3 = s6;                                \\\n   int p1 = (p2+p3) * RJPEG_F2F(0.5411961f);   \\\n   int t2 = p1 + p3 * RJPEG_F2F(-1.847759065f);\\\n   int t3 = p1 + p2 * RJPEG_F2F( 0.765366865f);\\\n   p2 = s0;                                    \\\n   p3 = s4;                                    \\\n   t0 = RJPEG_FSH(p2+p3);                      \\\n   t1 = RJPEG_FSH(p2-p3);                      \\\n   x0 = t0+t3;                                 \\\n   x3 = t0-t3;                                 \\\n   x1 = t1+t2;                                 \\\n   x2 = t1-t2;                                 \\\n   t0 = s7;                                    \\\n   t1 = s5;                                    \\\n   t2 = s3;                                    \\\n   t3 = s1;                                    \\\n   p3 = t0+t2;                                 \\\n   p4 = t1+t3;                                 \\\n   p1 = t0+t3;                                 \\\n   p2 = t1+t2;                                 \\\n   p5 = (p3+p4) * RJPEG_F2F( 1.175875602f);    \\\n   t0 = t0      * RJPEG_F2F( 0.298631336f);    \\\n   t1 = t1      * RJPEG_F2F( 2.053119869f);    \\\n   t2 = t2      * RJPEG_F2F( 3.072711026f);    \\\n   t3 = t3      * RJPEG_F2F( 1.501321110f);    \\\n   p1 = p5 + p1 * RJPEG_F2F(-0.899976223f);    \\\n   p2 = p5 + p2 * RJPEG_F2F(-2.562915447f);    \\\n   p3 = p3      * RJPEG_F2F(-1.961570560f);    \\\n   p4 = p4      * RJPEG_F2F(-0.390180644f);    \\\n   t3 += p1+p4;                                \\\n   t2 += p2+p3;                                \\\n   t1 += p2+p4;                                \\\n   t0 += p1+p3\n\nstatic void rjpeg_idct_block(uint8_t *out, int out_stride, short data[64])\n{\n   int i,val[64],*v=val;\n   uint8_t   *o = NULL;\n   int16_t   *d = data;\n\n   /* columns */\n   for (i = 0; i < 8; ++i,++d, ++v)\n   {\n      /* if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing */\n      if (     d[ 8] == 0\n            && d[16] == 0\n            && d[24] == 0\n            && d[32] == 0\n            && d[40] == 0\n            && d[48] == 0\n            && d[56] == 0)\n      {\n         /*    no shortcut                 0     seconds\n          *    (1|2|3|4|5|6|7)==0          0     seconds\n          *    all separate               -0.047 seconds\n          *    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds */\n         int dcterm = d[0] << 2;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      }\n      else\n      {\n         RJPEG_IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]);\n\n         /* constants scaled things up by 1<<12; let's bring them back\n          * down, but keep 2 extra bits of precision */\n         x0 += 512;\n         x1 += 512;\n         x2 += 512;\n         x3 += 512;\n\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i = 0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride)\n   {\n      /* no fast case since the first 1D IDCT spread components out */\n      RJPEG_IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]);\n\n      /* constants scaled things up by 1<<12, plus we had 1<<2 from first\n       * loop, plus horizontal and vertical each scale by sqrt(8) so together\n       * we've got an extra 1<<3, so 1<<17 total we need to remove.\n       * so we want to round that, which means adding 0.5 * 1<<17,\n       * aka 65536. Also, we'll end up with -128 to 127 that we want\n       * to encode as 0..255 by adding 128, so we'll add that before the shift\n       */\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n\n      /* Tried computing the shifts into temps, or'ing the temps to see\n       * if any were out of range, but that was slower */\n      o[0] = rjpeg_clamp((x0+t3) >> 17);\n      o[7] = rjpeg_clamp((x0-t3) >> 17);\n      o[1] = rjpeg_clamp((x1+t2) >> 17);\n      o[6] = rjpeg_clamp((x1-t2) >> 17);\n      o[2] = rjpeg_clamp((x2+t1) >> 17);\n      o[5] = rjpeg_clamp((x2-t1) >> 17);\n      o[3] = rjpeg_clamp((x3+t0) >> 17);\n      o[4] = rjpeg_clamp((x3-t0) >> 17);\n   }\n}\n\n#if defined(__SSE2__)\n/* sse2 integer IDCT. not the fastest possible implementation but it\n * produces bit-identical results to the generic C version so it's\n * fully \"transparent\".\n */\nstatic void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])\n{\n   /* This is constructed to match our regular (generic) integer IDCT exactly. */\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n\n   /* dot product constant: even elems=x, odd elems=y */\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   /* out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)\n    * out(1) = c1[even]*x + c1[odd]*y\n    */\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo   = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi   = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   /* out = in << 12  (in 16-bit, out 32-bit) */\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   /* wide add */\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   /* wide sub */\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   /* butterfly a/b, add bias, then shift by \"s\" and pack */\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   /* 8-bit interleave step (for transposes) */\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   /* 16-bit interleave step (for transposes) */\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         /* even part */ \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         /* odd part */ \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   __m128i rot0_0 = dct_const(RJPEG_F2F(0.5411961f), RJPEG_F2F(0.5411961f) + RJPEG_F2F(-1.847759065f));\n   __m128i rot0_1 = dct_const(RJPEG_F2F(0.5411961f) + RJPEG_F2F( 0.765366865f), RJPEG_F2F(0.5411961f));\n   __m128i rot1_0 = dct_const(RJPEG_F2F(1.175875602f) + RJPEG_F2F(-0.899976223f), RJPEG_F2F(1.175875602f));\n   __m128i rot1_1 = dct_const(RJPEG_F2F(1.175875602f), RJPEG_F2F(1.175875602f) + RJPEG_F2F(-2.562915447f));\n   __m128i rot2_0 = dct_const(RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 0.298631336f), RJPEG_F2F(-1.961570560f));\n   __m128i rot2_1 = dct_const(RJPEG_F2F(-1.961570560f), RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 3.072711026f));\n   __m128i rot3_0 = dct_const(RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 2.053119869f), RJPEG_F2F(-0.390180644f));\n   __m128i rot3_1 = dct_const(RJPEG_F2F(-0.390180644f), RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 1.501321110f));\n\n   /* rounding biases in column/row passes, see rjpeg_idct_block for explanation. */\n   __m128i bias_0 = _mm_set1_epi32(512);\n   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n   /* load */\n   row0 = _mm_load_si128((const __m128i *) (data + 0*8));\n   row1 = _mm_load_si128((const __m128i *) (data + 1*8));\n   row2 = _mm_load_si128((const __m128i *) (data + 2*8));\n   row3 = _mm_load_si128((const __m128i *) (data + 3*8));\n   row4 = _mm_load_si128((const __m128i *) (data + 4*8));\n   row5 = _mm_load_si128((const __m128i *) (data + 5*8));\n   row6 = _mm_load_si128((const __m128i *) (data + 6*8));\n   row7 = _mm_load_si128((const __m128i *) (data + 7*8));\n\n   /* DC-only shortcut: if all AC coefficients are zero, the entire\n    * 8x8 block is a uniform fill.  At quality 85, ~40% of blocks\n    * hit this path, skipping the full 2-pass butterfly + transpose.\n    *\n    * We OR rows 1-7 together and also mask out the DC element of\n    * row0 (position 0).  If the combined OR is all-zero, only the\n    * DC coefficient is non-zero.\n    *\n    * Cost: 7 OR ops + 1 shift + 1 compare + 1 movemask = ~10 cycles.\n    * Savings when hit: ~80 cycles of butterfly + transpose + pack. */\n   {\n      __m128i ac_or = _mm_or_si128(row1, row2);\n      ac_or = _mm_or_si128(ac_or, row3);\n      ac_or = _mm_or_si128(ac_or, row4);\n      ac_or = _mm_or_si128(ac_or, row5);\n      ac_or = _mm_or_si128(ac_or, row6);\n      ac_or = _mm_or_si128(ac_or, row7);\n      /* Mask out DC: shift row0 right by 2 bytes so element 0 drops\n       * off and elements 1-7 are checked */\n      ac_or = _mm_or_si128(ac_or, _mm_srli_si128(row0, 2));\n\n      if (_mm_movemask_epi8(_mm_cmpeq_epi16(ac_or,\n                  _mm_setzero_si128())) == 0xFFFF)\n      {\n         /* All AC == 0.  The IDCT of a DC-only block produces a\n          * uniform value: clamp(((dc + 4) >> 3) + 128).\n          * But data[0] is already dequantized (dc * dequant[0])\n          * by the caller, so we just apply the IDCT scale. */\n         int dc  = (int)(short)_mm_extract_epi16(row0, 0);\n         int val = ((dc + 4) >> 3) + 128;\n         uint8_t fill;\n         if ((unsigned)val > 255)\n            fill = (val < 0) ? 0 : 255;\n         else\n            fill = (uint8_t)val;\n\n         {\n            __m128i fv = _mm_set1_epi8((char)fill);\n            int r;\n            for (r = 0; r < 8; ++r, out += out_stride)\n               _mm_storel_epi64((__m128i*)out, fv);\n         }\n         return;\n      }\n   }\n\n   /* column pass */\n   dct_pass(bias_0, 10);\n\n   {\n      /* 16bit 8x8 transpose pass 1 */\n      dct_interleave16(row0, row4);\n      dct_interleave16(row1, row5);\n      dct_interleave16(row2, row6);\n      dct_interleave16(row3, row7);\n\n      /* transpose pass 2 */\n      dct_interleave16(row0, row2);\n      dct_interleave16(row1, row3);\n      dct_interleave16(row4, row6);\n      dct_interleave16(row5, row7);\n\n      /* transpose pass 3 */\n      dct_interleave16(row0, row1);\n      dct_interleave16(row2, row3);\n      dct_interleave16(row4, row5);\n      dct_interleave16(row6, row7);\n   }\n\n   /* row pass */\n   dct_pass(bias_1, 17);\n\n   {\n      /* pack */\n      __m128i p0 = _mm_packus_epi16(row0, row1); /* a0a1a2a3...a7b0b1b2b3...b7 */\n      __m128i p1 = _mm_packus_epi16(row2, row3);\n      __m128i p2 = _mm_packus_epi16(row4, row5);\n      __m128i p3 = _mm_packus_epi16(row6, row7);\n\n      /* 8bit 8x8 transpose pass 1 */\n      dct_interleave8(p0, p2); /* a0e0a1e1... */\n      dct_interleave8(p1, p3); /* c0g0c1g1... */\n\n      /* transpose pass 2 */\n      dct_interleave8(p0, p1); /* a0c0e0g0... */\n      dct_interleave8(p2, p3); /* b0d0f0h0... */\n\n      /* transpose pass 3 */\n      dct_interleave8(p0, p2); /* a0b0c0d0... */\n      dct_interleave8(p1, p3); /* a4b4c4d4... */\n\n      /* store */\n      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n   }\n\n#undef dct_const\n#undef dct_rot\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_interleave8\n#undef dct_interleave16\n#undef dct_pass\n}\n\n#endif\n\n#ifdef RJPEG_NEON\n\n/* NEON integer IDCT. should produce bit-identical\n * results to the generic C version. */\nstatic void rjpeg_idct_simd(uint8_t *out, int out_stride, short data[64])\n{\n   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;\n\n   int16x4_t rot0_0 = vdup_n_s16(RJPEG_F2F(0.5411961f));\n   int16x4_t rot0_1 = vdup_n_s16(RJPEG_F2F(-1.847759065f));\n   int16x4_t rot0_2 = vdup_n_s16(RJPEG_F2F( 0.765366865f));\n   int16x4_t rot1_0 = vdup_n_s16(RJPEG_F2F( 1.175875602f));\n   int16x4_t rot1_1 = vdup_n_s16(RJPEG_F2F(-0.899976223f));\n   int16x4_t rot1_2 = vdup_n_s16(RJPEG_F2F(-2.562915447f));\n   int16x4_t rot2_0 = vdup_n_s16(RJPEG_F2F(-1.961570560f));\n   int16x4_t rot2_1 = vdup_n_s16(RJPEG_F2F(-0.390180644f));\n   int16x4_t rot3_0 = vdup_n_s16(RJPEG_F2F( 0.298631336f));\n   int16x4_t rot3_1 = vdup_n_s16(RJPEG_F2F( 2.053119869f));\n   int16x4_t rot3_2 = vdup_n_s16(RJPEG_F2F( 3.072711026f));\n   int16x4_t rot3_3 = vdup_n_s16(RJPEG_F2F( 1.501321110f));\n\n#define dct_long_mul(out, inq, coeff) \\\n   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)\n\n#define dct_long_mac(out, acc, inq, coeff) \\\n   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)\n\n#define dct_widen(out, inq) \\\n   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \\\n   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)\n\n/* wide add */\n#define dct_wadd(out, a, b) \\\n   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)\n\n/* wide sub */\n#define dct_wsub(out, a, b) \\\n   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)\n\n/* butterfly a/b, then shift using \"shiftop\" by \"s\" and pack */\n#define dct_bfly32o(out0,out1, a,b,shiftop,s) \\\n   { \\\n      dct_wadd(sum, a, b); \\\n      dct_wsub(dif, a, b); \\\n      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \\\n      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \\\n   }\n\n#define dct_pass(shiftop, shift) \\\n   { \\\n      /* even part */ \\\n      int16x8_t sum26 = vaddq_s16(row2, row6); \\\n      dct_long_mul(p1e, sum26, rot0_0); \\\n      dct_long_mac(t2e, p1e, row6, rot0_1); \\\n      dct_long_mac(t3e, p1e, row2, rot0_2); \\\n      int16x8_t sum04 = vaddq_s16(row0, row4); \\\n      int16x8_t dif04 = vsubq_s16(row0, row4); \\\n      dct_widen(t0e, sum04); \\\n      dct_widen(t1e, dif04); \\\n      dct_wadd(x0, t0e, t3e); \\\n      dct_wsub(x3, t0e, t3e); \\\n      dct_wadd(x1, t1e, t2e); \\\n      dct_wsub(x2, t1e, t2e); \\\n      /* odd part */ \\\n      int16x8_t sum15 = vaddq_s16(row1, row5); \\\n      int16x8_t sum17 = vaddq_s16(row1, row7); \\\n      int16x8_t sum35 = vaddq_s16(row3, row5); \\\n      int16x8_t sum37 = vaddq_s16(row3, row7); \\\n      int16x8_t sumodd = vaddq_s16(sum17, sum35); \\\n      dct_long_mul(p5o, sumodd, rot1_0); \\\n      dct_long_mac(p1o, p5o, sum17, rot1_1); \\\n      dct_long_mac(p2o, p5o, sum35, rot1_2); \\\n      dct_long_mul(p3o, sum37, rot2_0); \\\n      dct_long_mul(p4o, sum15, rot2_1); \\\n      dct_wadd(sump13o, p1o, p3o); \\\n      dct_wadd(sump24o, p2o, p4o); \\\n      dct_wadd(sump23o, p2o, p3o); \\\n      dct_wadd(sump14o, p1o, p4o); \\\n      dct_long_mac(x4, sump13o, row7, rot3_0); \\\n      dct_long_mac(x5, sump24o, row5, rot3_1); \\\n      dct_long_mac(x6, sump23o, row3, rot3_2); \\\n      dct_long_mac(x7, sump14o, row1, rot3_3); \\\n      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \\\n      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \\\n      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \\\n      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \\\n   }\n\n   /* load */\n   row0 = vld1q_s16(data + 0*8);\n   row1 = vld1q_s16(data + 1*8);\n   row2 = vld1q_s16(data + 2*8);\n   row3 = vld1q_s16(data + 3*8);\n   row4 = vld1q_s16(data + 4*8);\n   row5 = vld1q_s16(data + 5*8);\n   row6 = vld1q_s16(data + 6*8);\n   row7 = vld1q_s16(data + 7*8);\n\n   /* DC-only shortcut (same logic as SSE2 path).\n    * Uses vmaxvq_u16 (ARMv8) or a reduction chain (ARMv7)\n    * to check if all AC coefficients are zero. */\n   {\n      int16x8_t ac_or = vorrq_s16(row1, row2);\n      ac_or = vorrq_s16(ac_or, row3);\n      ac_or = vorrq_s16(ac_or, row4);\n      ac_or = vorrq_s16(ac_or, row5);\n      ac_or = vorrq_s16(ac_or, row6);\n      ac_or = vorrq_s16(ac_or, row7);\n      /* Check AC positions of row0 (elements 1-7) */\n      ac_or = vorrq_s16(ac_or, vextq_s16(row0, vdupq_n_s16(0), 1));\n\n#if defined(__aarch64__)\n      if (vmaxvq_u16(vreinterpretq_u16_s16(\n            vabsq_s16(ac_or))) == 0)\n#else\n      /* ARMv7 fallback: OR-reduce to a single lane */\n      {\n         uint32x4_t w = vreinterpretq_u32_s16(ac_or);\n         uint32x2_t h = vorr_u32(vget_low_u32(w), vget_high_u32(w));\n         if ((vget_lane_u32(h, 0) | vget_lane_u32(h, 1)) == 0)\n#endif\n      {\n         int dc  = vgetq_lane_s16(row0, 0);\n         int val = ((dc + 4) >> 3) + 128;\n         uint8_t fill;\n         if ((unsigned)val > 255)\n            fill = (val < 0) ? 0 : 255;\n         else\n            fill = (uint8_t)val;\n\n         {\n            uint8x8_t fv = vdup_n_u8(fill);\n            int r;\n            for (r = 0; r < 8; ++r, out += out_stride)\n               vst1_u8(out, fv);\n         }\n         return;\n      }\n#if !defined(__aarch64__)\n      }\n#endif\n   }\n\n   /* add DC bias */\n   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));\n\n   /* column pass */\n   dct_pass(vrshrn_n_s32, 10);\n\n   /* 16bit 8x8 transpose */\n   {\n/* these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.\n * whether compilers actually get this is another story, sadly. */\n#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }\n#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]); }\n#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)); }\n\n      /* pass 1 */\n      dct_trn16(row0, row1); /* a0b0a2b2a4b4a6b6 */\n      dct_trn16(row2, row3);\n      dct_trn16(row4, row5);\n      dct_trn16(row6, row7);\n\n      /* pass 2 */\n      dct_trn32(row0, row2); /* a0b0c0d0a4b4c4d4 */\n      dct_trn32(row1, row3);\n      dct_trn32(row4, row6);\n      dct_trn32(row5, row7);\n\n      /* pass 3 */\n      dct_trn64(row0, row4); /* a0b0c0d0e0f0g0h0 */\n      dct_trn64(row1, row5);\n      dct_trn64(row2, row6);\n      dct_trn64(row3, row7);\n\n#undef dct_trn16\n#undef dct_trn32\n#undef dct_trn64\n   }\n\n   /* row pass\n    * vrshrn_n_s32 only supports shifts up to 16, we need\n    * 17. so do a non-rounding shift of 16 first then follow\n    * up with a rounding shift by 1. */\n   dct_pass(vshrn_n_s32, 16);\n\n   {\n      /* pack and round */\n      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);\n      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);\n      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);\n      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);\n      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);\n      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);\n      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);\n      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);\n\n      /* again, these can translate into one instruction, but often don't. */\n#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }\n#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]); }\n#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]); }\n\n      /* sadly can't use interleaved stores here since we only write\n       * 8 bytes to each scan line! */\n\n      /* 8x8 8-bit transpose pass 1 */\n      dct_trn8_8(p0, p1);\n      dct_trn8_8(p2, p3);\n      dct_trn8_8(p4, p5);\n      dct_trn8_8(p6, p7);\n\n      /* pass 2 */\n      dct_trn8_16(p0, p2);\n      dct_trn8_16(p1, p3);\n      dct_trn8_16(p4, p6);\n      dct_trn8_16(p5, p7);\n\n      /* pass 3 */\n      dct_trn8_32(p0, p4);\n      dct_trn8_32(p1, p5);\n      dct_trn8_32(p2, p6);\n      dct_trn8_32(p3, p7);\n\n      /* store */\n      vst1_u8(out, p0);\n      out += out_stride;\n      vst1_u8(out, p1);\n      out += out_stride;\n      vst1_u8(out, p2);\n      out += out_stride;\n      vst1_u8(out, p3);\n      out += out_stride;\n      vst1_u8(out, p4);\n      out += out_stride;\n      vst1_u8(out, p5);\n      out += out_stride;\n      vst1_u8(out, p6);\n      out += out_stride;\n      vst1_u8(out, p7);\n\n#undef dct_trn8_8\n#undef dct_trn8_16\n#undef dct_trn8_32\n   }\n\n#undef dct_long_mul\n#undef dct_long_mac\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_pass\n}\n\n#endif /* RJPEG_NEON */\n\nstatic uint8_t rjpeg_get_marker(rjpeg_jpeg *j)\n{\n   uint8_t x;\n\n   if (j->marker != RJPEG_MARKER_NONE)\n   {\n      x = j->marker;\n      j->marker = RJPEG_MARKER_NONE;\n      return x;\n   }\n\n   x = rjpeg_get8(j);\n   if (x != 0xff)\n      return RJPEG_MARKER_NONE;\n   while (x == 0xff)\n      x = rjpeg_get8(j);\n   return x;\n}\n\n/* after a restart interval, rjpeg_jpeg_reset the entropy decoder and\n * the dc prediction\n */\nstatic void rjpeg_jpeg_reset(rjpeg_jpeg *j)\n{\n   j->code_bits           = 0;\n   j->code_buffer         = 0;\n   j->nomore              = 0;\n   j->img_comp[0].dc_pred = 0;\n   j->img_comp[1].dc_pred = 0;\n   j->img_comp[2].dc_pred = 0;\n   j->img_comp[3].dc_pred = 0;\n   j->marker              = RJPEG_MARKER_NONE;\n   j->todo                = j->restart_interval ? j->restart_interval : 0x7fffffff;\n   j->eob_run             = 0;\n\n   /* no more than 1<<31 MCUs if no restart_interval? that's plenty safe,\n    * since we don't even allow 1<<30 pixels */\n}\n\nstatic int rjpeg_parse_entropy_coded_data(rjpeg_jpeg *z)\n{\n   rjpeg_jpeg_reset(z);\n\n   if (z->scan_n == 1)\n   {\n      int i, j;\n      int n = z->order[0];\n      int w = (z->img_comp[n].x+7) >> 3;\n      int h = (z->img_comp[n].y+7) >> 3;\n\n      /* non-interleaved data, we just need to process one block at a time,\n       * in trivial scanline order\n       * number of blocks to do just depends on how many actual \"pixels\" this\n       * component has, independent of interleaved MCU blocking and such */\n\n      if (z->progressive)\n      {\n         for (j = 0; j < h; ++j)\n         {\n            for (i = 0; i < w; ++i)\n            {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n\n               if (z->spec_start == 0)\n               {\n                  if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                     return 0;\n               }\n               else\n               {\n                  int ha = z->img_comp[n].ha;\n                  if (!rjpeg_jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))\n                     return 0;\n               }\n\n               /* every data block is an MCU, so countdown the restart interval */\n               if (--z->todo <= 0)\n               {\n                  if (z->code_bits < 24)\n                     rjpeg_grow_buffer_unsafe(z);\n\n                  if (!RJPEG_RESTART(z->marker))\n                     return 1;\n                  rjpeg_jpeg_reset(z);\n               }\n            }\n         }\n      }\n      else\n      {\n         RJPEG_SIMD_ALIGN(short, data[64]);\n         int comp_ha    = z->img_comp[n].ha;\n         int comp_hd    = z->img_comp[n].hd;\n         int comp_w2    = z->img_comp[n].w2;\n         uint8_t *comp_data = z->img_comp[n].data;\n         rjpeg_huffman *hdc = z->huff_dc + comp_hd;\n         rjpeg_huffman *hac = z->huff_ac + comp_ha;\n         int16_t *fac       = z->fast_ac[comp_ha];\n         uint8_t *dq        = z->dequant[z->img_comp[n].tq];\n         void (*idct_fn)(uint8_t *out, int out_stride, short data[64])\n            = z->idct_block_kernel;\n\n         memset(data, 0, 64 * sizeof(data[0]));\n\n         for (j = 0; j < h; ++j)\n         {\n            for (i = 0; i < w; ++i)\n            {\n               int k_end = rjpeg_jpeg_decode_block(z, data,\n                        hdc, hac, fac, n, dq);\n               if (!k_end)\n                  return 0;\n\n               idct_fn(comp_data + comp_w2 * j * 8 + i * 8,\n                     comp_w2, data);\n\n               rjpeg_block_cleanup(data, k_end);\n\n               /* every data block is an MCU, so countdown the restart interval */\n               if (--z->todo <= 0)\n               {\n                  if (z->code_bits < 24)\n                     rjpeg_grow_buffer_unsafe(z);\n\n                  /* if it's NOT a restart, then just bail,\n                   * so we get corrupt data rather than no data */\n                  if (!RJPEG_RESTART(z->marker))\n                     return 1;\n                  rjpeg_jpeg_reset(z);\n               }\n            }\n         }\n      }\n   }\n   else\n   {\n      /* interleaved */\n      int i,j,k,x,y;\n\n      if (z->progressive)\n      {\n         for (j = 0; j < z->img_mcu_y; ++j)\n         {\n            for (i = 0; i < z->img_mcu_x; ++i)\n            {\n               /* scan an interleaved MCU... process scan_n components in order */\n               for (k = 0; k < z->scan_n; ++k)\n               {\n                  int n = z->order[k];\n                  /* scan out an MCU's worth of this component; that's just determined\n                   * by the basic H and V specified for the component */\n                  for (y = 0; y < z->img_comp[n].v; ++y)\n                  {\n                     for (x = 0; x < z->img_comp[n].h; ++x)\n                     {\n                        int      x2 = (i*z->img_comp[n].h + x);\n                        int      y2 = (j*z->img_comp[n].v + y);\n                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);\n                        if (!rjpeg_jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                           return 0;\n                     }\n                  }\n               }\n\n               /* after all interleaved components, that's an interleaved MCU,\n                * so now count down the restart interval */\n               if (--z->todo <= 0)\n               {\n                  if (z->code_bits < 24)\n                     rjpeg_grow_buffer_unsafe(z);\n                  if (!RJPEG_RESTART(z->marker))\n                     return 1;\n                  rjpeg_jpeg_reset(z);\n               }\n            }\n         }\n      }\n      else\n      {\n         RJPEG_SIMD_ALIGN(short, data[64]);\n         memset(data, 0, 64 * sizeof(data[0]));\n\n         for (j = 0; j < z->img_mcu_y; ++j)\n         {\n            for (i = 0; i < z->img_mcu_x; ++i)\n            {\n               /* scan an interleaved MCU... process scan_n components in order */\n               for (k = 0; k < z->scan_n; ++k)\n               {\n                  int n = z->order[k];\n                  int comp_h  = z->img_comp[n].h;\n                  int comp_v  = z->img_comp[n].v;\n                  int comp_ha = z->img_comp[n].ha;\n                  int comp_w2 = z->img_comp[n].w2;\n                  uint8_t *comp_data = z->img_comp[n].data;\n                  rjpeg_huffman *hdc = z->huff_dc + z->img_comp[n].hd;\n                  rjpeg_huffman *hac = z->huff_ac + comp_ha;\n                  int16_t *fac       = z->fast_ac[comp_ha];\n                  uint8_t *dq        = z->dequant[z->img_comp[n].tq];\n\n                  for (y = 0; y < comp_v; ++y)\n                  {\n                     for (x = 0; x < comp_h; ++x)\n                     {\n                        int x2 = (i * comp_h + x) * 8;\n                        int y2 = (j * comp_v + y) * 8;\n                        int k_end;\n\n                        k_end = rjpeg_jpeg_decode_block(z, data,\n                                 hdc, hac, fac,\n                                 n, dq);\n                        if (!k_end)\n                           return 0;\n\n                        z->idct_block_kernel(comp_data + comp_w2 * y2 + x2,\n                              comp_w2, data);\n\n                        rjpeg_block_cleanup(data, k_end);\n                     }\n                  }\n               }\n\n               /* after all interleaved components, that's an interleaved MCU,\n                * so now count down the restart interval */\n               if (--z->todo <= 0)\n               {\n                  if (z->code_bits < 24)\n                     rjpeg_grow_buffer_unsafe(z);\n                  if (!RJPEG_RESTART(z->marker))\n                     return 1;\n                  rjpeg_jpeg_reset(z);\n               }\n            }\n         }\n      }\n   }\n\n   return 1;\n}\n\n/* -----------------------------------------------------------------------\n * Fused dequantize + IDCT kernels\n *\n * The progressive path previously called rjpeg_jpeg_dequantize() then\n * idct_block_kernel() — two passes over the same 64-short block.\n * These fused versions fold the multiply-by-quantization-table into\n * the IDCT load, eliminating the intermediate store+load round-trip\n * (128 bytes written then immediately read back).\n *\n * Each variant also adds a DC-only fast path: if all 63 AC coefficients\n * are zero after dequantization, the output is a flat 8x8 fill — no\n * butterfly math needed.  At quality 85, ~40% of blocks hit this.\n * ----------------------------------------------------------------------- */\n\n/* Scalar fused dequant+IDCT with DC-only shortcut */\nstatic void rjpeg_dequant_idct_block(uint8_t *out, int out_stride,\n      short data[64], uint8_t *dequant)\n{\n   int i, val[64], *v = val;\n   uint8_t *o = NULL;\n   int16_t *d = data;\n\n   /* Dequantize in-place first, then check for DC-only shortcut.\n    * We need the dequantized values for the zero check anyway. */\n   for (i = 0; i < 64; ++i)\n      data[i] = (short)(data[i] * dequant[i]);\n\n   /* DC-only fast path: if all AC coefficients are zero, the entire\n    * 8x8 block is a uniform fill.  This avoids the full 2-pass IDCT. */\n   {\n      int all_zero = 1;\n      for (i = 1; i < 64; ++i)\n      {\n         if (data[i] != 0) { all_zero = 0; break; }\n      }\n      if (all_zero)\n      {\n         /* DC coefficient goes through the same scale path as the\n          * IDCT: column pass does d[0]<<2, row pass adds\n          * 65536+(128<<17) then >>17.  Net: clamp(((d[0]+4)>>3)+128). */\n         int dc = data[0];\n         int val8 = ((dc + 4) >> 3) + 128;\n         uint8_t fill;\n         if ((unsigned)val8 > 255)\n            fill = (val8 < 0) ? 0 : 255;\n         else\n            fill = (uint8_t)val8;\n\n         for (i = 0; i < 8; ++i, out += out_stride)\n            memset(out, fill, 8);\n         return;\n      }\n   }\n\n   /* Full IDCT — identical to rjpeg_idct_block but data is already\n    * dequantized so we skip the per-element multiply. */\n\n   /* columns */\n   for (i = 0; i < 8; ++i, ++d, ++v)\n   {\n      if (     d[ 8] == 0\n            && d[16] == 0\n            && d[24] == 0\n            && d[32] == 0\n            && d[40] == 0\n            && d[48] == 0\n            && d[56] == 0)\n      {\n         int dcterm = d[0] << 2;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      }\n      else\n      {\n         RJPEG_IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]);\n         x0 += 512; x1 += 512; x2 += 512; x3 += 512;\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i = 0, v = val, o = out; i < 8; ++i, v += 8, o += out_stride)\n   {\n      RJPEG_IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]);\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n      o[0] = rjpeg_clamp((x0+t3) >> 17);\n      o[7] = rjpeg_clamp((x0-t3) >> 17);\n      o[1] = rjpeg_clamp((x1+t2) >> 17);\n      o[6] = rjpeg_clamp((x1-t2) >> 17);\n      o[2] = rjpeg_clamp((x2+t1) >> 17);\n      o[5] = rjpeg_clamp((x2-t1) >> 17);\n      o[3] = rjpeg_clamp((x3+t0) >> 17);\n      o[4] = rjpeg_clamp((x3-t0) >> 17);\n   }\n}\n\n#if defined(__SSE2__)\n/* SSE2 fused dequant+IDCT: folds quantization multiply into the row\n * loads, adds DC-only shortcut using _mm_movemask_epi8. */\nstatic void rjpeg_dequant_idct_simd(uint8_t *out, int out_stride,\n      short data[64], uint8_t *dequant)\n{\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n   __m128i zero = _mm_setzero_si128();\n\n   /* Fused load+dequantize: load 8 coefficients and 8 quant values,\n    * widen quant from uint8 to int16, multiply in one step.\n    * This replaces the separate dequantize pass entirely. */\n#define LOAD_DEQUANT_ROW(rowvar, idx) \\\n   { \\\n      __m128i coeff = _mm_load_si128((const __m128i*)(data + (idx)*8)); \\\n      __m128i q8    = _mm_loadl_epi64((const __m128i*)(dequant + (idx)*8)); \\\n      __m128i q16   = _mm_unpacklo_epi8(q8, zero); \\\n      rowvar        = _mm_mullo_epi16(coeff, q16); \\\n   }\n\n   LOAD_DEQUANT_ROW(row0, 0)\n   LOAD_DEQUANT_ROW(row1, 1)\n   LOAD_DEQUANT_ROW(row2, 2)\n   LOAD_DEQUANT_ROW(row3, 3)\n   LOAD_DEQUANT_ROW(row4, 4)\n   LOAD_DEQUANT_ROW(row5, 5)\n   LOAD_DEQUANT_ROW(row6, 6)\n   LOAD_DEQUANT_ROW(row7, 7)\n\n#undef LOAD_DEQUANT_ROW\n\n   /* DC-only shortcut: if all AC coefficients are zero after dequant,\n    * the 8x8 block is a uniform fill.  Check rows 1-7 plus AC\n    * coefficients in row 0 (positions 1-7). */\n   {\n      __m128i ac_or = _mm_or_si128(row1, row2);\n      ac_or = _mm_or_si128(ac_or, row3);\n      ac_or = _mm_or_si128(ac_or, row4);\n      ac_or = _mm_or_si128(ac_or, row5);\n      ac_or = _mm_or_si128(ac_or, row6);\n      ac_or = _mm_or_si128(ac_or, row7);\n      /* Mask out DC (element 0 of row0) — shift row0 left by 2 bytes\n       * so element 0 becomes 0 and elements 1-7 shift into 0-6 */\n      ac_or = _mm_or_si128(ac_or, _mm_srli_si128(row0, 2));\n\n      if (_mm_movemask_epi8(_mm_cmpeq_epi16(ac_or, zero)) == 0xFFFF)\n      {\n         /* All AC == 0: output is flat fill from DC value.\n          * DC path: ((dc + 4) >> 3) + 128, clamped to [0,255]. */\n         int dc  = (int)(short)_mm_extract_epi16(row0, 0);\n         int val = ((dc + 4) >> 3) + 128;\n         uint8_t fill;\n         if ((unsigned)val > 255)\n            fill = (val < 0) ? 0 : 255;\n         else\n            fill = (uint8_t)val;\n\n         {\n            __m128i fillvec = _mm_set1_epi8((char)fill);\n            int r;\n            for (r = 0; r < 8; ++r, out += out_stride)\n               _mm_storel_epi64((__m128i*)out, fillvec);\n         }\n         return;\n      }\n   }\n\n   /* Full IDCT — same as rjpeg_idct_simd but rows are already\n    * dequantized from the fused load above. */\n\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo   = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi   = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   {\n      __m128i rot0_0 = dct_const(RJPEG_F2F(0.5411961f), RJPEG_F2F(0.5411961f) + RJPEG_F2F(-1.847759065f));\n      __m128i rot0_1 = dct_const(RJPEG_F2F(0.5411961f) + RJPEG_F2F( 0.765366865f), RJPEG_F2F(0.5411961f));\n      __m128i rot1_0 = dct_const(RJPEG_F2F(1.175875602f) + RJPEG_F2F(-0.899976223f), RJPEG_F2F(1.175875602f));\n      __m128i rot1_1 = dct_const(RJPEG_F2F(1.175875602f), RJPEG_F2F(1.175875602f) + RJPEG_F2F(-2.562915447f));\n      __m128i rot2_0 = dct_const(RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 0.298631336f), RJPEG_F2F(-1.961570560f));\n      __m128i rot2_1 = dct_const(RJPEG_F2F(-1.961570560f), RJPEG_F2F(-1.961570560f) + RJPEG_F2F( 3.072711026f));\n      __m128i rot3_0 = dct_const(RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 2.053119869f), RJPEG_F2F(-0.390180644f));\n      __m128i rot3_1 = dct_const(RJPEG_F2F(-0.390180644f), RJPEG_F2F(-0.390180644f) + RJPEG_F2F( 1.501321110f));\n\n      __m128i bias_0 = _mm_set1_epi32(512);\n      __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n      dct_pass(bias_0, 10);\n\n      {\n         dct_interleave16(row0, row4);\n         dct_interleave16(row1, row5);\n         dct_interleave16(row2, row6);\n         dct_interleave16(row3, row7);\n         dct_interleave16(row0, row2);\n         dct_interleave16(row1, row3);\n         dct_interleave16(row4, row6);\n         dct_interleave16(row5, row7);\n         dct_interleave16(row0, row1);\n         dct_interleave16(row2, row3);\n         dct_interleave16(row4, row5);\n         dct_interleave16(row6, row7);\n      }\n\n      dct_pass(bias_1, 17);\n\n      {\n         __m128i p0 = _mm_packus_epi16(row0, row1);\n         __m128i p1 = _mm_packus_epi16(row2, row3);\n         __m128i p2 = _mm_packus_epi16(row4, row5);\n         __m128i p3 = _mm_packus_epi16(row6, row7);\n         dct_interleave8(p0, p2);\n         dct_interleave8(p1, p3);\n         dct_interleave8(p0, p1);\n         dct_interleave8(p2, p3);\n         dct_interleave8(p0, p2);\n         dct_interleave8(p1, p3);\n         _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n         _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n      }\n   }\n\n   #undef dct_const\n   #undef dct_rot\n   #undef dct_widen\n   #undef dct_wadd\n   #undef dct_wsub\n   #undef dct_bfly32o\n   #undef dct_interleave8\n   #undef dct_interleave16\n   #undef dct_pass\n}\n#endif /* __SSE2__ fused dequant+IDCT */\n\n#ifdef RJPEG_NEON\n/* NEON fused dequant+IDCT with DC-only shortcut */\nstatic void rjpeg_dequant_idct_neon(uint8_t *out, int out_stride,\n      short data[64], uint8_t *dequant)\n{\n   /* Fuse dequantize into the NEON IDCT by multiplying during load,\n    * then run the standard NEON IDCT butterfly.\n    * For brevity, we dequantize in-place first (8 NEON multiply ops),\n    * then delegate to the existing rjpeg_idct_simd which loads from\n    * the same buffer.  This still saves the store+load round-trip vs\n    * the two-function path because the data stays hot in L1. */\n   int i;\n   for (i = 0; i < 64; i += 8)\n   {\n      int16x8_t d   = vld1q_s16(data + i);\n      uint8x8_t q8  = vld1_u8(dequant + i);\n      int16x8_t q16 = vreinterpretq_s16_u16(vmovl_u8(q8));\n      vst1q_s16(data + i, vmulq_s16(d, q16));\n   }\n\n   /* DC-only check: OR all AC coefficients */\n   {\n      int16x8_t r1 = vld1q_s16(data + 8);\n      int16x8_t r2 = vld1q_s16(data + 16);\n      int16x8_t r3 = vld1q_s16(data + 24);\n      int16x8_t r4 = vld1q_s16(data + 32);\n      int16x8_t r5 = vld1q_s16(data + 40);\n      int16x8_t r6 = vld1q_s16(data + 48);\n      int16x8_t r7 = vld1q_s16(data + 56);\n      int16x8_t ac_or = vorrq_s16(r1, r2);\n      ac_or = vorrq_s16(ac_or, r3);\n      ac_or = vorrq_s16(ac_or, r4);\n      ac_or = vorrq_s16(ac_or, r5);\n      ac_or = vorrq_s16(ac_or, r6);\n      ac_or = vorrq_s16(ac_or, r7);\n      /* Also check AC coefficients in row 0 (indices 1-7) */\n      {\n         int16x8_t r0 = vld1q_s16(data);\n         int16x8_t r0_shifted = vextq_s16(r0, vdupq_n_s16(0), 1);\n         ac_or = vorrq_s16(ac_or, r0_shifted);\n      }\n\n      /* If all AC zero: uniform fill */\n#if defined(__aarch64__)\n      if (vmaxvq_u16(vreinterpretq_u16_s16(\n            vabsq_s16(ac_or))) == 0)\n#else\n      /* ARMv7 fallback: OR-reduce to a single lane */\n      {\n         uint32x4_t w = vreinterpretq_u32_s16(ac_or);\n         uint32x2_t h = vorr_u32(vget_low_u32(w), vget_high_u32(w));\n         if ((vget_lane_u32(h, 0) | vget_lane_u32(h, 1)) == 0)\n#endif\n      {\n         int dc  = data[0];\n         int val = ((dc + 4) >> 3) + 128;\n         uint8_t fill;\n         if ((unsigned)val > 255)\n            fill = (val < 0) ? 0 : 255;\n         else\n            fill = (uint8_t)val;\n\n         {\n            uint8x8_t fv = vdup_n_u8(fill);\n            int r;\n            for (r = 0; r < 8; ++r, out += out_stride)\n               vst1_u8(out, fv);\n         }\n         return;\n      }\n#if !defined(__aarch64__)\n      }\n#endif\n   }\n\n   /* Full IDCT on already-dequantized data */\n   rjpeg_idct_simd(out, out_stride, data);\n}\n#endif /* RJPEG_NEON fused dequant+IDCT */\n\nstatic void rjpeg_jpeg_finish(rjpeg_jpeg *z)\n{\n   int i,j,n;\n\n   if (!z->progressive)\n      return;\n\n   /* Fused dequantize+IDCT: single pass per block instead of\n    * the old rjpeg_jpeg_dequantize() + z->idct_block_kernel()\n    * two-pass sequence.  Saves one 128-byte store+load round-trip\n    * per 8x8 block and adds a DC-only fast path. */\n   for (n = 0; n < z->img_n; ++n)\n   {\n      int w = (z->img_comp[n].x+7) >> 3;\n      int h = (z->img_comp[n].y+7) >> 3;\n      for (j = 0; j < h; ++j)\n      {\n         for (i = 0; i < w; ++i)\n         {\n            short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n            z->dequant_idct_block_kernel(\n                  z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8,\n                  z->img_comp[n].w2, data,\n                  z->dequant[z->img_comp[n].tq]);\n         }\n      }\n   }\n}\n\nstatic int rjpeg_process_marker(rjpeg_jpeg *z, int m)\n{\n   int L;\n   switch (m)\n   {\n      case RJPEG_MARKER_NONE: /* no marker found */\n         /* Expected marker. Corrupt JPEG? */\n         return 0;\n\n      case 0xDD: /* DRI - specify restart interval */\n\n         /* Bad DRI length. Corrupt JPEG? */\n         if (RJPEG_GET16BE(z) != 4)\n            return 0;\n\n         z->restart_interval = RJPEG_GET16BE(z);\n         return 1;\n\n      case 0xDB: /* DQT - define quantization table */\n         L = RJPEG_GET16BE(z)-2;\n         while (L > 0)\n         {\n            int q = rjpeg_get8(z);\n            int p = q >> 4;\n            int t = q & 15,i;\n\n            /* Bad DQT type. Corrupt JPEG? */\n            if (p != 0)\n               return 0;\n\n            /* Bad DQT table. Corrupt JPEG? */\n            if (t > 3)\n               return 0;\n\n            /* Bulk-read 64 quantization values directly from buffer.\n             * The old code called rjpeg_get8 64 times (64 bounds checks).\n             * After verifying 64 bytes remain, we read with no per-byte check. */\n            if (z->img_buffer + 64 <= z->img_buffer_end)\n            {\n               for (i = 0; i < 64; ++i)\n                  z->dequant[t][rjpeg_jpeg_dezigzag[i]] = rjpeg_get8_fast(z);\n            }\n            else\n            {\n               for (i = 0; i < 64; ++i)\n                  z->dequant[t][rjpeg_jpeg_dezigzag[i]] = rjpeg_get8(z);\n            }\n            L -= 65;\n         }\n         return L == 0;\n\n      case 0xC4: /* DHT - define huffman table */\n         L = RJPEG_GET16BE(z)-2;\n         while (L > 0)\n         {\n            int sizes[16],i,n = 0;\n            uint8_t *v = NULL;\n            int q      = rjpeg_get8(z);\n            int tc     = q >> 4;\n            int th     = q & 15;\n\n            /* Bad DHT header. Corrupt JPEG? */\n            if (tc > 1 || th > 3)\n               return 0;\n\n            /* Bulk-read 16 size bytes: one bounds check instead of 16. */\n            if (z->img_buffer + 16 <= z->img_buffer_end)\n            {\n               for (i = 0; i < 16; ++i)\n               {\n                  sizes[i] = rjpeg_get8_fast(z);\n                  n += sizes[i];\n               }\n            }\n            else\n            {\n               for (i = 0; i < 16; ++i)\n               {\n                  sizes[i] = rjpeg_get8(z);\n                  n += sizes[i];\n               }\n            }\n            L -= 17;\n\n            if (tc == 0)\n            {\n               if (!rjpeg_build_huffman(z->huff_dc+th, sizes))\n                  return 0;\n               v = z->huff_dc[th].values;\n            }\n            else\n            {\n               if (!rjpeg_build_huffman(z->huff_ac+th, sizes))\n                  return 0;\n               v = z->huff_ac[th].values;\n            }\n            /* Bulk-read n value bytes */\n            if (z->img_buffer + n <= z->img_buffer_end)\n            {\n               memcpy(v, z->img_buffer, n);\n               z->img_buffer += n;\n            }\n            else\n            {\n               for (i = 0; i < n; ++i)\n                  v[i] = rjpeg_get8(z);\n            }\n            if (tc != 0)\n               rjpeg_build_fast_ac(z->fast_ac[th], z->huff_ac + th);\n            L -= n;\n         }\n         return L == 0;\n   }\n\n   /* check for comment block or APP blocks */\n   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE)\n   {\n      int n = RJPEG_GET16BE(z)-2;\n      rjpeg_skip(z, n);\n      return 1;\n   }\n   return 0;\n}\n\n/* after we see SOS */\nstatic int rjpeg_process_scan_header(rjpeg_jpeg *z)\n{\n   int i;\n   int aa;\n   int Ls    = RJPEG_GET16BE(z);\n\n   z->scan_n = rjpeg_get8(z);\n\n   /* Bad SOS component count. Corrupt JPEG? */\n   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->img_n)\n      return 0;\n\n   /* Bad SOS length. Corrupt JPEG? */\n   if (Ls != 6+2*z->scan_n)\n      return 0;\n\n   for (i = 0; i < z->scan_n; ++i)\n   {\n      int which;\n      int id = rjpeg_get8(z);\n      int q  = rjpeg_get8(z);\n\n      for (which = 0; which < z->img_n; ++which)\n         if (z->img_comp[which].id == id)\n            break;\n      if (which == z->img_n)\n         return 0; /* no match */\n\n      /* Bad DC huff. Corrupt JPEG? */\n      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3)\n         return 0;\n\n      /* Bad AC huff. Corrupt JPEG? */\n      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3)\n         return 0;\n\n      z->order[i] = which;\n   }\n\n   z->spec_start = rjpeg_get8(z);\n   z->spec_end   = rjpeg_get8(z); /* should be 63, but might be 0 */\n   aa            = rjpeg_get8(z);\n   z->succ_high  = (aa >> 4);\n   z->succ_low   = (aa & 15);\n\n   if (z->progressive)\n   {\n      /* Bad SOS. Corrupt JPEG? */\n      if (  z->spec_start > 63 ||\n            z->spec_end > 63   ||\n            z->spec_start > z->spec_end ||\n            z->succ_high > 13           ||\n            z->succ_low > 13)\n         return 0;\n   }\n   else\n   {\n      /* Bad SOS. Corrupt JPEG? */\n      if (z->spec_start != 0)\n         return 0;\n      if (z->succ_high != 0 || z->succ_low != 0)\n         return 0;\n\n      z->spec_end = 63;\n   }\n\n   return 1;\n}\n\nstatic int rjpeg_process_frame_header(rjpeg_jpeg *z, int scan)\n{\n   rjpeg_jpeg *s = z;\n   int Lf,p,i,q, h_max=1,v_max=1,c;\n   Lf = RJPEG_GET16BE(s);\n\n   /* JPEG */\n\n   /* Bad SOF len. Corrupt JPEG? */\n   if (Lf < 11)\n      return 0;\n\n   p  = rjpeg_get8(s);\n\n   /* JPEG baseline */\n\n   /* Only 8-bit. JPEG format not supported? */\n   if (p != 8)\n      return 0;\n\n   s->img_y = RJPEG_GET16BE(s);\n\n   /* Legal, but we don't handle it--but neither does IJG */\n\n   /* No header height, JPEG format not supported? */\n   if (s->img_y == 0)\n      return 0;\n\n   s->img_x = RJPEG_GET16BE(s);\n\n   /* No header width. Corrupt JPEG? */\n   if (s->img_x == 0)\n      return 0;\n\n   /* On 32-bit hosts the (size_t) casts on the malloc sites below\n    * are not enough by themselves: the per-component arena and\n    * iter_output buffers can still demand multi-hundred-MB\n    * allocations that fragment or fail the address space, even\n    * with overflow-safe arithmetic.  Cap dimensions on 32-bit\n    * (matching the cap rbmp.c, rtga.c and rwebp.c apply) to\n    * preserve the previous host-resource ceiling there.\n    *\n    * On 64-bit hosts the SIZE_MAX/4 guard further down in this\n    * function plus the (size_t) casts make the allocations safe\n    * regardless of dimensions, and a desktop user loading a\n    * large legitimate JPEG (cf. IrfanView, image-pipeline tools)\n    * is a real use case.  Do not cap there. */\n#if SIZE_MAX <= 0xFFFFFFFFu\n   if (s->img_x > 0x4000u || s->img_y > 0x4000u)\n      return 0;\n#endif\n\n   c = rjpeg_get8(s);\n\n   /* JFIF requires */\n\n   /* Bad component count. Corrupt JPEG? */\n   if (c != 3 && c != 1)\n      return 0;\n\n   s->img_n = c;\n\n   for (i = 0; i < c; ++i)\n   {\n      z->img_comp[i].data = NULL;\n      z->img_comp[i].linebuf = NULL;\n   }\n\n   /* Bad SOF length. Corrupt JPEG? */\n   if (Lf != 8+3*s->img_n)\n      return 0;\n\n   for (i = 0; i < s->img_n; ++i)\n   {\n      z->img_comp[i].id = rjpeg_get8(s);\n      if (z->img_comp[i].id != i+1)   /* JFIF requires */\n         if (z->img_comp[i].id != i)  /* some version of jpegtran outputs non-JFIF-compliant files! */\n            return 0;\n\n      q                = rjpeg_get8(s);\n      z->img_comp[i].h = (q >> 4);\n\n      /* Bad H. Corrupt JPEG? */\n      if (!z->img_comp[i].h || z->img_comp[i].h > 4)\n         return 0;\n\n      z->img_comp[i].v = q & 15;\n\n      /* Bad V. Corrupt JPEG? */\n      if (!z->img_comp[i].v || z->img_comp[i].v > 4)\n         return 0;\n\n      z->img_comp[i].tq = rjpeg_get8(s);\n\n      /* Bad TQ. Corrupt JPEG? */\n      if (z->img_comp[i].tq > 3)\n         return 0;\n   }\n\n   if (scan != RJPEG_SCAN_LOAD)\n      return 1;\n\n   /* Image too large to decode?\n    * Guard against allocations that would overflow size_t.\n    * The output buffer is img_x * img_y * 4 bytes (BGRA), so we check\n    * that img_x * img_n * img_y fits in size_t with room for the ×4. */\n   {\n      size_t max_pixels = (size_t)-1 / 4; /* SIZE_MAX / 4, portable */\n      if (max_pixels / s->img_x / s->img_n < s->img_y)\n         return 0;\n   }\n\n   for (i = 0; i < s->img_n; ++i)\n   {\n      if (z->img_comp[i].h > h_max)\n         h_max = z->img_comp[i].h;\n      if (z->img_comp[i].v > v_max)\n         v_max = z->img_comp[i].v;\n   }\n\n   /* compute interleaved MCU info */\n   z->img_h_max = h_max;\n   z->img_v_max = v_max;\n   z->img_mcu_w = h_max * 8;\n   z->img_mcu_h = v_max * 8;\n   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;\n   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;\n\n   if (z->progressive)\n   {\n      /* ----------------------------------------------------------------\n       * Arena allocation for progressive component buffers\n       *\n       * Instead of N separate malloc calls (raw_data + raw_coeff per\n       * component), we compute the total size, allocate once, and\n       * partition the arena into aligned sub-regions.  This reduces\n       * syscall overhead and guarantees spatial locality.\n       * ---------------------------------------------------------------- */\n      size_t arena_size = 0;\n      size_t offsets_data[4], offsets_coeff[4], offsets_linebuf[4];\n      uint8_t *arena;\n\n      for (i = 0; i < s->img_n; ++i)\n      {\n         z->img_comp[i].x        = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n         z->img_comp[i].y        = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n         z->img_comp[i].w2       = z->img_mcu_x * z->img_comp[i].h * 8;\n         z->img_comp[i].h2       = z->img_mcu_y * z->img_comp[i].v * 8;\n         z->img_comp[i].coeff_w  = (z->img_comp[i].w2 + 7) >> 3;\n         z->img_comp[i].coeff_h  = (z->img_comp[i].h2 + 7) >> 3;\n\n         /* raw_data: w2*h2 bytes + 15 for alignment */\n         offsets_data[i] = arena_size;\n         arena_size += (size_t)z->img_comp[i].w2 * z->img_comp[i].h2 + 15;\n         arena_size = (arena_size + 15) & ~(size_t)15;\n\n         /* raw_coeff: coeff_w * coeff_h * 64 shorts + 15 for alignment */\n         offsets_coeff[i] = arena_size;\n         arena_size += (size_t)z->img_comp[i].coeff_w\n                     * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15;\n         arena_size = (arena_size + 15) & ~(size_t)15;\n\n         /* linebuf: img_x + 3 bytes (resample scratch, used later) */\n         offsets_linebuf[i] = arena_size;\n         arena_size += (size_t)s->img_x + 3;\n         arena_size = (arena_size + 15) & ~(size_t)15;\n      }\n\n      arena = (uint8_t*)malloc(arena_size);\n      if (!arena)\n         return 0;\n\n      z->comp_arena      = arena;\n      z->comp_arena_size = arena_size;\n\n      for (i = 0; i < s->img_n; ++i)\n      {\n         z->img_comp[i].raw_data  = arena + offsets_data[i];\n         z->img_comp[i].data      = (uint8_t*)(((size_t)(arena + offsets_data[i]) + 15) & ~(size_t)15);\n         z->img_comp[i].linebuf   = arena + offsets_linebuf[i];\n         z->img_comp[i].raw_coeff = arena + offsets_coeff[i];\n         z->img_comp[i].coeff     = (short*)(((size_t)(arena + offsets_coeff[i]) + 15) & ~(size_t)15);\n      }\n   }\n   else\n   {\n      /* ----------------------------------------------------------------\n       * Arena allocation for baseline component buffers\n       * Only raw_data needed (no coefficient storage).\n       * ---------------------------------------------------------------- */\n      size_t arena_size = 0;\n      size_t offsets_data[4], offsets_linebuf[4];\n      uint8_t *arena;\n\n      for (i = 0; i < s->img_n; ++i)\n      {\n         z->img_comp[i].x        = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n         z->img_comp[i].y        = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n         z->img_comp[i].w2       = z->img_mcu_x * z->img_comp[i].h * 8;\n         z->img_comp[i].h2       = z->img_mcu_y * z->img_comp[i].v * 8;\n\n         offsets_data[i] = arena_size;\n         arena_size += (size_t)z->img_comp[i].w2 * z->img_comp[i].h2 + 15;\n         arena_size = (arena_size + 15) & ~(size_t)15;\n\n         /* linebuf: img_x + 3 bytes (resample scratch, used later) */\n         offsets_linebuf[i] = arena_size;\n         arena_size += (size_t)s->img_x + 3;\n         arena_size = (arena_size + 15) & ~(size_t)15;\n      }\n\n      arena = (uint8_t*)malloc(arena_size);\n      if (!arena)\n         return 0;\n\n      z->comp_arena      = arena;\n      z->comp_arena_size = arena_size;\n\n      for (i = 0; i < s->img_n; ++i)\n      {\n         z->img_comp[i].raw_data  = arena + offsets_data[i];\n         z->img_comp[i].data      = (uint8_t*)(((size_t)(arena + offsets_data[i]) + 15) & ~(size_t)15);\n         z->img_comp[i].linebuf   = arena + offsets_linebuf[i];\n         z->img_comp[i].coeff     = 0;\n         z->img_comp[i].raw_coeff = 0;\n      }\n   }\n\n   return 1;\n}\n\nstatic int rjpeg_decode_jpeg_header(rjpeg_jpeg *z, int scan)\n{\n   int m;\n   z->marker = RJPEG_MARKER_NONE; /* initialize cached marker to empty */\n   m         = rjpeg_get_marker(z);\n\n   /* No SOI. Corrupt JPEG? */\n   if (m != JPEG_MARKER_SOI)\n      return 0;\n\n   if (scan == RJPEG_SCAN_TYPE)\n      return 1;\n\n   m = rjpeg_get_marker(z);\n   while (!RJPEG_SOF(m))\n   {\n      if (!rjpeg_process_marker(z,m))\n         return 0;\n      m = rjpeg_get_marker(z);\n      while (m == RJPEG_MARKER_NONE)\n      {\n         /* some files have extra padding after their blocks, so ok, we'll scan */\n\n         /* No SOF. Corrupt JPEG? */\n         if (RJPEG_AT_EOF(z))\n            return 0;\n\n         m = rjpeg_get_marker(z);\n      }\n   }\n   z->progressive = RJPEG_SOF_PROGRESSIVE(m);\n   if (!rjpeg_process_frame_header(z, scan))\n      return 0;\n   return 1;\n}\n\n/* decode image to YCbCr format */\nstatic int rjpeg_decode_jpeg_image(rjpeg_jpeg *j)\n{\n   int m;\n   for (m = 0; m < 4; m++)\n   {\n      j->img_comp[m].raw_data = NULL;\n      j->img_comp[m].raw_coeff = NULL;\n   }\n   j->restart_interval = 0;\n   if (!rjpeg_decode_jpeg_header(j, RJPEG_SCAN_LOAD))\n      return 0;\n   m = rjpeg_get_marker(j);\n\n   while (m != JPEG_MARKER_EOI)\n   {\n      if (m == JPEG_MARKER_SOS)\n      {\n         if (!rjpeg_process_scan_header(j))\n            return 0;\n         if (!rjpeg_parse_entropy_coded_data(j))\n            return 0;\n\n         if (j->marker == RJPEG_MARKER_NONE )\n         {\n            /* handle 0s at the end of image data from IP Kamera 9060 */\n            uint8_t *p   = j->img_buffer;\n            uint8_t *end = j->img_buffer_end;\n            while (p < end)\n            {\n               uint8_t x = *p++;\n               if (x == 0xFF && p < end)\n               {\n                  j->marker = *p++;\n                  break;\n               }\n               else if (x != 0) /* Junk before marker. Corrupt JPEG? */\n               {\n                  j->img_buffer = p;\n                  return 0;\n               }\n            }\n            j->img_buffer = p;\n\n            /* if we reach eof without hitting a marker,\n             * rjpeg_get_marker() below will fail and we'll eventually return 0 */\n         }\n      }\n      else\n      {\n         if (!rjpeg_process_marker(j, m))\n            return 0;\n      }\n      m = rjpeg_get_marker(j);\n   }\n\n   if (j->progressive)\n      rjpeg_jpeg_finish(j);\n   return 1;\n}\n\n/* static jfif-centered resampling (across block boundaries) */\n\nstatic uint8_t *rjpeg_resample_row_1(uint8_t *out, uint8_t *in_near,\n      uint8_t *in_far, int w, int hs)\n{\n   (void)out;\n   (void)in_far;\n   (void)w;\n   (void)hs;\n   return in_near;\n}\n\nstatic uint8_t* rjpeg_resample_row_v_2(uint8_t *out, uint8_t *in_near,\n      uint8_t *in_far, int w, int hs)\n{\n   /* need to generate two samples vertically for every one in input */\n   int i = 0;\n   (void)hs;\n\n#if defined(__SSE2__)\n   for (; i + 15 < w; i += 16)\n   {\n      __m128i zero    = _mm_setzero_si128();\n      __m128i near_b  = _mm_loadu_si128((const __m128i*)(in_near + i));\n      __m128i far_b   = _mm_loadu_si128((const __m128i*)(in_far  + i));\n      __m128i near_lo, far_lo, sum_lo;\n      __m128i near_hi, far_hi, sum_hi;\n\n      /* Process low 8 bytes: (3*near + far + 2) >> 2 */\n      near_lo = _mm_unpacklo_epi8(near_b, zero);\n      far_lo  = _mm_unpacklo_epi8(far_b, zero);\n      sum_lo  = _mm_add_epi16(_mm_add_epi16(near_lo, _mm_slli_epi16(near_lo, 1)), far_lo);\n      sum_lo  = _mm_srli_epi16(_mm_add_epi16(sum_lo, _mm_set1_epi16(2)), 2);\n\n      /* Process high 8 bytes */\n      near_hi = _mm_unpackhi_epi8(near_b, zero);\n      far_hi  = _mm_unpackhi_epi8(far_b, zero);\n      sum_hi  = _mm_add_epi16(_mm_add_epi16(near_hi, _mm_slli_epi16(near_hi, 1)), far_hi);\n      sum_hi  = _mm_srli_epi16(_mm_add_epi16(sum_hi, _mm_set1_epi16(2)), 2);\n\n      _mm_storeu_si128((__m128i*)(out + i), _mm_packus_epi16(sum_lo, sum_hi));\n   }\n#elif defined(RJPEG_NEON)\n   for (; i + 7 < w; i += 8)\n   {\n      uint8x8_t near_b = vld1_u8(in_near + i);\n      uint8x8_t far_b  = vld1_u8(in_far  + i);\n      uint16x8_t near_w = vmovl_u8(near_b);\n      uint16x8_t far_w  = vmovl_u8(far_b);\n      /* 3*near + far + 2, then >> 2 */\n      uint16x8_t sum = vaddq_u16(vaddq_u16(near_w, vshlq_n_u16(near_w, 1)), far_w);\n      sum = vshrq_n_u16(vaddq_u16(sum, vdupq_n_u16(2)), 2);\n      vst1_u8(out + i, vmovn_u16(sum));\n   }\n#endif\n\n   for (; i < w; ++i)\n      out[i] = RJPEG_DIV4(3*in_near[i] + in_far[i] + 2);\n   return out;\n}\n\nstatic uint8_t*  rjpeg_resample_row_h_2(uint8_t *out, uint8_t *in_near,\n      uint8_t *in_far, int w, int hs)\n{\n   /* need to generate two samples horizontally for every one in input */\n   int i;\n   uint8_t *input = in_near;\n\n   if (w == 1)\n   {\n      /* if only one sample, can't do any interpolation */\n      out[0] = out[1] = input[0];\n      return out;\n   }\n\n   out[0] = input[0];\n   out[1] = RJPEG_DIV4(input[0]*3 + input[1] + 2);\n\n   i = 1;\n\n#if defined(__SSE2__)\n   /* Process 8 input pixels at a time -> 16 output pixels.\n    * For each input pixel i:\n    *   out[i*2+0] = (3*input[i] + input[i-1] + 2) >> 2\n    *   out[i*2+1] = (3*input[i] + input[i+1] + 2) >> 2\n    */\n   for (; i + 8 < w - 1; i += 8)\n   {\n      __m128i zero, bias, cur, prev, next;\n      __m128i cur_w, prev_w, next_w;\n      __m128i base, even, odd, lo, hi, result;\n\n      zero = _mm_setzero_si128();\n      bias = _mm_set1_epi16(2);\n\n      cur  = _mm_loadl_epi64((const __m128i*)(input + i));\n      prev = _mm_loadl_epi64((const __m128i*)(input + i - 1));\n      next = _mm_loadl_epi64((const __m128i*)(input + i + 1));\n\n      cur_w  = _mm_unpacklo_epi8(cur, zero);\n      prev_w = _mm_unpacklo_epi8(prev, zero);\n      next_w = _mm_unpacklo_epi8(next, zero);\n\n      /* 3*cur + 2 */\n      base = _mm_add_epi16(_mm_add_epi16(cur_w, _mm_slli_epi16(cur_w, 1)), bias);\n      even = _mm_srli_epi16(_mm_add_epi16(base, prev_w), 2);\n      odd  = _mm_srli_epi16(_mm_add_epi16(base, next_w), 2);\n\n      /* Interleave even/odd into output */\n      lo = _mm_unpacklo_epi16(even, odd);\n      hi = _mm_unpackhi_epi16(even, odd);\n      /* Pack back to bytes */\n      result = _mm_packus_epi16(lo, hi);\n      _mm_storeu_si128((__m128i*)(out + i * 2), result);\n   }\n#elif defined(RJPEG_NEON)\n   for (; i + 8 < w - 1; i += 8)\n   {\n      uint8x8_t cur  = vld1_u8(input + i);\n      uint8x8_t prev = vld1_u8(input + i - 1);\n      uint8x8_t next = vld1_u8(input + i + 1);\n\n      uint16x8_t cur_w  = vmovl_u8(cur);\n      uint16x8_t prev_w = vmovl_u8(prev);\n      uint16x8_t next_w = vmovl_u8(next);\n\n      /* 3*cur + 2 */\n      uint16x8_t base = vaddq_u16(vaddq_u16(cur_w, vshlq_n_u16(cur_w, 1)),\n                                  vdupq_n_u16(2));\n      uint16x8_t even = vshrq_n_u16(vaddq_u16(base, prev_w), 2);\n      uint16x8_t odd  = vshrq_n_u16(vaddq_u16(base, next_w), 2);\n\n      /* Interleave even/odd */\n      uint8x8x2_t o;\n      o.val[0] = vmovn_u16(even);\n      o.val[1] = vmovn_u16(odd);\n      vst2_u8(out + i * 2, o);\n   }\n#endif\n\n   for (; i < w-1; ++i)\n   {\n      int n      = 3 * input[i] + 2;\n      out[i*2+0] = RJPEG_DIV4(n+input[i-1]);\n      out[i*2+1] = RJPEG_DIV4(n+input[i+1]);\n   }\n   out[i*2+0] = RJPEG_DIV4(input[w-1]*3 + input[w-2] + 2);\n   out[i*2+1] = input[w-1];\n\n   (void)in_far;\n   (void)hs;\n\n   return out;\n}\n\nstatic uint8_t *rjpeg_resample_row_hv_2(uint8_t *out, uint8_t *in_near,\n      uint8_t *in_far, int w, int hs)\n{\n   /* need to generate 2x2 samples for every one in input */\n   int i,t0,t1;\n   if (w == 1)\n   {\n      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1     = 3*in_near[0] + in_far[0];\n   out[0] = RJPEG_DIV4(t1+2);\n\n   for (i = 1; i < w; ++i)\n   {\n      t0         = t1;\n      t1         = 3*in_near[i]+in_far[i];\n      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);\n      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = RJPEG_DIV4(t1+2);\n\n   (void)hs;\n\n   return out;\n}\n\n#if defined(__SSE2__) || defined(RJPEG_NEON)\nstatic uint8_t *rjpeg_resample_row_hv_2_simd(uint8_t *out, uint8_t *in_near,\n      uint8_t *in_far, int w, int hs)\n{\n   /* need to generate 2x2 samples for every one in input */\n   int i = 0,t0,t1;\n\n   if (w == 1)\n   {\n      out[0] = out[1] = RJPEG_DIV4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   /* process groups of 8 pixels for as long as we can.\n    * note we can't handle the last pixel in a row in this loop\n    * because we need to handle the filter boundary conditions.\n    */\n   for (; i < ((w-1) & ~7); i += 8)\n   {\n#if defined(__SSE2__)\n      /* load and perform the vertical filtering pass\n       * this uses 3*x + y = 4*x + (y - x) */\n      __m128i zero, farb, nearb, farw, nearw, diff, nears, curr;\n      __m128i prv0, nxt0, prev, next;\n      __m128i bias, curs, prvd, nxtd, curb, even, odd;\n      __m128i int0, int1, de0, de1, outv;\n\n      zero  = _mm_setzero_si128();\n      farb  = _mm_loadl_epi64((__m128i *) (in_far + i));\n      nearb = _mm_loadl_epi64((__m128i *) (in_near + i));\n      farw  = _mm_unpacklo_epi8(farb, zero);\n      nearw = _mm_unpacklo_epi8(nearb, zero);\n      diff  = _mm_sub_epi16(farw, nearw);\n      nears = _mm_slli_epi16(nearw, 2);\n      curr  = _mm_add_epi16(nears, diff); /* current row */\n\n      /* horizontal filter works the same based on shifted vers of current\n       * row. \"prev\" is current row shifted right by 1 pixel; we need to\n       * insert the previous pixel value (from t1).\n       * \"next\" is current row shifted left by 1 pixel, with first pixel\n       * of next block of 8 pixels added in.\n       */\n      prv0 = _mm_slli_si128(curr, 2);\n      nxt0 = _mm_srli_si128(curr, 2);\n      prev = _mm_insert_epi16(prv0, t1, 0);\n      next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);\n\n      /* horizontal filter, polyphase implementation since it's convenient:\n       * even pixels = 3*cur + prev = cur*4 + (prev - cur)\n       * odd  pixels = 3*cur + next = cur*4 + (next - cur)\n       * note the shared term. */\n      bias = _mm_set1_epi16(8);\n      curs = _mm_slli_epi16(curr, 2);\n      prvd = _mm_sub_epi16(prev, curr);\n      nxtd = _mm_sub_epi16(next, curr);\n      curb = _mm_add_epi16(curs, bias);\n      even = _mm_add_epi16(prvd, curb);\n      odd  = _mm_add_epi16(nxtd, curb);\n\n      /* interleave even and odd pixels, then undo scaling. */\n      int0 = _mm_unpacklo_epi16(even, odd);\n      int1 = _mm_unpackhi_epi16(even, odd);\n      de0  = _mm_srli_epi16(int0, 4);\n      de1  = _mm_srli_epi16(int1, 4);\n\n      /* pack and write output */\n      outv = _mm_packus_epi16(de0, de1);\n      _mm_storeu_si128((__m128i *) (out + i*2), outv);\n#elif defined(RJPEG_NEON)\n      /* load and perform the vertical filtering pass\n       * this uses 3*x + y = 4*x + (y - x) */\n      uint8x8_t farb  = vld1_u8(in_far + i);\n      uint8x8_t nearb = vld1_u8(in_near + i);\n      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));\n      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));\n      int16x8_t curr  = vaddq_s16(nears, diff); /* current row */\n\n      /* horizontal filter works the same based on shifted vers of current\n       * row. \"prev\" is current row shifted right by 1 pixel; we need to\n       * insert the previous pixel value (from t1).\n       * \"next\" is current row shifted left by 1 pixel, with first pixel\n       * of next block of 8 pixels added in. */\n      int16x8_t prv0 = vextq_s16(curr, curr, 7);\n      int16x8_t nxt0 = vextq_s16(curr, curr, 1);\n      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);\n      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);\n\n      /* horizontal filter, polyphase implementation since it's convenient:\n       * even pixels = 3*cur + prev = cur*4 + (prev - cur)\n       * odd  pixels = 3*cur + next = cur*4 + (next - cur)\n       * note the shared term.\n       */\n      int16x8_t curs = vshlq_n_s16(curr, 2);\n      int16x8_t prvd = vsubq_s16(prev, curr);\n      int16x8_t nxtd = vsubq_s16(next, curr);\n      int16x8_t even = vaddq_s16(curs, prvd);\n      int16x8_t odd  = vaddq_s16(curs, nxtd);\n\n      /* undo scaling and round, then store with even/odd phases interleaved */\n      uint8x8x2_t o;\n      o.val[0] = vqrshrun_n_s16(even, 4);\n      o.val[1] = vqrshrun_n_s16(odd,  4);\n      vst2_u8(out + i*2, o);\n#endif\n\n      /* \"previous\" value for next iteration */\n      t1 = 3*in_near[i+7] + in_far[i+7];\n   }\n\n   t0       = t1;\n   t1       = 3*in_near[i] + in_far[i];\n   out[i*2] = RJPEG_DIV16(3*t1 + t0 + 8);\n\n   for (++i; i < w; ++i)\n   {\n      t0         = t1;\n      t1         = 3*in_near[i]+in_far[i];\n      out[i*2-1] = RJPEG_DIV16(3*t0 + t1 + 8);\n      out[i*2  ] = RJPEG_DIV16(3*t1 + t0 + 8);\n   }\n   out[w*2-1]    = RJPEG_DIV4(t1+2);\n\n   (void)hs;\n\n   return out;\n}\n#endif\n\nstatic uint8_t *rjpeg_resample_row_generic(uint8_t *out,\n      uint8_t *in_near, uint8_t *in_far, int w, int hs)\n{\n   /* resample with nearest-neighbor */\n   int i,j;\n   (void)in_far;\n\n   for (i = 0; i < w; ++i)\n      for (j = 0; j < hs; ++j)\n         out[i*hs+j] = in_near[i];\n   return out;\n}\n\n/* this is a reduced-precision calculation of YCbCr-to-RGB introduced\n * to make sure the code produces the same results in both SIMD and scalar */\n#ifndef FLOAT2FIXED\n#define FLOAT2FIXED(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)\n#endif\n\n/* Scalar YCbCr -> RGBA8888 (BGRA byte order) or RGBA (RGBA byte order).\n *\n * Byte order is selected by supports_rgba:\n *   false -> out[0..3] = B,G,R,0xff  (reads as ARGB32 on LE; default)\n *   true  -> out[0..3] = R,G,B,0xff  (reads as ABGR32 on LE; needed by\n *                                     GLES drivers without BGRA8888)\n *\n * The branch is hoisted out of the loop: two tight loops rather than\n * per-pixel branching. Matches rpng's pattern. */\nstatic void rjpeg_YCbCr_to_RGB_row(uint8_t *out, const uint8_t *y,\n      const uint8_t *pcb, const uint8_t *pcr, int count, int step,\n      bool supports_rgba)\n{\n   int i;\n   if (supports_rgba)\n   {\n      for (i = 0; i < count; ++i)\n      {\n         int y_fixed = (y[i] << 20) + (1<<19); /* rounding */\n         int cr = pcr[i] - 128;\n         int cb = pcb[i] - 128;\n         int r = y_fixed +  cr* FLOAT2FIXED(1.40200f);\n         int g = y_fixed + (cr*-FLOAT2FIXED(0.71414f)) + ((cb*-FLOAT2FIXED(0.34414f)) & 0xffff0000);\n         int b = y_fixed                               +   cb* FLOAT2FIXED(1.77200f);\n         r >>= 20;\n         g >>= 20;\n         b >>= 20;\n         if ((unsigned) r > 255)\n            r = (r < 0) ? 0 : 255;\n         if ((unsigned) g > 255)\n            g = (g < 0) ? 0 : 255;\n         if ((unsigned) b > 255)\n            b = (b < 0) ? 0 : 255;\n         out[0] = (uint8_t)r;\n         out[1] = (uint8_t)g;\n         out[2] = (uint8_t)b;\n         out[3] = 255;\n         out += step;\n      }\n   }\n   else\n   {\n      for (i = 0; i < count; ++i)\n      {\n         int y_fixed = (y[i] << 20) + (1<<19); /* rounding */\n         int cr = pcr[i] - 128;\n         int cb = pcb[i] - 128;\n         int r = y_fixed +  cr* FLOAT2FIXED(1.40200f);\n         int g = y_fixed + (cr*-FLOAT2FIXED(0.71414f)) + ((cb*-FLOAT2FIXED(0.34414f)) & 0xffff0000);\n         int b = y_fixed                               +   cb* FLOAT2FIXED(1.77200f);\n         r >>= 20;\n         g >>= 20;\n         b >>= 20;\n         if ((unsigned) r > 255)\n            r = (r < 0) ? 0 : 255;\n         if ((unsigned) g > 255)\n            g = (g < 0) ? 0 : 255;\n         if ((unsigned) b > 255)\n            b = (b < 0) ? 0 : 255;\n         /* BGRA byte order -- reads as ARGB32 on LE. */\n         out[0] = (uint8_t)b;\n         out[1] = (uint8_t)g;\n         out[2] = (uint8_t)r;\n         out[3] = 255;\n         out += step;\n      }\n   }\n}\n\n#if defined(__SSE2__) || defined(RJPEG_NEON)\nstatic void rjpeg_YCbCr_to_RGB_simd(uint8_t *out, const uint8_t *y,\n      const uint8_t *pcb, const uint8_t *pcr, int count, int step,\n      bool supports_rgba)\n{\n   int i = 0;\n\n#if defined(__SSE2__)\n   /* step == 3 is pretty ugly on the final interleave, and i'm not convinced\n    * it's useful in practice (you wouldn't use it for textures, for example).\n    * so just accelerate step == 4 case.\n    */\n   if (step == 4)\n   {\n      /* this is a fairly straightforward implementation and not super-optimized. */\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias    = _mm_set1_epi8((char) (unsigned char) 128);\n      __m128i xw        = _mm_set1_epi16(255); /* alpha channel */\n\n      for (; i+7 < count; i += 8)\n      {\n         /* load */\n         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));\n         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));\n         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));\n         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); /* -128 */\n         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); /* -128 */\n\n         /* unpack to short (and left-shift cr, cb by 8) */\n         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);\n         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);\n         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);\n\n         /* color transform */\n         __m128i yws = _mm_srli_epi16(yw, 4);\n         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);\n         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);\n         __m128i rws = _mm_add_epi16(cr0, yws);\n         __m128i gwt = _mm_add_epi16(cb0, yws);\n         __m128i bws = _mm_add_epi16(yws, cb1);\n         __m128i gws = _mm_add_epi16(gwt, cr1);\n\n         /* descale */\n         __m128i rw = _mm_srai_epi16(rws, 4);\n         __m128i bw = _mm_srai_epi16(bws, 4);\n         __m128i gw = _mm_srai_epi16(gws, 4);\n\n         /* Back to byte, set up for transpose. The first pack decides\n          * whether R or B goes into the low position of each output pixel:\n          *   packus(bw, rw) -> BGRA byte order (ARGB32 on LE)\n          *   packus(rw, bw) -> RGBA byte order (ABGR32 on LE, supports_rgba)\n          * The rest of the unpack cascade is identical either way. */\n         __m128i brb = supports_rgba\n            ? _mm_packus_epi16(rw, bw)\n            : _mm_packus_epi16(bw, rw);\n         __m128i gxb = _mm_packus_epi16(gw, xw);\n\n         /* transpose to interleave channels */\n         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);\n         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);\n         __m128i o0 = _mm_unpacklo_epi16(t0, t1);\n         __m128i o1 = _mm_unpackhi_epi16(t0, t1);\n\n         /* store */\n         _mm_storeu_si128((__m128i *) (out + 0), o0);\n         _mm_storeu_si128((__m128i *) (out + 16), o1);\n         out += 32;\n      }\n   }\n#endif\n\n#ifdef RJPEG_NEON\n   /* in this version, step=3 support would be easy to add. but is there demand? */\n   if (step == 4)\n   {\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i+7 < count; i += 8)\n      {\n         uint8x8x4_t o;\n\n         /* load */\n         uint8x8_t y_bytes  = vld1_u8(y + i);\n         uint8x8_t cr_bytes = vld1_u8(pcr + i);\n         uint8x8_t cb_bytes = vld1_u8(pcb + i);\n         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));\n         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));\n\n         /* expand to s16 */\n         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));\n         int16x8_t crw = vshll_n_s8(cr_biased, 7);\n         int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n         /* color transform */\n         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n         int16x8_t rws = vaddq_s16(yws, cr0);\n         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);\n         int16x8_t bws = vaddq_s16(yws, cb1);\n\n         /* Undo scaling, round, convert to byte. vst4_u8 interleaves\n          * val[0..3] into successive output bytes; whichever of R/B\n          * we put into val[0] becomes the pixel's low byte:\n          *   val[0]=b, val[2]=r -> BGRA byte order (ARGB32 on LE)\n          *   val[0]=r, val[2]=b -> RGBA byte order (ABGR32 on LE, supports_rgba)\n          * val[1]=g and val[3]=alpha are invariant. */\n         if (supports_rgba)\n         {\n            o.val[0] = vqrshrun_n_s16(rws, 4);\n            o.val[2] = vqrshrun_n_s16(bws, 4);\n         }\n         else\n         {\n            o.val[0] = vqrshrun_n_s16(bws, 4);\n            o.val[2] = vqrshrun_n_s16(rws, 4);\n         }\n         o.val[1] = vqrshrun_n_s16(gws, 4);\n         o.val[3] = vdup_n_u8(255);\n\n         /* store, interleaving low/1/2/alpha */\n         vst4_u8(out, o);\n         out += 8*4;\n      }\n   }\n#endif\n\n   /* Scalar tail for the remaining pixels the SIMD loop couldn't\n    * consume: count%8 at step==4, or step!=4, or the whole row in\n    * rgba mode on NEON where the SIMD loop was skipped entirely.\n    * Delegating to the scalar kernel keeps the two paths bit-identical\n    * and honours supports_rgba without duplicating the branch here. */\n   if (i < count)\n      rjpeg_YCbCr_to_RGB_row(out, y + i, pcb + i, pcr + i,\n            count - i, step, supports_rgba);\n}\n#endif\n\n/* -----------------------------------------------------------------------\n * Fused chroma upsample (hv_2) + YCbCr→BGRA\n *\n * Eliminates the linebuf write+read round-trip (~7.7 KB/row at 1080p)\n * by keeping upsampled chroma values in SIMD registers and feeding\n * them directly to the color transform math.\n *\n * Input:  Y row (out_w pixels), Cb/Cr near+far rows (chroma_w pixels each)\n * Output: BGRA row (out_w * 4 bytes)\n *\n * The chroma upsample logic is identical to resample_row_hv_2_simd:\n *   vert:  curr = 4*near + (far - near)    [per 8 chroma pixels]\n *   horiz: even = 3*curr + prev, odd = 3*curr + next, both >> 4\n * But instead of packing to uint8 and storing, we keep the int16\n * values and feed them straight into the YCbCr→RGB color math.\n * ----------------------------------------------------------------------- */\n\n/* Scalar fallback: performs hv_2 upsample + YCbCr→BGRA without SIMD.\n * Calls the existing scalar resample + color convert functions directly\n * through a stack buffer, guaranteeing bit-exact output. */\nstatic void rjpeg_upsample_YCbCr_to_BGRA_row(uint8_t *out, const uint8_t *y_row,\n      uint8_t *cb_near, uint8_t *cb_far,\n      uint8_t *cr_near, uint8_t *cr_far,\n      int chroma_w, int out_w, bool supports_rgba)\n{\n   /* Stack buffers for upsampled chroma (chroma_w*2 output pixels).\n    * For typical RetroArch images, chroma_w <= 960 so 1920 bytes each. */\n   uint8_t cb_buf[1920], cr_buf[1920];\n\n   rjpeg_resample_row_hv_2(cb_buf, cb_near, cb_far, chroma_w, 2);\n   rjpeg_resample_row_hv_2(cr_buf, cr_near, cr_far, chroma_w, 2);\n   rjpeg_YCbCr_to_RGB_row(out, y_row, cb_buf, cr_buf, out_w, 4, supports_rgba);\n}\n\n#if defined(__SSE2__) || defined(RJPEG_NEON)\nstatic void rjpeg_upsample_YCbCr_to_BGRA_simd(uint8_t *out, const uint8_t *y_row,\n      uint8_t *cb_near, uint8_t *cb_far,\n      uint8_t *cr_near, uint8_t *cr_far,\n      int chroma_w, int out_w, bool supports_rgba)\n{\n   int i = 0, px = 0;\n   int cb_carry = 3 * cb_near[0] + cb_far[0];\n   int cr_carry = 3 * cr_near[0] + cr_far[0];\n\n#if defined(__SSE2__)\n   {\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias    = _mm_set1_epi8((char)(unsigned char)128);\n      __m128i xw        = _mm_set1_epi16(255);\n      __m128i bias16    = _mm_set1_epi16(8);\n      __m128i zero      = _mm_setzero_si128();\n\n      for (; i < ((chroma_w - 1) & ~7); i += 8, px += 16)\n      {\n         __m128i cb_farb, cb_nearb, cb_farw, cb_nearw, cb_diff, cb_nears, cb_curr;\n         __m128i cr_farb, cr_nearb, cr_farw, cr_nearw, cr_diff, cr_nears, cr_curr;\n         __m128i cb_prv0, cb_nxt0, cb_prev, cb_next, cb_curs, cb_prvd, cb_nxtd, cb_curb, cb_even, cb_odd;\n         __m128i cr_prv0, cr_nxt0, cr_prev, cr_next, cr_curs, cr_prvd, cr_nxtd, cr_curb, cr_even, cr_odd;\n\n         /* ---- Vertical filter: curr = 4*near + (far - near) ---- */\n         cb_farb  = _mm_loadl_epi64((__m128i*)(cb_far + i));\n         cb_nearb = _mm_loadl_epi64((__m128i*)(cb_near + i));\n         cb_farw  = _mm_unpacklo_epi8(cb_farb, zero);\n         cb_nearw = _mm_unpacklo_epi8(cb_nearb, zero);\n         cb_diff  = _mm_sub_epi16(cb_farw, cb_nearw);\n         cb_nears = _mm_slli_epi16(cb_nearw, 2);\n         cb_curr  = _mm_add_epi16(cb_nears, cb_diff);\n\n         cr_farb  = _mm_loadl_epi64((__m128i*)(cr_far + i));\n         cr_nearb = _mm_loadl_epi64((__m128i*)(cr_near + i));\n         cr_farw  = _mm_unpacklo_epi8(cr_farb, zero);\n         cr_nearw = _mm_unpacklo_epi8(cr_nearb, zero);\n         cr_diff  = _mm_sub_epi16(cr_farw, cr_nearw);\n         cr_nears = _mm_slli_epi16(cr_nearw, 2);\n         cr_curr  = _mm_add_epi16(cr_nears, cr_diff);\n\n         /* ---- Horizontal filter ---- */\n         cb_prv0 = _mm_slli_si128(cb_curr, 2);\n         cb_nxt0 = _mm_srli_si128(cb_curr, 2);\n         cb_prev = _mm_insert_epi16(cb_prv0, cb_carry, 0);\n         cb_next = _mm_insert_epi16(cb_nxt0, 3*cb_near[i+8]+cb_far[i+8], 7);\n\n         cr_prv0 = _mm_slli_si128(cr_curr, 2);\n         cr_nxt0 = _mm_srli_si128(cr_curr, 2);\n         cr_prev = _mm_insert_epi16(cr_prv0, cr_carry, 0);\n         cr_next = _mm_insert_epi16(cr_nxt0, 3*cr_near[i+8]+cr_far[i+8], 7);\n\n         cb_curs = _mm_slli_epi16(cb_curr, 2);\n         cb_prvd = _mm_sub_epi16(cb_prev, cb_curr);\n         cb_nxtd = _mm_sub_epi16(cb_next, cb_curr);\n         cb_curb = _mm_add_epi16(cb_curs, bias16);\n         cb_even = _mm_add_epi16(cb_prvd, cb_curb);\n         cb_odd  = _mm_add_epi16(cb_nxtd, cb_curb);\n\n         cr_curs = _mm_slli_epi16(cr_curr, 2);\n         cr_prvd = _mm_sub_epi16(cr_prev, cr_curr);\n         cr_nxtd = _mm_sub_epi16(cr_next, cr_curr);\n         cr_curb = _mm_add_epi16(cr_curs, bias16);\n         cr_even = _mm_add_epi16(cr_prvd, cr_curb);\n         cr_odd  = _mm_add_epi16(cr_nxtd, cr_curb);\n\n         /* Pack upsampled chroma to uint8 (16 pixels each).\n          * cb_bytes_16[0..7] = first 8 output pixels, [8..15] = second 8. */\n         {\n            __m128i int0, int1, de0, de1;\n            __m128i cb_bytes_16, cr_bytes_16;\n            __m128i y_all, yb_lo, yb_hi;\n            __m128i cb_lo, cb_hi, cr_lo, cr_hi;\n            __m128i cb_biased, cr_biased;\n            __m128i yw, crw, cbw, yws;\n            __m128i cr0, cb0, cb1, cr1, rws, gws, bws;\n            __m128i rw, gw, bw, brb, gxb, t0, t1, o0, o1;\n\n            /* Cb: interleave even/odd, descale, pack */\n            int0 = _mm_unpacklo_epi16(cb_even, cb_odd);\n            int1 = _mm_unpackhi_epi16(cb_even, cb_odd);\n            de0  = _mm_srli_epi16(int0, 4);\n            de1  = _mm_srli_epi16(int1, 4);\n            cb_bytes_16 = _mm_packus_epi16(de0, de1);\n\n            /* Cr: interleave even/odd, descale, pack */\n            int0 = _mm_unpacklo_epi16(cr_even, cr_odd);\n            int1 = _mm_unpackhi_epi16(cr_even, cr_odd);\n            de0  = _mm_srli_epi16(int0, 4);\n            de1  = _mm_srli_epi16(int1, 4);\n            cr_bytes_16 = _mm_packus_epi16(de0, de1);\n\n            /* Load all 16 Y bytes at once */\n            y_all = _mm_loadu_si128((__m128i*)(y_row + px));\n\n            /* ---- Pixels 0-7 (low halves) ---- */\n            yb_lo = y_all; /* low 8 bytes used by unpacklo */\n            cb_lo = cb_bytes_16;\n            cr_lo = cr_bytes_16;\n\n            cb_biased = _mm_xor_si128(cb_lo, signflip);\n            cr_biased = _mm_xor_si128(cr_lo, signflip);\n\n            yw  = _mm_unpacklo_epi8(y_bias, yb_lo);\n            crw = _mm_unpacklo_epi8(zero, cr_biased);\n            cbw = _mm_unpacklo_epi8(zero, cb_biased);\n\n            yws = _mm_srli_epi16(yw, 4);\n            cr0 = _mm_mulhi_epi16(cr_const0, crw);\n            cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n            cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n            cr1 = _mm_mulhi_epi16(crw, cr_const1);\n            rws = _mm_add_epi16(cr0, yws);\n            gws = _mm_add_epi16(_mm_add_epi16(cb0, yws), cr1);\n            bws = _mm_add_epi16(yws, cb1);\n\n            rw  = _mm_srai_epi16(rws, 4);\n            bw  = _mm_srai_epi16(bws, 4);\n            gw  = _mm_srai_epi16(gws, 4);\n\n            /* Swap pack arg order when emitting RGBA byte order; see\n             * rjpeg_YCbCr_to_RGB_simd for the reasoning. */\n            brb = supports_rgba\n               ? _mm_packus_epi16(rw, bw)\n               : _mm_packus_epi16(bw, rw);\n            gxb = _mm_packus_epi16(gw, xw);\n\n            t0 = _mm_unpacklo_epi8(brb, gxb);\n            t1 = _mm_unpackhi_epi8(brb, gxb);\n            o0 = _mm_unpacklo_epi16(t0, t1);\n            o1 = _mm_unpackhi_epi16(t0, t1);\n\n            _mm_storeu_si128((__m128i*)(out + px*4),      o0);\n            _mm_storeu_si128((__m128i*)(out + px*4 + 16), o1);\n\n            /* ---- Pixels 8-15 (high halves) ---- */\n            yb_hi = _mm_srli_si128(y_all, 8);\n            cb_hi = _mm_srli_si128(cb_bytes_16, 8);\n            cr_hi = _mm_srli_si128(cr_bytes_16, 8);\n\n            cb_biased = _mm_xor_si128(cb_hi, signflip);\n            cr_biased = _mm_xor_si128(cr_hi, signflip);\n\n            yw  = _mm_unpacklo_epi8(y_bias, yb_hi);\n            crw = _mm_unpacklo_epi8(zero, cr_biased);\n            cbw = _mm_unpacklo_epi8(zero, cb_biased);\n\n            yws = _mm_srli_epi16(yw, 4);\n            cr0 = _mm_mulhi_epi16(cr_const0, crw);\n            cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n            cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n            cr1 = _mm_mulhi_epi16(crw, cr_const1);\n            rws = _mm_add_epi16(cr0, yws);\n            gws = _mm_add_epi16(_mm_add_epi16(cb0, yws), cr1);\n            bws = _mm_add_epi16(yws, cb1);\n\n            rw  = _mm_srai_epi16(rws, 4);\n            bw  = _mm_srai_epi16(bws, 4);\n            gw  = _mm_srai_epi16(gws, 4);\n\n            brb = supports_rgba\n               ? _mm_packus_epi16(rw, bw)\n               : _mm_packus_epi16(bw, rw);\n            gxb = _mm_packus_epi16(gw, xw);\n\n            t0 = _mm_unpacklo_epi8(brb, gxb);\n            t1 = _mm_unpackhi_epi8(brb, gxb);\n            o0 = _mm_unpacklo_epi16(t0, t1);\n            o1 = _mm_unpackhi_epi16(t0, t1);\n\n            _mm_storeu_si128((__m128i*)(out + (px+8)*4),      o0);\n            _mm_storeu_si128((__m128i*)(out + (px+8)*4 + 16), o1);\n         }\n\n         cb_carry = 3*cb_near[i+7] + cb_far[i+7];\n         cr_carry = 3*cr_near[i+7] + cr_far[i+7];\n      }\n   }\n#endif\n\n#ifdef RJPEG_NEON\n   {\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i < ((chroma_w - 1) & ~7); i += 8, px += 16)\n      {\n         /* Vertical filter */\n         uint8x8_t cb_farb  = vld1_u8(cb_far + i);\n         uint8x8_t cb_nearb = vld1_u8(cb_near + i);\n         int16x8_t cb_diff  = vreinterpretq_s16_u16(vsubl_u8(cb_farb, cb_nearb));\n         int16x8_t cb_nears = vreinterpretq_s16_u16(vshll_n_u8(cb_nearb, 2));\n         int16x8_t cb_curr  = vaddq_s16(cb_nears, cb_diff);\n\n         uint8x8_t cr_farb  = vld1_u8(cr_far + i);\n         uint8x8_t cr_nearb = vld1_u8(cr_near + i);\n         int16x8_t cr_diff  = vreinterpretq_s16_u16(vsubl_u8(cr_farb, cr_nearb));\n         int16x8_t cr_nears = vreinterpretq_s16_u16(vshll_n_u8(cr_nearb, 2));\n         int16x8_t cr_curr  = vaddq_s16(cr_nears, cr_diff);\n\n         /* Horizontal filter */\n         int16x8_t cb_prv0 = vextq_s16(cb_curr, cb_curr, 7);\n         int16x8_t cb_nxt0 = vextq_s16(cb_curr, cb_curr, 1);\n         int16x8_t cb_prev = vsetq_lane_s16(cb_carry, cb_prv0, 0);\n         int16x8_t cb_next = vsetq_lane_s16(3*cb_near[i+8]+cb_far[i+8], cb_nxt0, 7);\n\n         int16x8_t cr_prv0 = vextq_s16(cr_curr, cr_curr, 7);\n         int16x8_t cr_nxt0 = vextq_s16(cr_curr, cr_curr, 1);\n         int16x8_t cr_prev = vsetq_lane_s16(cr_carry, cr_prv0, 0);\n         int16x8_t cr_next = vsetq_lane_s16(3*cr_near[i+8]+cr_far[i+8], cr_nxt0, 7);\n\n         int16x8_t cb_curs = vshlq_n_s16(cb_curr, 2);\n         int16x8_t cb_even = vaddq_s16(cb_curs, vsubq_s16(cb_prev, cb_curr));\n         int16x8_t cb_odd  = vaddq_s16(cb_curs, vsubq_s16(cb_next, cb_curr));\n\n         int16x8_t cr_curs = vshlq_n_s16(cr_curr, 2);\n         int16x8_t cr_even = vaddq_s16(cr_curs, vsubq_s16(cr_prev, cr_curr));\n         int16x8_t cr_odd  = vaddq_s16(cr_curs, vsubq_s16(cr_next, cr_curr));\n\n         /* Pack to uint8, interleaved even/odd */\n         uint8x8x2_t cb_packed, cr_packed;\n         cb_packed.val[0] = vqrshrun_n_s16(cb_even, 4);\n         cb_packed.val[1] = vqrshrun_n_s16(cb_odd, 4);\n         cr_packed.val[0] = vqrshrun_n_s16(cr_even, 4);\n         cr_packed.val[1] = vqrshrun_n_s16(cr_odd, 4);\n\n         /* Process two batches of 8 output pixels */\n         {\n            int j;\n            uint8_t cb_tmp[16], cr_tmp[16];\n            vst2_u8(cb_tmp, cb_packed);\n            vst2_u8(cr_tmp, cr_packed);\n\n            for (j = 0; j < 2; ++j)\n            {\n               uint8x8_t yb  = vld1_u8(y_row + px + j*8);\n               uint8x8_t cbb = vld1_u8(cb_tmp + j*8);\n               uint8x8_t crb = vld1_u8(cr_tmp + j*8);\n\n               int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cbb, signflip));\n               int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(crb, signflip));\n\n               int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(yb, 4));\n               int16x8_t crw = vshll_n_s8(cr_biased, 7);\n               int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n               int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n               int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n               int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n               int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n\n               /* Match rjpeg_YCbCr_to_RGB_simd: val[0]<->val[2] swap\n                * selects the output byte order. B goes into the\n                * (y + cb1) slot and R into (y + cr0) regardless;\n                * only which output lane they land in changes. */\n               uint8x8x4_t o;\n               if (supports_rgba)\n               {\n                  o.val[0] = vqrshrun_n_s16(vaddq_s16(yws, cr0), 4);\n                  o.val[2] = vqrshrun_n_s16(vaddq_s16(yws, cb1), 4);\n               }\n               else\n               {\n                  o.val[0] = vqrshrun_n_s16(vaddq_s16(yws, cb1), 4);\n                  o.val[2] = vqrshrun_n_s16(vaddq_s16(yws, cr0), 4);\n               }\n               o.val[1] = vqrshrun_n_s16(vaddq_s16(vaddq_s16(yws, cb0), cr1), 4);\n               o.val[3] = vdup_n_u8(255);\n\n               vst4_u8(out + (px + j*8)*4, o);\n            }\n         }\n\n         cb_carry = 3*cb_near[i+7] + cb_far[i+7];\n         cr_carry = 3*cr_near[i+7] + cr_far[i+7];\n      }\n   }\n#endif\n\n   /* Scalar tail: upsample remaining chroma into a stack buffer,\n    * then call the standard color convert function for bit-exact output. */\n   if (i < chroma_w)\n   {\n      int tail_out = out_w - px;\n      if (tail_out > 0)\n      {\n         uint8_t cb_buf[256], cr_buf[256];\n         int j, op = 0;\n         int cb_t0 = cb_carry;\n         int cr_t0 = cr_carry;\n         int cb_t1 = 3*cb_near[i] + cb_far[i];\n         int cr_t1 = 3*cr_near[i] + cr_far[i];\n\n         cb_buf[op] = RJPEG_DIV16(3*cb_t1 + cb_t0 + 8);\n         cr_buf[op] = RJPEG_DIV16(3*cr_t1 + cr_t0 + 8);\n         op++;\n\n         for (j = i + 1; j < chroma_w; ++j)\n         {\n            cb_t0 = cb_t1; cr_t0 = cr_t1;\n            cb_t1 = 3*cb_near[j] + cb_far[j];\n            cr_t1 = 3*cr_near[j] + cr_far[j];\n            cb_buf[op] = RJPEG_DIV16(3*cb_t0 + cb_t1 + 8);\n            cr_buf[op] = RJPEG_DIV16(3*cr_t0 + cr_t1 + 8);\n            op++;\n            cb_buf[op] = RJPEG_DIV16(3*cb_t1 + cb_t0 + 8);\n            cr_buf[op] = RJPEG_DIV16(3*cr_t1 + cr_t0 + 8);\n            op++;\n         }\n\n         cb_buf[op] = RJPEG_DIV4(cb_t1 + 2);\n         cr_buf[op] = RJPEG_DIV4(cr_t1 + 2);\n         op++;\n\n         if (tail_out > op) tail_out = op;\n         rjpeg_YCbCr_to_RGB_row(out + px*4, y_row + px,\n               cb_buf, cr_buf, tail_out, 4, supports_rgba);\n      }\n   }\n}\n#endif\n\n\n/* set up the kernels */\nstatic void rjpeg_setup_jpeg(rjpeg_jpeg *j)\n{\n   uint64_t mask = cpu_features_get();\n\n   (void)mask;\n\n   j->idct_block_kernel        = rjpeg_idct_block;\n   j->dequant_idct_block_kernel = rjpeg_dequant_idct_block;\n   j->YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_row;\n   j->resample_row_hv_2_kernel = rjpeg_resample_row_hv_2;\n   j->upsample_YCbCr_to_BGRA_kernel = rjpeg_upsample_YCbCr_to_BGRA_row;\n\n#if defined(__SSE2__)\n   if (mask & RETRO_SIMD_SSE2)\n   {\n      j->idct_block_kernel        = rjpeg_idct_simd;\n      j->dequant_idct_block_kernel = rjpeg_dequant_idct_simd;\n      j->YCbCr_to_RGB_kernel      = rjpeg_YCbCr_to_RGB_simd;\n      j->resample_row_hv_2_kernel = rjpeg_resample_row_hv_2_simd;\n      j->upsample_YCbCr_to_BGRA_kernel = rjpeg_upsample_YCbCr_to_BGRA_simd;\n   }\n#endif\n\n#ifdef RJPEG_NEON\n   j->idct_block_kernel           = rjpeg_idct_simd;\n   j->dequant_idct_block_kernel   = rjpeg_dequant_idct_neon;\n   j->YCbCr_to_RGB_kernel         = rjpeg_YCbCr_to_RGB_simd;\n   j->resample_row_hv_2_kernel    = rjpeg_resample_row_hv_2_simd;\n   j->upsample_YCbCr_to_BGRA_kernel = rjpeg_upsample_YCbCr_to_BGRA_simd;\n#endif\n}\n\n/* clean up the temporary component buffers */\nstatic void rjpeg_cleanup_jpeg(rjpeg_jpeg *j)\n{\n   int i;\n\n   /* If an arena was used, all component data/coeff pointers\n    * live inside it — free the arena and null everything. */\n   if (j->comp_arena)\n   {\n      free(j->comp_arena);\n      j->comp_arena      = NULL;\n      j->comp_arena_size = 0;\n\n      for (i = 0; i < j->img_n; ++i)\n      {\n         j->img_comp[i].raw_data  = NULL;\n         j->img_comp[i].data      = NULL;\n         j->img_comp[i].raw_coeff = NULL;\n         j->img_comp[i].coeff     = NULL;\n         j->img_comp[i].linebuf   = NULL;\n      }\n   }\n   else\n   {\n      /* Fallback: individually-allocated buffers (shouldn't happen\n       * with the arena path, but kept for safety). */\n      for (i = 0; i < j->img_n; ++i)\n      {\n         if (j->img_comp[i].raw_data)\n         {\n            free(j->img_comp[i].raw_data);\n            j->img_comp[i].raw_data = NULL;\n            j->img_comp[i].data = NULL;\n         }\n\n         if (j->img_comp[i].raw_coeff)\n         {\n            free(j->img_comp[i].raw_coeff);\n            j->img_comp[i].raw_coeff = 0;\n            j->img_comp[i].coeff = 0;\n         }\n\n         if (j->img_comp[i].linebuf)\n         {\n            free(j->img_comp[i].linebuf);\n            j->img_comp[i].linebuf = NULL;\n         }\n      }\n   }\n}\n\nstatic void rjpeg_process_free(struct rjpeg_process *proc)\n{\n   if (!proc)\n      return;\n\n   if (proc->j)\n   {\n      rjpeg_cleanup_jpeg(proc->j);\n      free(proc->j);\n   }\n\n   if (proc->output)\n      free(proc->output);\n\n   free(proc);\n}\n\n/* -----------------------------------------------------------------------\n * Iterative decode helpers\n *\n * These break the old monolithic rjpeg_decode_jpeg_image() into pieces\n * that return after bounded work, matching the rpng_iterate_image()\n * pattern so the task scheduler can yield between calls.\n *\n * Baseline (non-progressive) interleaved images (the vast majority)\n * are split into MCU-row batches: each call to rjpeg_iterate_image()\n * decodes one row of MCUs (img_mcu_x blocks × scan_n components).\n * For a 1920×1080 4:2:0 image that's ~120 MCU-rows, each taking\n * ~40-80 µs, well within any per-frame time budget.\n *\n * Progressive images and single-scan non-interleaved images still\n * complete in one iteration (the per-block granularity doesn't map\n * to a sensible yield point without major restructuring of the\n * coefficient storage walk).  This is acceptable because progressive\n * JPEGs are rare in RetroArch assets.\n * ----------------------------------------------------------------------- */\n\n/* Decode one MCU-row (j=mcu_row) of an interleaved baseline scan.\n * Returns 1 on success, 0 on error. */\nstatic int rjpeg_parse_entropy_one_mcu_row_interleaved(\n      rjpeg_jpeg *z, int mcu_row)\n{\n   int i, k, x, y;\n   RJPEG_SIMD_ALIGN(short, data[64]);\n   void (*idct_fn)(uint8_t *out, int out_stride, short data[64])\n      = z->idct_block_kernel;\n   int mcu_x  = z->img_mcu_x;\n   int scan_n = z->scan_n;\n\n   /* Zero once at the start of the row.  decode_block maintains the\n    * zero invariant via rjpeg_block_cleanup after each IDCT. */\n   memset(data, 0, 64 * sizeof(data[0]));\n\n   for (i = 0; i < mcu_x; ++i)\n   {\n      for (k = 0; k < scan_n; ++k)\n      {\n         /* Hoist all img_comp[n] fields into locals.\n          * The compiler can't do this because decode_block takes z\n          * as a pointer — the aliasing barrier forces it to reload\n          * every field through z->img_comp[n] on each iteration.\n          * These fields are constant across the block loop. */\n         int n            = z->order[k];\n         int comp_h       = z->img_comp[n].h;\n         int comp_v       = z->img_comp[n].v;\n         int comp_ha      = z->img_comp[n].ha;\n         int comp_hd      = z->img_comp[n].hd;\n         int comp_w2      = z->img_comp[n].w2;\n         uint8_t *comp_data = z->img_comp[n].data;\n         rjpeg_huffman *hdc = z->huff_dc + comp_hd;\n         rjpeg_huffman *hac = z->huff_ac + comp_ha;\n         int16_t *fac       = z->fast_ac[comp_ha];\n         uint8_t *dq        = z->dequant[z->img_comp[n].tq];\n\n         for (y = 0; y < comp_v; ++y)\n         {\n            int y2 = (mcu_row * comp_v + y) * 8;\n            for (x = 0; x < comp_h; ++x)\n            {\n               int x2 = (i * comp_h + x) * 8;\n               int k_end;\n\n               k_end = rjpeg_jpeg_decode_block(z, data,\n                        hdc, hac, fac, n, dq);\n               if (!k_end)\n                  return 0;\n\n               idct_fn(comp_data + comp_w2 * y2 + x2,\n                     comp_w2, data);\n\n               rjpeg_block_cleanup(data, k_end);\n            }\n         }\n      }\n\n      if (--z->todo <= 0)\n      {\n         if (z->code_bits < 24)\n            rjpeg_grow_buffer_unsafe(z);\n         if (!RJPEG_RESTART(z->marker))\n            return 1;\n         rjpeg_jpeg_reset(z);\n      }\n   }\n\n   return 1;\n}\n\nbool rjpeg_start(rjpeg_t *rjpeg)\n{\n   rjpeg_jpeg    *j = NULL;\n\n   if (!rjpeg || !rjpeg->buff_data)\n      return false;\n\n   /* Allocate the decode state structures */\n   j = (rjpeg_jpeg*)malloc(sizeof(*j));\n   if (!j)\n      return false;\n\n   /* Zero only fields that need init — saves zeroing ~18 KB of\n    * Huffman tables that build_huffman will fully overwrite. */\n   memset(j->img_comp, 0, sizeof(j->img_comp));\n   j->code_bits = 0; j->code_buffer = 0;\n   j->nomore = 0; j->progressive = 0;\n   j->scan_n = 0; j->eob_run = 0;\n   j->marker = RJPEG_MARKER_NONE;\n   j->restart_interval = 0; j->todo = 0;\n   j->comp_arena = NULL; j->comp_arena_size = 0;\n   j->img_n = 0;\n\n   /* Context fields embedded in j */\n   j->img_buffer          = (uint8_t*)rjpeg->buff_data;\n   j->img_buffer_original = (uint8_t*)rjpeg->buff_data;\n   j->img_buffer_end      = (uint8_t*)rjpeg->buff_data + rjpeg->buff_len;\n\n   rjpeg->iter_j    = j;\n   rjpeg->iter_state    = RJPEG_ITER_PARSE_HEADER;\n   rjpeg->iter_mcu_row  = 0;\n   rjpeg->iter_marker   = 0;\n   rjpeg->iter_started  = true;\n   rjpeg->iter_output   = NULL;\n   rjpeg->iter_out_row  = 0;\n   rjpeg->iter_resample_ready = 0;\n\n   rjpeg_setup_jpeg(j);\n\n   return true;\n}\n\nbool rjpeg_is_valid(rjpeg_t *rjpeg)\n{\n   if (!rjpeg)\n      return false;\n   /* Valid if we started and didn't error out */\n   if (!rjpeg->iter_started)\n      return false;\n   if (rjpeg->iter_state == RJPEG_ITER_ERROR)\n      return false;\n   return true;\n}\n\n/* Resample output rows from a completed MCU-row during iteration.\n * Called after each MCU-row's entropy+IDCT finishes.  Each MCU-row\n * produces vs*8 rows of component data (16 at 4:2:0); we resample\n * those rows into the BGRA output buffer.\n *\n * max_row = min(img_y, (mcu_row+1) * v_max * 8) -- clamp to image height. */\nstatic void rjpeg_iterate_resample_rows(rjpeg_t *rjpeg, unsigned max_row)\n{\n   rjpeg_jpeg *z = rjpeg->iter_j;\n   uint8_t *coutput[4];\n   int decode_n = (z->img_n >= 3) ? 3 : z->img_n;\n\n   while (rjpeg->iter_out_row < max_row)\n   {\n      int k;\n      unsigned jj  = rjpeg->iter_out_row;\n      uint8_t *out = rjpeg->iter_output + 4 * z->img_x * jj;\n\n      int use_fused = (z->img_n == 3\n            && z->upsample_YCbCr_to_BGRA_kernel\n            && decode_n >= 3\n            && rjpeg->iter_res[1].hs == 2\n            && rjpeg->iter_res[1].vs == 2);\n      int fused_y_bot1 = 0, fused_y_bot2 = 0;\n      uint8_t *fused_cb_near = NULL, *fused_cb_far = NULL;\n      uint8_t *fused_cr_near = NULL, *fused_cr_far = NULL;\n\n      if (use_fused)\n      {\n         rjpeg_resample *r1 = &rjpeg->iter_res[1];\n         rjpeg_resample *r2 = &rjpeg->iter_res[2];\n         fused_y_bot1 = r1->ystep >= (r1->vs >> 1);\n         fused_y_bot2 = r2->ystep >= (r2->vs >> 1);\n         fused_cb_near = fused_y_bot1 ? r1->line1 : r1->line0;\n         fused_cb_far  = fused_y_bot1 ? r1->line0 : r1->line1;\n         fused_cr_near = fused_y_bot2 ? r2->line1 : r2->line0;\n         fused_cr_far  = fused_y_bot2 ? r2->line0 : r2->line1;\n      }\n\n      for (k = 0; k < decode_n; ++k)\n      {\n         rjpeg_resample *r = &rjpeg->iter_res[k];\n         int y_bot = r->ystep >= (r->vs >> 1);\n\n         if (use_fused && k >= 1)\n            coutput[k] = NULL;\n         else\n            coutput[k] = r->resample(z->img_comp[k].linebuf,\n                  y_bot ? r->line1 : r->line0,\n                  y_bot ? r->line0 : r->line1,\n                  r->w_lores, r->hs);\n\n         if (++r->ystep >= r->vs)\n         {\n            r->ystep = 0;\n            r->line0 = r->line1;\n            if (++r->ypos < z->img_comp[k].y)\n               r->line1 += z->img_comp[k].w2;\n         }\n      }\n\n      if (z->img_n >= 3)\n      {\n         uint8_t *y = coutput[0];\n         if (y)\n         {\n            if (use_fused)\n            {\n               z->upsample_YCbCr_to_BGRA_kernel(out, y,\n                     fused_cb_near, fused_cb_far,\n                     fused_cr_near, fused_cr_far,\n                     rjpeg->iter_res[1].w_lores, z->img_x,\n                     rjpeg->supports_rgba);\n            }\n            else\n            {\n               z->YCbCr_to_RGB_kernel(out, y, coutput[1],\n                     coutput[2], z->img_x, 4,\n                     rjpeg->supports_rgba);\n            }\n         }\n      }\n      else\n      {\n         uint8_t *y = coutput[0];\n         if (y)\n         {\n            unsigned i;\n            for (i = 0; i < z->img_x; ++i)\n            {\n               out[0] = out[1] = out[2] = y[i];\n               out[3] = 255;\n               out += 4;\n            }\n         }\n      }\n\n      rjpeg->iter_out_row++;\n   }\n}\n\n/* Initialize the fused iterate+resample state after the header is parsed.\n * Sets up resample contexts and allocates the output buffer. */\nstatic int rjpeg_iterate_init_resample(rjpeg_t *rjpeg)\n{\n   rjpeg_jpeg *j = rjpeg->iter_j;\n   int k;\n\n   for (k = 0; k < j->img_n; ++k)\n   {\n      rjpeg_resample *r = &rjpeg->iter_res[k];\n\n      r->hs       = j->img_h_max / j->img_comp[k].h;\n      r->vs       = j->img_v_max / j->img_comp[k].v;\n      r->ystep    = r->vs >> 1;\n      r->w_lores  = (j->img_x + r->hs - 1) / r->hs;\n      r->ypos     = 0;\n      r->line0    = r->line1 = j->img_comp[k].data;\n      r->resample = rjpeg_resample_row_generic;\n\n      if      (r->hs == 1 && r->vs == 1)\n         r->resample = rjpeg_resample_row_1;\n      else if (r->hs == 1 && r->vs == 2)\n         r->resample = rjpeg_resample_row_v_2;\n      else if (r->hs == 2 && r->vs == 1)\n         r->resample = rjpeg_resample_row_h_2;\n      else if (r->hs == 2 && r->vs == 2)\n         r->resample = j->resample_row_hv_2_kernel;\n   }\n\n   /* (size_t) casts: img_x and img_y are uint32_t.  Even with the\n    * 0x4000 cap above this only matters on 32-bit hosts, but the\n    * cast makes the expression robust against future cap changes. */\n   rjpeg->iter_output = (uint8_t *)malloc(\n         (size_t)4 * (size_t)j->img_x * (size_t)j->img_y);\n   if (!rjpeg->iter_output)\n      return 0;\n\n   rjpeg->iter_out_row = 0;\n   rjpeg->iter_resample_ready = 0; /* TODO: fix ystep state bug */\n   return 1;\n}\n\nbool rjpeg_iterate_image(rjpeg_t *rjpeg)\n{\n   rjpeg_jpeg *j;\n\n   if (!rjpeg || !rjpeg->iter_started)\n      return false;\n\n   j = rjpeg->iter_j;\n   if (!j)\n      return false;\n\n   switch (rjpeg->iter_state)\n   {\n      case RJPEG_ITER_PARSE_HEADER:\n      {\n         /* Phase 1: Parse the JPEG header and all markers up to the\n          * first SOS, allocate component buffers, then set up for\n          * entropy decode.  This is typically fast (<100 µs) so we\n          * do it in one shot. */\n         int m;\n\n         for (m = 0; m < 4; m++)\n         {\n            j->img_comp[m].raw_data  = NULL;\n            j->img_comp[m].raw_coeff = NULL;\n         }\n         j->restart_interval = 0;\n\n         if (!rjpeg_decode_jpeg_header(j, RJPEG_SCAN_LOAD))\n         {\n            rjpeg->iter_state = RJPEG_ITER_ERROR;\n            return false;\n         }\n\n         /* Get the first marker after the header */\n         rjpeg->iter_marker = rjpeg_get_marker(j);\n\n         /* For progressive: transition to per-scan iterative decode.\n          * Each call to rjpeg_iterate_image in RJPEG_ITER_PROG_SCAN\n          * processes one SOS scan, yielding between scans.  After all\n          * scans complete, RJPEG_ITER_FINISH_PROG runs the fused\n          * dequant+IDCT one component-row at a time. */\n         if (j->progressive)\n         {\n            rjpeg->iter_state  = RJPEG_ITER_PROG_SCAN;\n            return true; /* more work — start processing scans */\n         }\n\n         /* Baseline: find SOS, parse it, prepare for MCU-row iteration */\n         m = rjpeg->iter_marker;\n         while (m != JPEG_MARKER_SOS)\n         {\n            if (m == JPEG_MARKER_EOI || RJPEG_AT_EOF(j))\n            {\n               rjpeg->iter_state = RJPEG_ITER_ERROR;\n               return false;\n            }\n            if (!rjpeg_process_marker(j, m))\n            {\n               rjpeg->iter_state = RJPEG_ITER_ERROR;\n               return false;\n            }\n            m = rjpeg_get_marker(j);\n         }\n\n         if (!rjpeg_process_scan_header(j))\n         {\n            rjpeg->iter_state = RJPEG_ITER_ERROR;\n            return false;\n         }\n\n         rjpeg_jpeg_reset(j);\n         rjpeg->iter_mcu_row = 0;\n\n         /* For non-interleaved single-component scans, fall back\n          * to the monolithic path (same rationale as progressive). */\n         if (j->scan_n == 1)\n         {\n            if (!rjpeg_parse_entropy_coded_data(j))\n            {\n               rjpeg->iter_state = RJPEG_ITER_ERROR;\n               return false;\n            }\n            /* Check for trailing markers / EOI */\n            {\n               int mx = rjpeg_get_marker(j);\n               while (mx != JPEG_MARKER_EOI && !RJPEG_AT_EOF(j))\n               {\n                  if (mx == JPEG_MARKER_SOS)\n                  {\n                     /* Multi-scan baseline is unusual but handle it */\n                     if (!rjpeg_process_scan_header(j))\n                        break;\n                     if (!rjpeg_parse_entropy_coded_data(j))\n                        break;\n                  }\n                  else\n                  {\n                     if (!rjpeg_process_marker(j, mx))\n                        break;\n                  }\n                  mx = rjpeg_get_marker(j);\n               }\n            }\n            rjpeg->iter_state = RJPEG_ITER_DONE;\n            return false;\n         }\n\n         rjpeg->iter_state = RJPEG_ITER_ENTROPY_ROWS;\n\n         /* Initialize fused resample so we can process output rows\n          * as MCU-rows complete, overlapping entropy+resample. */\n         if (!rjpeg->iter_resample_ready)\n            rjpeg_iterate_init_resample(rjpeg);\n\n         return true; /* more work to do */\n      }\n\n      case RJPEG_ITER_ENTROPY_ROWS:\n      {\n         /* Phase 2: Decode one MCU-row per call.\n          * This is the key yield point that makes JPEG non-blocking. */\n         if (rjpeg->iter_mcu_row >= j->img_mcu_y)\n         {\n            /* All MCU rows done -- consume remaining markers to EOI */\n            if (j->marker == RJPEG_MARKER_NONE)\n            {\n               /* Scan for next marker: direct pointer access avoids\n                * redundant AT_EOF + get8 bounds checks. */\n               uint8_t *p   = j->img_buffer;\n               uint8_t *end = j->img_buffer_end;\n               while (p < end)\n               {\n                  uint8_t x = *p++;\n                  if (x == 0xFF && p < end)\n                  {\n                     uint8_t c = *p++;\n                     if (c != 0)\n                     {\n                        j->marker = c;\n                        break;\n                     }\n                  }\n                  else if (x != 0)\n                     break; /* junk, but tolerate it */\n               }\n               j->img_buffer = p;\n            }\n            rjpeg->iter_state = RJPEG_ITER_DONE;\n            return false; /* iteration complete */\n         }\n\n         if (!rjpeg_parse_entropy_one_mcu_row_interleaved(\n                  j, rjpeg->iter_mcu_row))\n         {\n            rjpeg->iter_state = RJPEG_ITER_ERROR;\n            return false;\n         }\n\n         rjpeg->iter_mcu_row++;\n\n         /* Fused resample: the MCU-row we just decoded produced up to\n          * v_max*8 rows of component data.  Resample them now while\n          * the data is hot in cache, overlapping with the next\n          * entropy decode on the next iterate call. */\n         if (rjpeg->iter_resample_ready && rjpeg->iter_output)\n         {\n            unsigned max_row = rjpeg->iter_mcu_row * j->img_v_max * 8;\n            if (max_row > j->img_y)\n               max_row = j->img_y;\n            rjpeg_iterate_resample_rows(rjpeg, max_row);\n         }\n\n         if (rjpeg->iter_mcu_row >= j->img_mcu_y)\n         {\n            /* Last row -- handle trailing data */\n            if (j->marker == RJPEG_MARKER_NONE)\n            {\n               uint8_t *p   = j->img_buffer;\n               uint8_t *end = j->img_buffer_end;\n               while (p < end)\n               {\n                  uint8_t x = *p++;\n                  if (x == 0xFF && p < end)\n                  {\n                     uint8_t c = *p++;\n                     if (c != 0) { j->marker = c; break; }\n                  }\n                  else if (x != 0)\n                     break;\n               }\n               j->img_buffer = p;\n            }\n            rjpeg->iter_state = RJPEG_ITER_DONE;\n            return false;\n         }\n\n         return true; /* more MCU rows remain */\n      }\n\n      /* -----------------------------------------------------------\n       * Progressive scan-at-a-time iteration\n       *\n       * Each call processes markers until the next SOS, runs one\n       * complete entropy scan, then yields.  A typical progressive\n       * JPEG has 6-10 scans; each scan at 1080p takes ~0.5-2 ms,\n       * giving the task scheduler regular yield points.\n       *\n       * After the last scan (EOI reached), we transition to\n       * RJPEG_ITER_FINISH_PROG for the dequant+IDCT phase.\n       * ----------------------------------------------------------- */\n      case RJPEG_ITER_PROG_SCAN:\n      {\n         int m = rjpeg->iter_marker;\n\n         /* Consume non-SOS markers (DHT, DQT, etc. between scans) */\n         while (m != JPEG_MARKER_SOS && m != JPEG_MARKER_EOI)\n         {\n            if (RJPEG_AT_EOF(j))\n            {\n               rjpeg->iter_state = RJPEG_ITER_ERROR;\n               return false;\n            }\n            if (!rjpeg_process_marker(j, m))\n            {\n               rjpeg->iter_state = RJPEG_ITER_ERROR;\n               return false;\n            }\n            m = rjpeg_get_marker(j);\n         }\n\n         if (m == JPEG_MARKER_EOI)\n         {\n            /* All scans consumed — transition to IDCT phase */\n            rjpeg->iter_finish_comp = 0;\n            rjpeg->iter_finish_row  = 0;\n            rjpeg->iter_state       = RJPEG_ITER_FINISH_PROG;\n            return true;\n         }\n\n         /* Process this SOS scan */\n         if (!rjpeg_process_scan_header(j))\n         {\n            rjpeg->iter_state = RJPEG_ITER_ERROR;\n            return false;\n         }\n         if (!rjpeg_parse_entropy_coded_data(j))\n         {\n            rjpeg->iter_state = RJPEG_ITER_ERROR;\n            return false;\n         }\n\n         /* Handle trailing padding/junk after entropy data */\n         if (j->marker == RJPEG_MARKER_NONE)\n         {\n            uint8_t *p   = j->img_buffer;\n            uint8_t *end = j->img_buffer_end;\n            while (p < end)\n            {\n               uint8_t x = *p++;\n               if (x == 0xFF && p < end)\n               {\n                  uint8_t c = *p++;\n                  if (c != 0) { j->marker = c; break; }\n               }\n               else if (x != 0)\n               {\n                  j->img_buffer = p;\n                  rjpeg->iter_state = RJPEG_ITER_ERROR;\n                  return false;\n               }\n            }\n            j->img_buffer = p;\n         }\n\n         /* Fetch the next marker for the next iteration */\n         rjpeg->iter_marker = rjpeg_get_marker(j);\n         return true; /* more scans may follow */\n      }\n\n      /* -----------------------------------------------------------\n       * Progressive finish phase: dequant + IDCT\n       *\n       * After all scans are decoded, the coefficient buffer holds\n       * the full DCT data.  We run the fused dequant+IDCT one\n       * component block-row at a time, yielding between rows.\n       *\n       * For a 1080p 4:2:0 image this gives ~135 Y rows + ~68 Cb\n       * rows + ~68 Cr rows = ~271 yield points, each processing\n       * one row of 8×8 blocks (~40-80 µs per row).\n       * ----------------------------------------------------------- */\n      case RJPEG_ITER_FINISH_PROG:\n      {\n         int n = rjpeg->iter_finish_comp;\n\n         /* Find next component that has work remaining */\n         while (n < j->img_n)\n         {\n            int w = (j->img_comp[n].x + 7) >> 3;\n            int h = (j->img_comp[n].y + 7) >> 3;\n            int row = rjpeg->iter_finish_row;\n\n            if (row < h)\n            {\n               /* Process one block-row of this component */\n               int i;\n               for (i = 0; i < w; ++i)\n               {\n                  short *data = j->img_comp[n].coeff\n                     + 64 * (i + row * j->img_comp[n].coeff_w);\n                  j->dequant_idct_block_kernel(\n                        j->img_comp[n].data\n                        + j->img_comp[n].w2 * row * 8 + i * 8,\n                        j->img_comp[n].w2, data,\n                        j->dequant[j->img_comp[n].tq]);\n               }\n\n               rjpeg->iter_finish_row = row + 1;\n\n               /* Check if this component is done */\n               if (rjpeg->iter_finish_row >= h)\n               {\n                  /* Move to next component */\n                  rjpeg->iter_finish_comp = n + 1;\n                  rjpeg->iter_finish_row  = 0;\n               }\n               return true; /* yield after each block-row */\n            }\n\n            /* This component done, try next */\n            n++;\n            rjpeg->iter_finish_comp = n;\n            rjpeg->iter_finish_row  = 0;\n         }\n\n         /* All components finished */\n         rjpeg->iter_state = RJPEG_ITER_DONE;\n         return false;\n      }\n\n      case RJPEG_ITER_DONE:\n         return false;\n\n      case RJPEG_ITER_ERROR:\n      default:\n         return false;\n   }\n\n   return false;\n}\n\nint rjpeg_process_image(rjpeg_t *rjpeg, void **buf_data,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba)\n{\n   if (!rjpeg)\n      return IMAGE_PROCESS_ERROR;\n\n   /* Latch for the kernel callsites below. */\n   rjpeg->supports_rgba = supports_rgba;\n\n   /* -----------------------------------------------------------\n    * Phase 0 -- DECODE: either use the already-decoded data from\n    * the iterative path (rjpeg_iterate_image), or fall back to\n    * the monolithic decode for the synchronous caller.\n    * Then set up resample state for incremental row processing.\n    * ----------------------------------------------------------- */\n   if (!rjpeg->process)\n   {\n      int k;\n      struct rjpeg_process *proc = NULL;\n      rjpeg_jpeg    *j    = NULL;\n\n      proc = (struct rjpeg_process*)calloc(1, sizeof(*proc));\n      if (!proc)\n         return IMAGE_PROCESS_ERROR;\n\n      if (rjpeg->iter_started\n            && rjpeg->iter_state == RJPEG_ITER_DONE\n            && rjpeg->iter_j)\n      {\n         /* Iterative path completed -- reuse its decode state.\n          * Transfer ownership from rjpeg->iter_j to proc->j. */\n         j             = rjpeg->iter_j;\n         rjpeg->iter_j = NULL;\n\n         /* If the fused iterate+resample already produced the BGRA\n          * output, skip the entire resample phase. */\n         if (rjpeg->iter_resample_ready && rjpeg->iter_output\n               && rjpeg->iter_out_row >= j->img_y)\n         {\n            *buf_data = rjpeg->iter_output;\n            *width  = j->img_x;\n            *height = j->img_y;\n            rjpeg->iter_output = NULL; /* transfer ownership */\n\n            rjpeg_cleanup_jpeg(j);\n            free(j);\n            free(proc);\n            return IMAGE_PROCESS_END;\n         }\n\n         /* Set the buffer end pointer if the iterative path\n          * didn't have it (start() is called before size is known\n          * via set_buf_ptr, but the buffer was already set). */\n         if (!j->img_buffer_end || j->img_buffer_end == j->img_buffer_original)\n            j->img_buffer_end = (uint8_t*)rjpeg->buff_data + size;\n      }\n      else\n      {\n         /* Synchronous fallback -- do the full decode now.\n          * This path is used by image_texture_load_internal()\n          * which calls iterate in a tight loop anyway. */\n         j = (rjpeg_jpeg*)malloc(sizeof(*j));\n         if (!j)\n         {\n            free(proc);\n            return IMAGE_PROCESS_ERROR;\n         }\n\n         /* Zero only fields that need init */\n         memset(j->img_comp, 0, sizeof(j->img_comp));\n         j->code_bits = 0; j->code_buffer = 0;\n         j->nomore = 0; j->progressive = 0;\n         j->scan_n = 0; j->eob_run = 0;\n         j->marker = RJPEG_MARKER_NONE;\n         j->restart_interval = 0; j->todo = 0;\n         j->comp_arena = NULL; j->comp_arena_size = 0;\n\n         /* Context fields embedded in j */\n         j->img_buffer          = (uint8_t*)rjpeg->buff_data;\n         j->img_buffer_original = (uint8_t*)rjpeg->buff_data;\n         j->img_buffer_end      = (uint8_t*)rjpeg->buff_data + size;\n\n         rjpeg_setup_jpeg(j);\n\n         j->img_n            = 0;\n\n         if (!rjpeg_decode_jpeg_image(j))\n         {\n            rjpeg_cleanup_jpeg(j);\n            free(j);\n            free(proc);\n            return IMAGE_PROCESS_ERROR;\n         }\n      }\n\n      proc->j = j;\n\n      /* Determine actual number of components to generate */\n      proc->n       = 4; /* always request RGBA */\n\n      if (j->img_n == 3 && proc->n < 3)\n         proc->decode_n = 1;\n      else\n         proc->decode_n = j->img_n;\n\n      /* Set up per-component resample state */\n      for (k = 0; k < proc->decode_n; ++k)\n      {\n         rjpeg_resample *r = &proc->res_comp[k];\n\n         /* allocate line buffer big enough for upsampling off the edges\n          * with upsample factor of 4.  If the arena already allocated\n          * linebuf (it points into comp_arena), skip the malloc. */\n         if (!j->img_comp[k].linebuf)\n         {\n            j->img_comp[k].linebuf = (uint8_t *) malloc(j->img_x + 3);\n            if (!j->img_comp[k].linebuf)\n            {\n               rjpeg_process_free(proc);\n               return IMAGE_PROCESS_ERROR;\n            }\n         }\n\n         r->hs       = j->img_h_max / j->img_comp[k].h;\n         r->vs       = j->img_v_max / j->img_comp[k].v;\n         r->ystep    = r->vs >> 1;\n         r->w_lores  = (j->img_x + r->hs-1) / r->hs;\n         r->ypos     = 0;\n         r->line0    = r->line1 = j->img_comp[k].data;\n         r->resample = rjpeg_resample_row_generic;\n\n         if      (r->hs == 1 && r->vs == 1)\n            r->resample = rjpeg_resample_row_1;\n         else if (r->hs == 1 && r->vs == 2)\n            r->resample = rjpeg_resample_row_v_2;\n         else if (r->hs == 2 && r->vs == 1)\n            r->resample = rjpeg_resample_row_h_2;\n         else if (r->hs == 2 && r->vs == 2)\n            r->resample = j->resample_row_hv_2_kernel;\n      }\n\n      /* Allocate output buffer */\n      proc->output = (uint8_t *) malloc(\n            (size_t)proc->n * (size_t)j->img_x * (size_t)j->img_y);\n      if (!proc->output)\n      {\n         rjpeg_process_free(proc);\n         return IMAGE_PROCESS_ERROR;\n      }\n\n      proc->cur_row     = 0;\n      proc->phase       = RJPEG_PHASE_RESAMPLE;\n\n      *width            = j->img_x;\n      *height           = j->img_y;\n\n      rjpeg->process    = proc;\n\n      return IMAGE_PROCESS_NEXT;\n   }\n\n   /* -----------------------------------------------------------\n    * Phase 1 -- RESAMPLE: process a batch of output rows per call.\n    * Chroma upsampling + YCbCr-to-RGB conversion.\n    * Batching amortises per-call overhead while still giving the\n    * caller regular yield points.\n    * ----------------------------------------------------------- */\n   if (rjpeg->process->phase == RJPEG_PHASE_RESAMPLE)\n   {\n      struct rjpeg_process *proc = rjpeg->process;\n      rjpeg_jpeg           *z   = proc->j;\n      unsigned          rows_done = 0;\n\n      /* Process up to 8 rows per call. 8 rows at ~6 us/row (1080p) ~ 50 us,\n       * well within any reasonable frame budget while cutting call count\n       * from ~1080 to ~135 for 1080p images. */\n      #define RJPEG_ROWS_PER_CALL 8\n\n      *width  = z->img_x;\n      *height = z->img_y;\n\n      while (proc->cur_row < z->img_y && rows_done < RJPEG_ROWS_PER_CALL)\n      {\n         int k;\n         unsigned jj  = proc->cur_row;\n         uint8_t *out = proc->output + proc->n * z->img_x * jj;\n\n         /* Determine if we can use the fused upsample+colorconvert path\n          * for this row.  Must be computed BEFORE the resample loop\n          * advances ystep. */\n         int use_fused = (proc->n >= 3 && z->img_n == 3\n               && z->upsample_YCbCr_to_BGRA_kernel\n               && proc->decode_n >= 3\n               && proc->res_comp[1].hs == 2\n               && proc->res_comp[1].vs == 2);\n         int fused_y_bot1 = 0, fused_y_bot2 = 0;\n         uint8_t *fused_cb_near = NULL, *fused_cb_far = NULL;\n         uint8_t *fused_cr_near = NULL, *fused_cr_far = NULL;\n\n         if (use_fused)\n         {\n            rjpeg_resample *r1 = &proc->res_comp[1];\n            rjpeg_resample *r2 = &proc->res_comp[2];\n            fused_y_bot1 = r1->ystep >= (r1->vs >> 1);\n            fused_y_bot2 = r2->ystep >= (r2->vs >> 1);\n            fused_cb_near = fused_y_bot1 ? r1->line1 : r1->line0;\n            fused_cb_far  = fused_y_bot1 ? r1->line0 : r1->line1;\n            fused_cr_near = fused_y_bot2 ? r2->line1 : r2->line0;\n            fused_cr_far  = fused_y_bot2 ? r2->line0 : r2->line1;\n         }\n\n         for (k = 0; k < proc->decode_n; ++k)\n         {\n            rjpeg_resample *r = &proc->res_comp[k];\n            int         y_bot = r->ystep >= (r->vs >> 1);\n\n            /* Skip the actual Cb/Cr resample when the fused kernel\n             * will do the upsample+colorconvert in one shot.\n             * Y (k==0) still needs resample_row_1 for the zero-copy ptr. */\n            if (use_fused && k >= 1)\n               proc->coutput[k] = NULL; /* not used */\n            else\n               proc->coutput[k]  = r->resample(z->img_comp[k].linebuf,\n                     y_bot ? r->line1 : r->line0,\n                     y_bot ? r->line0 : r->line1,\n                     r->w_lores, r->hs);\n\n            if (++r->ystep >= r->vs)\n            {\n               r->ystep = 0;\n               r->line0 = r->line1;\n               if (++r->ypos < z->img_comp[k].y)\n                  r->line1 += z->img_comp[k].w2;\n            }\n         }\n\n         if (proc->n >= 3)\n         {\n            uint8_t *y = proc->coutput[0];\n            if (y)\n            {\n               if (z->img_n == 3)\n               {\n                  if (use_fused)\n                  {\n                     z->upsample_YCbCr_to_BGRA_kernel(out, y,\n                           fused_cb_near, fused_cb_far,\n                           fused_cr_near, fused_cr_far,\n                           proc->res_comp[1].w_lores, z->img_x,\n                           rjpeg->supports_rgba);\n                  }\n                  else\n                  {\n                     z->YCbCr_to_RGB_kernel(out, y, proc->coutput[1],\n                           proc->coutput[2], z->img_x, proc->n,\n                           rjpeg->supports_rgba);\n                  }\n               }\n               else\n               {\n                  unsigned i;\n                  for (i = 0; i < z->img_x; ++i)\n                  {\n                     out[0]  = out[1] = out[2] = y[i];\n                     out[3]  = 255; /* not used if n==3 */\n                     out    += proc->n;\n                  }\n               }\n            }\n         }\n         else\n         {\n            uint8_t *y = proc->coutput[0];\n            if (proc->n == 1)\n            {\n               unsigned i;\n               for (i = 0; i < z->img_x; ++i)\n                  out[i] = y[i];\n            }\n            else\n            {\n               unsigned i;\n               for (i = 0; i < z->img_x; ++i)\n               {\n                  *out++ = y[i];\n                  *out++ = 255;\n               }\n            }\n         }\n\n         proc->cur_row++;\n         rows_done++;\n      }\n\n      if (proc->cur_row < z->img_y)\n         return IMAGE_PROCESS_NEXT;\n\n      /* All rows resampled -- YCbCr conversion already wrote BGRA\n       * (ARGB as uint32), so no swizzle pass is needed.\n       * Free decode buffers and hand off the pixel buffer. */\n      rjpeg_cleanup_jpeg(z);\n\n      /* Transfer ownership of the pixel buffer to the caller */\n      *buf_data     = proc->output;\n      proc->output  = NULL; /* prevent rjpeg_process_free from freeing it */\n\n      /* Clean up the process state */\n      rjpeg_process_free(rjpeg->process);\n      rjpeg->process = NULL;\n\n      return IMAGE_PROCESS_END;\n   }\n\n   return IMAGE_PROCESS_ERROR;\n}\n\nbool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data, size_t len)\n{\n   if (!rjpeg)\n      return false;\n\n   rjpeg->buff_data = (uint8_t*)data;\n   rjpeg->buff_len  = len;\n\n   return true;\n}\n\nvoid rjpeg_free(rjpeg_t *rjpeg)\n{\n   if (!rjpeg)\n      return;\n\n   if (rjpeg->process)\n   {\n      rjpeg_process_free(rjpeg->process);\n      rjpeg->process = NULL;\n   }\n\n   /* Clean up iterative decode state if it wasn't\n    * transferred to process by rjpeg_process_image */\n   if (rjpeg->iter_j)\n   {\n      rjpeg_cleanup_jpeg(rjpeg->iter_j);\n      free(rjpeg->iter_j);\n      rjpeg->iter_j = NULL;\n   }\n\n   if (rjpeg->iter_output)\n   {\n      free(rjpeg->iter_output);\n      rjpeg->iter_output = NULL;\n   }\n\n   free(rjpeg);\n}\n\nrjpeg_t *rjpeg_alloc(void)\n{\n   rjpeg_t *rjpeg = (rjpeg_t*)calloc(1, sizeof(*rjpeg));\n   if (!rjpeg)\n      return NULL;\n   return rjpeg;\n}\n"
  },
  {
    "path": "formats/json/rjson.c",
    "content": "/* Copyright  (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rjson.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* The parser is based on Public Domain JSON Parser for C by Christopher Wellons - https://github.com/skeeto/pdjson */\n\n#include <stdio.h>  /* snprintf, vsnprintf */\n#include <stdarg.h> /* va_list */\n#include <string.h> /* memcpy */\n#include <stdint.h> /* int64_t, SIZE_MAX */\n#include <stdlib.h> /* malloc, realloc, atof, atoi */\n#include <limits.h> /* INT_MAX */\n\n/* Ceiling for the parser's growing string buffer and the writer's\n * in-memory buffer.  Reached in practice only by pathologically large\n * (and almost certainly malformed) JSON inputs on a 32-bit system,\n * but having an explicit cap avoids undefined behaviour in the\n * signed-int arithmetic of the writer and the size_t doubling in the\n * parser wrapping past SIZE_MAX / 2.  Callers with legitimate giant\n * payloads should not be using these APIs in the first place --\n * stream in chunks. */\n#define _RJSON_MAX_SIZE ((size_t)256 * 1024 * 1024)\n\n#include <formats/rjson.h>\n#include <compat/posix_string.h>\n#include <streams/interface_stream.h>\n#include <streams/file_stream.h>\n\nstruct _rjson_stack { enum rjson_type type; size_t count; };\n\nstruct rjson\n{\n   /* Order of the top few struct elements have an impact on performance */\n   /* Place most frequently accessed things on top */\n   const unsigned char *input_p;\n   struct _rjson_stack *stack_top;\n   const unsigned char *input_end;\n   const unsigned char* source_column_p;\n   size_t source_line;\n\n   char *string, *string_pass_through;\n   size_t string_len, string_cap;\n\n   struct _rjson_stack inline_stack[10];\n   struct _rjson_stack *stack;\n\n   rjson_io_t io;\n   void *user_data;\n\n   unsigned int stack_cap, stack_max;\n   int input_len;\n\n   char option_flags;\n   char decimal_sep;\n   char error_text[80];\n   char inline_string[512];\n\n   /* Must be at the end of the struct, can be allocated with custom size */\n   unsigned char input_buf[512];\n};\n\nenum _rjson_token\n{\n   _rJSON_TOK_WHITESPACE, _rJSON_TOK_NEWLINE, _rJSON_TOK_OPTIONAL_SKIP,\n   _rJSON_TOK_OBJECT, _rJSON_TOK_ARRAY, _rJSON_TOK_STRING, _rJSON_TOK_NUMBER,\n   _rJSON_TOK_TRUE, _rJSON_TOK_FALSE, _rJSON_TOK_NULL,\n   _rJSON_TOK_OBJECT_END, _rJSON_TOK_ARRAY_END, _rJSON_TOK_COLON,\n   _rJSON_TOK_COMMA, _rJSON_TOK_ERROR, _rJSON_TOK_EOF, _rJSON_TOKCOUNT\n};\n\n/* The used char type is int and not short for better performance */\ntypedef unsigned int _rjson_char_t;\n#define _rJSON_EOF ((_rjson_char_t)256)\n\n/* Compiler branching hint for expression with high probability\n * Explicitly only have likely (and no unlikely) because compilers\n * that don't support it expect likely branches to come first. */\n#if defined(__GNUC__) || defined(__clang__)\n#define _rJSON_LIKELY(x) __builtin_expect(!!(x), 1)\n#else\n#define _rJSON_LIKELY(x) (x)\n#endif\n\n/* These 3 error functions return RJSON_ERROR for convenience */\nstatic enum rjson_type _rjson_error(rjson_t *json, const char *fmt, ...)\n{\n   va_list ap;\n   if (json->stack_top->type == RJSON_ERROR)\n      return RJSON_ERROR;\n   json->stack_top->type = RJSON_ERROR;\n   va_start(ap, fmt);\n   vsnprintf(json->error_text, sizeof(json->error_text), fmt, ap);\n   va_end(ap);\n   return RJSON_ERROR;\n}\n\nstatic enum rjson_type _rjson_error_char(rjson_t *json,\n      const char *fmt, _rjson_char_t chr)\n{\n   char buf[16];\n   if (json->stack_top->type == RJSON_ERROR)\n      return RJSON_ERROR;\n   snprintf(buf, sizeof(buf),\n         (chr == _rJSON_EOF ? \"end of stream\" :\n         (chr >= ' ' && chr <= '~' ? \"'%c'\" : \"byte 0x%02X\")), chr);\n   return _rjson_error(json, fmt, buf);\n}\n\nstatic enum rjson_type _rjson_error_token(rjson_t *json,\n   const char *fmt, enum _rjson_token tok)\n{\n   return _rjson_error_char(json, fmt,\n         (tok == _rJSON_TOK_EOF ? _rJSON_EOF : json->input_p[-1]));\n}\n\nstatic bool _rjson_io_input(rjson_t *json)\n{\n   if (json->input_end == json->input_buf)\n      return false;\n   json->source_column_p -= (json->input_end - json->input_buf);\n   json->input_p = json->input_buf;\n   json->input_end = json->input_buf +\n         json->io(json->input_buf, json->input_len, json->user_data);\n   if (json->input_end < json->input_buf)\n   {\n      _rjson_error(json, \"input stream read error\");\n      json->input_end = json->input_buf;\n   }\n   return (json->input_end != json->input_p);\n}\n\nstatic bool _rjson_grow_string(rjson_t *json)\n{\n   char *string;\n   size_t new_string_cap;\n   /* Bound the doubling so string_cap * 2 can never wrap past\n    * SIZE_MAX.  Pre-patch a pathological input on 32-bit (string_cap\n    * nearing 2 GiB) doubled to 0 and realloc() returned either NULL\n    * (benign) or a 0-byte pointer (heap overflow on next pushchar).\n    * Post-patch we fail cleanly before the arithmetic wrap. */\n   if (json->string_cap > _RJSON_MAX_SIZE / 2)\n   {\n      if (json->string_cap >= _RJSON_MAX_SIZE)\n      {\n         _rjson_error(json, \"string token too large\");\n         return false;\n      }\n      new_string_cap = _RJSON_MAX_SIZE;\n   }\n   else\n      new_string_cap = json->string_cap * 2;\n   if (json->string != json->inline_string)\n      string             = (char*)realloc(json->string, new_string_cap);\n   else if ((string      = (char*)malloc(new_string_cap)) != NULL)\n      memcpy(string, json->inline_string, sizeof(json->inline_string));\n   if (!string)\n   {\n      _rjson_error(json, \"out of memory\");\n      return false;\n   }\n   json->string_cap      = new_string_cap;\n   json->string          = string;\n   return true;\n}\n\nstatic INLINE bool _rjson_pushchar(rjson_t *json, _rjson_char_t c)\n{\n   json->string[json->string_len++] = (char)c;\n   return (json->string_len != json->string_cap || _rjson_grow_string(json));\n}\n\nstatic INLINE bool _rjson_pushchars(rjson_t *json,\n      const unsigned char *from, const unsigned char *to)\n{\n   unsigned char* string;\n   size_t _len    = json->string_len;\n   size_t new_len = _len + (to - from);\n   while (new_len >= json->string_cap)\n      if (!_rjson_grow_string(json))\n         return false;\n   string = (unsigned char *)json->string;\n   while (_len != new_len)\n      string[_len++] = *(from++);\n   json->string_len = new_len;\n   return true;\n}\n\nstatic INLINE _rjson_char_t _rjson_char_get(rjson_t *json)\n{\n   return (json->input_p != json->input_end || _rjson_io_input(json)\n        ? *json->input_p++ : _rJSON_EOF);\n}\n\nstatic unsigned int _rjson_get_unicode_cp(rjson_t *json)\n{\n   unsigned int cp = 0, shift = 16;\n   for (;;)\n   {\n      _rjson_char_t c = _rjson_char_get(json);\n      switch (c)\n      {\n         case '0': case '1': case '2': case '3': case '4':\n         case '5': case '6': case '7': case '8': case '9':\n            c -= '0';\n            break;\n         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':\n            c -= ('a' - 10);\n            break;\n         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':\n            c -= ('A' - 10);\n            break;\n         case _rJSON_EOF:\n            _rjson_error(json, \"unterminated string literal in Unicode\");\n            return (unsigned int)-1;\n         default:\n            _rjson_error_char(json, \"invalid Unicode escape hexadecimal %s\", c);\n            return (unsigned int)-1;\n      }\n      shift -= 4;\n      cp |= ((unsigned int)c << shift);\n      if (!shift)\n         return cp;\n   }\n}\n\nstatic bool _rjson_read_unicode(rjson_t *json)\n{\n   #define _rJSON_READ_UNICODE_REPLACE_OR_IGNORE \\\n      if (json->option_flags & (RJSON_OPTION_IGNORE_INVALID_ENCODING \\\n            | RJSON_OPTION_REPLACE_INVALID_ENCODING)) goto replace_or_ignore;\n\n   unsigned int cp;\n\n   if ((cp = _rjson_get_unicode_cp(json)) == (unsigned int)-1)\n      return false;\n\n   if (cp >= 0xd800 && cp <= 0xdbff)\n   {\n      /* This is the high portion of a surrogate pair; we need to read the\n       * lower portion to get the codepoint */\n      unsigned int l, h = cp;\n\n      _rjson_char_t c = _rjson_char_get(json);\n      if (c == _rJSON_EOF)\n      {\n         _rjson_error(json, \"unterminated string literal in Unicode\");\n         return false;\n      }\n      if (c != '\\\\')\n      {\n         _rjson_error_char(json, \"invalid continuation %s\"\n               \" for surrogate pair, expected '\\\\'\", c);\n         return false;\n      }\n\n      c = _rjson_char_get(json);\n      if (c == _rJSON_EOF)\n      {\n         _rjson_error(json, \"unterminated string literal in Unicode\");\n         return false;\n      }\n      if (c != 'u')\n      {\n         _rjson_error_char(json, \"invalid continuation %s\"\n               \" for surrogate pair, expected 'u'\", c);\n         return false;\n      }\n      if ((l = _rjson_get_unicode_cp(json)) == (unsigned int)-1)\n         return false;\n      if (l < 0xdc00 || l > 0xdfff)\n      {\n         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE\n         _rjson_error(json, \"surrogate pair continuation \\\\u%04x out \"\n            \"of range (dc00-dfff)\", l);\n         return false;\n      }\n      cp = ((h - 0xd800) * 0x400) + ((l - 0xdc00) + 0x10000);\n   }\n   else if (cp >= 0xdc00 && cp <= 0xdfff)\n   {\n      _rJSON_READ_UNICODE_REPLACE_OR_IGNORE\n      _rjson_error(json, \"dangling surrogate \\\\u%04x\", cp);\n      return false;\n   }\n\n   if (cp < 0x80UL)\n      return _rjson_pushchar(json, cp);\n\n   if (cp < 0x0800UL)\n      return (_rjson_pushchar(json, (cp >> 6 & 0x1F) | 0xC0) &&\n              _rjson_pushchar(json, (cp >> 0 & 0x3F) | 0x80));\n\n   if (cp < 0x010000UL)\n   {\n      if (cp >= 0xd800 && cp <= 0xdfff)\n      {\n         _rJSON_READ_UNICODE_REPLACE_OR_IGNORE\n         _rjson_error(json, \"invalid codepoint %04x\", cp);\n         return false;\n      }\n      return (_rjson_pushchar(json, (cp >> 12 & 0x0F) | 0xE0) &&\n              _rjson_pushchar(json, (cp >>  6 & 0x3F) | 0x80) &&\n              _rjson_pushchar(json, (cp >>  0 & 0x3F) | 0x80));\n   }\n   if (cp < 0x110000UL)\n      return (_rjson_pushchar(json, (cp >> 18 & 0x07) | 0xF0) &&\n              _rjson_pushchar(json, (cp >> 12 & 0x3F) | 0x80) &&\n              _rjson_pushchar(json, (cp >>  6 & 0x3F) | 0x80) &&\n              _rjson_pushchar(json, (cp >>  0 & 0x3F) | 0x80));\n\n   _rJSON_READ_UNICODE_REPLACE_OR_IGNORE\n   _rjson_error(json, \"unable to encode %04x as UTF-8\", cp);\n   return false;\n\nreplace_or_ignore:\n   return ((json->option_flags & RJSON_OPTION_IGNORE_INVALID_ENCODING) ||\n         _rjson_pushchar(json, '?'));\n   #undef _rJSON_READ_UNICODE_REPLACE_OR_IGNORE\n}\n\nstatic bool _rjson_validate_utf8(rjson_t *json)\n{\n   unsigned char first, c;\n   unsigned char *p;\n   unsigned char *from = (unsigned char *)\n         (json->string_pass_through ? json->string_pass_through : json->string);\n   unsigned char *to = from + json->string_len;\n\n   if (json->option_flags & RJSON_OPTION_IGNORE_INVALID_ENCODING)\n      return true;\n\n   for (;;)\n   {\n      if (from == to)\n         return true;\n      first = *from;\n      if (first <= 0x7F) /* ASCII */\n      {\n         from++;\n         continue;\n      }\n      p = from;\n      /* Continuation or overlong encoding of an ASCII byte */\n      if (first <= 0xC1)\n         goto invalid_utf8;\n      if (first <= 0xDF)\n      {\n         if ((from = p + 2) > to)\n            goto invalid_utf8;\ncontinue_length_2:\n         c = p[1];\n         switch (first)\n         {\n            case 0xE0:\n               c = (c < 0xA0 || c > 0xBF);\n               break;\n            case 0xED:\n               c = (c < 0x80 || c > 0x9F);\n               break;\n            case 0xF0:\n               c = (c < 0x90 || c > 0xBF);\n               break;\n            case 0xF4:\n               c = (c < 0x80 || c > 0x8F);\n               break;\n            default:\n               c = (c < 0x80 || c > 0xBF);\n               break;\n         }\n         if (c)\n            goto invalid_utf8;\n      }\n      else if (first <= 0xEF)\n      {\n         if ((from = p + 3) > to)\n            goto invalid_utf8;\ncontinue_length_3:\n         if ((c = p[2]) < 0x80 || c > 0xBF)\n            goto invalid_utf8;\n         goto continue_length_2;\n      }\n      else if (first <= 0xF4)\n      {\n         if ((from = p + 4) > to)\n            goto invalid_utf8;\n         if ((c = p[3]) < 0x80 || c > 0xBF)\n            goto invalid_utf8;\n         goto continue_length_3;\n      }\n      else\n         goto invalid_utf8; /* length 5 or 6 or invalid UTF-8 */\n      continue;\ninvalid_utf8:\n      if (!(json->option_flags & RJSON_OPTION_REPLACE_INVALID_ENCODING))\n      {\n         _rjson_error(json, \"invalid UTF-8 character in string\");\n         return false;\n      }\n      from    = p;\n      *from++ = '?';\n      while (from != to && (*from & 0x80))\n         *from++ = '?';\n   }\n}\n\nstatic enum rjson_type _rjson_read_string(rjson_t *json)\n{\n   const unsigned char *p    = json->input_p, *raw = p;\n   const unsigned char *end  = json->input_end;\n   unsigned char utf8mask    = 0;\n   json->string_pass_through = NULL;\n   json->string_len          = 0;\n\n   for (;;)\n   {\n      if (_rJSON_LIKELY(p != end))\n      {\n         unsigned char c = *p;\n         if (_rJSON_LIKELY(c != '\"' && c != '\\\\' && c >= 0x20))\n         {\n            /* handle most common case first, it's faster */\n            utf8mask |= c;\n            p++;\n         }\n         else if (c == '\"')\n         {\n            json->input_p = p + 1;\n            if (json->string_len == 0 && p + 1 != end)\n            {\n               /* raw string fully inside input buffer, pass through */\n               json->string_len          = p - raw;\n               json->string_pass_through = (char*)raw;\n            }\n            else if (raw != p && !_rjson_pushchars(json, raw, p)) /* OOM */\n               return RJSON_ERROR;\n            /* Contains invalid UTF-8 byte sequences */\n            if ((utf8mask & 0x80) && !_rjson_validate_utf8(json))\n               return RJSON_ERROR;\n            return RJSON_STRING;\n         }\n         else if (c == '\\\\')\n         {\n            _rjson_char_t esc;\n            if (raw != p)\n            {\n               /* Can't pass through string with escapes, use string buffer */\n               if (!_rjson_pushchars(json, raw, p))\n                  return RJSON_ERROR;\n            }\n            json->input_p = p + 1;\n            esc = _rjson_char_get(json);\n            switch (esc)\n            {\n               case 'u':\n                  if (!_rjson_read_unicode(json))\n                     return RJSON_ERROR;\n                  break;\n\n               case 'b':\n                  esc = '\\b';\n                  goto escape_pushchar;\n               case 'f':\n                  esc = '\\f';\n                  goto escape_pushchar;\n               case 'n':\n                  esc = '\\n';\n                  goto escape_pushchar;\n               case 'r':\n                  if (!(json->option_flags & RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN))\n                  {\n                     esc = '\\r';\n                     goto escape_pushchar;\n                  }\n                  break;\n               case 't':\n                  esc = '\\t';\n                  goto escape_pushchar;\n               case '/':\n               case '\"':\n               case '\\\\':\nescape_pushchar:\n                  if (!_rjson_pushchar(json, esc))\n                     return RJSON_ERROR;\n                  break;\n\n               case _rJSON_EOF:\n                  return _rjson_error(json, \"unterminated string literal in escape\");\n\n               default:\n                  return _rjson_error_char(json, \"invalid escaped %s\", esc);\n            }\n            raw = p = json->input_p;\n            end     = json->input_end;\n         }\n         else if (!(json->option_flags & RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS))\n            return _rjson_error_char(json, \"unescaped control character %s in string\", c);\n         else\n            p++;\n      }\n      else\n      {\n         if (raw != p)\n         {\n            /* not fully inside input buffer, copy to string buffer */\n            if (!_rjson_pushchars(json, raw, p))\n               return RJSON_ERROR;\n         }\n         if (!_rjson_io_input(json))\n            return _rjson_error(json, \"unterminated string literal\");\n         raw = p = json->input_p;\n         end     = json->input_end;\n      }\n   }\n}\n\nstatic enum rjson_type _rjson_read_number(rjson_t *json)\n{\n   const unsigned char *p     = json->input_p - 1;\n   const unsigned char *end   = json->input_end;\n   const unsigned char *start = p;\n\n   json->string_len = 0;\n   json->string_pass_through = NULL;\n   for (;;)\n   {\n      if (_rJSON_LIKELY(p != end))\n      {\n         switch (*p++)\n         {\n            case '+': case '-': case '.':\n            case '0': case '1': case '2': case '3': case '4':\n            case '5': case '6': case '7': case '8': case '9':\n            case 'E': case 'e':\n               continue;\n         }\n         p--;\n         json->input_p = p;\n         if (!_rjson_pushchars(json, start, p))\n            return RJSON_ERROR; /* out of memory */\n         break;\n      }\n      else\n      {\n         /* number sequences are always copied to the string buffer */\n         if (!_rjson_pushchars(json, start, p))\n            return RJSON_ERROR;\n         if (!_rjson_io_input(json))\n         {\n            /* EOF here is not an error for a number */\n            json->input_p = json->input_end;\n            break;\n         }\n         start = p = json->input_p;\n         end = json->input_end;\n      }\n   }\n\n   p = (const unsigned char *)json->string;\n   end = (p + json->string_len);\n\n   /* validate json number */\n   if (*p == '-' && ++p == end)\n      goto invalid_number;\n   if (*p == '0')\n   {\n      if (++p == end)\n         return RJSON_NUMBER;\n   }\n   else\n   {\n      if (*p < '1' || *p > '9')\n         goto invalid_number;\n      do\n      {\n         if (++p == end)\n            return RJSON_NUMBER;\n      }\n      while (*p >= '0' && *p <= '9');\n   }\n   if (*p == '.')\n   {\n      if (++p == end)\n         goto invalid_number;\n      if (*p < '0' || *p > '9')\n         goto invalid_number;\n      do\n      {\n         if (++p == end)\n            return RJSON_NUMBER;\n      }\n      while (*p >= '0' && *p <= '9');\n   }\n   if (((*p)|0x20) == 'e')\n   {\n      if (++p == end)\n         goto invalid_number;\n      if ((*p == '-' || *p == '+') && ++p == end)\n         goto invalid_number;\n      if (*p < '0' || *p > '9')\n         goto invalid_number;\n      do\n      {\n         if (++p == end)\n            return RJSON_NUMBER;\n      }\n      while (*p >= '0' && *p <= '9');\n   }\ninvalid_number:\n   return _rjson_error_char(json, \"unexpected %s in number\",\n         (p == json->input_end ? _rJSON_EOF : p[p == end ? -1 : 0]));\n}\n\nstatic enum rjson_type _rjson_push_stack(rjson_t *json, enum _rjson_token t)\n{\n   if (json->stack_top + 1 == json->stack + json->stack_cap)\n   {\n      /* reached allocated stack size, either reallocate or abort */\n      unsigned int new_stack_cap;\n      struct _rjson_stack *new_stack;\n      size_t stack_alloc;\n      if (json->stack_cap == json->stack_max)\n         return _rjson_error(json, \"maximum depth of nesting reached\");\n\n      new_stack_cap = json->stack_cap + 4;\n      if (new_stack_cap > json->stack_max)\n         new_stack_cap = json->stack_max;\n      stack_alloc = new_stack_cap * sizeof(struct _rjson_stack);\n      if (json->stack != json->inline_stack)\n         new_stack = (struct _rjson_stack *)realloc(json->stack, stack_alloc);\n      else if ((new_stack = (struct _rjson_stack*)malloc(stack_alloc)) != NULL)\n         memcpy(new_stack, json->inline_stack, sizeof(json->inline_stack));\n      if (!new_stack)\n         return _rjson_error(json, \"out of memory\");\n\n      json->stack     = new_stack;\n      json->stack_top = new_stack + json->stack_cap - 1;\n      json->stack_cap = new_stack_cap;\n   }\n   json->stack_top++;\n   json->stack_top->count = 0;\n   return (json->stack_top->type =\n            (t == _rJSON_TOK_ARRAY ? RJSON_ARRAY : RJSON_OBJECT));\n}\n\nstatic enum rjson_type _rjson_read_name(rjson_t *json, const char *pattern, enum rjson_type type)\n{\n   _rjson_char_t c;\n   const char *p;\n   for (p = pattern; *p; p++)\n   {\n      if ((_rjson_char_t)*p != (c = _rjson_char_get(json)))\n         return _rjson_error_char(json, \"unexpected %s in value\", c);\n   }\n   return type;\n}\n\nstatic bool _rjson_optional_skip(rjson_t *json, const unsigned char **p, const unsigned char **end)\n{\n   unsigned char c, skip = (*p)[-1];\n   int state = 0;\n\n   if (skip == '/' && !(json->option_flags & RJSON_OPTION_ALLOW_COMMENTS))\n      return false;\n\n   if (     skip == 0xEF && (!(json->option_flags & RJSON_OPTION_ALLOW_UTF8BOM)\n         || json->source_line != 1 || json->source_column_p != json->input_p))\n      return false;\n\n   for (;;)\n   {\n      if (*p == *end)\n      {\n         if (!_rjson_io_input(json))\n         {\n            _rjson_error(json, \"unfinished %s\",\n                  (skip == '/' ? \"comment\" : \"utf8 byte order mark\"));\n            break;\n         }\n         *p   = json->input_p;\n         *end = json->input_end;\n      }\n      c = *(*p)++;\n      if (skip == '/')\n      {\n         if      (state == 0 && c == '/')\n            state = 1;\n         else if (state == 0 && c == '*')\n            state = 2;\n         else if (state == 0)\n            break;\n         else if (state == 1 && c == '\\n')\n            return true;\n         else if (state == 2 && c == '*')\n            state = 3;\n         else if (state == 3 && c == '/')\n            return true;\n         else if (state == 3 && c != '*')\n            state = 2;\n      }\n      else if (skip == 0xEF)\n      {\n         /* Silence warning - state being set never used */\n         if      (state == 0 && c == 0xBB)\n            state = 1;\n         else if (state == 1 && c == 0xBF)\n            return true;\n         else\n            break;\n      }\n   }\n   return false;\n}\n\nenum rjson_type rjson_next(rjson_t *json)\n{\n   unsigned char tok;\n   struct _rjson_stack *stack = json->stack_top;\n   const unsigned char *p     = json->input_p;\n   const unsigned char *end   = json->input_end;\n   unsigned char passed_token = false;\n\n   /* JSON token look-up-table */\n   static const unsigned char token_lut[256] =\n   {\n      #define i _rJSON_TOK_ERROR\n      /*   0 | 0x00 |   */ i,i,i,i,i,i,i,i,i,\n      /*   9 | 0x09 |\\t */ _rJSON_TOK_WHITESPACE,\n      /*  10 | 0x0A |\\n */ _rJSON_TOK_NEWLINE, i,i,\n      /*  13 | 0x0D |\\r */ _rJSON_TOK_WHITESPACE, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,\n      /*  32 | 0x20 |   */ _rJSON_TOK_WHITESPACE, i,\n      /*  34 | 0x22 | \" */ _rJSON_TOK_STRING, i,i,i,i,i,i,i,i,i,\n      /*  44 | 0x2C | , */ _rJSON_TOK_COMMA,\n      /*  45 | 0x2D | - */ _rJSON_TOK_NUMBER, i,\n      /*  47 | 0x2F | / */ _rJSON_TOK_OPTIONAL_SKIP,\n      /*  48 | 0x30 | 0 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,\n      /*  53 | 0x35 | 5 */ _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER, _rJSON_TOK_NUMBER,\n      /*  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,\n      /*  91 | 0x5B | [ */ _rJSON_TOK_ARRAY, i,\n      /*  93 | 0x5D | ] */ _rJSON_TOK_ARRAY_END, i,i,i,i,i,i,i,i,\n      /* 102 | 0x66 | f */ _rJSON_TOK_FALSE, i,i,i,i,i,i,i,\n      /* 110 | 0x6E | n */ _rJSON_TOK_NULL, i,i,i,i,i,\n      /* 116 | 0x74 | t */ _rJSON_TOK_TRUE, i,i,i,i,i,i,\n      /* 123 | 0x7B | { */ _rJSON_TOK_OBJECT, i,\n      /* 125 | 0x7D | } */ _rJSON_TOK_OBJECT_END,\n      /* 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,\n      /* 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,\n      /* 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,\n      /* 239 | 0xEF |   */ _rJSON_TOK_OPTIONAL_SKIP, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i\n      #undef i\n   };\n\n   if (_rJSON_LIKELY(stack->type != RJSON_ERROR))\n   {\n      for (;;)\n      {\n         if (_rJSON_LIKELY(p != end))\n         {\n            tok = token_lut[*p++];\n            if (_rJSON_LIKELY(tok > _rJSON_TOK_OPTIONAL_SKIP))\n            {\n               /* Actual JSON token, process below */\n            }\n            else if (_rJSON_LIKELY(tok == _rJSON_TOK_WHITESPACE))\n               continue;\n            else if (tok == _rJSON_TOK_NEWLINE)\n            {\n               json->source_line++;\n               json->source_column_p = p;\n               continue;\n            }\n            else if (tok == _rJSON_TOK_OPTIONAL_SKIP)\n            {\n               if (_rjson_optional_skip(json, &p, &end))\n                  continue;\n            }\n         }\n         else if (_rJSON_LIKELY(_rjson_io_input(json)))\n         {\n            p   = json->input_p;\n            end = json->input_end;\n            continue;\n         }\n         else\n         {\n            p   = json->input_end;\n            tok = _rJSON_TOK_EOF;\n         }\n\n         if (stack->type == RJSON_OBJECT)\n         {\n            if (stack->count & 1)\n            {\n               /* Expecting colon followed by value. */\n               if (passed_token)\n                  goto read_value;\n               if (_rJSON_LIKELY(tok == _rJSON_TOK_COLON))\n               {\n                  passed_token = true;\n                  continue;\n               }\n               json->input_p = p;\n               return _rjson_error_token(json,\n                     \"expected ':' not %s after member name\", (enum _rjson_token)tok);\n            }\n            if (passed_token)\n            {\n               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))\n                  goto read_value;\n               json->input_p = p;\n               return _rjson_error(json, \"expected member name after ','\");\n            }\n            if (tok == _rJSON_TOK_OBJECT_END)\n            {\n               json->input_p = p;\n               json->stack_top--;\n               return RJSON_OBJECT_END;\n            }\n            if (stack->count == 0)\n            {\n               /* No member name/value pairs yet. */\n               if (_rJSON_LIKELY(tok == _rJSON_TOK_STRING))\n                  goto read_value;\n               json->input_p = p;\n               return _rjson_error(json, \"expected member name or '}'\");\n            }\n            /* Expecting comma followed by member name. */\n            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))\n            {\n               passed_token = true;\n               continue;\n            }\n            json->input_p = p;\n            return _rjson_error_token(json,\n                  \"expected ',' or '}' not %s after member value\", (enum _rjson_token)tok);\n         }\n         else if (stack->type == RJSON_ARRAY)\n         {\n            if (passed_token)\n               goto read_value;\n            if (tok == _rJSON_TOK_ARRAY_END)\n            {\n               json->input_p = p;\n               json->stack_top--;\n               return RJSON_ARRAY_END;\n            }\n            if (stack->count == 0)\n               goto read_value;\n            if (_rJSON_LIKELY(tok == _rJSON_TOK_COMMA))\n            {\n               passed_token = true;\n               continue;\n            }\n            json->input_p = p;\n            return _rjson_error_token(json,\n                  \"expected ',' or ']' not %s in array\", (enum _rjson_token)tok);\n         }\n         else\n         {\n            if (_rJSON_LIKELY(!stack->count && tok != _rJSON_TOK_EOF))\n               goto read_value;\n            json->input_p = p;\n            if (!stack->count)\n               return _rjson_error(json, \"reached end without any data\");\n            if (tok == _rJSON_TOK_EOF)\n               return RJSON_DONE;\n            if (!(json->option_flags & RJSON_OPTION_ALLOW_TRAILING_DATA))\n               return _rjson_error_token(json,\n                     \"expected end of stream instead of %s\", (enum _rjson_token)tok);\n            json->input_p--;\n            return RJSON_DONE;\n         }\n\n         /* read value for current token */\n         read_value:\n         json->input_p = p;\n         stack->count++;\n         /* This is optimal when there are many strings, otherwise a switch statement\n          * or a function pointer table is better (depending on compiler/cpu) */\n         if      (tok == _rJSON_TOK_STRING)\n            return _rjson_read_string(json);\n         else if (tok == _rJSON_TOK_NUMBER)\n            return _rjson_read_number(json);\n         else if (tok == _rJSON_TOK_OBJECT)\n            return _rjson_push_stack(json, _rJSON_TOK_OBJECT);\n         else if (tok == _rJSON_TOK_ARRAY)\n            return _rjson_push_stack(json, _rJSON_TOK_ARRAY);\n         else if (tok == _rJSON_TOK_TRUE)\n            return _rjson_read_name(json, \"rue\", RJSON_TRUE);\n         else if (tok == _rJSON_TOK_FALSE)\n            return _rjson_read_name(json, \"alse\", RJSON_FALSE);\n         else if (tok == _rJSON_TOK_NULL)\n            return _rjson_read_name(json, \"ull\", RJSON_NULL);\n         else return _rjson_error_token(json,\n               \"unexpected %s in value\", (enum _rjson_token)tok);\n      }\n   }\n   return RJSON_ERROR;\n}\n\nvoid _rjson_setup(rjson_t *json, rjson_io_t io, void *user_data, int input_len)\n{\n   json->io                  = io;\n   json->user_data           = user_data;\n   json->input_len           = input_len;\n   json->input_p             = json->input_end = json->input_buf + input_len;\n\n   json->stack               = json->inline_stack;\n   json->stack_top           = json->stack;\n   json->stack_top->type     = RJSON_DONE;\n   json->stack_top->count    = 0;\n   json->stack_cap           = (unsigned int)(sizeof(json->inline_stack) / sizeof(json->inline_stack[0]));\n   json->stack_max           = (unsigned int)50;\n\n   json->string              = json->inline_string;\n   json->string_pass_through = NULL;\n   json->string_len          = 0;\n   json->string_cap          = sizeof(json->inline_string);\n\n   json->source_line         = 1;\n   json->source_column_p     = json->input_p;\n   json->option_flags        = 0;\n   json->decimal_sep         = 0;\n}\n\nrjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size)\n{\n   rjson_t* json;\n   /* Clamp io_block_size against negative / tiny / oversized values.\n    * The two internal callers (rjson_open_stream / rjson_open_rfile)\n    * already bound this, but this function is public and can be\n    * reached directly. */\n   if (io_block_size < 16)\n      io_block_size = 16;\n   else if ((size_t)io_block_size > _RJSON_MAX_SIZE)\n      io_block_size = (int)_RJSON_MAX_SIZE;\n   json = (rjson_t*)malloc(\n         sizeof(rjson_t) - sizeof(((rjson_t*)0)->input_buf) + io_block_size);\n   if (json) _rjson_setup(json, io, user_data, io_block_size);\n   return json;\n}\n\nstatic int _rjson_buffer_io(void* buf, int len, void *user)\n{\n   const char **ud = (const char **)user;\n   if (ud[1] - ud[0] < len) len = (int)(ud[1] - ud[0]);\n   memcpy(buf, ud[0], len);\n   ud[0] += len;\n   return len;\n}\n\nrjson_t *rjson_open_buffer(const void *buffer, size_t len)\n{\n   rjson_t *json   = (rjson_t *)malloc(sizeof(rjson_t) + sizeof(const char *)*2);\n   const char **ud = (const char **)(json + 1);\n   if (!json)\n      return NULL;\n   ud[0] = (const char *)buffer;\n   ud[1] = ud[0] + len;\n   _rjson_setup(json, _rjson_buffer_io, (void*)ud, sizeof(json->input_buf));\n   return json;\n}\n\nrjson_t *rjson_open_string(const char *string, size_t len)\n{\n   return rjson_open_buffer(string, len);\n}\n\nstatic int _rjson_stream_io(void* buf, int len, void *user)\n{\n   return (int)intfstream_read((intfstream_t*)user, buf, (uint64_t)len);\n}\n\nrjson_t *rjson_open_stream(struct intfstream_internal *stream)\n{\n   /* Allocate an input buffer based on the file size */\n   int64_t size = intfstream_get_size(stream);\n   int io_size  =\n         (size > 1024*1024 ? 4096 :\n         (size >  256*1024 ? 2048 : 1024));\n   return rjson_open_user(_rjson_stream_io, stream, io_size);\n}\n\nstatic int _rjson_rfile_io(void* buf, int len, void *user)\n{\n   return (int)filestream_read((RFILE*)user, buf, (int64_t)len);\n}\n\nrjson_t *rjson_open_rfile(RFILE *rfile)\n{\n   /* Allocate an input buffer based on the file size */\n   int64_t size = filestream_get_size(rfile);\n   int io_size =\n         (size > 1024*1024 ? 4096 :\n         (size >  256*1024 ? 2048 : 1024));\n   return rjson_open_user(_rjson_rfile_io, rfile, io_size);\n}\n\nvoid rjson_set_options(rjson_t *json, char rjson_option_flags)\n{\n   json->option_flags = rjson_option_flags;\n}\n\nvoid rjson_set_max_depth(rjson_t *json, unsigned int max_depth)\n{\n   json->stack_max = max_depth;\n}\n\nconst char *rjson_get_string(rjson_t *json, size_t *len)\n{\n   char* str             = (json->string_pass_through\n         ? json->string_pass_through : json->string);\n   if (len)\n      *len               = json->string_len;\n   str[json->string_len] = '\\0';\n   return str;\n}\n\ndouble rjson_get_double(rjson_t *json)\n{\n   char* str = (json->string_pass_through ? json->string_pass_through : json->string);\n   str[json->string_len] = '\\0';\n   if (json->decimal_sep != '.')\n   {\n      /* handle locale that uses a non-standard decimal separator */\n      char *p;\n      if (json->decimal_sep == 0)\n      {\n         char test[4];\n         snprintf(test, sizeof(test), \"%.1f\", 0.0f);\n         json->decimal_sep = test[1];\n      }\n      if (json->decimal_sep != '.' && (p = (char*)memchr(str, '.', strlen(str) + 1)) != NULL)\n      {\n         double res;\n         *p  = json->decimal_sep;\n         res = atof(str);\n         *p  = '.';\n         return res;\n      }\n   }\n   return atof(str);\n}\n\nint rjson_get_int(rjson_t *json)\n{\n   char* str = (json->string_pass_through ? json->string_pass_through : json->string);\n   str[json->string_len] = '\\0';\n   return atoi(str);\n}\n\nconst char *rjson_get_error(rjson_t *json)\n{\n   return (json->stack_top->type == RJSON_ERROR ? json->error_text : \"\");\n}\n\nvoid rjson_set_error(rjson_t *json, const char* error)\n{\n   _rjson_error(json, \"%s\", error);\n}\n\nsize_t rjson_get_source_line(rjson_t *json)\n{\n   return json->source_line;\n}\n\nsize_t rjson_get_source_column(rjson_t *json)\n{\n   return (json->input_p == json->source_column_p ? 1 :\n         json->input_p - json->source_column_p);\n}\n\nint rjson_get_source_context_len(rjson_t *json)\n{\n   const unsigned char *from = json->input_buf, *to = json->input_end, *p = json->input_p;\n   return (int)(((p + 256 < to ? p + 256 : to) - (p > from + 256 ? p - 256 : from)));\n}\n\nconst char* rjson_get_source_context_buf(rjson_t *json)\n{\n   /* inside the input buffer, some \" may have been replaced with \\0. */\n   const unsigned char *p = json->input_p, *from = json->input_buf;\n   unsigned char *i = json->input_buf;\n   for (; i != json->input_end; i++)\n   {\n      if (*i == '\\0')\n         *i = '\"';\n   }\n   return (const char*)(p > from + 256 ? p - 256 : from);\n}\n\nbool rjson_check_context(rjson_t *json, unsigned int depth, ...)\n{\n   va_list ap;\n   const struct _rjson_stack *stack = json->stack, *stack_top = json->stack_top;\n   if ((unsigned int)(stack_top - stack) != depth)\n      return false;\n   va_start(ap, depth);\n   while (++stack <= stack_top)\n   {\n      if (va_arg(ap, int) == (int)stack->type) continue;\n      va_end(ap);\n      return false;\n   }\n   va_end(ap);\n   return true;\n}\n\nunsigned int rjson_get_context_depth(rjson_t *json)\n{\n   return (unsigned int)(json->stack_top - json->stack);\n}\n\nsize_t rjson_get_context_count(rjson_t *json)\n{\n   return json->stack_top->count;\n}\n\nenum rjson_type rjson_get_context_type(rjson_t *json)\n{\n   return json->stack_top->type;\n}\n\nvoid rjson_free(rjson_t *json)\n{\n   if (json->stack != json->inline_stack)\n      free(json->stack);\n   if (json->string != json->inline_string)\n      free(json->string);\n   free(json);\n}\n\nstatic bool _rjson_nop_default(void *context) { return true; }\nstatic bool _rjson_nop_string(void *context, const char *value, size_t len) { return true; }\nstatic bool _rjson_nop_bool(void *context, bool value) { return true; }\n\nenum rjson_type rjson_parse(rjson_t *json, void* context,\n      bool (*object_member_handler)(void *context, const char *str, size_t len),\n      bool (*string_handler       )(void *context, const char *str, size_t len),\n      bool (*number_handler       )(void *context, const char *str, size_t len),\n      bool (*start_object_handler )(void *context),\n      bool (*end_object_handler   )(void *context),\n      bool (*start_array_handler  )(void *context),\n      bool (*end_array_handler    )(void *context),\n      bool (*boolean_handler      )(void *context, bool value),\n      bool (*null_handler         )(void *context))\n{\n   bool in_object = false;\n   size_t _len;\n   const char* string;\n   if (!object_member_handler) object_member_handler = _rjson_nop_string;\n   if (!string_handler       ) string_handler        = _rjson_nop_string;\n   if (!number_handler       ) number_handler        = _rjson_nop_string;\n   if (!start_object_handler ) start_object_handler  = _rjson_nop_default;\n   if (!end_object_handler   ) end_object_handler    = _rjson_nop_default;\n   if (!start_array_handler  ) start_array_handler   = _rjson_nop_default;\n   if (!end_array_handler    ) end_array_handler     = _rjson_nop_default;\n   if (!boolean_handler      ) boolean_handler       = _rjson_nop_bool;\n   if (!null_handler         ) null_handler          = _rjson_nop_default;\n   for (;;)\n   {\n      switch (rjson_next(json))\n      {\n         case RJSON_STRING:\n            string = rjson_get_string(json, &_len);\n            if (_rJSON_LIKELY(\n                  (in_object && (json->stack_top->count & 1) ?\n                     object_member_handler : string_handler)\n                     (context, string, _len)))\n               continue;\n            return RJSON_STRING;\n         case RJSON_NUMBER:\n            string = rjson_get_string(json, &_len);\n            if (_rJSON_LIKELY(number_handler(context, string, _len)))\n               continue;\n            return RJSON_NUMBER;\n         case RJSON_OBJECT:\n            in_object = true;\n            if (_rJSON_LIKELY(start_object_handler(context)))\n               continue;\n            return RJSON_OBJECT;\n         case RJSON_ARRAY:\n            in_object = false;\n            if (_rJSON_LIKELY(start_array_handler(context)))\n               continue;\n            return RJSON_ARRAY;\n         case RJSON_OBJECT_END:\n            if (_rJSON_LIKELY(end_object_handler(context)))\n            {\n               in_object = (json->stack_top->type == RJSON_OBJECT);\n               continue;\n            }\n            return RJSON_OBJECT_END;\n         case RJSON_ARRAY_END:\n            if (_rJSON_LIKELY(end_array_handler(context)))\n            {\n               in_object = (json->stack_top->type == RJSON_OBJECT);\n               continue;\n            }\n            return RJSON_ARRAY_END;\n         case RJSON_TRUE:\n            if (_rJSON_LIKELY(boolean_handler(context, true)))\n               continue;\n            return RJSON_TRUE;\n         case RJSON_FALSE:\n            if (_rJSON_LIKELY(boolean_handler(context, false)))\n               continue;\n            return RJSON_FALSE;\n         case RJSON_NULL:\n            if (_rJSON_LIKELY(null_handler(context)))\n               continue;\n            return RJSON_NULL;\n         case RJSON_ERROR:\n            return RJSON_ERROR;\n         case RJSON_DONE:\n            return RJSON_DONE;\n      }\n   }\n}\n\nbool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,\n      bool (*object_member_handler)(void *context, const char *str, size_t len),\n      bool (*string_handler       )(void *context, const char *str, size_t len),\n      bool (*number_handler       )(void *context, const char *str, size_t len),\n      bool (*start_object_handler )(void *context),\n      bool (*end_object_handler   )(void *context),\n      bool (*start_array_handler  )(void *context),\n      bool (*end_array_handler    )(void *context),\n      bool (*boolean_handler      )(void *context, bool value),\n      bool (*null_handler         )(void *context),\n      void (*error_handler        )(void *context, int line, int col, const char* error))\n{\n   const char *user_data[2];\n   rjson_t json;\n   user_data[0] = string;\n   user_data[1] = string + len;\n   _rjson_setup(&json, _rjson_buffer_io, (void*)user_data, sizeof(json.input_buf));\n   rjson_set_options(&json, option_flags);\n   if (rjson_parse(&json, context,\n         object_member_handler, string_handler, number_handler,\n         start_object_handler, end_object_handler,\n         start_array_handler, end_array_handler,\n         boolean_handler, null_handler) == RJSON_DONE)\n      return true;\n   if (error_handler)\n      error_handler(context,\n            (int)rjson_get_source_line(&json),\n            (int)rjson_get_source_column(&json),\n            rjson_get_error(&json));\n   return false;\n}\n\nstruct rjsonwriter\n{\n   char* buf;\n   int buf_num, buf_cap;\n\n   rjsonwriter_io_t io;\n   void *user_data;\n\n   const char* error_text;\n   char option_flags, decimal_sep;\n   bool buf_is_output, final_flush;\n\n   char inline_buf[1024];\n};\n\nrjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data)\n{\n   rjsonwriter_t* writer = (rjsonwriter_t*)malloc(sizeof(rjsonwriter_t));\n   if (!writer)\n      return NULL;\n\n   writer->buf           = writer->inline_buf;\n   writer->buf_num       = 0;\n   writer->buf_cap       = sizeof(writer->inline_buf);\n\n   writer->error_text    = NULL;\n   writer->option_flags  = writer->decimal_sep = 0;\n   writer->buf_is_output = writer->final_flush = false;\n\n   writer->io            = io;\n   writer->user_data     = user_data;\n\n   return writer;\n}\n\nstatic int _rjsonwriter_stream_io(const void* buf, int len, void *user)\n{\n   return (int)intfstream_write((intfstream_t*)user, buf, (uint64_t)len);\n}\n\nrjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream)\n{\n   return rjsonwriter_open_user(_rjsonwriter_stream_io, stream);\n}\n\nstatic int _rjsonwriter_rfile_io(const void* buf, int len, void *user)\n{\n   return (int)filestream_write((RFILE*)user, buf, (int64_t)len);\n}\n\nrjsonwriter_t *rjsonwriter_open_rfile(RFILE *rfile)\n{\n   return rjsonwriter_open_user(_rjsonwriter_rfile_io, rfile);\n}\n\nstatic int _rjsonwriter_memory_io(const void* buf, int len, void *user)\n{\n   rjsonwriter_t *writer = (rjsonwriter_t *)user;\n   bool is_append        = (buf != writer->buf);\n   size_t append_len     = (is_append ? (size_t)len : 0);\n   size_t target;\n   int    new_cap;\n   /* Detect the int-overflow pre-patch, where buf_num + len + 512\n    * wrapped past INT_MAX and new_cap went negative.  The subsequent\n    * \"new_cap > buf_cap\" comparison then misbehaved and memcpy wrote\n    * past the existing allocation on a post-overflow buffer that\n    * hadn't been grown.  Do the arithmetic in size_t and cap at\n    * _RJSON_MAX_SIZE (which also fits comfortably in int). */\n   if (len < 0 || (size_t)writer->buf_num > _RJSON_MAX_SIZE - append_len\n                                           - 512)\n   {\n      if (!writer->error_text)\n         writer->error_text = \"output buffer too large\";\n      return 0;\n   }\n   target = (size_t)writer->buf_num + append_len + 512;\n   new_cap = (int)target;\n   if (!writer->final_flush && (is_append || new_cap > writer->buf_cap))\n   {\n      bool can_realloc   = (writer->buf != writer->inline_buf);\n      char* new_buf      = (char*)(can_realloc ? realloc(writer->buf, new_cap) : malloc(new_cap));\n      if (!new_buf)\n         return 0;\n      if (!can_realloc)\n         memcpy(new_buf, writer->buf, writer->buf_num);\n      if (is_append)\n      {\n         memcpy(new_buf + writer->buf_num, buf, len);\n         writer->buf_num += len;\n      }\n      writer->buf        = new_buf;\n      writer->buf_cap    = new_cap;\n   }\n   return len;\n}\n\nrjsonwriter_t *rjsonwriter_open_memory(void)\n{\n   rjsonwriter_t *writer = rjsonwriter_open_user(_rjsonwriter_memory_io, NULL);\n   if (!writer)\n      return NULL;\n   writer->user_data     = writer;\n   writer->buf_is_output = true;\n   return writer;\n}\n\nchar* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len)\n{\n   if (writer->io != _rjsonwriter_memory_io || writer->error_text)\n      return NULL;\n   if (writer->buf_num == writer->buf_cap)\n      rjsonwriter_flush(writer);\n   writer->buf[writer->buf_num] = '\\0';\n   if (len)\n      *len = writer->buf_num;\n   return writer->buf;\n}\n\nint rjsonwriter_count_memory_buffer(rjsonwriter_t *writer)\n{\n   return writer->buf_num;\n}\n\nvoid rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len)\n{\n   if (keep_len <= writer->buf_num)\n      writer->buf_num = (keep_len < 0 ? 0 : keep_len);\n}\n\nbool rjsonwriter_free(rjsonwriter_t *writer)\n{\n   bool res;\n   writer->final_flush = true;\n   res = rjsonwriter_flush(writer);\n   if (writer->buf != writer->inline_buf)\n      free(writer->buf);\n   free(writer);\n   return res;\n}\n\nvoid rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags)\n{\n   writer->option_flags = rjsonwriter_option_flags;\n}\n\nbool rjsonwriter_flush(rjsonwriter_t *writer)\n{\n   if (writer->buf_num && !writer->error_text && writer->io(writer->buf,\n            writer->buf_num, writer->user_data) != writer->buf_num)\n      writer->error_text = \"output error\";\n   if (!writer->buf_is_output || writer->error_text)\n      writer->buf_num = 0;\n   return !writer->error_text;\n}\n\nconst char *rjsonwriter_get_error(rjsonwriter_t *writer)\n{\n   return (writer->error_text ? writer->error_text : \"\");\n}\n\nvoid rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len)\n{\n   /* Guard against negative len and against buf_num+len signed\n    * overflow.  A caller that somehow passes a huge len would\n    * pre-patch compute a negative sum, skip the flush, then memcpy\n    * past the existing buffer below. */\n   if (len < 0)\n      return;\n   if ((size_t)writer->buf_num + (size_t)len > (size_t)writer->buf_cap)\n      rjsonwriter_flush(writer);\n   if (len == 1)\n   {\n      if (buf[0] > ' ' ||\n            !(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))\n         writer->buf[writer->buf_num++] = buf[0];\n   }\n   else\n   {\n      int add = writer->buf_cap - writer->buf_num;\n      if (add > len)\n         add = len;\n      memcpy(writer->buf + writer->buf_num, buf, add);\n      writer->buf_num += add;\n      if (len == add)\n         return;\n      rjsonwriter_flush(writer);\n      len -= add;\n      buf += add;\n      if (writer->buf_num + len <= writer->buf_cap)\n      {\n         memcpy(writer->buf + writer->buf_num, buf, len);\n         writer->buf_num += len;\n      }\n      else if (writer->io(buf, len, writer->user_data) != len)\n         writer->error_text = \"output error\";\n   }\n}\n\nvoid rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...)\n{\n   int available, need;\n   va_list ap, ap2;\n   if (writer->buf_num >= writer->buf_cap - 16)\n      rjsonwriter_flush(writer);\n   available = (writer->buf_cap - writer->buf_num);\n   va_start(ap, fmt);\n   need = vsnprintf(writer->buf + writer->buf_num, available, fmt, ap);\n   va_end(ap);\n   if (need <= 0)\n      return;\n   if (need < available)\n   {\n      writer->buf_num += need;\n      return;\n   }\n   rjsonwriter_flush(writer);\n   /* Guard signed-int overflow on newcap: buf_num + need + 1 could\n    * wrap past INT_MAX for a single very large formatted value. */\n   if ((size_t)writer->buf_num + (size_t)need + 1 > _RJSON_MAX_SIZE)\n   {\n      if (!writer->error_text)\n         writer->error_text = \"output buffer too large\";\n      return;\n   }\n   if (writer->buf_num + need >= writer->buf_cap)\n   {\n      int newcap   = writer->buf_num + need + 1;\n      char* newbuf = (char*)malloc(newcap);\n      if (!newbuf)\n      {\n         if (!writer->error_text)\n            writer->error_text = \"out of memory\";\n         return;\n      }\n      if (writer->buf_num)\n         memcpy(newbuf, writer->buf, writer->buf_num);\n      if (writer->buf != writer->inline_buf)\n         free(writer->buf);\n      writer->buf = newbuf;\n      writer->buf_cap = newcap;\n   }\n   va_start(ap2, fmt);\n   vsnprintf(writer->buf + writer->buf_num, writer->buf_cap - writer->buf_num, fmt, ap2);\n   va_end(ap2);\n   writer->buf_num += need;\n}\n\nvoid _rjsonwriter_add_escaped(rjsonwriter_t *writer, unsigned char c)\n{\n   char esc_buf[8], esc_len = 2;\n   const char* esc;\n   switch (c)\n   {\n      case '\\b':\n         esc = \"\\\\b\";\n         break;\n      case '\\t':\n         esc = \"\\\\t\";\n         break;\n      case '\\n':\n         esc = \"\\\\n\";\n         break;\n      case '\\f':\n         esc = \"\\\\f\";\n         break;\n      case '\\r':\n         esc = \"\\\\r\";\n         break;\n      case '\\\"':\n         esc = \"\\\\\\\"\";\n         break;\n      case '\\\\':\n         esc = \"\\\\\\\\\";\n         break;\n      case '/':\n         esc = \"\\\\/\";\n         break;\n      default:\n         snprintf(esc_buf, sizeof(esc_buf), \"\\\\u%04x\", c);\n         esc     = esc_buf;\n         esc_len = 6;\n   }\n   rjsonwriter_raw(writer, esc, esc_len);\n}\n\nvoid rjsonwriter_add_string(rjsonwriter_t *writer, const char *value)\n{\n   const char *p = (const char*)value, *raw = p;\n   unsigned char c;\n   rjsonwriter_raw(writer, \"\\\"\", 1);\n   if (!p)\n      goto string_end;\n   while ((c = (unsigned char)*p++) != '\\0')\n   {\n      /* forward slash is special, it should be escaped if the previous character\n       * was a < (intended to avoid having </script> html tags in JSON files) */\n      if (   c >= 0x20 && c != '\\\"' && c != '\\\\' &&\n            (c != '/' || p < value + 2 || p[-2] != '<'))\n         continue;\n      if (raw != p - 1)\n         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));\n      _rjsonwriter_add_escaped(writer, c);\n      raw = p;\n   }\n   if (raw != p - 1)\n      rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));\nstring_end:\n   rjsonwriter_raw(writer, \"\\\"\", 1);\n}\n\nvoid rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len)\n{\n   const char *p = (const char*)value, *raw = p, *end = p + len;\n   rjsonwriter_raw(writer, \"\\\"\", 1);\n   while (p != end)\n   {\n      unsigned char c = (unsigned char)*p++;\n      if (      c >= 0x20 && c != '\\\"' && c != '\\\\'\n            && (c != '/' || p < value + 2 || p[-2] != '<'))\n         continue;\n      if (raw != p - 1)\n         rjsonwriter_raw(writer, raw, (int)(p - 1 - raw));\n      _rjsonwriter_add_escaped(writer, c);\n      raw = p;\n   }\n   if (raw != end)\n      rjsonwriter_raw(writer, raw, (int)(end - raw));\n   rjsonwriter_raw(writer, \"\\\"\", 1);\n}\n\nvoid rjsonwriter_add_double(rjsonwriter_t *writer, double value)\n{\n   int old_buf_num = writer->buf_num;\n   rjsonwriter_rawf(writer, \"%G\", value);\n   if (writer->decimal_sep != '.')\n   {\n      /* handle locale that uses a non-standard decimal separator */\n      char *p, *str;\n      if (writer->decimal_sep == 0)\n      {\n         char test[4];\n         snprintf(test, sizeof(test), \"%.1f\", 0.0f);\n         if ((writer->decimal_sep = test[1]) == '.')\n            return;\n      }\n      str = writer->buf + (old_buf_num > writer->buf_num ? 0 : old_buf_num);\n      if ((p = strchr(str, writer->decimal_sep)) != NULL)\n         *p = '.';\n   }\n}\n\nvoid rjsonwriter_add_spaces(rjsonwriter_t *writer, int count)\n{\n   if (!(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))\n      for (; count > 0; count -= 8)\n         rjsonwriter_raw(writer, \"        \", (count > 8 ? 8 : count));\n}\n\nvoid rjsonwriter_add_tabs(rjsonwriter_t *writer, int count)\n{\n   if (!(writer->option_flags & RJSONWRITER_OPTION_SKIP_WHITESPACE))\n      for (; count > 0; count -= 8)\n         rjsonwriter_raw(writer, \"\\t\\t\\t\\t\\t\\t\\t\\t\", (count > 8 ? 8 : count));\n}\n\n#undef _rJSON_EOF\n#undef _rJSON_LIKELY\n"
  },
  {
    "path": "formats/libchdr/libchdr_bitstream.c",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n***************************************************************************\n\n    bitstream.c\n\n    Helper classes for reading/writing at the bit level.\n\n***************************************************************************/\n\n#include <stdlib.h>\n#include <libchdr/bitstream.h>\n\n/***************************************************************************\n *  INLINE FUNCTIONS\n ***************************************************************************\n */\n\nint bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); }\n\n/*-------------------------------------------------\n *  create_bitstream - constructor\n *-------------------------------------------------\n */\n\nstruct bitstream* create_bitstream(const void *src, uint32_t srclength)\n{\n\tstruct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream));\n\tbitstream->buffer = 0;\n\tbitstream->bits = 0;\n\tbitstream->read = (const uint8_t*)src;\n\tbitstream->doffset = 0;\n\tbitstream->dlength = srclength;\n\treturn bitstream;\n}\n\n\n/*-----------------------------------------------------\n *  bitstream_peek - fetch the requested number of bits\n *  but don't advance the input pointer\n *-----------------------------------------------------\n */\n\nuint32_t bitstream_peek(struct bitstream* bitstream, int numbits)\n{\n\tif (numbits == 0)\n\t\treturn 0;\n\n\t/* fetch data if we need more */\n\tif (numbits > bitstream->bits)\n\t{\n\t\twhile (bitstream->bits <= 24)\n\t\t{\n\t\t\tif (bitstream->doffset < bitstream->dlength)\n\t\t\t\tbitstream->buffer |= bitstream->read[bitstream->doffset] << (24 - bitstream->bits);\n\t\t\tbitstream->doffset++;\n\t\t\tbitstream->bits += 8;\n\t\t}\n\t}\n\n\t/* return the data */\n\treturn bitstream->buffer >> (32 - numbits);\n}\n\n\n/*-----------------------------------------------------\n *  bitstream_remove - advance the input pointer by the\n *  specified number of bits\n *-----------------------------------------------------\n */\n\nvoid bitstream_remove(struct bitstream* bitstream, int numbits)\n{\n\tbitstream->buffer <<= numbits;\n\tbitstream->bits -= numbits;\n}\n\n\n/*-----------------------------------------------------\n *  bitstream_read - fetch the requested number of bits\n *-----------------------------------------------------\n */\n\nuint32_t bitstream_read(struct bitstream* bitstream, int numbits)\n{\n\tuint32_t result = bitstream_peek(bitstream, numbits);\n\tbitstream_remove(bitstream, numbits);\n\treturn result;\n}\n\n\n/*-------------------------------------------------\n *  read_offset - return the current read offset\n *-------------------------------------------------\n */\n\nuint32_t bitstream_read_offset(struct bitstream* bitstream)\n{\n\tuint32_t result = bitstream->doffset;\n\tint bits = bitstream->bits;\n\twhile (bits >= 8)\n\t{\n\t\tresult--;\n\t\tbits -= 8;\n\t}\n\treturn result;\n}\n\n\n/*-------------------------------------------------\n *  flush - flush to the nearest byte\n *-------------------------------------------------\n */\n\nuint32_t bitstream_flush(struct bitstream* bitstream)\n{\n\twhile (bitstream->bits >= 8)\n\t{\n\t\tbitstream->doffset--;\n\t\tbitstream->bits -= 8;\n\t}\n\tbitstream->bits = bitstream->buffer = 0;\n\treturn bitstream->doffset;\n}\n\n"
  },
  {
    "path": "formats/libchdr/libchdr_cdrom.c",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n***************************************************************************\n\n    cdrom.c\n\n    Generic MAME CD-ROM utilities - build IDE and SCSI CD-ROMs on top of this\n\n****************************************************************************\n\n    IMPORTANT:\n    \"physical\" block addresses are the actual addresses on the emulated CD.\n    \"chd\" block addresses are the block addresses in the CHD file.\n    Because we pad each track to a 4-frame boundary, these addressing\n    schemes will differ after track 1!\n\n***************************************************************************/\n\n#include <string.h>\n\n#include <libchdr/cdrom.h>\n\n#ifdef WANT_RAW_DATA_SECTOR\n\n/***************************************************************************\n    DEBUGGING\n***************************************************************************/\n\n/** @brief  The verbose. */\n#define VERBOSE (0)\n#if VERBOSE\n\n/**\n * @def LOG(x) do\n *\n * @brief   A macro that defines log.\n *\n * @param   x   The void to process.\n */\n\n#define LOG(x) do { if (VERBOSE) logerror x; } while (0)\n\n/**\n * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);\n *\n * @brief   Logerrors the given text.\n *\n * @param   text    The text.\n *\n * @return  A CLIB_DECL.\n */\n\nvoid CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);\n#else\n\n/**\n * @def LOG(x);\n *\n * @brief   A macro that defines log.\n *\n * @param   x   The void to process.\n */\n\n#define LOG(x)\n#endif\n\n/***************************************************************************\n    CONSTANTS\n***************************************************************************/\n\n/** @brief  offset within sector. */\n#define SYNC_OFFSET 0x000\n/** @brief  12 bytes. */\n#define SYNC_NUM_BYTES 12\n\n/** @brief  offset within sector. */\n#define MODE_OFFSET 0x00f\n\n/** @brief  offset within sector. */\n#define ECC_P_OFFSET 0x81c\n/** @brief  2 lots of 86. */\n#define ECC_P_NUM_BYTES 86\n/** @brief  24 bytes each. */\n#define ECC_P_COMP 24\n\n/** @brief  The ECC q offset. */\n#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)\n/** @brief  2 lots of 52. */\n#define ECC_Q_NUM_BYTES 52\n/** @brief  43 bytes each. */\n#define ECC_Q_COMP 43\n\n/**\n * @brief   -------------------------------------------------\n *            ECC lookup tables pre-calculated tables for ECC data calcs\n *          -------------------------------------------------.\n */\n\nstatic const uint8_t ecclow[256] =\n{\n\t0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,\n\t0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,\n\t0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,\n\t0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,\n\t0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,\n\t0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,\n\t0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,\n\t0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,\n\t0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,\n\t0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,\n\t0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,\n\t0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,\n\t0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,\n\t0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,\n\t0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,\n\t0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3\n};\n\n/** @brief  The ecchigh[ 256]. */\nstatic const uint8_t ecchigh[256] =\n{\n\t0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,\n\t0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,\n\t0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,\n\t0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,\n\t0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,\n\t0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,\n\t0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,\n\t0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,\n\t0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,\n\t0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,\n\t0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,\n\t0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,\n\t0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,\n\t0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,\n\t0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,\n\t0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55\n};\n\n/**\n * @brief   -------------------------------------------------\n *            poffsets - each row represents the addresses used to calculate a byte of the ECC P\n *            data 86 (*2) ECC P bytes, 24 values represented by each\n *          -------------------------------------------------.\n */\n\nstatic const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =\n{\n\t{ 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },\n\t{ 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },\n\t{ 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },\n\t{ 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },\n\t{ 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },\n\t{ 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },\n\t{ 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },\n\t{ 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },\n\t{ 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },\n\t{ 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },\n\t{ 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },\n\t{ 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },\n\t{ 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },\n\t{ 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },\n\t{ 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },\n\t{ 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },\n\t{ 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },\n\t{ 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },\n\t{ 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },\n\t{ 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },\n\t{ 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },\n\t{ 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },\n\t{ 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },\n\t{ 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },\n\t{ 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },\n\t{ 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },\n\t{ 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },\n\t{ 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },\n\t{ 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },\n\t{ 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },\n\t{ 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },\n\t{ 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },\n\t{ 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },\n\t{ 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },\n\t{ 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },\n\t{ 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },\n\t{ 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },\n\t{ 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },\n\t{ 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },\n\t{ 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },\n\t{ 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },\n\t{ 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },\n\t{ 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },\n\t{ 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },\n\t{ 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },\n\t{ 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },\n\t{ 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },\n\t{ 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },\n\t{ 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },\n\t{ 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },\n\t{ 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },\n\t{ 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },\n\t{ 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },\n\t{ 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },\n\t{ 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },\n\t{ 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },\n\t{ 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },\n\t{ 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },\n\t{ 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },\n\t{ 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },\n\t{ 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },\n\t{ 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },\n\t{ 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },\n\t{ 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },\n\t{ 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },\n\t{ 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },\n\t{ 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },\n\t{ 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },\n\t{ 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },\n\t{ 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },\n\t{ 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },\n\t{ 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },\n\t{ 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },\n\t{ 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },\n\t{ 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },\n\t{ 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },\n\t{ 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },\n\t{ 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },\n\t{ 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },\n\t{ 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },\n\t{ 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },\n\t{ 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },\n\t{ 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },\n\t{ 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },\n\t{ 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },\n\t{ 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }\n};\n\n/**\n * @brief   -------------------------------------------------\n *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q\n *            data 52 (*2) ECC Q bytes, 43 values represented by each\n *          -------------------------------------------------.\n */\n\nstatic const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =\n{\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 },\n\t{ 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 }\n};\n\n/*-------------------------------------------------\n *  ecc_source_byte - return data from the sector\n *  at the given offset, masking anything\n *  particular to a mode\n *-------------------------------------------------\n */\n\nstatic INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)\n{\n\t/* in mode 2 always treat these as 0 bytes */\n\treturn (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];\n}\n\n/**\n * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2)\n *\n * @brief   -------------------------------------------------\n *            ecc_compute_bytes - calculate an ECC value (P or Q)\n *          -------------------------------------------------.\n *\n * @param   sector          The sector.\n * @param   row             The row.\n * @param   rowlen          The rowlen.\n * @param [in,out]  val1    The first value.\n * @param [in,out]  val2    The second value.\n */\n\nvoid ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)\n{\n\tint component;\n\t*val1 = *val2 = 0;\n\tfor (component = 0; component < rowlen; component++)\n\t{\n\t\t*val1 ^= ecc_source_byte(sector, row[component]);\n\t\t*val2 ^= ecc_source_byte(sector, row[component]);\n\t\t*val1 = ecclow[*val1];\n\t}\n\t*val1 = ecchigh[ecclow[*val1] ^ *val2];\n\t*val2 ^= *val1;\n}\n\n/**\n * @fn  int ecc_verify(const uint8_t *sector)\n *\n * @brief   -------------------------------------------------\n *            ecc_verify - verify the P and Q ECC codes in a sector\n *          -------------------------------------------------.\n *\n * @param   sector  The sector.\n *\n * @return  true if it succeeds, false if it fails.\n */\n\nint ecc_verify(const uint8_t *sector)\n{\n\tint byte;\n\t/* first verify P bytes */\n\tfor (byte = 0; byte < ECC_P_NUM_BYTES; byte++)\n\t{\n\t\tuint8_t val1, val2;\n\t\tecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);\n\t\tif (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)\n\t\t\treturn 0;\n\t}\n\n\t/* then verify Q bytes */\n\tfor (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)\n\t{\n\t\tuint8_t val1, val2;\n\t\tecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);\n\t\tif (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)\n\t\t\treturn 0;\n\t}\n\treturn 1;\n}\n\n/**\n * @fn  void ecc_generate(uint8_t *sector)\n *\n * @brief   -------------------------------------------------\n *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any\n *            existing codes\n *          -------------------------------------------------.\n *\n * @param [in,out]  sector  If non-null, the sector.\n */\n\nvoid ecc_generate(uint8_t *sector)\n{\n\tint byte;\n\t/* first verify P bytes */\n\tfor (byte = 0; byte < ECC_P_NUM_BYTES; byte++)\n\t\tecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);\n\n\t/* then verify Q bytes */\n\tfor (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)\n\t\tecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);\n}\n\n/**\n * @fn  void ecc_clear(uint8_t *sector)\n *\n * @brief   -------------------------------------------------\n *            ecc_clear - erase the ECC P and Q cods to 0 within a sector\n *          -------------------------------------------------.\n *\n * @param [in,out]  sector  If non-null, the sector.\n */\n\nvoid ecc_clear(uint8_t *sector)\n{\n\tmemset(&sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);\n\tmemset(&sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);\n}\n\n#endif /* WANT_RAW_DATA_SECTOR */\n"
  },
  {
    "path": "formats/libchdr/libchdr_chd.c",
    "content": "/***************************************************************************\n\n    chd.c\n\n    MAME Compressed Hunks of Data file format\n\n****************************************************************************\n\n    Copyright Aaron Giles\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n          notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in\n          the documentation and/or other materials provided with the\n          distribution.\n        * Neither the name 'MAME' nor the names of its contributors may be\n          used to endorse or promote products derived from this software\n          without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,\n    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n***************************************************************************/\n\n#include <stddef.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n#include <libchdr/chd.h>\n#include <libchdr/cdrom.h>\n#include <libchdr/huffman.h>\n#include <libchdr/minmax.h>\n\n#ifdef HAVE_FLAC\n#include <libchdr/flac.h>\n#endif\n\n#ifdef HAVE_ZLIB\n#include <libchdr/libchdr_zlib.h>\n#endif\n\n#ifdef HAVE_7ZIP\n#include <libchdr/lzma.h>\n#endif\n\n#ifdef HAVE_ZSTD\n#include <libchdr/libchdr_zstd.h>\n#endif\n\n#if defined(__PS3__) || defined(__PSL1GHT__)\n#define __MACTYPES__\n#endif\n\n#define TRUE 1\n#define FALSE 0\n#define SHA1_DIGEST_SIZE 20\n\n/***************************************************************************\n    DEBUGGING\n***************************************************************************/\n\n#define PRINTF_MAX_HUNK\t\t\t\t(0)\n\n/***************************************************************************\n    CONSTANTS\n***************************************************************************/\n\n#define MAP_STACK_ENTRIES\t\t\t512\t\t\t/* max number of entries to use on the stack */\n#define MAP_ENTRY_SIZE\t\t\t\t16\t\t\t/* V3 and later */\n#define OLD_MAP_ENTRY_SIZE\t\t\t8\t\t\t/* V1-V2 */\n#define METADATA_HEADER_SIZE\t\t16\t\t\t/* metadata header size */\n\n#define MAP_ENTRY_FLAG_TYPE_MASK\t0x0f\t\t/* what type of hunk */\n#define MAP_ENTRY_FLAG_NO_CRC\t\t0x10\t\t/* no CRC is present */\n\n#define CHD_V1_SECTOR_SIZE\t\t\t512\t\t\t/* size of a \"sector\" in the V1 header */\n\n#define COOKIE_VALUE\t\t\t\t0xbaadf00d\n#define MAX_ZLIB_ALLOCS\t\t\t\t64\n\n#define END_OF_LIST_COOKIE\t\t\t\"EndOfListCookie\"\n\n#define NO_MATCH\t\t\t\t\t(~0)\n\n/* V3-V4 entry types */\nenum\n{\n\tV34_MAP_ENTRY_TYPE_INVALID = 0,             /* invalid type */\n\tV34_MAP_ENTRY_TYPE_COMPRESSED = 1,          /* standard compression */\n\tV34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        /* uncompressed data */\n\tV34_MAP_ENTRY_TYPE_MINI = 3,                /* mini: use offset as raw data */\n\tV34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           /* same as another hunk in this file */\n\tV34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         /* same as a hunk in the parent file */\n\tV34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       /* compressed with secondary algorithm (usually FLAC CDDA) */\n};\n\n/* V5 compression types */\nenum\n{\n\t/* codec #0\n\t * these types are live when running */\n\tCOMPRESSION_TYPE_0 = 0,\n\t/* codec #1 */\n\tCOMPRESSION_TYPE_1 = 1,\n\t/* codec #2 */\n\tCOMPRESSION_TYPE_2 = 2,\n\t/* codec #3 */\n\tCOMPRESSION_TYPE_3 = 3,\n\t/* no compression; implicit length = hunkbytes */\n\tCOMPRESSION_NONE = 4,\n\t/* same as another block in this chd */\n\tCOMPRESSION_SELF = 5,\n\t/* same as a hunk's worth of units in the parent chd */\n\tCOMPRESSION_PARENT = 6,\n\n\t/* start of small RLE run (4-bit length)\n\t * these additional pseudo-types are used for compressed encodings: */\n\tCOMPRESSION_RLE_SMALL,\n\t/* start of large RLE run (8-bit length) */\n\tCOMPRESSION_RLE_LARGE,\n\t/* same as the last COMPRESSION_SELF block */\n\tCOMPRESSION_SELF_0,\n\t/* same as the last COMPRESSION_SELF block + 1 */\n\tCOMPRESSION_SELF_1,\n\t/* same block in the parent */\n\tCOMPRESSION_PARENT_SELF,\n\t/* same as the last COMPRESSION_PARENT block */\n\tCOMPRESSION_PARENT_0,\n\t/* same as the last COMPRESSION_PARENT block + 1 */\n\tCOMPRESSION_PARENT_1\n};\n\n/***************************************************************************\n    MACROS\n***************************************************************************/\n\n#define EARLY_EXIT(x)\t\t\t\tdo { (void)(x); goto cleanup; } while (0)\n\n/***************************************************************************\n    TYPE DEFINITIONS\n***************************************************************************/\n\n/* interface to a codec */\ntypedef struct _codec_interface codec_interface;\nstruct _codec_interface\n{\n\tuint32_t\t\tcompression;\t\t\t\t\t\t\t\t/* type of compression */\n\tconst char *compname;\t\t\t\t\t\t\t\t\t/* name of the algorithm */\n\tuint8_t\t\tlossy;\t\t\t\t\t\t\t\t\t\t/* is this a lossy algorithm? */\n\tchd_error\t(*init)(void *codec, uint32_t hunkbytes);\t\t/* codec initialize */\n\tvoid\t\t(*free)(void *codec);\t\t\t\t\t\t/* codec free */\n\tchd_error\t(*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */\n\tchd_error\t(*config)(void *codec, int param, void *config); /* configure */\n};\n\n/* a single map entry */\ntypedef struct _map_entry map_entry;\nstruct _map_entry\n{\n\tuint64_t\t\t\t\t\toffset;\t\t\t/* offset within the file of the data */\n\tuint32_t\t\t\t\t\tcrc;\t\t\t/* 32-bit CRC of the data */\n\tuint32_t\t\t\t\t\tlength;\t\t\t/* length of the data */\n\tuint8_t\t\t\t\t\tflags;\t\t\t/* misc flags */\n};\n\n/* a single metadata entry */\ntypedef struct _metadata_entry metadata_entry;\nstruct _metadata_entry\n{\n\tuint64_t\t\t\t\t\toffset;\t\t\t/* offset within the file of the header */\n\tuint64_t\t\t\t\t\tnext;\t\t\t/* offset within the file of the next header */\n\tuint64_t\t\t\t\t\tprev;\t\t\t/* offset within the file of the previous header */\n\tuint32_t\t\t\t\t\tlength;\t\t\t/* length of the metadata */\n\tuint32_t\t\t\t\t\tmetatag;\t\t/* metadata tag */\n\tuint8_t\t\t\t\t\tflags;\t\t\t/* flag bits */\n};\n\n\ntypedef struct _huff_codec_data huff_codec_data;\nstruct _huff_codec_data\n{\n\tstruct huffman_decoder* decoder;\n};\n\n\n/* internal representation of an open CHD file */\nstruct _chd_file\n{\n\tuint32_t\t\t\t\t\tcookie;\t\t\t/* cookie, should equal COOKIE_VALUE */\n\n\tcore_file *\t\t\t\tfile;\t\t\t/* handle to the open core file */\n\tchd_header\t\t\t\theader;\t\t\t/* header, extracted from file */\n\n\tchd_file *\t\t\t\tparent;\t\t\t/* pointer to parent file, or NULL */\n\n\tmap_entry *\t\t\t\tmap;\t\t\t/* array of map entries */\n\n#ifdef NEED_CACHE_HUNK\n\tuint8_t *\t\t\t\t\tcache;\t\t\t/* hunk cache pointer */\n\tuint32_t\t\t\t\t\tcachehunk;\t\t/* index of currently cached hunk */\n\n\tuint8_t *\t\t\t\t\tcompare;\t\t/* hunk compare pointer */\n\tuint32_t\t\t\t\t\tcomparehunk;\t/* index of current compare data */\n#endif\n\n\tuint8_t *\t\t\t\t\tcompressed;\t\t/* pointer to buffer for compressed data */\n\tconst codec_interface *\tcodecintf[4];\t/* interface to the codec */\n\n\thuff_codec_data\t\t\thuff_codec_data;\t\t/* huff codec data */\n#ifdef HAVE_ZLIB\n\tzlib_codec_data\t\t\tzlib_codec_data;\t\t/* zlib codec data */\n\tcdzl_codec_data\t\t\tcdzl_codec_data;\t\t/* cdzl codec data */\n#endif\n#ifdef HAVE_7ZIP\n\tlzma_codec_data\t\t\tlzma_codec_data;\t\t/* lzma codec data */\n\tcdlz_codec_data\t\t\tcdlz_codec_data;\t\t/* cdlz codec data */\n#endif\n#ifdef HAVE_FLAC\n\tflac_codec_data\t\t\tflac_codec_data;\t\t/* flac codec data */\n\tcdfl_codec_data\t\t\tcdfl_codec_data;\t\t/* cdfl codec data */\n#endif\n#ifdef HAVE_ZSTD\n\tzstd_codec_data\t\t\tzstd_codec_data;\t\t/* zstd codec data */\n\tcdzs_codec_data\t\t\tcdzs_codec_data;\t\t/* cdzs codec data */\n#endif\n\n#ifdef NEED_CACHE_HUNK\n\tuint32_t\t\t\t\t\tmaxhunk;\t\t/* maximum hunk accessed */\n#endif\n\n\tuint8_t *\t\t\t\t\tfile_cache;\t\t/* cache of underlying file */\n};\n\n\n/***************************************************************************\n    GLOBAL VARIABLES\n***************************************************************************/\n\nstatic const uint8_t nullmd5[CHD_MD5_BYTES] = { 0 };\nstatic const uint8_t nullsha1[CHD_SHA1_BYTES] = { 0 };\n\n/***************************************************************************\n    PROTOTYPES\n***************************************************************************/\n\n/* core_file wrappers over stdio */\nstatic core_file *core_stdio_fopen(char const *path);\nstatic uint64_t core_stdio_fsize(core_file *file);\nstatic size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file);\nstatic int core_stdio_fclose(core_file *file);\nstatic int core_stdio_fclose_nonowner(core_file *file); /* alternate fclose used by chd_open_file */\nstatic int core_stdio_fseek(core_file* file, int64_t offset, int whence);\n\n/* internal header operations */\nstatic chd_error header_validate(const chd_header *header);\nstatic chd_error header_read(chd_file *chd, chd_header *header);\n\n/* internal hunk read/write */\n#ifdef NEED_CACHE_HUNK\nstatic chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum);\n#endif\nstatic chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest);\n\n/* internal map access */\nstatic chd_error map_read(chd_file *chd);\n\n/* metadata management */\nstatic chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry);\n\n/* zlib compression codec */\nchd_error zlib_codec_init(void *codec, uint32_t hunkbytes);\nvoid zlib_codec_free(void *codec);\nchd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\nvoidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);\nvoid zlib_fast_free(voidpf opaque, voidpf address);\nvoid zlib_allocator_free(voidpf opaque);\n\n/* lzma compression codec */\nchd_error lzma_codec_init(void *codec, uint32_t hunkbytes);\nvoid lzma_codec_free(void *codec);\nchd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* huff compression codec */\nstatic chd_error huff_codec_init(void *codec, uint32_t hunkbytes);\nstatic void huff_codec_free(void *codec);\nstatic chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* flac compression codec */\nchd_error flac_codec_init(void *codec, uint32_t hunkbytes);\nvoid flac_codec_free(void *codec);\nchd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* zstd compression codec */\nchd_error zstd_codec_init(void *codec, uint32_t hunkbytes);\nvoid zstd_codec_free(void *codec);\nchd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* cdzl compression codec */\nchd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);\nvoid cdzl_codec_free(void* codec);\nchd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* cdlz compression codec */\nchd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);\nvoid cdlz_codec_free(void* codec);\nchd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* cdfl compression codec */\nchd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);\nvoid cdfl_codec_free(void* codec);\nchd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n/* cdzs compression codec */\nchd_error cdzs_codec_init(void *codec, uint32_t hunkbytes);\nvoid cdzs_codec_free(void *codec);\nchd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n\n/***************************************************************************\n *  HUFFMAN DECOMPRESSOR\n ***************************************************************************\n */\n\nstatic chd_error huff_codec_init(void* codec, uint32_t hunkbytes)\n{\n\thuff_codec_data* huff_codec = (huff_codec_data*) codec;\n\thuff_codec->decoder = create_huffman_decoder(256, 16);\n\treturn CHDERR_NONE;\n}\n\nstatic void huff_codec_free(void *codec)\n{\n\thuff_codec_data* huff_codec = (huff_codec_data*) codec;\n\tdelete_huffman_decoder(huff_codec->decoder);\n}\n\nstatic chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tuint32_t cur;\n\tchd_error result;\n\thuff_codec_data* huff_codec = (huff_codec_data*) codec;\n\tstruct bitstream* bitbuf = create_bitstream(src, complen);\n\n\t/* first import the tree */\n\tenum huffman_error err = huffman_import_tree_huffman(huff_codec->decoder, bitbuf);\n\tif (err != HUFFERR_NONE)\n\t{\n\t\tfree(bitbuf);\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\n\t/* then decode the data */\n\tfor (cur = 0; cur < destlen; cur++)\n\t\tdest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf);\n\tbitstream_flush(bitbuf);\n\tresult = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE;\n\n\tfree(bitbuf);\n\treturn result;\n}\n\n\n/***************************************************************************\n    CODEC INTERFACES\n***************************************************************************/\n\nstatic const codec_interface codec_interfaces[] =\n{\n\t/* \"none\" or no compression */\n\t{\n\t\tCHDCOMPRESSION_NONE,\n\t\t\"none\",\n\t\tFALSE,\n\t\tNULL,\n\t\tNULL,\n\t\tNULL,\n\t\tNULL\n\t},\n\n#ifdef HAVE_ZLIB\n\t/* standard zlib compression */\n\t{\n\t\tCHDCOMPRESSION_ZLIB,\n\t\t\"zlib\",\n\t\tFALSE,\n\t\tzlib_codec_init,\n\t\tzlib_codec_free,\n\t\tzlib_codec_decompress,\n\t\tNULL\n\t},\n\n\t/* zlib+ compression */\n\t{\n\t\tCHDCOMPRESSION_ZLIB_PLUS,\n\t\t\"zlib+\",\n\t\tFALSE,\n\t\tzlib_codec_init,\n\t\tzlib_codec_free,\n\t\tzlib_codec_decompress,\n\t\tNULL\n\t},\n\n\t/* V5 zlib compression */\n\t{\n\t\tCHD_CODEC_ZLIB,\n\t\t\"zlib (Deflate)\",\n\t\tFALSE,\n\t\tzlib_codec_init,\n\t\tzlib_codec_free,\n\t\tzlib_codec_decompress,\n\t\tNULL\n\t},\n\t/* V5 CD zlib compression */\n\t{\n\t\tCHD_CODEC_CD_ZLIB,\n\t\t\"cdzl (CD Deflate)\",\n\t\tFALSE,\n\t\tcdzl_codec_init,\n\t\tcdzl_codec_free,\n\t\tcdzl_codec_decompress,\n\t\tNULL\n\t},\n#endif\n#ifdef HAVE_7ZIP\n\t/* V5 lzma compression */\n\t{\n\t\tCHD_CODEC_LZMA,\n\t\t\"lzma (LZMA)\",\n\t\tFALSE,\n\t\tlzma_codec_init,\n\t\tlzma_codec_free,\n\t\tlzma_codec_decompress,\n\t\tNULL\n\t},\n\t/* V5 CD lzma compression */\n\t{\n\t\tCHD_CODEC_CD_LZMA,\n\t\t\"cdlz (CD LZMA)\",\n\t\tFALSE,\n\t\tcdlz_codec_init,\n\t\tcdlz_codec_free,\n\t\tcdlz_codec_decompress,\n\t\tNULL\n\t},\n#endif\n\t/* V5 huffman compression */\n\t{\n\t\tCHD_CODEC_HUFFMAN,\n\t\t\"Huffman\",\n\t\tFALSE,\n\t\thuff_codec_init,\n\t\thuff_codec_free,\n\t\thuff_codec_decompress,\n\t\tNULL\n\t},\n#ifdef HAVE_FLAC\n\t/* V5 flac compression */\n\t{\n\t\tCHD_CODEC_FLAC,\n\t\t\"flac (FLAC)\",\n\t\tFALSE,\n\t\tflac_codec_init,\n\t\tflac_codec_free,\n\t\tflac_codec_decompress,\n\t\tNULL\n\t},\n\t/* V5 CD flac compression */\n\t{\n\t\tCHD_CODEC_CD_FLAC,\n\t\t\"cdfl (CD FLAC)\",\n\t\tFALSE,\n\t\tcdfl_codec_init,\n\t\tcdfl_codec_free,\n\t\tcdfl_codec_decompress,\n\t\tNULL\n\t},\n#endif\n#ifdef HAVE_ZSTD\n\t/* V5 zstd compression */\n\t{\n\t\tCHD_CODEC_ZSTD,\n\t\t\"zstd (Zstandard)\",\n\t\tFALSE,\n\t\tzstd_codec_init,\n\t\tzstd_codec_free,\n\t\tzstd_codec_decompress,\n\t\tNULL\n\t},\n\t/* V5 CD zstd compression */\n\t{\n\t\tCHD_CODEC_CD_ZSTD,\n\t\t\"cdzs (CD Zstandard)\",\n\t\tFALSE,\n\t\tcdzs_codec_init,\n\t\tcdzs_codec_free,\n\t\tcdzs_codec_decompress,\n\t\tNULL\n\t}\n#endif\n\n};\n\n/***************************************************************************\n    INLINE FUNCTIONS\n***************************************************************************/\n\n/*-------------------------------------------------\n    get_bigendian_uint64_t - fetch a uint64_t from\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE uint64_t get_bigendian_uint64_t(const uint8_t *base)\n{\n\treturn ((uint64_t)base[0] << 56) | ((uint64_t)base[1] << 48) | ((uint64_t)base[2] << 40) | ((uint64_t)base[3] << 32) |\n\t\t\t((uint64_t)base[4] << 24) | ((uint64_t)base[5] << 16) | ((uint64_t)base[6] << 8) | (uint64_t)base[7];\n}\n\n/*-------------------------------------------------\n    put_bigendian_uint64_t - write a uint64_t to\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE void put_bigendian_uint64_t(uint8_t *base, uint64_t value)\n{\n\tbase[0] = value >> 56;\n\tbase[1] = value >> 48;\n\tbase[2] = value >> 40;\n\tbase[3] = value >> 32;\n\tbase[4] = value >> 24;\n\tbase[5] = value >> 16;\n\tbase[6] = value >> 8;\n\tbase[7] = value;\n}\n\n/*-------------------------------------------------\n    get_bigendian_uint48 - fetch a UINT48 from\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE uint64_t get_bigendian_uint48(const uint8_t *base)\n{\n\treturn  ((uint64_t)base[0] << 40) | ((uint64_t)base[1] << 32) |\n\t\t\t((uint64_t)base[2] << 24) | ((uint64_t)base[3] << 16) | ((uint64_t)base[4] << 8) | (uint64_t)base[5];\n}\n\n/*-------------------------------------------------\n    put_bigendian_uint48 - write a UINT48 to\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE void put_bigendian_uint48(uint8_t *base, uint64_t value)\n{\n\tvalue &= 0xffffffffffff;\n\tbase[0] = value >> 40;\n\tbase[1] = value >> 32;\n\tbase[2] = value >> 24;\n\tbase[3] = value >> 16;\n\tbase[4] = value >> 8;\n\tbase[5] = value;\n}\n/*-------------------------------------------------\n    get_bigendian_uint32_t - fetch a uint32_t from\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE uint32_t get_bigendian_uint32_t(const uint8_t *base)\n{\n\treturn (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];\n}\n\n/*-------------------------------------------------\n    put_bigendian_uint24 - write a UINT24 to\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE void put_bigendian_uint24(uint8_t *base, uint32_t value)\n{\n\tvalue &= 0xffffff;\n\tbase[0] = value >> 16;\n\tbase[1] = value >> 8;\n\tbase[2] = value;\n}\n\n/*-------------------------------------------------\n    get_bigendian_uint24 - fetch a UINT24 from\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE uint32_t get_bigendian_uint24(const uint8_t *base)\n{\n\treturn (base[0] << 16) | (base[1] << 8) | base[2];\n}\n\n/*-------------------------------------------------\n    get_bigendian_uint16 - fetch a uint16_t from\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE uint16_t get_bigendian_uint16(const uint8_t *base)\n{\n\treturn (base[0] << 8) | base[1];\n}\n\n/*-------------------------------------------------\n    put_bigendian_uint16 - write a uint16_t to\n    the data stream in bigendian order\n-------------------------------------------------*/\n\nstatic INLINE void put_bigendian_uint16(uint8_t *base, uint16_t value)\n{\n\tbase[0] = value >> 8;\n\tbase[1] = value;\n}\n\n/*-------------------------------------------------\n    map_extract - extract a single map\n    entry from the datastream\n-------------------------------------------------*/\n\nstatic INLINE void map_extract(const uint8_t *base, map_entry *entry)\n{\n\tentry->offset = get_bigendian_uint64_t(&base[0]);\n\tentry->crc = get_bigendian_uint32_t(&base[8]);\n\tentry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);\n\tentry->flags = base[15];\n}\n\n/*-------------------------------------------------\n    map_size_v5 - calculate CHDv5 map size\n-------------------------------------------------*/\nstatic INLINE int map_size_v5(chd_header* header)\n{\n\treturn header->hunkcount * header->mapentrybytes;\n}\n\n/*-------------------------------------------------\n    crc16 - calculate CRC16 (from hashing.cpp)\n-------------------------------------------------*/\nuint16_t crc16(const void *data, uint32_t length)\n{\n\tuint16_t crc = 0xffff;\n\n\tstatic const uint16_t s_table[256] =\n\t{\n\t\t0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,\n\t\t0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,\n\t\t0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,\n\t\t0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,\n\t\t0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,\n\t\t0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,\n\t\t0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,\n\t\t0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,\n\t\t0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,\n\t\t0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,\n\t\t0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,\n\t\t0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,\n\t\t0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,\n\t\t0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,\n\t\t0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,\n\t\t0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,\n\t\t0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,\n\t\t0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,\n\t\t0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,\n\t\t0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,\n\t\t0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,\n\t\t0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,\n\t\t0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,\n\t\t0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,\n\t\t0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,\n\t\t0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,\n\t\t0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,\n\t\t0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,\n\t\t0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,\n\t\t0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,\n\t\t0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,\n\t\t0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0\n\t};\n\n\tconst uint8_t *src = (uint8_t*)data;\n\n\t/* fetch the current value into a local and rip through the source data */\n\twhile (length-- != 0)\n\t\tcrc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];\n\treturn crc;\n}\n\n/*-------------------------------------------------\n\tcompressed - test if CHD file is compressed\n+-------------------------------------------------*/\nstatic INLINE int chd_compressed(chd_header* header) {\n\treturn header->compression[0] != CHD_CODEC_NONE;\n}\n\n/*-------------------------------------------------\n\tdecompress_v5_map - decompress the v5 map\n-------------------------------------------------*/\n\nstatic chd_error decompress_v5_map(chd_file* chd, chd_header* header)\n{\n\tuint32_t hunknum;\n\tint repcount = 0;\n\tuint8_t lastcomp = 0;\n\tuint32_t last_self = 0;\n\tuint64_t last_parent = 0;\n\tstruct bitstream* bitbuf;\n\tuint32_t mapbytes;\n\tuint64_t firstoffs;\n\tuint16_t mapcrc;\n\tuint8_t lengthbits;\n\tuint8_t selfbits;\n\tuint8_t parentbits;\n\tuint8_t *compressed_ptr;\n\tuint8_t rawbuf[16];\n\tstruct huffman_decoder* decoder;\n\tenum huffman_error err;\n\tuint64_t curoffset;\n\tint rawmapsize = map_size_v5(header);\n\n\tif (!chd_compressed(header))\n\t{\n\t\theader->rawmap = (uint8_t*)malloc(rawmapsize);\n\t\tif (header->rawmap == NULL)\n\t\t\treturn CHDERR_OUT_OF_MEMORY;\n\t\tcore_fseek(chd->file, header->mapoffset, SEEK_SET);\n\t\tcore_fread(chd->file, header->rawmap, rawmapsize);\n\t\treturn CHDERR_NONE;\n\t}\n\n\t/* read the reader */\n\tcore_fseek(chd->file, header->mapoffset, SEEK_SET);\n\tcore_fread(chd->file, rawbuf, sizeof(rawbuf));\n\tmapbytes = get_bigendian_uint32_t(&rawbuf[0]);\n\tfirstoffs = get_bigendian_uint48(&rawbuf[4]);\n\tmapcrc = get_bigendian_uint16(&rawbuf[10]);\n\tlengthbits = rawbuf[12];\n\tselfbits = rawbuf[13];\n\tparentbits = rawbuf[14];\n\n\t/* now read the map */\n\tcompressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);\n\tif (compressed_ptr == NULL)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\tcore_fseek(chd->file, header->mapoffset + 16, SEEK_SET);\n\tcore_fread(chd->file, compressed_ptr, mapbytes);\n\tbitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes);\n\theader->rawmap = (uint8_t*)malloc(rawmapsize);\n\tif (header->rawmap == NULL)\n\t{\n\t\tfree(compressed_ptr);\n\t\tfree(bitbuf);\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\t}\n\n\t/* first decode the compression types */\n\tdecoder = create_huffman_decoder(16, 8);\n\tif (decoder == NULL)\n\t{\n\t\tfree(compressed_ptr);\n\t\tfree(bitbuf);\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\t}\n\n\terr = huffman_import_tree_rle(decoder, bitbuf);\n\tif (err != HUFFERR_NONE)\n\t{\n\t\tfree(compressed_ptr);\n\t\tfree(bitbuf);\n\t\tdelete_huffman_decoder(decoder);\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\n\tfor (hunknum = 0; hunknum < header->hunkcount; hunknum++)\n\t{\n\t\tuint8_t *rawmap = header->rawmap + (hunknum * 12);\n\t\tif (repcount > 0)\n\t\t\trawmap[0] = lastcomp, repcount--;\n\t\telse\n\t\t{\n\t\t\tuint8_t val = huffman_decode_one(decoder, bitbuf);\n\t\t\tif (val == COMPRESSION_RLE_SMALL)\n\t\t\t\trawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf);\n\t\t\telse if (val == COMPRESSION_RLE_LARGE)\n\t\t\t\trawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf);\n\t\t\telse\n\t\t\t\trawmap[0] = lastcomp = val;\n\t\t}\n\t}\n\n\t/* then iterate through the hunks and extract the needed data */\n\tcuroffset = firstoffs;\n\tfor (hunknum = 0; hunknum < header->hunkcount; hunknum++)\n\t{\n\t\tuint8_t *rawmap = header->rawmap + (hunknum * 12);\n\t\tuint64_t offset = curoffset;\n\t\tuint32_t length = 0;\n\t\tuint16_t crc = 0;\n\t\tswitch (rawmap[0])\n\t\t{\n\t\t\t/* base types */\n\t\t\tcase COMPRESSION_TYPE_0:\n\t\t\tcase COMPRESSION_TYPE_1:\n\t\t\tcase COMPRESSION_TYPE_2:\n\t\t\tcase COMPRESSION_TYPE_3:\n\t\t\t\tcuroffset += length = bitstream_read(bitbuf, lengthbits);\n\t\t\t\tcrc = bitstream_read(bitbuf, 16);\n\t\t\t\tbreak;\n\n\t\t\tcase COMPRESSION_NONE:\n\t\t\t\tcuroffset += length = header->hunkbytes;\n\t\t\t\tcrc = bitstream_read(bitbuf, 16);\n\t\t\t\tbreak;\n\n\t\t\tcase COMPRESSION_SELF:\n\t\t\t\tlast_self = offset = bitstream_read(bitbuf, selfbits);\n\t\t\t\tbreak;\n\n\t\t\tcase COMPRESSION_PARENT:\n\t\t\t\toffset = bitstream_read(bitbuf, parentbits);\n\t\t\t\tlast_parent = offset;\n\t\t\t\tbreak;\n\n\t\t\t/* pseudo-types; convert into base types */\n\t\t\tcase COMPRESSION_SELF_1:\n\t\t\t\tlast_self++;\n\t\t\tcase COMPRESSION_SELF_0:\n\t\t\t\trawmap[0] = COMPRESSION_SELF;\n\t\t\t\toffset = last_self;\n\t\t\t\tbreak;\n\n\t\t\tcase COMPRESSION_PARENT_SELF:\n\t\t\t\trawmap[0] = COMPRESSION_PARENT;\n\t\t\t\tlast_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;\n\t\t\t\tbreak;\n\n\t\t\tcase COMPRESSION_PARENT_1:\n\t\t\t\tlast_parent += header->hunkbytes / header->unitbytes;\n\t\t\tcase COMPRESSION_PARENT_0:\n\t\t\t\trawmap[0] = COMPRESSION_PARENT;\n\t\t\t\toffset = last_parent;\n\t\t\t\tbreak;\n\t\t}\n\t\t/* UINT24 length */\n\t\tput_bigendian_uint24(&rawmap[1], length);\n\n\t\t/* UINT48 offset */\n\t\tput_bigendian_uint48(&rawmap[4], offset);\n\n\t\t/* crc16 */\n\t\tput_bigendian_uint16(&rawmap[10], crc);\n\t}\n\n\t/* free memory */\n\tfree(compressed_ptr);\n\tfree(bitbuf);\n\tdelete_huffman_decoder(decoder);\n\n\t/* verify the final CRC */\n\tif (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\n\treturn CHDERR_NONE;\n}\n\n/*-------------------------------------------------\n    map_extract_old - extract a single map\n    entry in old format from the datastream\n-------------------------------------------------*/\n\nstatic INLINE void map_extract_old(const uint8_t *base, map_entry *entry, uint32_t hunkbytes)\n{\n\tentry->offset = get_bigendian_uint64_t(&base[0]);\n\tentry->crc = 0;\n\tentry->length = entry->offset >> 44;\n\tentry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);\n#ifdef __MWERKS__\n\tentry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;\n#else\n\tentry->offset = (entry->offset << 20) >> 20;\n#endif\n}\n\n/***************************************************************************\n    CHD FILE MANAGEMENT\n***************************************************************************/\n\n/*-------------------------------------------------\n    chd_open_file - open a CHD file for access\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd)\n{\n\tcore_file *stream = (core_file*)malloc(sizeof(core_file));\n\tif (!stream)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\tstream->argp = file;\n\tstream->fsize = core_stdio_fsize;\n\tstream->fread = core_stdio_fread;\n\tstream->fclose = core_stdio_fclose_nonowner;\n\tstream->fseek = core_stdio_fseek;\n\n\treturn chd_open_core_file(stream, mode, parent, chd);\n}\n\n/*-------------------------------------------------\n    chd_open_core_file - open a CHD file for access\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd)\n{\n\tchd_file *newchd = NULL;\n\tchd_error err;\n\tsize_t intfnum;\n\n\t/* verify parameters */\n\tif (file == NULL)\n\t\tEARLY_EXIT(err = CHDERR_INVALID_PARAMETER);\n\n\t/* punt if invalid parent */\n\tif (parent != NULL && parent->cookie != COOKIE_VALUE)\n\t\tEARLY_EXIT(err = CHDERR_INVALID_PARAMETER);\n\n\t/* allocate memory for the final result */\n\tnewchd = (chd_file *)malloc(sizeof(**chd));\n\tif (newchd == NULL)\n\t\tEARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);\n\tmemset(newchd, 0, sizeof(*newchd));\n\tnewchd->cookie = COOKIE_VALUE;\n\tnewchd->parent = parent;\n\tnewchd->file = file;\n\n\t/* now attempt to read the header */\n\terr = header_read(newchd, &newchd->header);\n\tif (err != CHDERR_NONE)\n\t\tEARLY_EXIT(err);\n\n\t/* validate the header */\n\terr = header_validate(&newchd->header);\n\tif (err != CHDERR_NONE)\n\t\tEARLY_EXIT(err);\n\n\t/* make sure we don't open a read-only file writeable */\n\tif (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))\n\t\tEARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);\n\n\t/* also, never open an older version writeable */\n\tif (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)\n\t\tEARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);\n\n\t/* if we need a parent, make sure we have one */\n\tif (parent == NULL)\n\t{\n\t\t/* Detect parent requirement for versions below 5 */\n\t\tif (newchd->header.version < 5 && newchd->header.flags & CHDFLAGS_HAS_PARENT)\n\t\t\tEARLY_EXIT(err = CHDERR_REQUIRES_PARENT);\n\t\t/* Detection for version 5 and above - if parentsha1 != 0, we have a parent */\n\t\telse if (newchd->header.version >= 5 && memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)\n\t\t\tEARLY_EXIT(err = CHDERR_REQUIRES_PARENT);\n\t}\n\n\t/* make sure we have a valid parent */\n\tif (parent != NULL)\n\t{\n\t\t/* check MD5 if it isn't empty */\n\t\tif (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&\n\t\t\tmemcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&\n\t\t\tmemcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)\n\t\t\tEARLY_EXIT(err = CHDERR_INVALID_PARENT);\n\n\t\t/* check SHA1 if it isn't empty */\n\t\tif (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&\n\t\t\tmemcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&\n\t\t\tmemcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)\n\t\t\tEARLY_EXIT(err = CHDERR_INVALID_PARENT);\n\t}\n\n\t/* now read the hunk map */\n\tif (newchd->header.version < 5)\n\t{\n\t\terr = map_read(newchd);\n\t\tif (err != CHDERR_NONE)\n\t\t\tEARLY_EXIT(err);\n\t}\n\telse\n\t{\n\t\terr = decompress_v5_map(newchd, &(newchd->header));\n\t}\n\tif (err != CHDERR_NONE)\n\t\tEARLY_EXIT(err);\n\n#ifdef NEED_CACHE_HUNK\n\t/* allocate and init the hunk cache */\n\tnewchd->cache   = (uint8_t *)malloc(newchd->header.hunkbytes);\n\tnewchd->compare = (uint8_t *)malloc(newchd->header.hunkbytes);\n\tif (newchd->cache == NULL || newchd->compare == NULL)\n\t\tEARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);\n\tnewchd->cachehunk   = ~0;\n\tnewchd->comparehunk = ~0;\n#endif\n\n\t/* allocate the temporary compressed buffer */\n\tnewchd->compressed = (uint8_t *)malloc(newchd->header.hunkbytes);\n\tif (newchd->compressed == NULL)\n\t\tEARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);\n\n\t/* find the codec interface */\n\tif (newchd->header.version < 5)\n\t{\n\t\tfor (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)\n\t\t{\n\t\t\tif (codec_interfaces[intfnum].compression == newchd->header.compression[0])\n\t\t\t{\n\t\t\t\tnewchd->codecintf[0] = &codec_interfaces[intfnum];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (intfnum == ARRAY_LENGTH(codec_interfaces))\n\t\t\tEARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);\n\n#ifdef HAVE_ZLIB\n\t\t/* initialize the codec */\n\t\tif (newchd->codecintf[0]->init != NULL)\n\t\t{\n\t\t\terr = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);\n\t\t\tif (err != CHDERR_NONE)\n\t\t\t\tEARLY_EXIT(err);\n\t\t}\n#endif\n\t}\n\telse\n\t{\n\t\tsize_t decompnum;\n\t\t/* verify the compression types and initialize the codecs */\n\t\tfor (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)\n\t\t{\n\t\t\tsize_t i;\n\t\t\tfor (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)\n\t\t\t{\n\t\t\t\tif (codec_interfaces[i].compression == newchd->header.compression[decompnum])\n\t\t\t\t{\n\t\t\t\t\tnewchd->codecintf[decompnum] = &codec_interfaces[i];\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)\n\t\t\t\tEARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);\n\n\t\t\t/* initialize the codec */\n\t\t\tif (newchd->codecintf[decompnum]->init != NULL)\n\t\t\t{\n\t\t\t\tvoid* codec = NULL;\n\t\t\t\tswitch (newchd->header.compression[decompnum])\n\t\t\t\t{\n\t\t\t\t\tcase CHD_CODEC_ZLIB:\n#ifdef HAVE_ZLIB\n\t\t\t\t\t\tcodec = &newchd->zlib_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_LZMA:\n#ifdef HAVE_7ZIP\n\t\t\t\t\t\tcodec = &newchd->lzma_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_HUFFMAN:\n\t\t\t\t\t\tcodec = &newchd->huff_codec_data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_FLAC:\n#ifdef HAVE_FLAC\n\t\t\t\t\t\tcodec = &newchd->flac_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_ZSTD:\n#ifdef HAVE_ZSTD\n\t\t\t\t\t\tcodec = &newchd->zstd_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_ZLIB:\n#ifdef HAVE_ZLIB\n\t\t\t\t\t\tcodec = &newchd->cdzl_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_LZMA:\n#ifdef HAVE_7ZIP\n\t\t\t\t\t\tcodec = &newchd->cdlz_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_FLAC:\n#ifdef HAVE_FLAC\n\t\t\t\t\t\tcodec = &newchd->cdfl_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_ZSTD:\n#ifdef HAVE_ZSTD\n\t\t\t\t\t\tcodec = &newchd->cdzs_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (codec == NULL)\n\t\t\t\t\tEARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);\n\n\t\t\t\terr = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\tEARLY_EXIT(err);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* all done */\n\t*chd = newchd;\n\treturn CHDERR_NONE;\n\ncleanup:\n\tif (newchd != NULL)\n\t\tchd_close(newchd);\n\treturn err;\n}\n\n/*-------------------------------------------------\n    chd_precache - precache underlying file in\n    memory\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_precache(chd_file *chd)\n{\n\tuint64_t count;\n\tuint64_t size;\n\n\tif (chd->file_cache == NULL)\n\t{\n\t\tsize = core_fsize(chd->file);\n\t\tif ((int64_t)size <= 0)\n\t\t\treturn CHDERR_INVALID_DATA;\n\t\tchd->file_cache = malloc(size);\n\t\tif (chd->file_cache == NULL)\n\t\t\treturn CHDERR_OUT_OF_MEMORY;\n\t\tcore_fseek(chd->file, 0, SEEK_SET);\n\t\tcount = core_fread(chd->file, chd->file_cache, size);\n\t\tif (count != size)\n\t\t{\n\t\t\tfree(chd->file_cache);\n\t\t\tchd->file_cache = NULL;\n\t\t\treturn CHDERR_READ_ERROR;\n\t\t}\n\t}\n\n\treturn CHDERR_NONE;\n}\n\n/*-------------------------------------------------\n    chd_open - open a CHD file by\n    filename\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)\n{\n\tchd_error err;\n\tcore_file *file = NULL;\n\n\tif (filename == NULL)\n\t{\n\t\terr = CHDERR_INVALID_PARAMETER;\n\t\tgoto cleanup;\n\t}\n\n\t/* choose the proper mode */\n\tswitch(mode)\n\t{\n\t\tcase CHD_OPEN_READ:\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\terr = CHDERR_INVALID_PARAMETER;\n\t\t\tgoto cleanup;\n\t}\n\n\t/* open the file */\n\tfile = core_stdio_fopen(filename);\n\tif (file == 0)\n\t{\n\t\terr = CHDERR_FILE_NOT_FOUND;\n\t\tgoto cleanup;\n\t}\n\n\t/* now open the CHD */\n\treturn chd_open_core_file(file, mode, parent, chd);\n\ncleanup:\n\tif ((err != CHDERR_NONE) && (file != NULL))\n\t\tcore_fclose(file);\n\treturn err;\n}\n\n/*-------------------------------------------------\n    chd_close - close a CHD file for access\n-------------------------------------------------*/\n\nCHD_EXPORT void chd_close(chd_file *chd)\n{\n\t/* punt if NULL or invalid */\n\tif (chd == NULL || chd->cookie != COOKIE_VALUE)\n\t\treturn;\n\n\t/* deinit the codec */\n\tif (chd->header.version < 5)\n\t{\n#ifdef HAVE_ZLIB\n\t\tif (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)\n\t\t\t(*chd->codecintf[0]->free)(&chd->zlib_codec_data);\n#endif\n\t}\n\telse\n\t{\n\t\tsize_t i;\n\t\t/* Free the codecs */\n\t\tfor (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++)\n\t\t{\n\t\t\tvoid* codec = NULL;\n\n\t\t\tif (chd->codecintf[i] == NULL)\n\t\t\t\tcontinue;\n\n\t\t\tswitch (chd->codecintf[i]->compression)\n\t\t\t{\n\t\t\t\tcase CHD_CODEC_ZLIB:\n#ifdef HAVE_ZLIB\n\t\t\t\t\tcodec = &chd->zlib_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_LZMA:\n#ifdef HAVE_7ZIP\n\t\t\t\t\tcodec = &chd->lzma_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_HUFFMAN:\n\t\t\t\t\tcodec = &chd->huff_codec_data;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_FLAC:\n#ifdef HAVE_FLAC\n\t\t\t\t\tcodec = &chd->flac_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_ZSTD:\n#ifdef HAVE_ZSTD\n\t\t\t\t\tcodec = &chd->zstd_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_CD_ZLIB:\n#ifdef HAVE_ZLIB\n\t\t\t\t\tcodec = &chd->cdzl_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_CD_LZMA:\n#ifdef HAVE_7ZIP\n\t\t\t\t\tcodec = &chd->cdlz_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_CD_FLAC:\n#ifdef HAVE_FLAC\n\t\t\t\t\tcodec = &chd->cdfl_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CHD_CODEC_CD_ZSTD:\n#ifdef HAVE_ZSTD\n\t\t\t\t\tcodec = &chd->cdzs_codec_data;\n#endif\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (codec)\n\t\t\t{\n\t\t\t\t(*chd->codecintf[i]->free)(codec);\n\t\t\t}\n\t\t}\n\n\t\t/* Free the raw map */\n\t\tif (chd->header.rawmap != NULL)\n\t\t\tfree(chd->header.rawmap);\n\t}\n\n\t/* free the compressed data buffer */\n\tif (chd->compressed != NULL)\n\t\tfree(chd->compressed);\n\n#ifdef NEED_CACHE_HUNK\n\t/* free the hunk cache and compare data */\n\tif (chd->compare != NULL)\n\t\tfree(chd->compare);\n\tif (chd->cache != NULL)\n\t\tfree(chd->cache);\n#endif\n\n\t/* free the hunk map */\n\tif (chd->map != NULL)\n\t\tfree(chd->map);\n\n\t/* close the file */\n\tif (chd->file != NULL)\n\t\tcore_fclose(chd->file);\n\n#ifdef NEED_CACHE_HUNK\n\tif (PRINTF_MAX_HUNK) printf(\"Max hunk = %d/%d\\n\", chd->maxhunk, chd->header.totalhunks);\n#endif\n\tif (chd->file_cache)\n\t\tfree(chd->file_cache);\n\n\tif (chd->parent)\n\t\tchd_close(chd->parent);\n\n\t/* free our memory */\n\tfree(chd);\n}\n\n/*-------------------------------------------------\n    chd_core_file - return the associated\n    core_file\n-------------------------------------------------*/\n\nCHD_EXPORT core_file *chd_core_file(chd_file *chd)\n{\n\treturn chd->file;\n}\n\n/*-------------------------------------------------\n    chd_error_string - return an error string for\n    the given CHD error\n-------------------------------------------------*/\n\nCHD_EXPORT const char *chd_error_string(chd_error err)\n{\n\tswitch (err)\n\t{\n\t\tcase CHDERR_NONE:\t\t\t\t\t\treturn \"no error\";\n\t\tcase CHDERR_NO_INTERFACE:\t\t\t\treturn \"no drive interface\";\n\t\tcase CHDERR_OUT_OF_MEMORY:\t\t\t\treturn \"out of memory\";\n\t\tcase CHDERR_INVALID_FILE:\t\t\t\treturn \"invalid file\";\n\t\tcase CHDERR_INVALID_PARAMETER:\t\t\treturn \"invalid parameter\";\n\t\tcase CHDERR_INVALID_DATA:\t\t\t\treturn \"invalid data\";\n\t\tcase CHDERR_FILE_NOT_FOUND:\t\t\t\treturn \"file not found\";\n\t\tcase CHDERR_REQUIRES_PARENT:\t\t\treturn \"requires parent\";\n\t\tcase CHDERR_FILE_NOT_WRITEABLE:\t\t\treturn \"file not writeable\";\n\t\tcase CHDERR_READ_ERROR:\t\t\t\t\treturn \"read error\";\n\t\tcase CHDERR_WRITE_ERROR:\t\t\t\treturn \"write error\";\n\t\tcase CHDERR_CODEC_ERROR:\t\t\t\treturn \"codec error\";\n\t\tcase CHDERR_INVALID_PARENT:\t\t\t\treturn \"invalid parent\";\n\t\tcase CHDERR_HUNK_OUT_OF_RANGE:\t\t\treturn \"hunk out of range\";\n\t\tcase CHDERR_DECOMPRESSION_ERROR:\t\treturn \"decompression error\";\n\t\tcase CHDERR_COMPRESSION_ERROR:\t\t\treturn \"compression error\";\n\t\tcase CHDERR_CANT_CREATE_FILE:\t\t\treturn \"can't create file\";\n\t\tcase CHDERR_CANT_VERIFY:\t\t\t\treturn \"can't verify file\";\n\t\tcase CHDERR_NOT_SUPPORTED:\t\t\t\treturn \"operation not supported\";\n\t\tcase CHDERR_METADATA_NOT_FOUND:\t\t\treturn \"can't find metadata\";\n\t\tcase CHDERR_INVALID_METADATA_SIZE:\t\treturn \"invalid metadata size\";\n\t\tcase CHDERR_UNSUPPORTED_VERSION:\t\treturn \"unsupported CHD version\";\n\t\tcase CHDERR_VERIFY_INCOMPLETE:\t\t\treturn \"incomplete verify\";\n\t\tcase CHDERR_INVALID_METADATA:\t\t\treturn \"invalid metadata\";\n\t\tcase CHDERR_INVALID_STATE:\t\t\t\treturn \"invalid state\";\n\t\tcase CHDERR_OPERATION_PENDING:\t\t\treturn \"operation pending\";\n\t\tcase CHDERR_NO_ASYNC_OPERATION:\t\t\treturn \"no async operation in progress\";\n\t\tcase CHDERR_UNSUPPORTED_FORMAT:\t\t\treturn \"unsupported format\";\n\t\tdefault:\t\t\t\t\t\t\t\treturn \"undocumented error\";\n\t}\n}\n\n/***************************************************************************\n    CHD HEADER MANAGEMENT\n***************************************************************************/\n\n/*-------------------------------------------------\n    chd_get_header - return a pointer to the\n    extracted header data\n-------------------------------------------------*/\n\nCHD_EXPORT const chd_header *chd_get_header(chd_file *chd)\n{\n\t/* punt if NULL or invalid */\n\tif (chd == NULL || chd->cookie != COOKIE_VALUE)\n\t\treturn NULL;\n\n\treturn &chd->header;\n}\n\n/*-------------------------------------------------\n    chd_read_header - read CHD header data\n\tfrom file into the pointed struct\n-------------------------------------------------*/\nCHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header)\n{\n\tchd_error err = CHDERR_NONE;\n\tchd_file *chd = NULL;\n\n\t/* punt if NULL */\n\tif (filename == NULL || header == NULL)\n\t\tEARLY_EXIT(err = CHDERR_INVALID_PARAMETER);\n\n\t/* open the file */\n\tchd->file = core_stdio_fopen(filename);\n\tif (chd->file == NULL)\n\t\tEARLY_EXIT(err = CHDERR_FILE_NOT_FOUND);\n\n\t/* attempt to read the header */\n\terr = header_read(chd, header);\n\tif (err != CHDERR_NONE)\n\t\tEARLY_EXIT(err);\n\n\t/* validate the header */\n\terr = header_validate(header);\n\tif (err != CHDERR_NONE)\n\t\tEARLY_EXIT(err);\n\ncleanup:\n\tif (chd->file != NULL)\n\t\tcore_fclose(chd->file);\n\n\treturn err;\n}\n\n/***************************************************************************\n    CORE DATA READ/WRITE\n***************************************************************************/\n\n/*-------------------------------------------------\n    chd_read - read a single hunk from the CHD\n    file\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer)\n{\n\t/* punt if NULL or invalid */\n\tif (chd == NULL || chd->cookie != COOKIE_VALUE)\n\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t/* if we're past the end, fail */\n\tif (hunknum >= chd->header.totalhunks)\n\t\treturn CHDERR_HUNK_OUT_OF_RANGE;\n\n\t/* perform the read */\n\treturn hunk_read_into_memory(chd, hunknum, (uint8_t *)buffer);\n}\n\n/***************************************************************************\n    METADATA MANAGEMENT\n***************************************************************************/\n\n/*-------------------------------------------------\n    chd_get_metadata - get the indexed metadata\n    of the given type\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_get_metadata(chd_file *chd, uint32_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags)\n{\n\tmetadata_entry metaentry;\n\tchd_error err;\n\tuint32_t count;\n\n\t/* if we didn't find it, just return */\n\terr = metadata_find_entry(chd, searchtag, searchindex, &metaentry);\n\tif (err != CHDERR_NONE)\n\t{\n\t\t/* unless we're an old version and they are requesting hard disk metadata */\n\t\tif (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)\n\t\t{\n\t\t\tchar faux_metadata[256];\n\t\t\tuint32_t faux_length;\n\n\t\t\t/* fill in the faux metadata */\n\t\t\tsprintf(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);\n\t\t\tfaux_length = (uint32_t)strlen(faux_metadata) + 1;\n\n\t\t\t/* copy the metadata itself */\n\t\t\tmemcpy(output, faux_metadata, MIN(outputlen, faux_length));\n\n\t\t\t/* return the length of the data and the tag */\n\t\t\tif (resultlen != NULL)\n\t\t\t\t*resultlen = faux_length;\n\t\t\tif (resulttag != NULL)\n\t\t\t\t*resulttag = HARD_DISK_METADATA_TAG;\n\t\t\treturn CHDERR_NONE;\n\t\t}\n\t\treturn err;\n\t}\n\n\t/* read the metadata */\n\toutputlen = MIN(outputlen, metaentry.length);\n\tcore_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);\n\tcount = core_fread(chd->file, output, outputlen);\n\tif (count != outputlen)\n\t\treturn CHDERR_READ_ERROR;\n\n\t/* return the length of the data and the tag */\n\tif (resultlen != NULL)\n\t\t*resultlen = metaentry.length;\n\tif (resulttag != NULL)\n\t\t*resulttag = metaentry.metatag;\n\tif (resultflags != NULL)\n\t\t*resultflags = metaentry.flags;\n\treturn CHDERR_NONE;\n}\n\n/***************************************************************************\n    CODEC INTERFACES\n***************************************************************************/\n\n/*-------------------------------------------------\n    chd_codec_config - set internal codec\n    parameters\n-------------------------------------------------*/\n\nCHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config)\n{\n\treturn CHDERR_INVALID_PARAMETER;\n}\n\n/*-------------------------------------------------\n    chd_get_codec_name - get the name of a\n    particular codec\n-------------------------------------------------*/\n\nCHD_EXPORT const char *chd_get_codec_name(uint32_t codec)\n{\n\treturn \"Unknown\";\n}\n\n/***************************************************************************\n    INTERNAL HEADER OPERATIONS\n***************************************************************************/\n\n/*-------------------------------------------------\n    header_validate - check the validity of a\n    CHD header\n-------------------------------------------------*/\n\nstatic chd_error header_validate(const chd_header *header)\n{\n\tsize_t intfnum;\n\n\t/* require a valid version */\n\tif (header->version == 0 || header->version > CHD_HEADER_VERSION)\n\t\treturn CHDERR_UNSUPPORTED_VERSION;\n\n\t/* require a valid length */\n\tif ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||\n\t\t(header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||\n\t\t(header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||\n\t\t(header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||\n\t\t(header->version == 5 && header->length != CHD_V5_HEADER_SIZE))\n\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t/* Do not validate v5 header */\n\tif (header->version <= 4)\n\t{\n\t\t/* require valid flags */\n\t\tif (header->flags & CHDFLAGS_UNDEFINED)\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t\t/* require a supported compression mechanism */\n\t\tfor (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)\n\t\t\tif (codec_interfaces[intfnum].compression == header->compression[0])\n\t\t\t\tbreak;\n\n\t\tif (intfnum == ARRAY_LENGTH(codec_interfaces))\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t\t/* require a valid hunksize */\n\t\tif (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t\t/* require a valid hunk count */\n\t\tif (header->totalhunks == 0)\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t\t/* require a valid MD5 and/or SHA1 if we're using a parent */\n\t\tif ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t\t/* if we're V3 or later, the obsolete fields must be 0 */\n\t\tif (header->version >= 3 &&\n\t\t\t(header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||\n\t\t\t header->obsolete_heads != 0 || header->obsolete_hunksize != 0))\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t\t/* if we're pre-V3, the obsolete fields must NOT be 0 */\n\t\tif (header->version < 3 &&\n\t\t\t(header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||\n\t\t\t header->obsolete_heads == 0 || header->obsolete_hunksize == 0))\n\t\t\treturn CHDERR_INVALID_PARAMETER;\n\t}\n\n\treturn CHDERR_NONE;\n}\n\n/*-------------------------------------------------\n    header_guess_unitbytes - for older CHD formats,\n    guess at the bytes/unit based on metadata\n-------------------------------------------------*/\n\nstatic uint32_t header_guess_unitbytes(chd_file *chd)\n{\n\t/* look for hard disk metadata; if found, then the unit size == sector size */\n\tchar metadata[512];\n\tunsigned int i0, i1, i2, i3;\n\tif (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&\n\t\tsscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)\n\t\treturn i3;\n\n\t/* look for CD-ROM metadata; if found, then the unit size == CD frame size */\n\tif (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||\n\t\tchd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||\n\t\tchd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||\n\t\tchd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||\n\t\tchd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)\n\t\treturn CD_FRAME_SIZE;\n\n\t/* otherwise, just map 1:1 with the hunk size */\n\treturn chd->header.hunkbytes;\n}\n\n/*-------------------------------------------------\n    header_read - read a CHD header into the\n    internal data structure\n-------------------------------------------------*/\n\nstatic chd_error header_read(chd_file *chd, chd_header *header)\n{\n\tuint8_t rawheader[CHD_MAX_HEADER_SIZE];\n\tuint32_t count;\n\n\t/* punt if NULL */\n\tif (header == NULL)\n\t\treturn CHDERR_INVALID_PARAMETER;\n\n\t/* punt if invalid file */\n\tif (chd->file == NULL)\n\t\treturn CHDERR_INVALID_FILE;\n\n\t/* seek and read */\n\tcore_fseek(chd->file, 0, SEEK_SET);\n\tcount = core_fread(chd->file, rawheader, sizeof(rawheader));\n\tif (count != sizeof(rawheader))\n\t\treturn CHDERR_READ_ERROR;\n\n\t/* verify the tag */\n\tif (strncmp((char *)rawheader, \"MComprHD\", 8) != 0)\n\t\treturn CHDERR_INVALID_DATA;\n\n\t/* extract the direct data */\n\tmemset(header, 0, sizeof(*header));\n\theader->length        = get_bigendian_uint32_t(&rawheader[8]);\n\theader->version       = get_bigendian_uint32_t(&rawheader[12]);\n\n\t/* make sure it's a version we understand */\n\tif (header->version == 0 || header->version > CHD_HEADER_VERSION)\n\t\treturn CHDERR_UNSUPPORTED_VERSION;\n\n\t/* make sure the length is expected */\n\tif ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||\n\t\t(header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||\n\t\t(header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||\n\t\t(header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||\n\t\t(header->version == 5 && header->length != CHD_V5_HEADER_SIZE))\n\n\t\treturn CHDERR_INVALID_DATA;\n\n\t/* extract the common data */\n\theader->flags         \t= get_bigendian_uint32_t(&rawheader[16]);\n\theader->compression[0]\t= get_bigendian_uint32_t(&rawheader[20]);\n\theader->compression[1]\t= CHD_CODEC_NONE;\n\theader->compression[2]\t= CHD_CODEC_NONE;\n\theader->compression[3]\t= CHD_CODEC_NONE;\n\n\t/* extract the V1/V2-specific data */\n\tif (header->version < 3)\n\t{\n\t\tint seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32_t(&rawheader[76]);\n\t\theader->obsolete_hunksize  = get_bigendian_uint32_t(&rawheader[24]);\n\t\theader->totalhunks         = get_bigendian_uint32_t(&rawheader[28]);\n\t\theader->obsolete_cylinders = get_bigendian_uint32_t(&rawheader[32]);\n\t\theader->obsolete_heads     = get_bigendian_uint32_t(&rawheader[36]);\n\t\theader->obsolete_sectors   = get_bigendian_uint32_t(&rawheader[40]);\n\t\tmemcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);\n\t\tmemcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);\n\t\theader->logicalbytes = (uint64_t)header->obsolete_cylinders * (uint64_t)header->obsolete_heads * (uint64_t)header->obsolete_sectors * (uint64_t)seclen;\n\t\theader->hunkbytes = seclen * header->obsolete_hunksize;\n\t\theader->unitbytes          = header_guess_unitbytes(chd);\n\t\tif (header->unitbytes == 0)\n\t\t\treturn CHDERR_INVALID_DATA;\n\t\theader->unitcount          = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;\n\t\theader->metaoffset = 0;\n\t}\n\n\t/* extract the V3-specific data */\n\telse if (header->version == 3)\n\t{\n\t\theader->totalhunks   = get_bigendian_uint32_t(&rawheader[24]);\n\t\theader->logicalbytes = get_bigendian_uint64_t(&rawheader[28]);\n\t\theader->metaoffset   = get_bigendian_uint64_t(&rawheader[36]);\n\t\tmemcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);\n\t\tmemcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);\n\t\theader->hunkbytes    = get_bigendian_uint32_t(&rawheader[76]);\n\t\theader->unitbytes    = header_guess_unitbytes(chd);\n\t\tif (header->unitbytes == 0)\n\t\t\treturn CHDERR_INVALID_DATA;\n\t\theader->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;\n\t\tmemcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);\n\t\tmemcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);\n\t}\n\n\t/* extract the V4-specific data */\n\telse if (header->version == 4)\n\t{\n\t\theader->totalhunks   = get_bigendian_uint32_t(&rawheader[24]);\n\t\theader->logicalbytes = get_bigendian_uint64_t(&rawheader[28]);\n\t\theader->metaoffset   = get_bigendian_uint64_t(&rawheader[36]);\n\t\theader->hunkbytes    = get_bigendian_uint32_t(&rawheader[44]);\n\t\theader->unitbytes    = header_guess_unitbytes(chd);\n\t\tif (header->unitbytes == 0)\n\t\t\treturn CHDERR_INVALID_DATA;\n\t\theader->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;\n\t\tmemcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);\n\t\tmemcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);\n\t\tmemcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);\n\t}\n\n\t/* extract the V5-specific data */\n\telse if (header->version == 5)\n\t{\n\t\t/* TODO */\n\t\theader->compression[0]  = get_bigendian_uint32_t(&rawheader[16]);\n\t\theader->compression[1]  = get_bigendian_uint32_t(&rawheader[20]);\n\t\theader->compression[2]  = get_bigendian_uint32_t(&rawheader[24]);\n\t\theader->compression[3]  = get_bigendian_uint32_t(&rawheader[28]);\n\t\theader->logicalbytes    = get_bigendian_uint64_t(&rawheader[32]);\n\t\theader->mapoffset       = get_bigendian_uint64_t(&rawheader[40]);\n\t\theader->metaoffset      = get_bigendian_uint64_t(&rawheader[48]);\n\t\theader->hunkbytes       = get_bigendian_uint32_t(&rawheader[56]);\n\t\tif (header->hunkbytes == 0)\n\t\t\treturn CHDERR_INVALID_DATA;\n\t\theader->hunkcount       = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;\n\t\theader->unitbytes       = get_bigendian_uint32_t(&rawheader[60]);\n\t\tif (header->unitbytes == 0)\n\t\t\treturn CHDERR_INVALID_DATA;\n\t\theader->unitcount       = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;\n\t\tmemcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);\n\t\tmemcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);\n\t\tmemcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);\n\n\t\t/* determine properties of map entries */\n\t\theader->mapentrybytes = chd_compressed(header) ? 12 : 4;\n\n\t\t/* hack */\n\t\theader->totalhunks \t\t= header->hunkcount;\n\t}\n\n\t/* Unknown version */\n\telse\n\t{\n\t\t/* TODO */\n\t}\n\n\t/* guess it worked */\n\treturn CHDERR_NONE;\n}\n\n/***************************************************************************\n    INTERNAL HUNK READ/WRITE\n***************************************************************************/\n\n/*-------------------------------------------------\n    hunk_read_compressed - read a compressed\n    hunk\n-------------------------------------------------*/\n\nstatic uint8_t* hunk_read_compressed(chd_file *chd, uint64_t offset, size_t size)\n{\n\tsize_t bytes;\n\n\tif (chd->file_cache != NULL)\n\t{\n\t\treturn chd->file_cache + offset;\n\t}\n\telse\n\t{\n\t\tcore_fseek(chd->file, offset, SEEK_SET);\n\t\tbytes = core_fread(chd->file, chd->compressed, size);\n\t\tif (bytes != size)\n\t\t\treturn NULL;\n\t\treturn chd->compressed;\n\t}\n}\n\n/*-------------------------------------------------\n    hunk_read_uncompressed - read an uncompressed\n    hunk\n-------------------------------------------------*/\n\nstatic chd_error hunk_read_uncompressed(chd_file *chd, uint64_t offset, size_t size, uint8_t *dest)\n{\n\tsize_t bytes;\n\n\tif (chd->file_cache != NULL)\n\t{\n\t\tmemcpy(dest, chd->file_cache + offset, size);\n\t}\n\telse\n\t{\n\t\tcore_fseek(chd->file, offset, SEEK_SET);\n\t\tbytes = core_fread(chd->file, dest, size);\n\t\tif (bytes != size)\n\t\t\treturn CHDERR_READ_ERROR;\n\t}\n\treturn CHDERR_NONE;\n}\n\n#ifdef NEED_CACHE_HUNK\n/*-------------------------------------------------\n    hunk_read_into_cache - read a hunk into\n    the CHD's hunk cache\n-------------------------------------------------*/\n\nstatic chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum)\n{\n\tchd_error err;\n\n\t/* track the max */\n\tif (hunknum > chd->maxhunk)\n\t\tchd->maxhunk = hunknum;\n\n\t/* if we're already in the cache, we're done */\n\tif (chd->cachehunk == hunknum)\n\t\treturn CHDERR_NONE;\n\tchd->cachehunk = ~0;\n\n\t/* otherwise, read the data */\n\terr = hunk_read_into_memory(chd, hunknum, chd->cache);\n\tif (err != CHDERR_NONE)\n\t\treturn err;\n\n\t/* mark the hunk successfully cached in */\n\tchd->cachehunk = hunknum;\n\treturn CHDERR_NONE;\n}\n#endif\n\n/*-------------------------------------------------\n    hunk_read_into_memory - read a hunk into\n    memory at the given location\n-------------------------------------------------*/\n\nstatic chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest)\n{\n\tchd_error err;\n\n\t/* punt if no file */\n\tif (chd->file == NULL)\n\t\treturn CHDERR_INVALID_FILE;\n\n\t/* return an error if out of range */\n\tif (hunknum >= chd->header.totalhunks)\n\t\treturn CHDERR_HUNK_OUT_OF_RANGE;\n\n\tif (dest == NULL)\n\t\treturn CHDERR_INVALID_PARAMETER;\n\n\tif (chd->header.version < 5)\n\t{\n\t\tmap_entry *entry = &chd->map[hunknum];\n\t\tuint32_t bytes;\n\t\tuint8_t* compressed_bytes;\n\n\t\t/* switch off the entry type */\n\t\tswitch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)\n\t\t{\n\t\t\t/* compressed data */\n\t\t\tcase V34_MAP_ENTRY_TYPE_COMPRESSED:\n            {\n               void *codec = NULL;\n\n\t\t\t\t/* read it into the decompression buffer */\n\t\t\t\tcompressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length);\n\t\t\t\tif (compressed_bytes == NULL)\n\t\t\t\t\t{\n\t\t\t\t\treturn CHDERR_READ_ERROR;\n\t\t\t\t\t}\n\n#ifdef HAVE_ZLIB\n\t\t\t\t/* now decompress using the codec */\n\t\t\t\terr = CHDERR_NONE;\n\t\t\t\tcodec = &chd->zlib_codec_data;\n\t\t\t\tif (chd->codecintf[0]->decompress != NULL)\n\t\t\t\t\terr = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\treturn err;\n#endif\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* uncompressed data */\n\t\t\tcase V34_MAP_ENTRY_TYPE_UNCOMPRESSED:\n\t\t\t\terr = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\treturn err;\n\t\t\t\tbreak;\n\n\t\t\t/* mini-compressed data */\n\t\t\tcase V34_MAP_ENTRY_TYPE_MINI:\n\t\t\t\tput_bigendian_uint64_t(&dest[0], entry->offset);\n\t\t\t\tfor (bytes = 8; bytes < chd->header.hunkbytes; bytes++)\n\t\t\t\t\tdest[bytes] = dest[bytes - 8];\n\t\t\t\tbreak;\n\n\t\t\t/* self-referenced data */\n\t\t\tcase V34_MAP_ENTRY_TYPE_SELF_HUNK:\n#ifdef NEED_CACHE_HUNK\n\t\t\t\tif (chd->cachehunk == entry->offset && dest == chd->cache)\n\t\t\t\t\tbreak;\n#endif\n\t\t\t\treturn hunk_read_into_memory(chd, entry->offset, dest);\n\n\t\t\t/* parent-referenced data */\n\t\t\tcase V34_MAP_ENTRY_TYPE_PARENT_HUNK:\n\t\t\t\terr = hunk_read_into_memory(chd->parent, entry->offset, dest);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\treturn err;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn CHDERR_NONE;\n\t}\n\telse\n\t{\n\t\tvoid* codec = NULL;\n\t\t/* get a pointer to the map entry */\n\t\tuint64_t blockoffs;\n\t\tuint32_t blocklen;\n#ifdef VERIFY_BLOCK_CRC\n\t\tuint16_t blockcrc;\n#endif\n\t\tuint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];\n\t\tuint8_t* compressed_bytes;\n\n\t\t/* uncompressed case */\n\t\tif (!chd_compressed(&chd->header))\n\t\t{\n\t\t\tblockoffs = (uint64_t)get_bigendian_uint32_t(rawmap) * (uint64_t)chd->header.hunkbytes;\n\t\t\tif (blockoffs != 0) {\n\t\t\t\tcore_fseek(chd->file, blockoffs, SEEK_SET);\n\t\t\t\t/*int result =*/\n\t\t\t\tcore_fread(chd->file, dest, chd->header.hunkbytes);\n\t\t\t/* TODO\n\t\t\telse if (m_parent_missing)\n\t\t\t\tthrow CHDERR_REQUIRES_PARENT; */\n\t\t\t} else if (chd->parent) {\n\t\t\t\terr = hunk_read_into_memory(chd->parent, hunknum, dest);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\treturn err;\n\t\t\t} else {\n\t\t\t\tmemset(dest, 0, chd->header.hunkbytes);\n\t\t\t}\n\n\t\t\treturn CHDERR_NONE;\n\t\t}\n\n\t\t/* compressed case */\n\t\tblocklen = get_bigendian_uint24(&rawmap[1]);\n\t\tblockoffs = get_bigendian_uint48(&rawmap[4]);\n#ifdef VERIFY_BLOCK_CRC\n\t\tblockcrc = get_bigendian_uint16(&rawmap[10]);\n#endif\n\t\tcodec = NULL;\n\t\tswitch (rawmap[0])\n\t\t{\n\t\t\tcase COMPRESSION_TYPE_0:\n\t\t\tcase COMPRESSION_TYPE_1:\n\t\t\tcase COMPRESSION_TYPE_2:\n\t\t\tcase COMPRESSION_TYPE_3:\n\t\t\t\tcompressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);\n\t\t\t\tif (compressed_bytes == NULL)\n\t\t\t\t\treturn CHDERR_READ_ERROR;\n\t\t\t\tswitch (chd->codecintf[rawmap[0]]->compression)\n\t\t\t\t{\n\t\t\t\t\tcase CHD_CODEC_ZLIB:\n#ifdef HAVE_ZLIB\n\t\t\t\t\t\tcodec = &chd->zlib_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_LZMA:\n#ifdef HAVE_7ZIP\n\t\t\t\t\t\tcodec = &chd->lzma_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_HUFFMAN:\n\t\t\t\t\t\tcodec = &chd->huff_codec_data;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_FLAC:\n#ifdef HAVE_FLAC\n\t\t\t\t\t\tcodec = &chd->flac_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_ZSTD:\n#ifdef HAVE_ZSTD\n\t\t\t\t\t\tcodec = &chd->zstd_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_ZLIB:\n#ifdef HAVE_ZLIB\n\t\t\t\t\t\tcodec = &chd->cdzl_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_LZMA:\n#ifdef HAVE_7ZIP\n\t\t\t\t\t\tcodec = &chd->cdlz_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_FLAC:\n#ifdef HAVE_FLAC\n\t\t\t\t\t\tcodec = &chd->cdfl_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CHD_CODEC_CD_ZSTD:\n#ifdef HAVE_ZSTD\n\t\t\t\t\t\tcodec = &chd->cdzs_codec_data;\n#endif\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (codec==NULL)\n\t\t\t\t\treturn CHDERR_CODEC_ERROR;\n\t\t\t\terr = chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\treturn err;\n#ifdef VERIFY_BLOCK_CRC\n\t\t\t\tif (crc16(dest, chd->header.hunkbytes) != blockcrc)\n\t\t\t\t\treturn CHDERR_DECOMPRESSION_ERROR;\n#endif\n\t\t\t\treturn CHDERR_NONE;\n\n\t\t\tcase COMPRESSION_NONE:\n\t\t\t\terr = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);\n\t\t\t\tif (err != CHDERR_NONE)\n\t\t\t\t\treturn err;\n#ifdef VERIFY_BLOCK_CRC\n\t\t\t\tif (crc16(dest, chd->header.hunkbytes) != blockcrc)\n\t\t\t\t\treturn CHDERR_DECOMPRESSION_ERROR;\n#endif\n\t\t\t\treturn CHDERR_NONE;\n\n\t\t\tcase COMPRESSION_SELF:\n\t\t\t\treturn hunk_read_into_memory(chd, blockoffs, dest);\n\n\t\t\tcase COMPRESSION_PARENT:\n\t\t\t{\n\t\t\t\tuint8_t units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes;\n\n\t\t\t\tif (chd->parent == NULL)\n\t\t\t\t\treturn CHDERR_REQUIRES_PARENT;\n\n\t\t\t\t/* blockoffs is aligned to units_in_hunk */\n\t\t\t\tif (blockoffs % units_in_hunk == 0) {\n\t\t\t\t\treturn hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, dest);\n\t\t\t\t/* blockoffs is not aligned to units_in_hunk */\n\t\t\t\t} else {\n\t\t\t\t\tuint32_t unit_in_hunk = blockoffs % units_in_hunk;\n\t\t\t\t\tuint8_t *buf = malloc(chd->header.hunkbytes);\n\t\t\t\t\t/* Read first half of hunk which contains blockoffs */\n\t\t\t\t\terr = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf);\n\t\t\t\t\tif (err != CHDERR_NONE) {\n\t\t\t\t\t\tfree(buf);\n\t\t\t\t\t\treturn err;\n\t\t\t\t\t}\n\t\t\t\t\tmemcpy(dest, buf + unit_in_hunk * chd->header.unitbytes, (units_in_hunk - unit_in_hunk) * chd->header.unitbytes);\n\t\t\t\t\t/* Read second half of hunk which contains blockoffs */\n\t\t\t\t\terr = hunk_read_into_memory(chd->parent, (blockoffs / units_in_hunk) + 1, buf);\n\t\t\t\t\tif (err != CHDERR_NONE) {\n\t\t\t\t\t\tfree(buf);\n\t\t\t\t\t\treturn err;\n\t\t\t\t\t}\n\t\t\t\t\tmemcpy(dest + (units_in_hunk - unit_in_hunk) * chd->header.unitbytes, buf, unit_in_hunk * chd->header.unitbytes);\n\t\t\t\t\tfree(buf);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn CHDERR_NONE;\n\t}\n\n\t/* We should not reach this code */\n\treturn CHDERR_DECOMPRESSION_ERROR;\n}\n\n/***************************************************************************\n    INTERNAL MAP ACCESS\n***************************************************************************/\n\n/*-------------------------------------------------\n    map_read - read the initial sector map\n-------------------------------------------------*/\n\nstatic chd_error map_read(chd_file *chd)\n{\n\tuint32_t entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;\n\tuint8_t raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];\n\tuint64_t fileoffset, maxoffset = 0;\n\tuint8_t cookie[MAP_ENTRY_SIZE];\n\tuint32_t count;\n\tchd_error err;\n\tuint32_t i;\n\n\t/* first allocate memory */\n\tchd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);\n\tif (!chd->map)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\t/* read the map entries in in chunks and extract to the map list */\n\tfileoffset = chd->header.length;\n\tfor (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)\n\t{\n\t\t/* compute how many entries this time */\n\t\tint entries = chd->header.totalhunks - i, j;\n\t\tif (entries > MAP_STACK_ENTRIES)\n\t\t\tentries = MAP_STACK_ENTRIES;\n\n\t\t/* read that many */\n\t\tcore_fseek(chd->file, fileoffset, SEEK_SET);\n\t\tcount = core_fread(chd->file, raw_map_entries, entries * entrysize);\n\t\tif (count != entries * entrysize)\n\t\t{\n\t\t\terr = CHDERR_READ_ERROR;\n\t\t\tgoto cleanup;\n\t\t}\n\t\tfileoffset += entries * entrysize;\n\n\t\t/* process that many */\n\t\tif (entrysize == MAP_ENTRY_SIZE)\n\t\t{\n\t\t\tfor (j = 0; j < entries; j++)\n\t\t\t\tmap_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (j = 0; j < entries; j++)\n\t\t\t\tmap_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);\n\t\t}\n\n\t\t/* track the maximum offset */\n\t\tfor (j = 0; j < entries; j++)\n\t\t\tif ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||\n\t\t\t\t(chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)\n\t\t\t\tmaxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);\n\t}\n\n\t/* verify the cookie */\n\tcore_fseek(chd->file, fileoffset, SEEK_SET);\n\tcount = core_fread(chd->file, &cookie, entrysize);\n\tif (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))\n\t{\n\t\terr = CHDERR_INVALID_FILE;\n\t\tgoto cleanup;\n\t}\n\n\t/* verify the length */\n\tif (maxoffset > core_fsize(chd->file))\n\t{\n\t\terr = CHDERR_INVALID_FILE;\n\t\tgoto cleanup;\n\t}\n\treturn CHDERR_NONE;\n\ncleanup:\n\tif (chd->map)\n\t\tfree(chd->map);\n\tchd->map = NULL;\n\treturn err;\n}\n\n/***************************************************************************\n    INTERNAL METADATA ACCESS\n***************************************************************************/\n\n/*-------------------------------------------------\n    metadata_find_entry - find a metadata entry\n-------------------------------------------------*/\n\nstatic chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry)\n{\n\t/* start at the beginning */\n\tmetaentry->offset = chd->header.metaoffset;\n\tmetaentry->prev = 0;\n\n\t/* loop until we run out of options */\n\twhile (metaentry->offset != 0)\n\t{\n\t\tuint8_t\traw_meta_header[METADATA_HEADER_SIZE];\n\t\tuint32_t\tcount;\n\n\t\t/* read the raw header */\n\t\tcore_fseek(chd->file, metaentry->offset, SEEK_SET);\n\t\tcount = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));\n\t\tif (count != sizeof(raw_meta_header))\n\t\t\tbreak;\n\n\t\t/* extract the data */\n\t\tmetaentry->metatag = get_bigendian_uint32_t(&raw_meta_header[0]);\n\t\tmetaentry->length = get_bigendian_uint32_t(&raw_meta_header[4]);\n\t\tmetaentry->next = get_bigendian_uint64_t(&raw_meta_header[8]);\n\n\t\t/* flags are encoded in the high byte of length */\n\t\tmetaentry->flags = metaentry->length >> 24;\n\t\tmetaentry->length &= 0x00ffffff;\n\n\t\t/* if we got a match, proceed */\n\t\tif (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)\n\t\t\tif (metaindex-- == 0)\n\t\t\t\treturn CHDERR_NONE;\n\n\t\t/* no match, fetch the next link */\n\t\tmetaentry->prev = metaentry->offset;\n\t\tmetaentry->offset = metaentry->next;\n\t}\n\n\t/* if we get here, we didn't find it */\n\treturn CHDERR_METADATA_NOT_FOUND;\n}\n\n/*-------------------------------------------------\n\tcore_stdio_fopen - core_file wrapper over fopen\n-------------------------------------------------*/\nstatic core_file *core_stdio_fopen(char const *path) {\n\tcore_file *file = malloc(sizeof(core_file));\n\tif (!file)\n\t\treturn NULL;\n\tif (!(file->argp = fopen(path, \"rb\"))) {\n\t\tfree(file);\n\t\treturn NULL;\n\t}\n\tfile->fsize = core_stdio_fsize;\n\tfile->fread = core_stdio_fread;\n\tfile->fclose = core_stdio_fclose;\n\tfile->fseek = core_stdio_fseek;\n\treturn file;\n}\n\n/*-------------------------------------------------\n\tcore_stdio_fsize - core_file function for\n\tgetting file size with stdio\n-------------------------------------------------*/\nstatic uint64_t core_stdio_fsize(core_file *file) {\n#if defined USE_LIBRETRO_VFS\n\t#define core_stdio_fseek_impl fseek\n\t#define core_stdio_ftell_impl ftell\n#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__)\n\t#define core_stdio_fseek_impl _fseeki64\n\t#define core_stdio_ftell_impl _ftelli64\n#elif defined(_LARGEFILE_SOURCE) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(fseeko64) && defined(ftello64)\n\t#define core_stdio_fseek_impl fseeko64\n\t#define core_stdio_ftell_impl ftello64\n#elif defined(__PS3__) && !defined(__PSL1GHT__) || defined(__SWITCH__) || defined(__vita__)\n\t#define core_stdio_fseek_impl(x,y,z) fseek(x,(off_t)y,z)\n\t#define core_stdio_ftell_impl(x) (off_t)ftell(x)\n#else\n\t#define core_stdio_fseek_impl fseeko\n\t#define core_stdio_ftell_impl ftello\n#endif\n\tFILE *fp;\n\tuint64_t p, rv;\n\tfp = (FILE*)file->argp;\n\n\tp = core_stdio_ftell_impl(fp);\n\tcore_stdio_fseek_impl(fp, 0, SEEK_END);\n\trv = core_stdio_ftell_impl(fp);\n\tcore_stdio_fseek_impl(fp, p, SEEK_SET);\n\treturn rv;\n}\n\n/*-------------------------------------------------\n\tcore_stdio_fread - core_file wrapper over fread\n-------------------------------------------------*/\nstatic size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file) {\n\treturn fread(ptr, size, nmemb, (FILE*)file->argp);\n}\n\n/*-------------------------------------------------\n\tcore_stdio_fclose - core_file wrapper over fclose\n-------------------------------------------------*/\nstatic int core_stdio_fclose(core_file *file) {\n\tint err = fclose((FILE*)file->argp);\n\tif (err == 0)\n\t\tfree(file);\n\treturn err;\n}\n\n/*-------------------------------------------------\n\tcore_stdio_fclose_nonowner - don't call fclose because\n\t\twe don't own the underlying file, but do free the\n\t\tcore_file because libchdr did allocate that itself.\n-------------------------------------------------*/\nstatic int core_stdio_fclose_nonowner(core_file *file) {\n\tfree(file);\n\treturn 0;\n}\n\n/*-------------------------------------------------\n\tcore_stdio_fseek - core_file wrapper over fclose\n-------------------------------------------------*/\nstatic int core_stdio_fseek(core_file* file, int64_t offset, int whence) {\n\treturn core_stdio_fseek_impl((FILE*)file->argp, offset, whence);\n}\n"
  },
  {
    "path": "formats/libchdr/libchdr_flac.c",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n***************************************************************************\n\n    flac.c\n\n    FLAC compression wrappers\n\n***************************************************************************/\n\n#include <string.h>\n#include <boolean.h>\n\n#include <libchdr/flac.h>\n#ifdef HAVE_DR_FLAC\n#include <retro_inline.h>\n#define DR_FLAC_IMPLEMENTATION\n#define DRFLAC_API static INLINE\n#include <dr/dr_flac.h>\n#endif\n\n/***************************************************************************\n *  FLAC DECODER\n ***************************************************************************\n */\n\nstatic size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes);\nstatic drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin);\nstatic void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata);\nstatic void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes);\n\n\n/* getters (valid after reset) */\n/*static uint32_t sample_rate(flac_decoder *decoder)  { return decoder->sample_rate; }*/\nstatic uint8_t channels(flac_decoder *decoder)  { return decoder->channels; }\n/*static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }*/\n\n/*-------------------------------------------------\n *  flac_decoder - constructor\n *-------------------------------------------------\n */\n\nint flac_decoder_init(flac_decoder *decoder)\n{\n\tdecoder->decoder = NULL;\n\tdecoder->sample_rate = 0;\n\tdecoder->channels = 0;\n\tdecoder->bits_per_sample = 0;\n\tdecoder->compressed_offset = 0;\n\tdecoder->compressed_start = NULL;\n\tdecoder->compressed_length = 0;\n\tdecoder->compressed2_start = NULL;\n\tdecoder->compressed2_length = 0;\n\tdecoder->uncompressed_offset = 0;\n\tdecoder->uncompressed_length = 0;\n\tdecoder->uncompressed_swap = 0;\n\treturn 0;\n}\n\n/*-------------------------------------------------\n *  flac_decoder - destructor\n *-------------------------------------------------\n */\n\nvoid flac_decoder_free(flac_decoder* decoder)\n{\n\tif ((decoder != NULL) && (decoder->decoder != NULL)) {\n\t\tdrflac_close(decoder->decoder);\n\t\tdecoder->decoder = NULL;\n\t}\n}\n\n/*-------------------------------------------------\n *  reset - reset state with the original\n *  parameters\n *-------------------------------------------------\n */\n\nstatic int flac_decoder_internal_reset(flac_decoder* decoder)\n{\n\tdecoder->compressed_offset = 0;\n\tflac_decoder_free(decoder);\n\tdecoder->decoder = drflac_open_with_metadata(\n\t\tflac_decoder_read_callback, flac_decoder_seek_callback,\n\t\tflac_decoder_metadata_callback, decoder, NULL);\n\treturn (decoder->decoder != NULL);\n}\n\n/*-------------------------------------------------\n *  reset - reset state with new memory parameters\n *  and a custom-generated header\n *-------------------------------------------------\n */\n\nint flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)\n{\n\t/* modify the template header with our parameters */\n\tstatic const uint8_t s_header_template[0x2a] =\n\t{\n\t\t0x66, 0x4C, 0x61, 0x43,                         /* +00: 'fLaC' stream header */\n\t\t0x80,                                           /* +04: metadata block type 0 (STREAMINFO), */\n\t\t\t\t\t\t\t\t/*      flagged as last block */\n\t\t0x00, 0x00, 0x22,                               /* +05: metadata block length = 0x22 */\n\t\t0x00, 0x00,                                     /* +08: minimum block size */\n\t\t0x00, 0x00,                                     /* +0A: maximum block size */\n\t\t0x00, 0x00, 0x00,                               /* +0C: minimum frame size (0 == unknown) */\n\t\t0x00, 0x00, 0x00,                               /* +0F: maximum frame size (0 == unknown) */\n\t\t0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */\n\t\t\t\t\t\t\t\t/*      numchannels (2), sample bits (16), */\n\t\t\t\t\t\t\t\t/*      samples in stream (0 == unknown) */\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* +2A: start of stream data */\n\t};\n\tmemcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));\n\tdecoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8;\n\tdecoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff;\n\tdecoder->custom_header[0x12] = sample_rate >> 12;\n\tdecoder->custom_header[0x13] = sample_rate >> 4;\n\tdecoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);\n\n\t/* configure the header ahead of the provided buffer */\n\tdecoder->compressed_start = (const uint8_t *)(decoder->custom_header);\n\tdecoder->compressed_length = sizeof(decoder->custom_header);\n\tdecoder->compressed2_start = (const uint8_t *)(buffer);\n\tdecoder->compressed2_length = length;\n\treturn flac_decoder_internal_reset(decoder);\n}\n\n/*-------------------------------------------------\n *  decode_interleaved - decode to an interleaved\n *  sound stream\n *-------------------------------------------------\n */\n\nint flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)\n{\n#define\tBUFFER\t2352\t/* bytes per CD audio sector */\n\tint16_t buffer[BUFFER];\n\tuint32_t buf_samples = BUFFER / channels(decoder);\n\n\t/* configure the uncompressed buffer */\n\tmemset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));\n\tdecoder->uncompressed_start[0] = samples;\n\tdecoder->uncompressed_offset = 0;\n\tdecoder->uncompressed_length = num_samples;\n\tdecoder->uncompressed_swap = swap_endian;\n\n\t/* loop until we get everything we want */\n\twhile (decoder->uncompressed_offset < decoder->uncompressed_length) {\n\t\tuint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples);\n\t\tif (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer))\n\t\t\treturn 0;\n\t\tflac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder));\n\t\tnum_samples -= frames;\n\t}\n\treturn 1;\n}\n\n/*-------------------------------------------------\n *  finish - finish up the decode\n *-------------------------------------------------\n */\n\nuint32_t flac_decoder_finish(flac_decoder* decoder)\n{\n\t/* get the final decoding position and move forward */\n\tdrflac *flac = decoder->decoder;\n\tuint64_t position = decoder->compressed_offset;\n\n\t/* ugh... there's no function to obtain bytes used in drflac :-/ */\n\tposition -= DRFLAC_CACHE_L2_LINES_REMAINING(&flac->bs) * sizeof(drflac_cache_t);\n\tposition -= DRFLAC_CACHE_L1_BITS_REMAINING(&flac->bs) / 8;\n\tposition -= flac->bs.unalignedByteCount;\n\n\t/* adjust position if we provided the header */\n\tif (position == 0)\n\t\treturn 0;\n\tif (decoder->compressed_start == (const uint8_t *)(decoder->custom_header))\n\t\tposition -= decoder->compressed_length;\n\n\tflac_decoder_free(decoder);\n\treturn position;\n}\n\n/*-------------------------------------------------\n *  read_callback - handle reads from the input\n *  stream\n *-------------------------------------------------\n */\n\nstatic size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes)\n{\n\tflac_decoder* decoder = (flac_decoder*)userdata;\n\tuint8_t *dst = buffer;\n\n\t/* copy from primary buffer first */\n\tuint32_t outputpos = 0;\n\tif (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length)\n\t{\n\t\tuint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);\n\t\tmemcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);\n\t\toutputpos += bytes_to_copy;\n\t\tdecoder->compressed_offset += bytes_to_copy;\n\t}\n\n\t/* once we're out of that, copy from the secondary buffer */\n\tif (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)\n\t{\n\t\tuint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));\n\t\tmemcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);\n\t\toutputpos += bytes_to_copy;\n\t\tdecoder->compressed_offset += bytes_to_copy;\n\t}\n\n\treturn outputpos;\n}\n\n/*-------------------------------------------------\n *  metadata_callback - handle STREAMINFO metadata\n *-------------------------------------------------\n */\n\nstatic void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata)\n{\n\tflac_decoder *decoder = userdata;\n\n\t/* ignore all but STREAMINFO metadata */\n\tif (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO)\n\t\treturn;\n\n\t/* parse out the data we care about */\n\tdecoder->sample_rate = metadata->data.streaminfo.sampleRate;\n\tdecoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample;\n\tdecoder->channels = metadata->data.streaminfo.channels;\n}\n\n/*-------------------------------------------------\n *  write_callback - handle writes to the output\n *  stream\n *-------------------------------------------------\n */\n\nstatic void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes)\n{\n\tint sampnum, chan;\n\tint shift, blocksize;\n\tflac_decoder * decoder = (flac_decoder *)userdata;\n\tint16_t *sampbuf = (int16_t *)buffer;\n\tint sampch = channels(decoder);\n\tuint32_t offset = decoder->uncompressed_offset;\n\tuint16_t usample;\n\n\t/* interleaved case */\n\tshift = decoder->uncompressed_swap ? 8 : 0;\n\tblocksize = bytes / (sampch * sizeof(sampbuf[0]));\n\tif (decoder->uncompressed_start[1] == NULL)\n\t{\n\t\tint16_t *dest = decoder->uncompressed_start[0] + offset * sampch;\n\t\tfor (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)\n\t\t\tfor (chan = 0; chan < sampch; chan++) {\n\t\t\t\tusample = (uint16_t)*sampbuf++;\n\t\t\t\t*dest++ = (int16_t)((usample << shift) | (usample >> shift));\n\t\t\t}\n\t}\n\n\t/* non-interleaved case */\n\telse\n\t{\n\t\tfor (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)\n\t\t\tfor (chan = 0; chan < sampch; chan++) {\n\t\t\t\tusample = (uint16_t)*sampbuf++;\n\t\t\t\tif (decoder->uncompressed_start[chan] != NULL)\n\t\t\t\t\tdecoder->uncompressed_start[chan][offset] = (int16_t) ((usample << shift) | (usample >> shift));\n\t\t\t}\n\t}\n\tdecoder->uncompressed_offset = offset;\n}\n\n\n/*-------------------------------------------------\n *  seek_callback - handle seeks on the output\n *  stream\n *-------------------------------------------------\n */\n\nstatic drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin)\n{\n\tflac_decoder * decoder = (flac_decoder *)userdata;\n\tuint32_t length = decoder->compressed_length + decoder->compressed2_length;\n\n\tif (origin == drflac_seek_origin_start) {\n\t\tuint32_t pos = offset;\n\t\tif (pos <= length) {\n\t\t\tdecoder->compressed_offset = pos;\n\t\t\treturn 1;\n\t\t}\n\t} else if (origin == drflac_seek_origin_current) {\n\t\tuint32_t pos = decoder->compressed_offset + offset;\n\t\tif (pos <= length) {\n\t\t\tdecoder->compressed_offset = pos;\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "formats/libchdr/libchdr_flac_codec.c",
    "content": "/***************************************************************************\n\n    libchdr_flac_codec.c\n\n    MAME Compressed Hunks of Data file format\n\n****************************************************************************\n\n    Copyright Aaron Giles\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n          notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in\n          the documentation and/or other materials provided with the\n          distribution.\n        * Neither the name 'MAME' nor the names of its contributors may be\n          used to endorse or promote products derived from this software\n          without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,\n    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n***************************************************************************/\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <libchdr/chd.h>\n#include <libchdr/minmax.h>\n#include <libchdr/cdrom.h>\n#include <libchdr/flac.h>\n#include <libchdr/huffman.h>\n#include <libchdr/libchdr_zlib.h>\n#include <zlib.h>\n\n#include <retro_inline.h>\n#include <streams/file_stream.h>\n\n/***************************************************************************\n *  CD FLAC DECOMPRESSOR\n ***************************************************************************\n */\n\n/*------------------------------------------------------\n *  flac_codec_blocksize - return the optimal block size\n *------------------------------------------------------\n */\n\nstatic uint32_t flac_codec_blocksize(uint32_t bytes)\n{\n\t/* determine FLAC block size, which must be 16-65535\n\t * clamp to 2k since that's supposed to be the sweet spot */\n\tuint32_t blocksize = bytes / 4;\n\twhile (blocksize > 2048)\n\t\tblocksize /= 2;\n\treturn blocksize;\n}\n\nchd_error flac_codec_init(void *codec, uint32_t hunkbytes)\n{\n\tuint16_t native_endian = 0;\n\tflac_codec_data *flac = (flac_codec_data*)codec;\n\n\t/* make sure the CHD's hunk size is an even multiple of the sample size */\n\tif (hunkbytes % 4 != 0)\n\t\treturn CHDERR_CODEC_ERROR;\n\n\t/* determine whether we want native or swapped samples */\n\t*(uint8_t *)(&native_endian) = 1;\n\tflac->native_endian = (native_endian & 1);\n\n\t/* flac decoder init */\n\tif (flac_decoder_init(&flac->decoder))\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\treturn CHDERR_NONE;\n}\n\nvoid flac_codec_free(void *codec)\n{\n\tflac_codec_data *flac = (flac_codec_data*)codec;\n\tflac_decoder_free(&flac->decoder);\n}\n\nchd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tflac_codec_data *flac = (flac_codec_data*)codec;\n\tint swap_endian;\n\n\tif (src[0] == 'L')\n\t\tswap_endian = !flac->native_endian;\n\telse if (src[0] == 'B')\n\t\tswap_endian = flac->native_endian;\n\telse\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\n\tif (!flac_decoder_reset(&flac->decoder, 44100, 2, flac_codec_blocksize(destlen), src + 1, complen - 1))\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\tif (!flac_decoder_decode_interleaved(&flac->decoder, (int16_t *)(dest), destlen/4, swap_endian))\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\tflac_decoder_finish(&flac->decoder);\n\n\treturn CHDERR_NONE;\n}\n\nstatic uint32_t cdfl_codec_blocksize(uint32_t bytes)\n{\n\t/* for CDs it seems that CD_MAX_SECTOR_DATA is the right target */\n\tuint32_t blocksize = bytes / 4;\n\twhile (blocksize > CD_MAX_SECTOR_DATA)\n\t\tblocksize /= 2;\n\treturn blocksize;\n}\n\nchd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)\n{\n#ifdef WANT_SUBCODE\n\tchd_error ret;\n#endif\n\tuint16_t native_endian = 0;\n\tcdfl_codec_data *cdfl = (cdfl_codec_data*)codec;\n\n\t/* make sure the CHD's hunk size is an even multiple of the frame size */\n\tif (hunkbytes % CD_FRAME_SIZE != 0)\n\t\treturn CHDERR_CODEC_ERROR;\n\n\tcdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);\n\tif (cdfl->buffer == NULL)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\t/* determine whether we want native or swapped samples */\n\t*(uint8_t *)(&native_endian) = 1;\n\tcdfl->swap_endian = (native_endian & 1);\n\n#ifdef WANT_SUBCODE\n\t/* init zlib inflater */\n\tret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n#endif\n\n\t/* flac decoder init */\n\tif (flac_decoder_init(&cdfl->decoder))\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\treturn CHDERR_NONE;\n}\n\nvoid cdfl_codec_free(void *codec)\n{\n\tcdfl_codec_data *cdfl = (cdfl_codec_data*)codec;\n\tflac_decoder_free(&cdfl->decoder);\n#ifdef WANT_SUBCODE\n\tzlib_codec_free(&cdfl->subcode_decompressor);\n#endif\n\tif (cdfl->buffer)\n\t\tfree(cdfl->buffer);\n}\n\nchd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tuint32_t framenum;\n\tuint8_t *buffer;\n#ifdef WANT_SUBCODE\n\tuint32_t offset;\n\tchd_error ret;\n#endif\n\tcdfl_codec_data *cdfl = (cdfl_codec_data*)codec;\n\n\t/* reset and decode */\n\tuint32_t frames = destlen / CD_FRAME_SIZE;\n\n\tif (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\tbuffer = &cdfl->buffer[0];\n\tif (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\n#ifdef WANT_SUBCODE\n\t/* inflate the subcode data */\n\toffset = flac_decoder_finish(&cdfl->decoder);\n\tret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n#else\n\tflac_decoder_finish(&cdfl->decoder);\n#endif\n\n\t/* reassemble the data */\n\tfor (framenum = 0; framenum < frames; framenum++)\n\t{\n\t\tmemcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\t\tmemcpy(&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);\n#endif\n\t}\n\n\treturn CHDERR_NONE;\n}\n"
  },
  {
    "path": "formats/libchdr/libchdr_huffman.c",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n****************************************************************************\n\n    huffman.c\n\n    Static Huffman compression and decompression helpers.\n\n****************************************************************************\n\n    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits\n    (since we use 1 byte values). However, it is also dependent upon the number\n    of samples used, as follows:\n\n         2 bits -> 3..4 samples\n         3 bits -> 5..7 samples\n         4 bits -> 8..12 samples\n         5 bits -> 13..20 samples\n         6 bits -> 21..33 samples\n         7 bits -> 34..54 samples\n         8 bits -> 55..88 samples\n         9 bits -> 89..143 samples\n        10 bits -> 144..232 samples\n        11 bits -> 233..376 samples\n        12 bits -> 377..609 samples\n        13 bits -> 610..986 samples\n        14 bits -> 987..1596 samples\n        15 bits -> 1597..2583 samples\n        16 bits -> 2584..4180 samples   -> note that a 4k data size guarantees codelength <= 16 bits\n        17 bits -> 4181..6764 samples\n        18 bits -> 6765..10945 samples\n        19 bits -> 10946..17710 samples\n        20 bits -> 17711..28656 samples\n        21 bits -> 28657..46367 samples\n        22 bits -> 46368..75024 samples\n        23 bits -> 75025..121392 samples\n        24 bits -> 121393..196417 samples\n        25 bits -> 196418..317810 samples\n        26 bits -> 317811..514228 samples\n        27 bits -> 514229..832039 samples\n        28 bits -> 832040..1346268 samples\n        29 bits -> 1346269..2178308 samples\n        30 bits -> 2178309..3524577 samples\n        31 bits -> 3524578..5702886 samples\n        32 bits -> 5702887..9227464 samples\n\n    Looking at it differently, here is where powers of 2 fall into these buckets:\n\n          256 samples -> 11 bits max\n          512 samples -> 12 bits max\n           1k samples -> 14 bits max\n           2k samples -> 15 bits max\n           4k samples -> 16 bits max\n           8k samples -> 18 bits max\n          16k samples -> 19 bits max\n          32k samples -> 21 bits max\n          64k samples -> 22 bits max\n         128k samples -> 24 bits max\n         256k samples -> 25 bits max\n         512k samples -> 27 bits max\n           1M samples -> 28 bits max\n           2M samples -> 29 bits max\n           4M samples -> 31 bits max\n           8M samples -> 32 bits max\n\n****************************************************************************\n\n    Delta-RLE encoding works as follows:\n\n    Starting value is assumed to be 0. All data is encoded as a delta\n    from the previous value, such that final[i] = final[i - 1] + delta.\n    Long runs of 0s are RLE-encoded as follows:\n\n        0x100 = repeat count of 8\n        0x101 = repeat count of 9\n        0x102 = repeat count of 10\n        0x103 = repeat count of 11\n        0x104 = repeat count of 12\n        0x105 = repeat count of 13\n        0x106 = repeat count of 14\n        0x107 = repeat count of 15\n        0x108 = repeat count of 16\n        0x109 = repeat count of 32\n        0x10a = repeat count of 64\n        0x10b = repeat count of 128\n        0x10c = repeat count of 256\n        0x10d = repeat count of 512\n        0x10e = repeat count of 1024\n        0x10f = repeat count of 2048\n\n    Note that repeat counts are reset at the end of a row, so if a 0 run\n    extends to the end of a row, a large repeat count may be used.\n\n    The reason for starting the run counts at 8 is that 0 is expected to\n    be the most common symbol, and is typically encoded in 1 or 2 bits.\n\n***************************************************************************/\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <libchdr/huffman.h>\n#include <libchdr/minmax.h>\n\n/***************************************************************************\n *  MACROS\n ***************************************************************************\n */\n\n#define MAKE_LOOKUP(code,bits)  (((code) << 5) | ((bits) & 0x1f))\n\n/***************************************************************************\n *  IMPLEMENTATION\n ***************************************************************************\n */\n\n/*-------------------------------------------------\n *  huffman_context_base - create an encoding/\n *  decoding context\n *-------------------------------------------------\n */\n\nstruct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)\n{\n\tstruct huffman_decoder* decoder = NULL;\n\n\t/* limit to 24 bits */\n\tif (maxbits > 24)\n\t\treturn NULL;\n\n\tdecoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));\n\tdecoder->numcodes = numcodes;\n\tdecoder->maxbits = maxbits;\n\tdecoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));\n\tdecoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);\n\tdecoder->datahisto = NULL;\n\tdecoder->prevdata = 0;\n\tdecoder->rleremaining = 0;\n\treturn decoder;\n}\n\nvoid delete_huffman_decoder(struct huffman_decoder* decoder)\n{\n\tif (decoder != NULL)\n\t{\n\t\tif (decoder->lookup != NULL)\n\t\t\tfree(decoder->lookup);\n\t\tif (decoder->huffnode != NULL)\n\t\t\tfree(decoder->huffnode);\n\t\tfree(decoder);\n\t}\n}\n\n/*-------------------------------------------------\n *  decode_one - decode a single code from the\n *  huffman stream\n *-------------------------------------------------\n */\n\nuint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)\n{\n\t/* peek ahead to get maxbits worth of data */\n\tuint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);\n\n\t/* look it up, then remove the actual number of bits for this code */\n\tlookup_value lookup = decoder->lookup[bits];\n\tbitstream_remove(bitbuf, lookup & 0x1f);\n\n\t/* return the value */\n\treturn lookup >> 5;\n}\n\n/*-------------------------------------------------\n *  import_tree_rle - import an RLE-encoded\n *  huffman tree from a source data stream\n *-------------------------------------------------\n */\n\nenum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)\n{\n\tint numbits;\n\tuint32_t curnode;\n\tenum huffman_error error;\n\n\t/* bits per entry depends on the maxbits */\n\tif (decoder->maxbits >= 16)\n\t\tnumbits = 5;\n\telse if (decoder->maxbits >= 8)\n\t\tnumbits = 4;\n\telse\n\t\tnumbits = 3;\n\n\t/* loop until we read all the nodes */\n\tfor (curnode = 0; curnode < decoder->numcodes; )\n\t{\n\t\t/* a non-one value is just raw */\n\t\tint nodebits = bitstream_read(bitbuf, numbits);\n\t\tif (nodebits != 1)\n\t\t\tdecoder->huffnode[curnode++].numbits = nodebits;\n\n\t\t/* a one value is an escape code */\n\t\telse\n\t\t{\n\t\t\t/* a double 1 is just a single 1 */\n\t\t\tnodebits = bitstream_read(bitbuf, numbits);\n\t\t\tif (nodebits == 1)\n\t\t\t\tdecoder->huffnode[curnode++].numbits = nodebits;\n\n\t\t\t/* otherwise, we need one for value for the repeat count */\n\t\t\telse\n\t\t\t{\n\t\t\t\tint repcount = bitstream_read(bitbuf, numbits) + 3;\n\t\t\t\tif (repcount + curnode > decoder->numcodes)\n\t\t\t\t\treturn HUFFERR_INVALID_DATA;\n\t\t\t\twhile (repcount--)\n\t\t\t\t\tdecoder->huffnode[curnode++].numbits = nodebits;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* make sure we ended up with the right number */\n\tif (curnode != decoder->numcodes)\n\t\treturn HUFFERR_INVALID_DATA;\n\n\t/* assign canonical codes for all nodes based on their code lengths */\n\terror = huffman_assign_canonical_codes(decoder);\n\tif (error != HUFFERR_NONE)\n\t\treturn error;\n\n\t/* build the lookup table */\n\thuffman_build_lookup_table(decoder);\n\n\t/* determine final input length and report errors */\n\treturn bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;\n}\n\n\n/*-------------------------------------------------\n *  import_tree_huffman - import a huffman-encoded\n *  huffman tree from a source data stream\n *-------------------------------------------------\n */\n\nenum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)\n{\n\tint start;\n\tint last = 0;\n\tint count = 0;\n\tint index;\n\tuint32_t curcode;\n\tuint8_t rlefullbits = 0;\n\tuint32_t temp;\n\tenum huffman_error error;\n\t/* start by parsing the lengths for the small tree */\n\tstruct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);\n\tsmallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);\n\tstart = bitstream_read(bitbuf, 3) + 1;\n\tfor (index = 1; index < 24; index++)\n\t{\n\t\tif (index < start || count == 7)\n\t\t\tsmallhuff->huffnode[index].numbits = 0;\n\t\telse\n\t\t{\n\t\t\tcount = bitstream_read(bitbuf, 3);\n\t\t\tsmallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;\n\t\t}\n\t}\n\n\t/* then regenerate the tree */\n\terror = huffman_assign_canonical_codes(smallhuff);\n\tif (error != HUFFERR_NONE)\n\t\treturn error;\n\thuffman_build_lookup_table(smallhuff);\n\n\t/* determine the maximum length of an RLE count */\n\ttemp = decoder->numcodes - 9;\n\twhile (temp != 0)\n\t\ttemp >>= 1, rlefullbits++;\n\n\t/* now process the rest of the data */\n\tfor (curcode = 0; curcode < decoder->numcodes; )\n\t{\n\t\tint value = huffman_decode_one(smallhuff, bitbuf);\n\t\tif (value != 0)\n\t\t\tdecoder->huffnode[curcode++].numbits = last = value - 1;\n\t\telse\n\t\t{\n\t\t\tint count = bitstream_read(bitbuf, 3) + 2;\n\t\t\tif (count == 7+2)\n\t\t\t\tcount += bitstream_read(bitbuf, rlefullbits);\n\t\t\tfor ( ; count != 0 && curcode < decoder->numcodes; count--)\n\t\t\t\tdecoder->huffnode[curcode++].numbits = last;\n\t\t}\n\t}\n\n    /* make sure we free the local huffman decoder */\n    delete_huffman_decoder(smallhuff);\n\n\t/* make sure we ended up with the right number */\n\tif (curcode != decoder->numcodes)\n\t\treturn HUFFERR_INVALID_DATA;\n\n\t/* assign canonical codes for all nodes based on their code lengths */\n\terror = huffman_assign_canonical_codes(decoder);\n\tif (error != HUFFERR_NONE)\n\t\treturn error;\n\n\t/* build the lookup table */\n\thuffman_build_lookup_table(decoder);\n\n\t/* determine final input length and report errors */\n\treturn bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;\n}\n\n/*-------------------------------------------------\n *  compute_tree_from_histo - common backend for\n *  computing a tree based on the data histogram\n *-------------------------------------------------\n */\n\nenum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)\n{\n\tuint32_t i;\n\tuint32_t lowerweight;\n\tuint32_t upperweight;\n\t/* compute the number of data items in the histogram */\n\tuint32_t sdatacount = 0;\n\tfor (i = 0; i < decoder->numcodes; i++)\n\t\tsdatacount += decoder->datahisto[i];\n\n\t/* binary search to achieve the optimum encoding */\n\tlowerweight = 0;\n\tupperweight = sdatacount * 2;\n\twhile (1)\n\t{\n\t\t/* build a tree using the current weight */\n\t\tuint32_t curweight = (upperweight + lowerweight) / 2;\n\t\tint curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);\n\n\t\t/* apply binary search here */\n\t\tif (curmaxbits <= decoder->maxbits)\n\t\t{\n\t\t\tlowerweight = curweight;\n\n\t\t\t/* early out if it worked with the raw weights, or if we're done searching */\n\t\t\tif (curweight == sdatacount || (upperweight - lowerweight) <= 1)\n\t\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t\tupperweight = curweight;\n\t}\n\n\t/* assign canonical codes for all nodes based on their code lengths */\n\treturn huffman_assign_canonical_codes(decoder);\n}\n\n/***************************************************************************\n *  INTERNAL FUNCTIONS\n ***************************************************************************\n */\n\n/*-------------------------------------------------\n *  tree_node_compare - compare two tree nodes\n *  by weight\n *-------------------------------------------------\n */\n\nstatic int huffman_tree_node_compare(const void *item1, const void *item2)\n{\n\tconst struct node_t *node1 = *(const struct node_t **)item1;\n\tconst struct node_t *node2 = *(const struct node_t **)item2;\n\tif (node2->weight != node1->weight)\n\t\treturn node2->weight - node1->weight;\n\tif (node2->bits - node1->bits == 0)\n\t\tfprintf(stderr, \"identical node sort keys, should not happen!\\n\");\n\treturn (int)node1->bits - (int)node2->bits;\n}\n\n/*-------------------------------------------------\n *  build_tree - build a huffman tree based on the\n *  data distribution\n *-------------------------------------------------\n */\n\nint huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)\n{\n\tuint32_t curcode;\n\tint nextalloc;\n\tint listitems = 0;\n\tint maxbits = 0;\n\t/* make a list of all non-zero nodes */\n\tstruct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);\n\tmemset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));\n\tfor (curcode = 0; curcode < decoder->numcodes; curcode++)\n\t\tif (decoder->datahisto[curcode] != 0)\n\t\t{\n\t\t\tlist[listitems++] = &decoder->huffnode[curcode];\n\t\t\tdecoder->huffnode[curcode].count = decoder->datahisto[curcode];\n\t\t\tdecoder->huffnode[curcode].bits = curcode;\n\n\t\t\t/* scale the weight by the current effective length, ensuring we don't go to 0 */\n\t\t\tdecoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);\n\t\t\tif (decoder->huffnode[curcode].weight == 0)\n\t\t\t\tdecoder->huffnode[curcode].weight = 1;\n\t\t}\n\n\t/* sort the list by weight, largest weight first */\n\tqsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);\n\n\t/* now build the tree */\n\tnextalloc = decoder->numcodes;\n\twhile (listitems > 1)\n\t{\n\t\tint curitem;\n\t\t/* remove lowest two items */\n\t\tstruct node_t* node1 = &(*list[--listitems]);\n\t\tstruct node_t* node0 = &(*list[--listitems]);\n\n\t\t/* create new node */\n\t\tstruct node_t* newnode = &decoder->huffnode[nextalloc++];\n\t\tnewnode->parent = NULL;\n\t\tnode0->parent = node1->parent = newnode;\n\t\tnewnode->weight = node0->weight + node1->weight;\n\n\t\t/* insert into list at appropriate location */\n\t\tfor (curitem = 0; curitem < listitems; curitem++)\n\t\t\tif (newnode->weight > list[curitem]->weight)\n\t\t\t{\n\t\t\t\tmemmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tlist[curitem] = newnode;\n\t\tlistitems++;\n\t}\n\n\t/* compute the number of bits in each code, and fill in another histogram */\n\tfor (curcode = 0; curcode < decoder->numcodes; curcode++)\n\t{\n\t\tstruct node_t *curnode;\n\t\tstruct node_t* node = &decoder->huffnode[curcode];\n\t\tnode->numbits = 0;\n\t\tnode->bits = 0;\n\n\t\t/* if we have a non-zero weight, compute the number of bits */\n\t\tif (node->weight > 0)\n\t\t{\n\t\t\t/* determine the number of bits for this node */\n\t\t\tfor (curnode = node; curnode->parent != NULL; curnode = curnode->parent)\n\t\t\t\tnode->numbits++;\n\t\t\tif (node->numbits == 0)\n\t\t\t\tnode->numbits = 1;\n\n\t\t\t/* keep track of the max */\n\t\t\tmaxbits = MAX(maxbits, ((int)node->numbits));\n\t\t}\n\t}\n\treturn maxbits;\n}\n\n/*-------------------------------------------------\n *  assign_canonical_codes - assign canonical codes\n *  to all the nodes based on the number of bits\n *  in each\n *-------------------------------------------------\n */\n\nenum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)\n{\n\tuint32_t curcode;\n\tint codelen;\n\tuint32_t curstart = 0;\n\t/* build up a histogram of bit lengths */\n\tuint32_t bithisto[33] = { 0 };\n\tfor (curcode = 0; curcode < decoder->numcodes; curcode++)\n\t{\n\t\tstruct node_t* node = &decoder->huffnode[curcode];\n\t\tif (node->numbits > decoder->maxbits)\n\t\t\treturn HUFFERR_INTERNAL_INCONSISTENCY;\n\t\tif (node->numbits <= 32)\n\t\t\tbithisto[node->numbits]++;\n\t}\n\n\t/* for each code length, determine the starting code number */\n\tfor (codelen = 32; codelen > 0; codelen--)\n\t{\n\t\tuint32_t nextstart = (curstart + bithisto[codelen]) >> 1;\n\t\tif (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))\n\t\t\treturn HUFFERR_INTERNAL_INCONSISTENCY;\n\t\tbithisto[codelen] = curstart;\n\t\tcurstart = nextstart;\n\t}\n\n\t/* now assign canonical codes */\n\tfor (curcode = 0; curcode < decoder->numcodes; curcode++)\n\t{\n\t\tstruct node_t* node = &decoder->huffnode[curcode];\n\t\tif (node->numbits > 0)\n\t\t\tnode->bits = bithisto[node->numbits]++;\n\t}\n\treturn HUFFERR_NONE;\n}\n\n/*-------------------------------------------------\n *  build_lookup_table - build a lookup table for\n *  fast decoding\n *-------------------------------------------------\n */\n\nvoid huffman_build_lookup_table(struct huffman_decoder* decoder)\n{\n\tuint32_t curcode;\n\t/* iterate over all codes */\n\tfor (curcode = 0; curcode < decoder->numcodes; curcode++)\n\t{\n\t\t/* process all nodes which have non-zero bits */\n\t\tstruct node_t* node = &decoder->huffnode[curcode];\n\t\tif (node->numbits > 0)\n\t\t{\n         int shift;\n         lookup_value *dest;\n         lookup_value *destend;\n\t\t\t/* set up the entry */\n\t\t\tlookup_value value = MAKE_LOOKUP(curcode, node->numbits);\n\n\t\t\t/* fill all matching entries */\n\t\t\tshift = decoder->maxbits - node->numbits;\n\t\t\tdest = &decoder->lookup[node->bits << shift];\n\t\t\tdestend = &decoder->lookup[((node->bits + 1) << shift) - 1];\n\t\t\twhile (dest <= destend)\n\t\t\t\t*dest++ = value;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "formats/libchdr/libchdr_lzma.c",
    "content": "/***************************************************************************\n\n    libchdr_lzma_codec.c\n\n    MAME Compressed Hunks of Data file format\n\n****************************************************************************\n\n    Copyright Aaron Giles\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n          notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in\n          the documentation and/or other materials provided with the\n          distribution.\n        * Neither the name 'MAME' nor the names of its contributors may be\n          used to endorse or promote products derived from this software\n          without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,\n    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n***************************************************************************/\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <zlib.h>\n#include <libchdr/chd.h>\n#include <libchdr/minmax.h>\n#include <libchdr/cdrom.h>\n#include <libchdr/huffman.h>\n#include <libchdr/lzma.h>\n\n#include <retro_inline.h>\n#include <streams/file_stream.h>\n\n/***************************************************************************\n *  LZMA ALLOCATOR HELPER\n ***************************************************************************\n */\n\nvoid *lzma_fast_alloc(void *p, size_t size);\nvoid lzma_fast_free(void *p, void *address);\n\n/*-------------------------------------------------\n *  lzma_allocator_init\n *-------------------------------------------------\n */\n\nstatic void lzma_allocator_init(void* p)\n{\n\tlzma_allocator *codec = (lzma_allocator *)(p);\n\n\t/* reset pointer list */\n\tmemset(codec->allocptr, 0, sizeof(codec->allocptr));\n\tmemset(codec->allocptr2, 0, sizeof(codec->allocptr2));\n\tcodec->Alloc = lzma_fast_alloc;\n\tcodec->Free = lzma_fast_free;\n}\n\n/*-------------------------------------------------\n *  lzma_allocator_free\n *-------------------------------------------------\n */\n\nstatic void lzma_allocator_free(void* p )\n{\n\tint i;\n\tlzma_allocator *codec = (lzma_allocator *)(p);\n\n\t/* free our memory */\n\tfor (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)\n\t{\n\t\tif (codec->allocptr[i] != NULL)\n\t\t\tfree(codec->allocptr[i]);\n\t}\n}\n\n/*-------------------------------------------------\n *  lzma_fast_alloc - fast malloc for lzma, which\n *  allocates and frees memory frequently\n *-------------------------------------------------\n */\n\n/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */\n#define LZMA_MIN_ALIGNMENT_BITS 512\n#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)\n\nvoid *lzma_fast_alloc(void *p, size_t size)\n{\n\tint scan;\n\tuint32_t *addr        = NULL;\n\tlzma_allocator *codec = (lzma_allocator *)(p);\n\tuintptr_t vaddr = 0;\n\n\t/* compute the size, rounding to the nearest 1k */\n\tsize = (size + 0x3ff) & ~0x3ff;\n\n\t/* reuse a hunk if we can */\n\tfor (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)\n\t{\n\t\tuint32_t *ptr = codec->allocptr[scan];\n\t\tif (ptr != NULL && size == *ptr)\n\t\t{\n\t\t\t/* set the low bit of the size so we don't match next time */\n\t\t\t*ptr |= 1;\n\n\t\t\t/* return aligned address of the block */\n\t\t\treturn codec->allocptr2[scan];\n\t\t}\n\t}\n\n\t/* alloc a new one and put it into the list */\n\taddr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);\n\tif (addr==NULL)\n\t\treturn NULL;\n\tfor (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)\n\t{\n\t\tif (codec->allocptr[scan] == NULL)\n\t\t{\n\t\t\t/* store block address */\n\t\t\tcodec->allocptr[scan] = addr;\n\n\t\t\t/* compute aligned address, store it */\n\t\t\tvaddr = (uintptr_t)addr;\n\t\t\tvaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));\n\t\t\tcodec->allocptr2[scan] = (uint32_t*)vaddr;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* set the low bit of the size so we don't match next time */\n\t*addr = size | 1;\n\n\t/* return aligned address */\n\treturn (void*)vaddr;\n}\n\n/*-------------------------------------------------\n *  lzma_fast_free - fast free for lzma, which\n *  allocates and frees memory frequently\n *-------------------------------------------------\n */\n\nvoid lzma_fast_free(void *p, void *address)\n{\n\tint scan;\n\tuint32_t *ptr = NULL;\n\tlzma_allocator *codec = NULL;\n\n\tif (address == NULL)\n\t\treturn;\n\n\tcodec = (lzma_allocator *)(p);\n\n\t/* find the hunk */\n\tptr = (uint32_t *)address;\n\tfor (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)\n\t{\n\t\tif (ptr == codec->allocptr2[scan])\n\t\t{\n\t\t\t/* clear the low bit of the size to allow matches */\n\t\t\t*codec->allocptr[scan] &= ~1;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/***************************************************************************\n *  LZMA DECOMPRESSOR\n ***************************************************************************\n */\n\n/*-------------------------------------------------\n *  lzma_codec_init - constructor\n *-------------------------------------------------\n */\n\nchd_error lzma_codec_init(void* codec, uint32_t hunkbytes)\n{\n\tCLzmaEncHandle enc;\n\tCLzmaEncProps encoder_props;\n\tByte decoder_props[LZMA_PROPS_SIZE];\n\tSizeT props_size;\n\tlzma_allocator* alloc;\n\tlzma_codec_data* lzma_codec = (lzma_codec_data*) codec;\n\n\t/* construct the decoder */\n\tLzmaDec_Construct(&lzma_codec->decoder);\n\n\t/* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK\n\t * This code assumes that the current version of the encoder imposes the same requirements on the\n\t * decoder as the encoder used to produce the file.  This is not necessarily true.  The format\n\t * needs to be changed so the encoder properties are written to the file.\n\n\t * configure the properties like the compressor did */\n\tLzmaEncProps_Init(&encoder_props);\n\tencoder_props.level = 9;\n\tencoder_props.reduceSize = hunkbytes;\n\tLzmaEncProps_Normalize(&encoder_props);\n\n\t/* convert to decoder properties */\n\talloc = &lzma_codec->allocator;\n\tlzma_allocator_init(alloc);\n\tenc = LzmaEnc_Create((ISzAlloc*)alloc);\n\tif (!enc)\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\tif (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)\n\t{\n\t\tLzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\tprops_size = sizeof(decoder_props);\n\tif (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)\n\t{\n\t\tLzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\tLzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);\n\n\t/* do memory allocations */\n\tif (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\n\t/* Okay */\n\treturn CHDERR_NONE;\n}\n\n/*-------------------------------------------------\n *  lzma_codec_free\n *-------------------------------------------------\n */\n\nvoid lzma_codec_free(void* codec)\n{\n\tlzma_codec_data* lzma_codec = (lzma_codec_data*) codec;\n\n\t/* free memory */\n\tLzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);\n\tlzma_allocator_free(&lzma_codec->allocator);\n}\n\n/*-------------------------------------------------\n *  decompress - decompress data using the LZMA\n *  codec\n *-------------------------------------------------\n */\n\nchd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tELzmaStatus status;\n\tSRes res;\n\tSizeT consumedlen, decodedlen;\n\t/* initialize */\n\tlzma_codec_data* lzma_codec = (lzma_codec_data*) codec;\n\tLzmaDec_Init(&lzma_codec->decoder);\n\n\t/* decode */\n\tconsumedlen = complen;\n\tdecodedlen = destlen;\n\tres = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);\n\tif ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\treturn CHDERR_NONE;\n}\n\n/* cdlz */\nchd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)\n{\n\tchd_error ret;\n\tcdlz_codec_data* cdlz = (cdlz_codec_data*) codec;\n\n\t/* allocate buffer */\n\tcdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);\n\tif (cdlz->buffer == NULL)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\t/* make sure the CHD's hunk size is an even multiple of the frame size */\n\tret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n\n#ifdef WANT_SUBCODE\n\tret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n#endif\n\n\tif (hunkbytes % CD_FRAME_SIZE != 0)\n\t\treturn CHDERR_CODEC_ERROR;\n\n\treturn CHDERR_NONE;\n}\n\nvoid cdlz_codec_free(void* codec)\n{\n\tcdlz_codec_data* cdlz = (cdlz_codec_data*) codec;\n\tfree(cdlz->buffer);\n\tlzma_codec_free(&cdlz->base_decompressor);\n#ifdef WANT_SUBCODE\n\tzlib_codec_free(&cdlz->subcode_decompressor);\n#endif\n}\n\nchd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tuint32_t framenum;\n\tcdlz_codec_data* cdlz = (cdlz_codec_data*)codec;\n\n\t/* determine header bytes */\n\tuint32_t frames = destlen / CD_FRAME_SIZE;\n\tuint32_t complen_bytes = (destlen < 65536) ? 2 : 3;\n\tuint32_t ecc_bytes = (frames + 7) / 8;\n\tuint32_t header_bytes = ecc_bytes + complen_bytes;\n\n\t/* extract compressed length of base */\n\tuint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];\n\tif (complen_bytes > 2)\n\t\tcomplen_base = (complen_base << 8) | src[ecc_bytes + 2];\n\n\t/* reset and decode */\n\tlzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\tzlib_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);\n#endif\n\n\t/* reassemble the data */\n\tfor (framenum = 0; framenum < frames; framenum++)\n\t{\n\t\tuint8_t *sector;\n\n\t\tmemcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\t\tmemcpy(&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);\n#endif\n\n#ifdef WANT_RAW_DATA_SECTOR\n\t\t/* reconstitute the ECC data and sync header */\n\t\tsector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];\n\t\tif ((src[framenum / 8] & (1 << (framenum % 8))) != 0)\n\t\t{\n\t\t\tconst uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };\n\t\t\tmemcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));\n\t\t\tecc_generate(sector);\n\t\t}\n#endif\n\t}\n\treturn CHDERR_NONE;\n}\n"
  },
  {
    "path": "formats/libchdr/libchdr_zlib.c",
    "content": "/***************************************************************************\n\n    libchdr_zlib.c\n\n    MAME Compressed Hunks of Data file format\n\n****************************************************************************\n\n    Copyright Aaron Giles\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n          notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in\n          the documentation and/or other materials provided with the\n          distribution.\n        * Neither the name 'MAME' nor the names of its contributors may be\n          used to endorse or promote products derived from this software\n          without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,\n    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n***************************************************************************/\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <libchdr/chd.h>\n#include <libchdr/minmax.h>\n#include <libchdr/cdrom.h>\n#include <libchdr/huffman.h>\n#include <libchdr/libchdr_zlib.h>\n#include <zlib.h>\n\n#include <retro_inline.h>\n#include <streams/file_stream.h>\n\n/***************************************************************************\n    ZLIB COMPRESSION CODEC\n***************************************************************************/\n\n/*-------------------------------------------------\n    zlib_codec_init - initialize the ZLIB codec\n-------------------------------------------------*/\n\nchd_error zlib_codec_init(void *codec, uint32_t hunkbytes)\n{\n\tint zerr;\n\tchd_error err;\n\tzlib_codec_data *data = (zlib_codec_data*)codec;\n\n\t/* clear the buffers */\n\tmemset(data, 0, sizeof(zlib_codec_data));\n\n\t/* init the inflater first */\n\tdata->inflater.next_in = (Bytef *)data;\t/* bogus, but that's ok */\n\tdata->inflater.avail_in = 0;\n\tdata->inflater.zalloc = zlib_fast_alloc;\n\tdata->inflater.zfree = zlib_fast_free;\n\tdata->inflater.opaque = &data->allocator;\n\tzerr = inflateInit2(&data->inflater, -MAX_WBITS);\n\n\t/* convert errors */\n\tif (zerr == Z_MEM_ERROR)\n\t\terr = CHDERR_OUT_OF_MEMORY;\n\telse if (zerr != Z_OK)\n\t\terr = CHDERR_CODEC_ERROR;\n\telse\n\t\terr = CHDERR_NONE;\n\n\treturn err;\n}\n\n/*-------------------------------------------------\n    zlib_codec_free - free data for the ZLIB\n    codec\n-------------------------------------------------*/\n\nvoid zlib_codec_free(void *codec)\n{\n\tzlib_codec_data *data = (zlib_codec_data *)codec;\n\n\t/* deinit the streams */\n\tif (data != NULL)\n\t{\n\t\tinflateEnd(&data->inflater);\n\n\t\t/* free our fast memory */\n\t\tzlib_allocator_free(&data->allocator);\n\t}\n}\n\n/*-------------------------------------------------\n    zlib_codec_decompress - decompress data using\n    the ZLIB codec\n-------------------------------------------------*/\n\nchd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tzlib_codec_data *data = (zlib_codec_data *)codec;\n\tint zerr;\n\n\t/* reset the decompressor */\n\tdata->inflater.next_in = (Bytef *)src;\n\tdata->inflater.avail_in = complen;\n\tdata->inflater.total_in = 0;\n\tdata->inflater.next_out = (Bytef *)dest;\n\tdata->inflater.avail_out = destlen;\n\tdata->inflater.total_out = 0;\n\tzerr = inflateReset(&data->inflater);\n\tif (zerr != Z_OK)\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\n\t/* do it */\n\tzerr = inflate(&data->inflater, Z_FINISH);\n\tif (data->inflater.total_out != destlen)\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\n\treturn CHDERR_NONE;\n}\n\n/*-------------------------------------------------\n    zlib_fast_alloc - fast malloc for ZLIB, which\n    allocates and frees memory frequently\n-------------------------------------------------*/\n\n/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */\n#define ZLIB_MIN_ALIGNMENT_BITS 512\n#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)\n\nvoidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)\n{\n\tzlib_allocator *alloc = (zlib_allocator *)opaque;\n\tuintptr_t paddr = 0;\n\tuint32_t *ptr;\n\tint i;\n\n\t/* compute the size, rounding to the nearest 1k */\n\tsize = (size * items + 0x3ff) & ~0x3ff;\n\n\t/* reuse a hunk if we can */\n\tfor (i = 0; i < MAX_ZLIB_ALLOCS; i++)\n\t{\n\t\tptr = alloc->allocptr[i];\n\t\tif (ptr && size == *ptr)\n\t\t{\n\t\t\t/* set the low bit of the size so we don't match next time */\n\t\t\t*ptr |= 1;\n\n\t\t\t/* return aligned block address */\n\t\t\treturn (voidpf)(alloc->allocptr2[i]);\n\t\t}\n\t}\n\n\t/* alloc a new one */\n    ptr = (uint32_t *)malloc(size + sizeof(uint32_t) + ZLIB_MIN_ALIGNMENT_BYTES);\n\tif (!ptr)\n\t\treturn NULL;\n\n\t/* put it into the list */\n\tfor (i = 0; i < MAX_ZLIB_ALLOCS; i++)\n\t\tif (!alloc->allocptr[i])\n\t\t{\n\t\t\talloc->allocptr[i] = ptr;\n\t\t\tpaddr = (((uintptr_t)ptr) + sizeof(uint32_t) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));\n\t\t\talloc->allocptr2[i] = (uint32_t*)paddr;\n\t\t\tbreak;\n\t\t}\n\n\t/* set the low bit of the size so we don't match next time */\n\t*ptr = size | 1;\n\n\t/* return aligned block address */\n\treturn (voidpf)paddr;\n}\n\n/*-------------------------------------------------\n    zlib_fast_free - fast free for ZLIB, which\n    allocates and frees memory frequently\n-------------------------------------------------*/\n\nvoid zlib_fast_free(voidpf opaque, voidpf address)\n{\n\tzlib_allocator *alloc = (zlib_allocator *)opaque;\n\tuint32_t *ptr = (uint32_t *)address;\n\tint i;\n\n\t/* find the hunk */\n\tfor (i = 0; i < MAX_ZLIB_ALLOCS; i++)\n\t\tif (ptr == alloc->allocptr2[i])\n\t\t{\n\t\t\t/* clear the low bit of the size to allow matches */\n\t\t\t*(alloc->allocptr[i]) &= ~1;\n\t\t\treturn;\n\t\t}\n}\n\n/*-------------------------------------------------\n    zlib_allocator_free\n-------------------------------------------------*/\nvoid zlib_allocator_free(voidpf opaque)\n{\n\tzlib_allocator *alloc = (zlib_allocator *)opaque;\n\tint i;\n\n\tfor (i = 0; i < MAX_ZLIB_ALLOCS; i++)\n\t\tif (alloc->allocptr[i])\n\t\t\tfree(alloc->allocptr[i]);\n}\n\n\n/* cdzl */\n\nchd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)\n{\n\tchd_error ret;\n\tcdzl_codec_data* cdzl = (cdzl_codec_data*)codec;\n\n\t/* make sure the CHD's hunk size is an even multiple of the frame size */\n\tif (hunkbytes % CD_FRAME_SIZE != 0)\n\t\treturn CHDERR_CODEC_ERROR;\n\n\tcdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);\n\tif (cdzl->buffer == NULL)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\tret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n\n#ifdef WANT_SUBCODE\n\tret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n#endif\n\n\treturn CHDERR_NONE;\n}\n\nvoid cdzl_codec_free(void *codec)\n{\n\tcdzl_codec_data* cdzl = (cdzl_codec_data*)codec;\n\tzlib_codec_free(&cdzl->base_decompressor);\n#ifdef WANT_SUBCODE\n\tzlib_codec_free(&cdzl->subcode_decompressor);\n#endif\n\tfree(cdzl->buffer);\n}\n\nchd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tuint32_t framenum;\n\tcdzl_codec_data* cdzl = (cdzl_codec_data*)codec;\n\n\t/* determine header bytes */\n\tuint32_t frames = destlen / CD_FRAME_SIZE;\n\tuint32_t complen_bytes = (destlen < 65536) ? 2 : 3;\n\tuint32_t ecc_bytes = (frames + 7) / 8;\n\tuint32_t header_bytes = ecc_bytes + complen_bytes;\n\n\t/* extract compressed length of base */\n\tuint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];\n\tif (complen_bytes > 2)\n\t\tcomplen_base = (complen_base << 8) | src[ecc_bytes + 2];\n\n\t/* reset and decode */\n\tzlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\tzlib_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);\n#endif\n\n\t/* reassemble the data */\n\tfor (framenum = 0; framenum < frames; framenum++)\n\t{\n\t\tuint8_t *sector;\n\n\t\tmemcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\t\tmemcpy(&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);\n#endif\n\n#ifdef WANT_RAW_DATA_SECTOR\n\t\t/* reconstitute the ECC data and sync header */\n\t\tsector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];\n\t\tif ((src[framenum / 8] & (1 << (framenum % 8))) != 0)\n\t\t{\n\t\t\tconst uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };\n\t\t\tmemcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));\n\t\t\tecc_generate(sector);\n\t\t}\n#endif\n\t}\n\treturn CHDERR_NONE;\n}\n"
  },
  {
    "path": "formats/libchdr/libchdr_zstd.c",
    "content": "/***************************************************************************\n\n    libchdr_zstd.c\n\n    MAME Compressed Hunks of Data file format\n\n****************************************************************************\n\n    Copyright Aaron Giles\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n          notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in\n          the documentation and/or other materials provided with the\n          distribution.\n        * Neither the name 'MAME' nor the names of its contributors may be\n          used to endorse or promote products derived from this software\n          without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,\n    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n***************************************************************************/\n\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <libchdr/chd.h>\n#include <libchdr/minmax.h>\n#include <libchdr/cdrom.h>\n#include <libchdr/huffman.h>\n#include <libchdr/libchdr_zlib.h>\n#include <zlib.h>\n#include <libchdr/libchdr_zstd.h>\n#include <zstd.h>\n\n#include <retro_inline.h>\n#include <streams/file_stream.h>\n\n/***************************************************************************\n *  ZSTD DECOMPRESSOR\n ***************************************************************************\n */\n\n/*-------------------------------------------------\n *  zstd_codec_init - constructor\n *-------------------------------------------------\n */\n\nchd_error zstd_codec_init(void* codec, uint32_t hunkbytes)\n{\n\tzstd_codec_data* zstd_codec = (zstd_codec_data*) codec;\n\n\tzstd_codec->dstream = ZSTD_createDStream();\n\tif (!zstd_codec->dstream) {\n\t\tprintf(\"NO DSTREAM CREATED!\\n\");\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\treturn CHDERR_NONE;\n}\n\n/*-------------------------------------------------\n *  zstd_codec_free\n *-------------------------------------------------\n */\n\nvoid zstd_codec_free(void* codec)\n{\n\tzstd_codec_data* zstd_codec = (zstd_codec_data*) codec;\n\n\tZSTD_freeDStream(zstd_codec->dstream);\n}\n\n/*-------------------------------------------------\n *  decompress - decompress data using the ZSTD \n *  codec\n *-------------------------------------------------\n */\nchd_error zstd_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tZSTD_inBuffer input;\n\tZSTD_outBuffer output;\n\n\t/* initialize */\n\tzstd_codec_data* zstd_codec = (zstd_codec_data*) codec;\n\n\t/* reset decompressor */\n\tsize_t zstd_res = ZSTD_initDStream(zstd_codec->dstream);\n\n\tinput.src   = src;\n\tinput.size  = complen;\n\tinput.pos   = 0;\n\n\toutput.dst  = dest;\n\toutput.size = destlen;\n\toutput.pos  = 0;\n\n\tif (ZSTD_isError(zstd_res)) \n\t{\n\t\tprintf(\"INITI DSTREAM FAILED!\\n\");\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\n\twhile ((input.pos < input.size) && (output.pos < output.size))\n\t{\n\t\tzstd_res = ZSTD_decompressStream(zstd_codec->dstream, &output, &input);\n\t\tif (ZSTD_isError(zstd_res))\n\t\t{\n\t\t\tprintf(\"DECOMPRESSION ERROR IN LOOP\\n\");\n\t\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t\t}\n\t}\n\tif (output.pos != output.size)\n\t{\n\t\tprintf(\"OUTPUT DOESN'T MATCH!\\n\");\n\t\treturn CHDERR_DECOMPRESSION_ERROR;\n\t}\n\treturn CHDERR_NONE;\n\n}\n\n/* cdzs */\nchd_error cdzs_codec_init(void* codec, uint32_t hunkbytes)\n{\n\tchd_error ret;\n\tcdzs_codec_data* cdzs = (cdzs_codec_data*) codec;\n\n\t/* allocate buffer */\n\tcdzs->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);\n\tif (cdzs->buffer == NULL)\n\t\treturn CHDERR_OUT_OF_MEMORY;\n\n\t/* make sure the CHD's hunk size is an even multiple of the frame size */\n\tret = zstd_codec_init(&cdzs->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n\n#ifdef WANT_SUBCODE\n\tret = zstd_codec_init(&cdzs->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);\n\tif (ret != CHDERR_NONE)\n\t\treturn ret;\n#endif\n\n\tif (hunkbytes % CD_FRAME_SIZE != 0)\n\t\treturn CHDERR_CODEC_ERROR;\n\n\treturn CHDERR_NONE;\n}\n\nvoid cdzs_codec_free(void* codec)\n{\n\tcdzs_codec_data* cdzs = (cdzs_codec_data*) codec;\n\tfree(cdzs->buffer);\n\tzstd_codec_free(&cdzs->base_decompressor);\n#ifdef WANT_SUBCODE\n\tzstd_codec_free(&cdzs->subcode_decompressor);\n#endif\n}\n\nchd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)\n{\n\tuint32_t framenum;\n\tcdzs_codec_data* cdzs = (cdzs_codec_data*)codec;\n\n\t/* determine header bytes */\n\tuint32_t frames = destlen / CD_FRAME_SIZE;\n\tuint32_t complen_bytes = (destlen < 65536) ? 2 : 3;\n\tuint32_t ecc_bytes = (frames + 7) / 8;\n\tuint32_t header_bytes = ecc_bytes + complen_bytes;\n\n\t/* extract compressed length of base */\n\tuint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];\n\tif (complen_bytes > 2)\n\t\tcomplen_base = (complen_base << 8) | src[ecc_bytes + 2];\n\n\t/* reset and decode */\n\tzstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\tzstd_codec_decompress(&cdzs->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzs->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);\n#endif\n\n\t/* reassemble the data */\n\tfor (framenum = 0; framenum < frames; framenum++)\n\t{\n\t\tuint8_t *sector;\n\n\t\tmemcpy(&dest[framenum * CD_FRAME_SIZE], &cdzs->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);\n#ifdef WANT_SUBCODE\n\t\tmemcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzs->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);\n#endif\n\n#ifdef WANT_RAW_DATA_SECTOR\n\t\t/* reconstitute the ECC data and sync header */\n\t\tsector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];\n\t\tif ((src[framenum / 8] & (1 << (framenum % 8))) != 0)\n\t\t{\n\t\t\tconst uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };\n\t\t\tmemcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));\n\t\t\tecc_generate(sector);\n\t\t}\n#endif\n\t}\n\treturn CHDERR_NONE;\n}\n"
  },
  {
    "path": "formats/logiqx_dat/logiqx_dat.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (logiqx_dat.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <file/file_path.h>\n#include <string/stdstring.h>\n#include <formats/rxml.h>\n\n#include <formats/logiqx_dat.h>\n\n/* Holds all internal DAT file data */\nstruct logiqx_dat\n{\n   rxml_document_t *data;\n   rxml_node_t *current_node;\n};\n\n/* List of HTML formatting codes that must\n * be replaced when parsing XML data */\nconst char *logiqx_dat_html_code_list[][2] = {\n   {\"&amp;\",  \"&\"},\n   {\"&apos;\", \"'\"},\n   {\"&gt;\",   \">\"},\n   {\"&lt;\",   \"<\"},\n   {\"&quot;\", \"\\\"\"}\n};\n\n#define LOGIQX_DAT_HTML_CODE_LIST_SIZE 5\n\n/* Validation */\n\n/* Performs rudimentary validation of the specified\n * Logiqx XML DAT file path (not rigorous - just\n * enough to prevent obvious errors).\n * Also provides access to file size (DAT files can\n * be very large, so it is useful to have this information\n * on hand - i.e. so we can check that the system has\n * enough free memory to load the file). */\nbool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size)\n{\n   const char *file_ext = NULL;\n   int64_t file_size_int;\n\n   if (!path || !*path)\n      return false;\n\n   /* Check file extension */\n   file_ext = path_get_extension(path);\n\n   if (!file_ext || !*file_ext)\n      return false;\n\n   if (   !string_is_equal_noncase(file_ext, \"dat\")\n       && !string_is_equal_noncase(file_ext, \"xml\"))\n      return false;\n\n   /* Ensure file exists */\n   if (!path_is_valid(path))\n      return false;\n\n   /* Get file size */\n   file_size_int = path_get_size(path);\n\n   if (file_size_int <= 0)\n      return false;\n\n   if (file_size)\n      *file_size = (uint64_t)file_size_int;\n\n   return true;\n}\n\n/* File initialisation/de-initialisation */\n\n/* Loads specified Logiqx XML DAT file from disk.\n * Returned logiqx_dat_t object must be free'd using\n * logiqx_dat_free().\n * Returns NULL if file is invalid or a read error\n * occurs. */\nlogiqx_dat_t *logiqx_dat_init(const char *path)\n{\n   logiqx_dat_t *dat_file = NULL;\n   rxml_node_t *root_node = NULL;\n\n   /* Check file path */\n   if (!logiqx_dat_path_is_valid(path, NULL))\n      goto error;\n\n   /* Create logiqx_dat_t object */\n   dat_file = (logiqx_dat_t*)calloc(1, sizeof(*dat_file));\n\n   if (!dat_file)\n      goto error;\n\n   /* Read file from disk */\n   dat_file->data = rxml_load_document(path);\n\n   if (!dat_file->data)\n      goto error;\n\n   /* Ensure root node has the correct name */\n   root_node = rxml_root_node(dat_file->data);\n\n   if (!root_node)\n      goto error;\n\n   if (!root_node->name || !*root_node->name)\n      goto error;\n\n   /* > Logiqx XML uses:           'datafile'\n    * > MAME List XML uses:        'mame'\n    * > MAME 'Software List' uses: 'softwarelist' */\n   if (   !string_is_equal(root_node->name, \"datafile\")\n       && !string_is_equal(root_node->name, \"mame\")\n       && !string_is_equal(root_node->name, \"softwarelist\"))\n      goto error;\n\n   /* Get pointer to initial child node */\n   dat_file->current_node = root_node->children;\n\n   if (!dat_file->current_node)\n      goto error;\n\n   /* All is well - return logiqx_dat_t object */\n   return dat_file;\n\nerror:\n   logiqx_dat_free(dat_file);\n   return NULL;\n}\n\n/* Frees specified DAT file */\nvoid logiqx_dat_free(logiqx_dat_t *dat_file)\n{\n   if (!dat_file)\n      return;\n\n   dat_file->current_node = NULL;\n\n   if (dat_file->data)\n   {\n      rxml_free_document(dat_file->data);\n      dat_file->data = NULL;\n   }\n\n   free(dat_file);\n   dat_file = NULL;\n}\n\n/* Game information access */\n\n/* Returns true if specified node is a 'game' entry */\nstatic bool logiqx_dat_is_game_node(rxml_node_t *node)\n{\n   const char *node_name = NULL;\n\n   if (!node)\n      return false;\n\n   /* Check node name */\n   node_name = node->name;\n\n   if (!node_name || !*node_name)\n      return false;\n\n   /* > Logiqx XML uses:           'game'\n    * > MAME List XML uses:        'machine'\n    * > MAME 'Software List' uses: 'software' */\n   return    string_is_equal(node_name, \"game\")\n          || string_is_equal(node_name, \"machine\")\n          || string_is_equal(node_name, \"software\");\n}\n\n/* Returns true if specified node is a game\n * node containing information for a game with\n * the specified name */\nstatic bool logiqx_dat_game_node_matches_name(\n      rxml_node_t *node, const char *game_name)\n{\n   const char *node_game_name = NULL;\n   if (  !logiqx_dat_is_game_node(node)\n       || (!game_name || !*game_name))\n      return false;\n   /* Get 'name' attribute of XML node */\n   node_game_name = rxml_node_attrib(node, \"name\");\n   if (!node_game_name || !*node_game_name)\n      return false;\n   return string_is_equal(node_game_name, game_name);\n}\n\n/* The XML element data strings returned from\n * DAT files are very 'messy'. This function\n * removes all cruft, replaces formatting strings\n * and copies the result (if valid) to 'str' */\nstatic void logiqx_dat_sanitise_element_data(\n      const char *data, char *str, size_t len)\n{\n   char sanitised_data[PATH_MAX_LENGTH];\n   size_t i;\n   sanitised_data[0] = '\\0';\n   if (!data || !*data)\n      return;\n   strlcpy(sanitised_data, data, sizeof(sanitised_data));\n   /* Element data includes leading/trailing\n    * newline characters - trim them away */\n   string_trim_whitespace_right(sanitised_data);\n   string_trim_whitespace_left(sanitised_data);\n   if (!*sanitised_data)\n      return;\n   /* XML has a number of special characters that\n    * are handled using a HTML formatting codes.\n    * All of these have to be replaced...\n    * &amp;  -> &\n    * &apos; -> '\n    * &gt;   -> >\n    * &lt;   -> <\n    * &quot; -> \"\n    */\n   for (i = 0; i < LOGIQX_DAT_HTML_CODE_LIST_SIZE; i++)\n   {\n      const char *find_string    = logiqx_dat_html_code_list[i][0];\n      const char *replace_string = logiqx_dat_html_code_list[i][1];\n\n      /* string_replace_substring() is expensive\n       * > only invoke if element string contains\n       *   HTML code */\n      if (strstr(sanitised_data, find_string))\n      {\n         char *tmp = string_replace_substring(\n               sanitised_data, strlen(sanitised_data),\n               find_string,    strlen(find_string),\n               replace_string, strlen(replace_string));\n\n         if (tmp)\n         {\n            if (*tmp)\n               strlcpy(sanitised_data, tmp, sizeof(sanitised_data));\n            free(tmp);\n         }\n      }\n   }\n\n   /* All is well - can copy result */\n   if (*sanitised_data)\n      strlcpy(str, sanitised_data, len);\n}\n\n/* Extracts game information from specified node.\n * Returns false if node is invalid */\nstatic bool logiqx_dat_parse_game_node(\n      rxml_node_t *node, logiqx_dat_game_info_t *game_info)\n{\n   const char *game_name   = NULL;\n   const char *is_bios     = NULL;\n   const char *is_runnable = NULL;\n   rxml_node_t *info_node  = NULL;\n   bool description_found  = false;\n   bool year_found         = false;\n   bool manufacturer_found = false;\n\n   if (!logiqx_dat_is_game_node(node))\n      return false;\n\n   if (!game_info)\n      return false;\n\n   /* Initialise logiqx_dat_game_info_t object */\n   game_info->name[0]         = '\\0';\n   game_info->description[0]  = '\\0';\n   game_info->year[0]         = '\\0';\n   game_info->manufacturer[0] = '\\0';\n   game_info->is_bios         = false;\n   game_info->is_runnable     = true;\n\n   /* Get game name */\n   game_name = rxml_node_attrib(node, \"name\");\n\n   if (game_name && *game_name)\n      strlcpy(game_info->name, game_name, sizeof(game_info->name));\n\n   /* Get 'is bios' status */\n   is_bios = rxml_node_attrib(node, \"isbios\");\n\n   if (is_bios && *is_bios)\n      game_info->is_bios = string_is_equal(is_bios, \"yes\");\n\n   /* Get 'is runnable' status\n    * > Note: This attribute only exists in MAME List\n    *   XML files, but there is no harm in checking for\n    *   it generally. For normal Logiqx XML files,\n    *   'is runnable' is just the inverse of 'is bios' */\n   is_runnable = rxml_node_attrib(node, \"runnable\");\n\n   if (is_runnable && *is_runnable)\n      game_info->is_runnable = string_is_equal(is_runnable, \"yes\");\n   else\n      game_info->is_runnable = !game_info->is_bios;\n\n   /* Loop over all game info nodes */\n   for (info_node = node->children; info_node; info_node = info_node->next)\n   {\n      const char *info_node_name = info_node->name;\n      const char *info_node_data = info_node->data;\n\n      if (!info_node_name || !*info_node_name)\n         continue;\n\n      /* Check description */\n      if (string_is_equal(info_node_name, \"description\"))\n      {\n         logiqx_dat_sanitise_element_data(\n            info_node_data, game_info->description,\n            sizeof(game_info->description));\n         description_found = true;\n      }\n      /* Check year */\n      else if (string_is_equal(info_node_name, \"year\"))\n      {\n         logiqx_dat_sanitise_element_data(\n            info_node_data, game_info->year,\n            sizeof(game_info->year));\n         year_found = true;\n      }\n      /* Check manufacturer */\n      else if (string_is_equal(info_node_name, \"manufacturer\"))\n      {\n         logiqx_dat_sanitise_element_data(\n            info_node_data, game_info->manufacturer,\n            sizeof(game_info->manufacturer));\n         manufacturer_found = true;\n      }\n\n      /* If all required entries have been found,\n       * can end loop */\n      if (description_found && year_found && manufacturer_found)\n         break;\n   }\n\n   return true;\n}\n\n/* Sets/resets internal node pointer to the first\n * entry in the DAT file */\nvoid logiqx_dat_set_first(logiqx_dat_t *dat_file)\n{\n   rxml_node_t *root_node = NULL;\n\n   if (!dat_file)\n      return;\n\n   if (!dat_file->data)\n      return;\n\n   /* Get root node */\n   root_node = rxml_root_node(dat_file->data);\n\n   if (!root_node)\n   {\n      dat_file->current_node = NULL;\n      return;\n   }\n\n   /* Get pointer to initial child node */\n   dat_file->current_node = root_node->children;\n}\n\n/* Fetches game information for the current entry\n * in the DAT file and increments the internal node\n * pointer.\n * Returns false if the end of the DAT file has been\n * reached (in which case 'game_info' will be invalid) */\nbool logiqx_dat_get_next(\n      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info)\n{\n   if (!dat_file || !game_info)\n      return false;\n\n   if (!dat_file->data)\n      return false;\n\n   while (dat_file->current_node)\n   {\n      rxml_node_t *current_node = dat_file->current_node;\n\n      /* Whatever happens, internal node pointer must\n       * be 'incremented' */\n      dat_file->current_node = dat_file->current_node->next;\n\n      /* If this is a game node, extract info\n       * and return */\n      if (logiqx_dat_is_game_node(current_node))\n         return logiqx_dat_parse_game_node(current_node, game_info);\n   }\n\n   return false;\n}\n\n/* Fetches information for the specified game.\n * Returns false if game does not exist, or arguments\n * are invalid. */\nbool logiqx_dat_search(\n      logiqx_dat_t *dat_file, const char *game_name,\n      logiqx_dat_game_info_t *game_info)\n{\n   rxml_node_t *root_node = NULL;\n   rxml_node_t *game_node = NULL;\n\n   if (!dat_file || !game_info || (!game_name || !*game_name))\n      return false;\n\n   if (!dat_file->data)\n      return false;\n\n   /* Get root node */\n   root_node = rxml_root_node(dat_file->data);\n\n   if (!root_node)\n      return false;\n\n   /* Loop over all child nodes of the DAT file */\n   for (game_node = root_node->children; game_node; game_node = game_node->next)\n   {\n      /* If this is the requested game, fetch info and return */\n      if (logiqx_dat_game_node_matches_name(game_node, game_name))\n         return logiqx_dat_parse_game_node(game_node, game_info);\n   }\n\n   return false;\n}\n"
  },
  {
    "path": "formats/m3u/m3u_file.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (m3u_file.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <retro_miscellaneous.h>\n\n#include <string/stdstring.h>\n#include <lists/string_list.h>\n#include <file/file_path.h>\n#include <streams/file_stream.h>\n#include <array/rbuf.h>\n\n#include <formats/m3u_file.h>\n\n/* We parse the following types of entry label:\n * - '#LABEL:<label>' non-standard, but used by\n *   some cores\n * - '#EXTINF:<runtime>,<label>' standard extended\n *   M3U directive\n * - '<content path>|<label>' non-standard, but\n *   used by some cores\n * All other comments/directives are ignored */\n#define M3U_FILE_COMMENT            '#'\n#define M3U_FILE_NONSTD_LABEL       \"#LABEL:\"\n#define M3U_FILE_EXTSTD_LABEL       \"#EXTINF:\"\n#define M3U_FILE_EXTSTD_LABEL_TOKEN ','\n#define M3U_FILE_RETRO_LABEL_TOKEN  '|'\n\n/* Holds all internal M3U file data\n * > Note the awkward name: 'content_m3u_file'\n *   If we used just 'm3u_file' here, it would\n *   lead to conflicts elsewhere... */\nstruct content_m3u_file\n{\n   char *path;\n   m3u_file_entry_t *entries;\n};\n\n/* File Initialisation / De-Initialisation */\n\n/* Reads M3U file contents from disk\n * - Does nothing if file does not exist\n * - Returns false in the event of an error */\nstatic bool m3u_file_load(m3u_file_t *m3u_file)\n{\n   size_t i;\n   char entry_label[NAME_MAX_LENGTH];\n   char entry_path[PATH_MAX_LENGTH];\n   const char *file_ext      = NULL;\n   int64_t file_len          = 0;\n   uint8_t *file_buf         = NULL;\n   struct string_list *lines = NULL;\n   bool success              = false;\n\n   entry_path[0]  = '\\0';\n   entry_label[0] = '\\0';\n\n   if (!m3u_file)\n      goto end;\n\n   /* Check whether file exists\n    * > If path is empty, then an error\n    *   has occurred... */\n   if (!m3u_file->path || !*m3u_file->path)\n      goto end;\n\n   /* > File must have the correct extension */\n   file_ext = path_get_extension(m3u_file->path);\n\n   if (    (!file_ext || !*file_ext)\n       || !string_is_equal_noncase(file_ext, M3U_FILE_EXT))\n      goto end;\n\n   /* > If file does not exist, no action\n    *   is required */\n   if (!path_is_valid(m3u_file->path))\n   {\n      success = true;\n      goto end;\n   }\n\n   /* Read file from disk */\n   if (filestream_read_file(m3u_file->path, (void**)&file_buf, &file_len) >= 0)\n   {\n      /* Split file into lines */\n      if (file_len > 0)\n         lines = string_split((const char*)file_buf, \"\\n\");\n\n      /* File buffer no longer required */\n      if (file_buf)\n      {\n         free(file_buf);\n         file_buf = NULL;\n      }\n   }\n   /* File IO error... */\n   else\n      goto end;\n\n   /* If file was empty, no action is required */\n   if (!lines)\n   {\n      success = true;\n      goto end;\n   }\n\n   /* Parse lines of file */\n   for (i = 0; i < lines->size; i++)\n   {\n      const char *line = lines->elems[i].data;\n\n      if (!line || !*line)\n         continue;\n\n      /* Determine line 'type' */\n\n      /* > '#LABEL:' */\n      if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL,\n            STRLEN_CONST(M3U_FILE_NONSTD_LABEL)))\n      {\n         /* Label is the string to the right\n          * of '#LABEL:' */\n         const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL);\n\n         if (label && *label)\n         {\n            strlcpy(\n                  entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL),\n                  sizeof(entry_label));\n            string_trim_whitespace_right(entry_label);\n            string_trim_whitespace_left(entry_label);\n         }\n      }\n      /* > '#EXTINF:' */\n      else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL,\n            STRLEN_CONST(M3U_FILE_EXTSTD_LABEL)))\n      {\n         /* Label is the string to the right\n          * of the first comma */\n         const char* label_ptr = strchr(\n               line + STRLEN_CONST(M3U_FILE_EXTSTD_LABEL),\n               M3U_FILE_EXTSTD_LABEL_TOKEN);\n\n         if (label_ptr && *label_ptr)\n         {\n            label_ptr++;\n            if (label_ptr && *label_ptr)\n            {\n               strlcpy(entry_label, label_ptr, sizeof(entry_label));\n               string_trim_whitespace_right(entry_label);\n               string_trim_whitespace_left(entry_label);\n            }\n         }\n      }\n      /* > Ignore other comments/directives */\n      else if (line[0] == M3U_FILE_COMMENT)\n         continue;\n      /* > An actual 'content' line */\n      else\n      {\n         /* This is normally a file name/path, but may\n          * have the format <content path>|<label> */\n         const char *token_ptr = strchr(line, M3U_FILE_RETRO_LABEL_TOKEN);\n\n         if (token_ptr)\n         {\n            size_t _len = (size_t)(1 + token_ptr - line);\n\n            /* Get entry_path segment */\n            if (_len > 0)\n            {\n               memset(entry_path, 0, sizeof(entry_path));\n               strlcpy(\n                     entry_path, line,\n                     ((_len < PATH_MAX_LENGTH ?\n                       _len : PATH_MAX_LENGTH) * sizeof(char)));\n               string_trim_whitespace_right(entry_path);\n               string_trim_whitespace_left(entry_path);\n            }\n\n            /* Get entry_label segment */\n            token_ptr++;\n            if (*token_ptr != '\\0')\n            {\n               strlcpy(entry_label, token_ptr, sizeof(entry_label));\n               string_trim_whitespace_right(entry_label);\n               string_trim_whitespace_left(entry_label);\n            }\n         }\n         else\n         {\n            /* Just a normal file name/path */\n            strlcpy(entry_path, line, sizeof(entry_path));\n            string_trim_whitespace_right(entry_path);\n            string_trim_whitespace_left(entry_path);\n         }\n\n         /* Add entry to file\n          * > Note: The only way that m3u_file_add_entry()\n          *   can fail here is if we run out of memory.\n          *   This is a critical error, and m3u_file must\n          *   be considered invalid in this case */\n         if (*entry_path\n             && !m3u_file_add_entry(m3u_file, entry_path, entry_label))\n            goto end;\n\n         /* Reset entry_path/entry_label */\n         entry_path[0]  = '\\0';\n         entry_label[0] = '\\0';\n      }\n   }\n\n   success = true;\n\nend:\n   /* Clean up */\n   if (lines)\n   {\n      string_list_free(lines);\n      lines = NULL;\n   }\n\n   if (file_buf)\n   {\n      free(file_buf);\n      file_buf = NULL;\n   }\n\n   return success;\n}\n\n/* Creates and initialises an M3U file\n * - If 'path' refers to an existing file,\n *   contents is parsed\n * - If path does not exist, an empty M3U file\n *   is created\n * - Returned m3u_file_t object must be free'd using\n *   m3u_file_free()\n * - Returns NULL in the event of an error */\nm3u_file_t *m3u_file_init(const char *path)\n{\n   m3u_file_t *m3u_file = NULL;\n   char m3u_path[PATH_MAX_LENGTH];\n\n   /* Sanity check */\n   if (!path || !*path)\n      return NULL;\n\n   /* Get 'real' file path */\n   strlcpy(m3u_path, path, sizeof(m3u_path));\n   path_resolve_realpath(m3u_path, sizeof(m3u_path), false);\n\n   if (!*m3u_path)\n      return NULL;\n\n   /* Create m3u_file_t object */\n   if (!(m3u_file = (m3u_file_t*)malloc(sizeof(*m3u_file))))\n      return NULL;\n\n   /* Initialise members */\n   m3u_file->path    = NULL;\n   m3u_file->entries = NULL;\n\n   /* Copy file path */\n   m3u_file->path    = strdup(m3u_path);\n\n   /* Read existing file contents from\n    * disk, if required */\n   if (!m3u_file_load(m3u_file))\n   {\n      m3u_file_free(m3u_file);\n      return NULL;\n   }\n\n   return m3u_file;\n}\n\n/* Frees specified M3U file entry */\nstatic void m3u_file_free_entry(m3u_file_entry_t *entry)\n{\n   if (!entry)\n      return;\n\n   if (entry->path)\n      free(entry->path);\n\n   if (entry->full_path)\n      free(entry->full_path);\n\n   if (entry->label)\n      free(entry->label);\n\n   entry->path      = NULL;\n   entry->full_path = NULL;\n   entry->label     = NULL;\n}\n\n/* Frees specified M3U file */\nvoid m3u_file_free(m3u_file_t *m3u_file)\n{\n   size_t i;\n\n   if (!m3u_file)\n      return;\n\n   if (m3u_file->path)\n      free(m3u_file->path);\n\n   m3u_file->path = NULL;\n\n   /* Free entries */\n   if (m3u_file->entries)\n   {\n      for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)\n      {\n         m3u_file_entry_t *entry = &m3u_file->entries[i];\n         m3u_file_free_entry(entry);\n      }\n\n      RBUF_FREE(m3u_file->entries);\n   }\n\n   free(m3u_file);\n}\n\n/* Getters */\n\n/* Returns M3U file path */\nchar *m3u_file_get_path(m3u_file_t *m3u_file)\n{\n   if (!m3u_file)\n      return NULL;\n\n   return m3u_file->path;\n}\n\n/* Returns number of entries in M3U file */\nsize_t m3u_file_get_size(m3u_file_t *m3u_file)\n{\n   if (!m3u_file)\n      return 0;\n\n   return RBUF_LEN(m3u_file->entries);\n}\n\n/* Fetches specified M3U file entry\n * - Returns false if 'idx' is invalid, or internal\n *   entry is NULL */\nbool m3u_file_get_entry(\n      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry)\n{\n   if (!m3u_file ||\n       !entry ||\n       (idx >= RBUF_LEN(m3u_file->entries)))\n      return false;\n\n   *entry = &m3u_file->entries[idx];\n\n   if (!*entry)\n      return false;\n\n   return true;\n}\n\n/* Setters */\n\n/* Adds specified entry to the M3U file\n * - Returns false if path is invalid, or\n *   memory could not be allocated for the\n *   entry */\nbool m3u_file_add_entry(\n      m3u_file_t *m3u_file, const char *path, const char *label)\n{\n   m3u_file_entry_t *entry = NULL;\n   size_t num_entries;\n   char full_path[PATH_MAX_LENGTH];\n\n   full_path[0] = '\\0';\n\n   if (!m3u_file || (!path || !*path))\n      return false;\n\n   /* Get current number of file entries */\n   num_entries = RBUF_LEN(m3u_file->entries);\n\n   /* Attempt to allocate memory for new entry */\n   if (!RBUF_TRYFIT(m3u_file->entries, num_entries + 1))\n      return false;\n\n   /* Allocation successful - increment array size */\n   RBUF_RESIZE(m3u_file->entries, num_entries + 1);\n\n   /* Fetch entry at end of list, and zero-initialise\n    * members */\n   entry = &m3u_file->entries[num_entries];\n   memset(entry, 0, sizeof(*entry));\n\n   /* Copy path and label */\n   entry->path = strdup(path);\n\n   if (label && *label)\n      entry->label = strdup(label);\n\n   /* Populate 'full_path' field */\n   if (path_is_absolute(path))\n   {\n      strlcpy(full_path, path, sizeof(full_path));\n      path_resolve_realpath(full_path, sizeof(full_path), false);\n   }\n   else\n      fill_pathname_resolve_relative(\n            full_path, m3u_file->path, path,\n            sizeof(full_path));\n\n   /* Handle unforeseen errors... */\n   if (!*full_path)\n   {\n      m3u_file_free_entry(entry);\n      return false;\n   }\n\n   entry->full_path = strdup(full_path);\n\n   return true;\n}\n\n/* Removes all entries in M3U file */\nvoid m3u_file_clear(m3u_file_t *m3u_file)\n{\n   size_t i;\n\n   if (!m3u_file)\n      return;\n\n   if (m3u_file->entries)\n   {\n      for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)\n      {\n         m3u_file_entry_t *entry = &m3u_file->entries[i];\n         m3u_file_free_entry(entry);\n      }\n\n      RBUF_FREE(m3u_file->entries);\n   }\n}\n\n/* Saving */\n\n/* Saves M3U file to disk\n * - Setting 'label_type' to M3U_FILE_LABEL_NONE\n *   just outputs entry paths - this the most\n *   common format supported by most cores\n * - Returns false in the event of an error */\nbool m3u_file_save(\n      m3u_file_t *m3u_file, enum m3u_file_label_type label_type)\n{\n   size_t i;\n   char base_dir[DIR_MAX_LENGTH];\n   RFILE *file      = NULL;\n\n   if (!m3u_file || !m3u_file->entries)\n      return false;\n\n   /* This should never happen */\n   if (!m3u_file->path || !*m3u_file->path)\n      return false;\n\n   /* Get M3U file base directory */\n   if (find_last_slash(m3u_file->path))\n      fill_pathname_basedir(base_dir, m3u_file->path, sizeof(base_dir));\n   else\n      base_dir[0]   = '\\0';\n\n   /* Open file for writing */\n   if (!(file = filestream_open(m3u_file->path,\n         RETRO_VFS_FILE_ACCESS_WRITE,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE)))\n      return false;\n\n   /* Loop over entries */\n   for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)\n   {\n      m3u_file_entry_t *entry = &m3u_file->entries[i];\n      char entry_path[PATH_MAX_LENGTH];\n\n      entry_path[0] = '\\0';\n\n      if (!entry || (!entry->full_path || !*entry->full_path))\n         continue;\n\n      /* When writing M3U files, entry paths are\n       * always relative */\n      if (!*base_dir)\n         strlcpy(\n               entry_path, entry->full_path,\n               sizeof(entry_path));\n      else\n         path_relative_to(\n               entry_path, entry->full_path, base_dir,\n               sizeof(entry_path));\n\n      if (!*entry_path)\n         continue;\n\n      /* Check if we need to write a label */\n      if (entry->label && *entry->label)\n      {\n         switch (label_type)\n         {\n            case M3U_FILE_LABEL_NONSTD:\n               filestream_printf(\n                     file, \"%s%s\\n%s\\n\",\n                     M3U_FILE_NONSTD_LABEL, entry->label,\n                     entry_path);\n               break;\n            case M3U_FILE_LABEL_EXTSTD:\n               filestream_printf(\n                     file, \"%s%c%s\\n%s\\n\",\n                     M3U_FILE_EXTSTD_LABEL, M3U_FILE_EXTSTD_LABEL_TOKEN, entry->label,\n                     entry_path);\n               break;\n            case M3U_FILE_LABEL_RETRO:\n               filestream_printf(\n                     file, \"%s%c%s\\n\",\n                     entry_path, M3U_FILE_RETRO_LABEL_TOKEN, entry->label);\n               break;\n            case M3U_FILE_LABEL_NONE:\n            default:\n               filestream_printf(\n                     file, \"%s\\n\", entry_path);\n               break;\n         }\n      }\n      /* No label - just write entry path */\n      else\n         filestream_printf(\n               file, \"%s\\n\", entry_path);\n   }\n\n   /* Close file */\n   filestream_close(file);\n\n   return true;\n}\n\n/* Utilities */\n\n/* Internal qsort function */\nstatic int m3u_file_qsort_func(\n      const m3u_file_entry_t *a, const m3u_file_entry_t *b)\n{\n   if (!a || !b)\n      return 0;\n\n   if ((!a->full_path || !*a->full_path) || (!b->full_path || !*b->full_path))\n      return 0;\n\n   return strcasecmp(a->full_path, b->full_path);\n}\n\n/* Sorts M3U file entries in alphabetical order */\nvoid m3u_file_qsort(m3u_file_t *m3u_file)\n{\n   size_t num_entries;\n\n   if (!m3u_file)\n      return;\n\n   num_entries = RBUF_LEN(m3u_file->entries);\n\n   if (num_entries < 2)\n      return;\n\n   qsort(\n         m3u_file->entries, num_entries,\n         sizeof(m3u_file_entry_t),\n         (int (*)(const void *, const void *))m3u_file_qsort_func);\n}\n\n/* Returns true if specified path corresponds\n * to an M3U file (simple convenience function) */\nbool m3u_file_is_m3u(const char *path)\n{\n   const char *file_ext = NULL;\n   if (!path || !*path)\n      return false;\n   /* Check file extension */\n   file_ext = path_get_extension(path);\n   if (!file_ext || !*file_ext)\n      return false;\n   if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT))\n      return false;\n   /* Ensure file exists */\n   if (!path_is_valid(path))\n      return false;\n   /* Ensure we have non-zero file size */\n   if (path_get_size(path) <= 0)\n      return false;\n   return true;\n}\n"
  },
  {
    "path": "formats/png/rpng.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rpng.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifdef DEBUG\n#include <stdio.h>\n#endif\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef GEKKO\n#include <malloc.h>\n#endif\n\n/* SIMD acceleration: SSE2 on x86/x86-64, NEON on ARM */\n#if defined(__SSE2__)\n#include <emmintrin.h>\n#define RPNG_SIMD_SSE2 1\n#elif defined(__ARM_NEON) || defined(__ARM_NEON__)\n#if !defined(VITA) && !defined(WEBOS) && !defined(HAVE_LIBNX)\n#include <arm_neon.h>\n#define RPNG_SIMD_NEON 1\n#endif\n#endif\n\n#include <boolean.h>\n#include <formats/image.h>\n#include <formats/rpng.h>\n#include <streams/trans_stream.h>\n\n#include \"rpng_internal.h\"\n\nenum png_ihdr_color_type\n{\n   PNG_IHDR_COLOR_GRAY       = 0,\n   PNG_IHDR_COLOR_RGB        = 2,\n   PNG_IHDR_COLOR_PLT        = 3,\n   PNG_IHDR_COLOR_GRAY_ALPHA = 4,\n   PNG_IHDR_COLOR_RGBA       = 6\n};\n\nenum png_line_filter\n{\n   PNG_FILTER_NONE = 0,\n   PNG_FILTER_SUB,\n   PNG_FILTER_UP,\n   PNG_FILTER_AVERAGE,\n   PNG_FILTER_PAETH\n};\n\nenum png_chunk_type\n{\n   PNG_CHUNK_NOOP = 0,\n   PNG_CHUNK_ERROR,\n   PNG_CHUNK_IHDR,\n   PNG_CHUNK_IDAT,\n   PNG_CHUNK_PLTE,\n   PNG_CHUNK_tRNS,\n   PNG_CHUNK_IEND\n};\n\nstruct adam7_pass\n{\n   unsigned x;\n   unsigned y;\n   unsigned stride_x;\n   unsigned stride_y;\n};\n\nstruct idat_buffer\n{\n   uint8_t *data;\n   size_t size;\n   size_t capacity;\n};\n\nenum rpng_process_flags\n{\n   RPNG_PROCESS_FLAG_INFLATE_INITIALIZED    = (1 << 0),\n   RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED = (1 << 1),\n   RPNG_PROCESS_FLAG_PASS_INITIALIZED       = (1 << 2)\n};\n\nstruct rpng_process\n{\n   uint32_t *data;\n   uint32_t *palette;\n   void *stream;\n   const struct trans_stream_backend *stream_backend;\n   uint8_t *prev_scanline;\n   uint8_t *decoded_scanline;\n   uint8_t *inflate_buf;\n   size_t restore_buf_size;\n   size_t adam7_restore_buf_size;\n   size_t data_restore_buf_size;\n   size_t inflate_buf_size;\n   size_t avail_in;\n   size_t avail_out;\n   size_t total_out;\n   size_t pass_size;\n   struct png_ihdr ihdr; /* uint32_t alignment */\n   unsigned bpp;\n   unsigned pitch;\n   unsigned h;\n   unsigned pass_width;\n   unsigned pass_height;\n   unsigned pass_pos;\n   uint8_t flags;\n   bool supports_rgba;\n};\n\nenum rpng_flags\n{\n   RPNG_FLAG_HAS_IHDR = (1 << 0),\n   RPNG_FLAG_HAS_IDAT = (1 << 1),\n   RPNG_FLAG_HAS_IEND = (1 << 2),\n   RPNG_FLAG_HAS_PLTE = (1 << 3),\n   RPNG_FLAG_HAS_TRNS = (1 << 4)\n};\n\nstruct rpng\n{\n   struct rpng_process *process;\n   uint8_t *buff_data;\n   uint8_t *buff_end;\n   struct idat_buffer idat_buf; /* ptr alignment */\n   struct png_ihdr ihdr; /* uint32 alignment */\n   uint32_t palette[256];\n   uint8_t flags;\n   bool supports_rgba;\n};\n\nstatic const struct adam7_pass rpng_passes[] = {\n   { 0, 0, 8, 8 },\n   { 4, 0, 8, 8 },\n   { 0, 4, 4, 8 },\n   { 2, 0, 4, 4 },\n   { 0, 2, 2, 4 },\n   { 1, 0, 2, 2 },\n   { 0, 1, 1, 2 },\n};\n\nstatic INLINE uint32_t rpng_dword_be(const uint8_t *buf)\n{\n   return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);\n}\n\n/* ---------------------------------------------------------------------------\n * SIMD-accelerated PNG filter reconstruction helpers\n * -------------------------------------------------------------------------*/\n\n/* PNG Filter Up: out[i] = raw[i] + prior[i]\n * This is a pure vector add with no data dependency between bytes, making\n * it the most parallelisable of all PNG filters. */\nstatic void rpng_filter_up(uint8_t *out,\n      const uint8_t *raw,\n      const uint8_t *prior,\n      size_t len)\n{\n#if defined(RPNG_SIMD_SSE2)\n   size_t i  = 0;\n   size_t n  = len & ~15UL;         /* floor to multiple of 16 */\n   for (; i < n; i += 16)\n   {\n      __m128i r  = _mm_loadu_si128((const __m128i*)(raw   + i));\n      __m128i p  = _mm_loadu_si128((const __m128i*)(prior + i));\n      _mm_storeu_si128((__m128i*)(out + i), _mm_add_epi8(r, p));\n   }\n   for (; i < len; i++)\n      out[i] = raw[i] + prior[i];\n#elif defined(RPNG_SIMD_NEON)\n   size_t i  = 0;\n   size_t n  = len & ~15UL;\n   for (; i < n; i += 16)\n   {\n      uint8x16_t r  = vld1q_u8(raw   + i);\n      uint8x16_t p  = vld1q_u8(prior + i);\n      vst1q_u8(out + i, vaddq_u8(r, p));\n   }\n   for (; i < len; i++)\n      out[i] = raw[i] + prior[i];\n#else\n   size_t i;\n   for (i = 0; i < len; i++)\n      out[i] = raw[i] + prior[i];\n#endif\n}\n\n/* --- PNG reverse filter SIMD paths for RGBA (bpp == 4) ------------------\n *\n * The SUB, AVERAGE and PAETH filters all have a per-pixel recurrence:\n *   decoded[i] depends on decoded[i - bpp] from the same scanline.\n *\n * For RGBA (bpp == 4) the recurrence distance equals one SIMD \"pixel\", so\n * we can process the 4 channels of each pixel in parallel within a single\n * vector register while still respecting the pixel-to-pixel chain.  This\n * eliminates the per-byte branch and scalar dependency chain that costs\n * most in the scalar versions (PAETH especially, where each byte has two\n * unpredictable branches).\n *\n * All three helpers assume:\n *   - bpp == 4, pitch is a multiple of 4 (guaranteed by PNG spec for RGBA)\n *   - prev is a valid prev_scanline pointer (zero-initialised on row 0\n *     by rpng_reverse_filter_init -> calloc)\n *   - raw and decoded may alias (the original code memcpy's raw->decoded\n *     first; we do the filter in-place from raw directly)\n *\n * For bpp != 4 we keep the scalar path.  The payoff would be smaller there\n * (palette/gray images are smaller to begin with) and the SIMD layout is\n * more awkward.\n */\n#if defined(RPNG_SIMD_SSE2)\n\n/* Load 4 bytes (one RGBA pixel) and zero-extend each to 16 bits so that\n * the subsequent arithmetic has one byte of headroom (additions, shifts,\n * signed subtraction for Paeth) without overflowing. */\nstatic INLINE __m128i rpng_load4_u8_to_u16(const uint8_t *p)\n{\n   /* memcpy into a properly-aligned temporary avoids UB from an\n    * unaligned dereference of int32_t*.  The scanline buffer\n    * (pngp->inflate_buf) is not guaranteed 4-byte aligned at the\n    * start of every filter step, so casting directly would be\n    * unsafe.  Compilers fold this to a single movd at -O2. */\n   int32_t tmp;\n   memcpy(&tmp, p, sizeof(tmp));\n   return _mm_unpacklo_epi8(_mm_cvtsi32_si128(tmp), _mm_setzero_si128());\n}\n\n/* Write the low 4 lanes (bytes) of a 16-bit-lane register back to memory\n * as packed u8.  We mask to 0x00FF before packus so wrap-around (the PNG\n * filter arithmetic is mod 256) is preserved rather than saturated. */\nstatic INLINE void rpng_store4_u16_to_u8(uint8_t *p, __m128i v)\n{\n   __m128i packed = _mm_packus_epi16(v, _mm_setzero_si128());\n   int32_t tmp    = _mm_cvtsi128_si32(packed);\n   memcpy(p, &tmp, sizeof(tmp));\n}\n\nstatic void rpng_filter_sub_rgba(uint8_t *decoded,\n      const uint8_t *raw, size_t pitch)\n{\n   size_t i;\n   __m128i prev_pixel = _mm_setzero_si128();\n   const __m128i mask = _mm_set1_epi16(0x00FF);\n   for (i = 0; i + 4 <= pitch; i += 4)\n   {\n      __m128i r   = rpng_load4_u8_to_u16(raw + i);\n      __m128i out = _mm_and_si128(_mm_add_epi16(r, prev_pixel), mask);\n      rpng_store4_u16_to_u8(decoded + i, out);\n      prev_pixel  = out;\n   }\n}\n\nstatic void rpng_filter_avg_rgba(uint8_t *decoded,\n      const uint8_t *raw, const uint8_t *prev, size_t pitch)\n{\n   size_t i;\n   __m128i prev_pixel = _mm_setzero_si128();\n   const __m128i mask = _mm_set1_epi16(0x00FF);\n   for (i = 0; i + 4 <= pitch; i += 4)\n   {\n      __m128i r   = rpng_load4_u8_to_u16(raw  + i);\n      __m128i pv  = rpng_load4_u8_to_u16(prev + i);\n      __m128i avg = _mm_srli_epi16(_mm_add_epi16(prev_pixel, pv), 1);\n      __m128i out = _mm_and_si128(_mm_add_epi16(r, avg), mask);\n      rpng_store4_u16_to_u8(decoded + i, out);\n      prev_pixel  = out;\n   }\n}\n\n/* Branch-free Paeth predictor for 16-bit lanes, following the identity\n *   pa = |b - c|\n *   pb = |a - c|\n *   pc = |(b - c) + (a - c)| = |a + b - 2c|\n * PNG selection rule (in priority order): a if pa <= pb && pa <= pc,\n * else b if pb <= pc, else c. */\nstatic INLINE __m128i rpng_paeth_predictor_epi16(\n      __m128i a, __m128i b, __m128i c)\n{\n   __m128i bc = _mm_sub_epi16(b, c);\n   __m128i ac = _mm_sub_epi16(a, c);\n   __m128i sm = _mm_add_epi16(bc, ac);\n   __m128i z  = _mm_setzero_si128();\n   /* SSE2 lacks abs_epi16; max(x, -x) is the standard substitute. */\n   __m128i pa = _mm_max_epi16(bc, _mm_sub_epi16(z, bc));\n   __m128i pb = _mm_max_epi16(ac, _mm_sub_epi16(z, ac));\n   __m128i pc = _mm_max_epi16(sm, _mm_sub_epi16(z, sm));\n   /* cmpgt returns 0xFFFF on \"greater than\" — mask of \"don't pick a/b\". */\n   __m128i not_a  = _mm_or_si128(_mm_cmpgt_epi16(pa, pb),\n                                 _mm_cmpgt_epi16(pa, pc));\n   __m128i pick_c = _mm_cmpgt_epi16(pb, pc);\n   __m128i bc_sel = _mm_or_si128(_mm_andnot_si128(pick_c, b),\n                                 _mm_and_si128(   pick_c, c));\n   return            _mm_or_si128(_mm_andnot_si128(not_a, a),\n                                  _mm_and_si128(   not_a, bc_sel));\n}\n\nstatic void rpng_filter_paeth_rgba(uint8_t *decoded,\n      const uint8_t *raw, const uint8_t *prev, size_t pitch)\n{\n   size_t i;\n   __m128i prev_pixel      = _mm_setzero_si128();  /* decoded[i-4] */\n   __m128i prev_upper_left = _mm_setzero_si128();  /* prev[i-4]    */\n   const __m128i mask      = _mm_set1_epi16(0x00FF);\n   for (i = 0; i + 4 <= pitch; i += 4)\n   {\n      __m128i r    = rpng_load4_u8_to_u16(raw  + i);\n      __m128i pv   = rpng_load4_u8_to_u16(prev + i);\n      __m128i pred = rpng_paeth_predictor_epi16(\n            prev_pixel, pv, prev_upper_left);\n      __m128i out  = _mm_and_si128(_mm_add_epi16(r, pred), mask);\n      rpng_store4_u16_to_u8(decoded + i, out);\n      prev_pixel      = out;\n      prev_upper_left = pv;\n   }\n}\n\n#elif defined(RPNG_SIMD_NEON)\n\nstatic INLINE uint16x4_t rpng_load4_u8_to_u16(const uint8_t *p)\n{\n   uint32_t v;\n   memcpy(&v, p, 4);\n   return vget_low_u16(vmovl_u8(vreinterpret_u8_u32(vdup_n_u32(v))));\n}\n\nstatic INLINE void rpng_store4_u16_to_u8(uint8_t *p, uint16x4_t v)\n{\n   /* Narrow 4x16 -> 4x8, reinterpret as u32 lane, then memcpy to dst.\n    * memcpy handles any alignment and compiles to a single str at -O2. */\n   uint8x8_t b    = vmovn_u16(vcombine_u16(v, v));\n   uint32_t  word = vget_lane_u32(vreinterpret_u32_u8(b), 0);\n   memcpy(p, &word, sizeof(word));\n}\n\nstatic void rpng_filter_sub_rgba(uint8_t *decoded,\n      const uint8_t *raw, size_t pitch)\n{\n   size_t i;\n   uint16x4_t prev_pixel = vdup_n_u16(0);\n   const uint16x4_t mask = vdup_n_u16(0xFF);\n   for (i = 0; i + 4 <= pitch; i += 4)\n   {\n      uint16x4_t r   = rpng_load4_u8_to_u16(raw + i);\n      uint16x4_t out = vand_u16(vadd_u16(r, prev_pixel), mask);\n      rpng_store4_u16_to_u8(decoded + i, out);\n      prev_pixel     = out;\n   }\n}\n\nstatic void rpng_filter_avg_rgba(uint8_t *decoded,\n      const uint8_t *raw, const uint8_t *prev, size_t pitch)\n{\n   size_t i;\n   uint16x4_t prev_pixel = vdup_n_u16(0);\n   const uint16x4_t mask = vdup_n_u16(0xFF);\n   for (i = 0; i + 4 <= pitch; i += 4)\n   {\n      uint16x4_t r   = rpng_load4_u8_to_u16(raw  + i);\n      uint16x4_t pv  = rpng_load4_u8_to_u16(prev + i);\n      uint16x4_t avg = vshr_n_u16(vadd_u16(prev_pixel, pv), 1);\n      uint16x4_t out = vand_u16(vadd_u16(r, avg), mask);\n      rpng_store4_u16_to_u8(decoded + i, out);\n      prev_pixel     = out;\n   }\n}\n\nstatic INLINE uint16x4_t rpng_paeth_predictor_u16(\n      uint16x4_t a, uint16x4_t b, uint16x4_t c)\n{\n   int16x4_t bc = vsub_s16(vreinterpret_s16_u16(b), vreinterpret_s16_u16(c));\n   int16x4_t ac = vsub_s16(vreinterpret_s16_u16(a), vreinterpret_s16_u16(c));\n   int16x4_t sm = vadd_s16(bc, ac);\n   uint16x4_t pa = vreinterpret_u16_s16(vabs_s16(bc));\n   uint16x4_t pb = vreinterpret_u16_s16(vabs_s16(ac));\n   uint16x4_t pc = vreinterpret_u16_s16(vabs_s16(sm));\n   uint16x4_t not_a  = vorr_u16(vcgt_u16(pa, pb), vcgt_u16(pa, pc));\n   uint16x4_t pick_c = vcgt_u16(pb, pc);\n   uint16x4_t bc_sel = vbsl_u16(pick_c, c, b);\n   return              vbsl_u16(not_a,  bc_sel, a);\n}\n\nstatic void rpng_filter_paeth_rgba(uint8_t *decoded,\n      const uint8_t *raw, const uint8_t *prev, size_t pitch)\n{\n   size_t i;\n   uint16x4_t prev_pixel      = vdup_n_u16(0);\n   uint16x4_t prev_upper_left = vdup_n_u16(0);\n   const uint16x4_t mask      = vdup_n_u16(0xFF);\n   for (i = 0; i + 4 <= pitch; i += 4)\n   {\n      uint16x4_t r    = rpng_load4_u8_to_u16(raw  + i);\n      uint16x4_t pv   = rpng_load4_u8_to_u16(prev + i);\n      uint16x4_t pred = rpng_paeth_predictor_u16(\n            prev_pixel, pv, prev_upper_left);\n      uint16x4_t out  = vand_u16(vadd_u16(r, pred), mask);\n      rpng_store4_u16_to_u8(decoded + i, out);\n      prev_pixel      = out;\n      prev_upper_left = pv;\n   }\n}\n\n#endif /* RPNG_SIMD_SSE2 / RPNG_SIMD_NEON */\n\n/* ---------------------------------------------------------------------------\n * SIMD pixel format conversion helpers\n * -------------------------------------------------------------------------*/\n\n/* Pack 8-bit RGB triples into ARGB32/ABGR32 words (alpha = 0xFF).\n * SSE2 version processes 4 pixels (12 input bytes) per iteration. */\n#if defined(RPNG_SIMD_SSE2)\nstatic void rpng_copy_line_rgb_sse2(uint32_t *data,\n      const uint8_t *src, unsigned width, bool supports_rgba)\n{\n   unsigned i = 0;\n   if (supports_rgba)\n   {\n      for (; (int)(width - i) >= 4; i += 4)\n      {\n         data[i + 0] = 0xFF000000u\n                     | ((unsigned)src[i*3+2] << 16)\n                     | ((unsigned)src[i*3+1] <<  8)\n                     | ((unsigned)src[i*3+0]      );\n         data[i + 1] = 0xFF000000u\n                     | ((unsigned)src[i*3+5] << 16)\n                     | ((unsigned)src[i*3+4] <<  8)\n                     | ((unsigned)src[i*3+3]      );\n         data[i + 2] = 0xFF000000u\n                     | ((unsigned)src[i*3+8] << 16)\n                     | ((unsigned)src[i*3+7] <<  8)\n                     | ((unsigned)src[i*3+6]      );\n         data[i + 3] = 0xFF000000u\n                     | ((unsigned)src[i*3+11] << 16)\n                     | ((unsigned)src[i*3+10] <<  8)\n                     | ((unsigned)src[i*3+9]       );\n      }\n      for (; i < width; i++)\n         data[i] = 0xFF000000u\n                 | ((unsigned)src[i*3+2] << 16)\n                 | ((unsigned)src[i*3+1] <<  8)\n                 | ((unsigned)src[i*3+0]      );\n   }\n   else\n   {\n      for (; (int)(width - i) >= 4; i += 4)\n      {\n         data[i + 0] = 0xFF000000u\n                     | ((unsigned)src[i*3+0] << 16)\n                     | ((unsigned)src[i*3+1] <<  8)\n                     | ((unsigned)src[i*3+2]      );\n         data[i + 1] = 0xFF000000u\n                     | ((unsigned)src[i*3+3] << 16)\n                     | ((unsigned)src[i*3+4] <<  8)\n                     | ((unsigned)src[i*3+5]      );\n         data[i + 2] = 0xFF000000u\n                     | ((unsigned)src[i*3+6] << 16)\n                     | ((unsigned)src[i*3+7] <<  8)\n                     | ((unsigned)src[i*3+8]      );\n         data[i + 3] = 0xFF000000u\n                     | ((unsigned)src[i*3+9]  << 16)\n                     | ((unsigned)src[i*3+10] <<  8)\n                     | ((unsigned)src[i*3+11]      );\n      }\n      for (; i < width; i++)\n         data[i] = 0xFF000000u\n                 | ((unsigned)src[i*3+0] << 16)\n                 | ((unsigned)src[i*3+1] <<  8)\n                 | ((unsigned)src[i*3+2]      );\n   }\n}\n#endif /* RPNG_SIMD_SSE2 */\n\n/* Pack 8-bit RGBA bytes into ARGB32 or ABGR32 words.\n * Each input pixel is 4 bytes: R G B A\n * ARGB output: (A<<24)|(R<<16)|(G<<8)|B\n * ABGR output: (A<<24)|(B<<16)|(G<<8)|R  (when supports_rgba) */\n#if defined(RPNG_SIMD_SSE2)\nstatic void rpng_copy_line_rgba_sse2(uint32_t *data,\n      const uint8_t *src, unsigned width, bool supports_rgba)\n{\n   unsigned i = 0;\n   if (supports_rgba)\n   {\n      for (; (int)(width - i) >= 4; i += 4)\n      {\n         data[i+0] = ((unsigned)src[i*4+3] << 24) | ((unsigned)src[i*4+2] << 16)\n                   | ((unsigned)src[i*4+1] <<  8) | ((unsigned)src[i*4+0]);\n         data[i+1] = ((unsigned)src[i*4+7] << 24) | ((unsigned)src[i*4+6] << 16)\n                   | ((unsigned)src[i*4+5] <<  8) | ((unsigned)src[i*4+4]);\n         data[i+2] = ((unsigned)src[i*4+11] << 24) | ((unsigned)src[i*4+10] << 16)\n                   | ((unsigned)src[i*4+9]  <<  8) | ((unsigned)src[i*4+8]);\n         data[i+3] = ((unsigned)src[i*4+15] << 24) | ((unsigned)src[i*4+14] << 16)\n                   | ((unsigned)src[i*4+13] <<  8) | ((unsigned)src[i*4+12]);\n      }\n      for (; i < width; i++)\n         data[i] = ((unsigned)src[i*4+3] << 24) | ((unsigned)src[i*4+2] << 16)\n                 | ((unsigned)src[i*4+1] <<  8) | ((unsigned)src[i*4+0]);\n   }\n   else\n   {\n      for (; (int)(width - i) >= 4; i += 4)\n      {\n         data[i+0] = ((unsigned)src[i*4+3] << 24) | ((unsigned)src[i*4+0] << 16)\n                   | ((unsigned)src[i*4+1] <<  8) | ((unsigned)src[i*4+2]);\n         data[i+1] = ((unsigned)src[i*4+7] << 24) | ((unsigned)src[i*4+4] << 16)\n                   | ((unsigned)src[i*4+5] <<  8) | ((unsigned)src[i*4+6]);\n         data[i+2] = ((unsigned)src[i*4+11] << 24) | ((unsigned)src[i*4+8]  << 16)\n                   | ((unsigned)src[i*4+9]  <<  8) | ((unsigned)src[i*4+10]);\n         data[i+3] = ((unsigned)src[i*4+15] << 24) | ((unsigned)src[i*4+12] << 16)\n                   | ((unsigned)src[i*4+13] <<  8) | ((unsigned)src[i*4+14]);\n      }\n      for (; i < width; i++)\n         data[i] = ((unsigned)src[i*4+3] << 24) | ((unsigned)src[i*4+0] << 16)\n                 | ((unsigned)src[i*4+1] <<  8) | ((unsigned)src[i*4+2]);\n   }\n}\n#endif /* RPNG_SIMD_SSE2 */\n\n/* NEON RGBA → ARGB32/ABGR32 conversion: vld4_u8 de-interleaves all 4 channels. */\n#if defined(RPNG_SIMD_NEON)\nstatic void rpng_copy_line_rgba_neon(uint32_t *data,\n      const uint8_t *src, unsigned width, bool supports_rgba)\n{\n   unsigned i = 0;\n   for (; (int)(width - i) >= 8; i += 8)\n   {\n      uint8x8x4_t px  = vld4_u8(src + i * 4); /* de-interleave R,G,B,A */\n      /* When supports_rgba, swap r and b to produce ABGR instead of ARGB */\n      uint8x8_t   hi  = supports_rgba ? px.val[2] : px.val[0]; /* R or B → byte 2 */\n      uint8x8_t   g   = px.val[1];\n      uint8x8_t   lo  = supports_rgba ? px.val[0] : px.val[2]; /* B or R → byte 0 */\n      uint8x8_t   a   = px.val[3];\n      uint32x4_t lo_a  = vshlq_n_u32(vmovl_u16(vget_low_u16(vmovl_u8(a))),  24);\n      uint32x4_t lo_hi = vshll_n_u16(vget_low_u16(vmovl_u8(hi)), 16);\n      uint32x4_t lo_g  = vshll_n_u16(vget_low_u16(vmovl_u8(g)),   8);\n      uint32x4_t lo_lo = vmovl_u16(vget_low_u16(vmovl_u8(lo)));\n      uint32x4_t lo_px = vorrq_u32(vorrq_u32(lo_a, lo_hi), vorrq_u32(lo_g, lo_lo));\n      uint32x4_t hi_a  = vshlq_n_u32(vmovl_u16(vget_high_u16(vmovl_u8(a))), 24);\n      uint32x4_t hi_hi = vshll_n_u16(vget_high_u16(vmovl_u8(hi)), 16);\n      uint32x4_t hi_g  = vshll_n_u16(vget_high_u16(vmovl_u8(g)),  8);\n      uint32x4_t hi_lo = vmovl_u16(vget_high_u16(vmovl_u8(lo)));\n      uint32x4_t hi_px = vorrq_u32(vorrq_u32(hi_a, hi_hi), vorrq_u32(hi_g, hi_lo));\n      vst1q_u32(data + i,     lo_px);\n      vst1q_u32(data + i + 4, hi_px);\n   }\n   if (supports_rgba)\n   {\n      for (; i < width; i++)\n         data[i] = ((unsigned)src[i*4+3] << 24) | ((unsigned)src[i*4+2] << 16)\n                 | ((unsigned)src[i*4+1] <<  8) | ((unsigned)src[i*4+0]);\n   }\n   else\n   {\n      for (; i < width; i++)\n         data[i] = ((unsigned)src[i*4+3] << 24) | ((unsigned)src[i*4+0] << 16)\n                 | ((unsigned)src[i*4+1] <<  8) | ((unsigned)src[i*4+2]);\n   }\n}\n\n/* NEON RGB → ARGB32/ABGR32 conversion using vld3 de-interleave */\nstatic void rpng_copy_line_rgb_neon(uint32_t *data,\n      const uint8_t *src, unsigned width, bool supports_rgba)\n{\n   unsigned i = 0;\n   for (; (int)(width - i) >= 8; i += 8)\n   {\n      uint8x8x3_t px  = vld3_u8(src + i * 3);\n      uint8x8_t   hi  = supports_rgba ? px.val[2] : px.val[0];\n      uint8x8_t   g   = px.val[1];\n      uint8x8_t   lo  = supports_rgba ? px.val[0] : px.val[2];\n      uint32x4_t lo_hi_v = vshll_n_u16(vget_low_u16(vmovl_u8(hi)),  16);\n      uint32x4_t lo_g    = vshll_n_u16(vget_low_u16(vmovl_u8(g)),    8);\n      uint32x4_t lo_lo_v = vmovl_u16(vget_low_u16(vmovl_u8(lo)));\n      uint32x4_t lo_a    = vdupq_n_u32(0xFF000000u);\n      uint32x4_t lo_px   = vorrq_u32(vorrq_u32(lo_a, lo_hi_v), vorrq_u32(lo_g, lo_lo_v));\n      uint32x4_t hi_hi_v = vshll_n_u16(vget_high_u16(vmovl_u8(hi)), 16);\n      uint32x4_t hi_g    = vshll_n_u16(vget_high_u16(vmovl_u8(g)),   8);\n      uint32x4_t hi_lo_v = vmovl_u16(vget_high_u16(vmovl_u8(lo)));\n      uint32x4_t hi_a    = vdupq_n_u32(0xFF000000u);\n      uint32x4_t hi_px   = vorrq_u32(vorrq_u32(hi_a, hi_hi_v), vorrq_u32(hi_g, hi_lo_v));\n      vst1q_u32(data + i,     lo_px);\n      vst1q_u32(data + i + 4, hi_px);\n   }\n   if (supports_rgba)\n   {\n      for (; i < width; i++)\n         data[i] = 0xFF000000u\n                 | ((unsigned)src[i*3+2] << 16)\n                 | ((unsigned)src[i*3+1] <<  8)\n                 | ((unsigned)src[i*3+0]      );\n   }\n   else\n   {\n      for (; i < width; i++)\n         data[i] = 0xFF000000u\n                 | ((unsigned)src[i*3+0] << 16)\n                 | ((unsigned)src[i*3+1] <<  8)\n                 | ((unsigned)src[i*3+2]      );\n   }\n}\n#endif /* RPNG_SIMD_NEON */\n\n#if defined(DEBUG) || defined(RPNG_TEST)\n#include <stdio.h>\n\nstatic bool rpng_process_ihdr(struct png_ihdr *ihdr)\n{\n   uint8_t ihdr_depth = ihdr->depth;\n\n   switch (ihdr->color_type)\n   {\n      case PNG_IHDR_COLOR_RGB:\n      case PNG_IHDR_COLOR_GRAY_ALPHA:\n      case PNG_IHDR_COLOR_RGBA:\n         if (ihdr_depth != 8 && ihdr_depth != 16)\n         {\n            fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__);\n            return false;\n         }\n         break;\n      case PNG_IHDR_COLOR_GRAY:\n         /* Valid bitdepths are: 1, 2, 4, 8, 16 */\n         if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)\n         {\n            fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__);\n            return false;\n         }\n         break;\n      case PNG_IHDR_COLOR_PLT:\n         /* Valid bitdepths are: 1, 2, 4, 8 */\n         if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)\n         {\n            fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__);\n            return false;\n         }\n         break;\n      default:\n         fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__);\n         return false;\n   }\n\n   /* On 32-bit hosts the per-row decode mallocs cannot fit much\n    * more than 1 GiB of decoded RGBA, and an undersized malloc\n    * combined with attacker-controlled dimensions has historically\n    * been the heap-overflow primitive prompting the 0x4000 caps\n    * in rbmp.c, rtga.c and rwebp.c.  Keep the tight cap there.\n    *\n    * On 64-bit the (size_t) casts in rpng_reverse_filter_init and\n    * the final allocator make the per-row arithmetic overflow-safe\n    * regardless of dimensions, and the 4 GiB output guard further\n    * down in rpng_iterate_image already rejects images whose\n    * decoded buffer cannot be addressed.  Loading a 30000x30000\n    * RGBA image on a desktop with the RAM to spare is a legitimate\n    * use case (cf. IrfanView), so do not impose the 0x4000 cap\n    * there. */\n#if SIZE_MAX <= 0xFFFFFFFFu\n   if (ihdr->width > 0x4000u || ihdr->height > 0x4000u)\n   {\n      fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__);\n      return false;\n   }\n#endif\n\n#ifdef RPNG_TEST\n   fprintf(stderr, \"IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\\n\",\n         ihdr->width, ihdr->height,\n         ihdr_depth, (ihdr->color_type == PNG_IHDR_COLOR_PLT) ? \"yes\" : \"no\",\n         (ihdr->color_type & PNG_IHDR_COLOR_RGB)              ? \"yes\" : \"no\",\n         (ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA)       ? \"yes\" : \"no\",\n         ihdr->interlace == 1 ? \"yes\" : \"no\");\n#endif\n\n   return true;\n}\n#else\nstatic bool rpng_process_ihdr(struct png_ihdr *ihdr)\n{\n   uint8_t ihdr_depth = ihdr->depth;\n\n   switch (ihdr->color_type)\n   {\n      case PNG_IHDR_COLOR_RGB:\n      case PNG_IHDR_COLOR_GRAY_ALPHA:\n      case PNG_IHDR_COLOR_RGBA:\n         if (ihdr_depth != 8 && ihdr_depth != 16)\n            return false;\n         break;\n      case PNG_IHDR_COLOR_GRAY:\n         /* Valid bitdepths are: 1, 2, 4, 8, 16 */\n         if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)\n            return false;\n         break;\n      case PNG_IHDR_COLOR_PLT:\n         /* Valid bitdepths are: 1, 2, 4, 8 */\n         if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)\n            return false;\n         break;\n      default:\n         return false;\n   }\n\n   /* See the matching comment in the RPNG_TEST/DEBUG variant\n    * above.  Cap only on 32-bit; 64-bit lets the (size_t)\n    * widening + 4 GiB output guard handle large legitimate\n    * images. */\n#if SIZE_MAX <= 0xFFFFFFFFu\n   if (ihdr->width > 0x4000u || ihdr->height > 0x4000u)\n      return false;\n#endif\n\n   return true;\n}\n#endif\n\nstatic void rpng_reverse_filter_copy_line_rgb(uint32_t *data,\n      const uint8_t *decoded, unsigned width, unsigned bpp,\n      bool supports_rgba)\n{\n   int i;\n\n   /* Fast path for 8-bit depth (bpp == 24): \n    * each pixel is exactly 3 bytes. */\n   if (bpp == 24)\n   {\n#if defined(RPNG_SIMD_NEON)\n      rpng_copy_line_rgb_neon(data, decoded, width, supports_rgba);\n      return;\n#elif defined(RPNG_SIMD_SSE2)\n      rpng_copy_line_rgb_sse2(data, decoded, width, supports_rgba);\n      return;\n#endif\n   }\n\n   bpp /= 8;\n\n   if (supports_rgba)\n   {\n      for (i = 0; i < (int)width; i++)\n      {\n         uint32_t r, g, b;\n         r        = *decoded;\n         decoded += bpp;\n         g        = *decoded;\n         decoded += bpp;\n         b        = *decoded;\n         decoded += bpp;\n         data[i]  = (0xffu << 24) | (b << 16) | (g << 8) | (r << 0);\n      }\n   }\n   else\n   {\n      for (i = 0; i < (int)width; i++)\n      {\n         uint32_t r, g, b;\n         r        = *decoded;\n         decoded += bpp;\n         g        = *decoded;\n         decoded += bpp;\n         b        = *decoded;\n         decoded += bpp;\n         data[i]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);\n      }\n   }\n}\n\nstatic void rpng_reverse_filter_copy_line_rgba(uint32_t *data,\n      const uint8_t *decoded, unsigned width, unsigned bpp,\n      bool supports_rgba)\n{\n   int i;\n\n   /* Fast path for 8-bit depth (bpp == 32): \n    * each pixel is exactly 4 bytes. */\n   if (bpp == 32)\n   {\n#if defined(RPNG_SIMD_NEON)\n      rpng_copy_line_rgba_neon(data, decoded, width, supports_rgba);\n      return;\n#elif defined(RPNG_SIMD_SSE2)\n      rpng_copy_line_rgba_sse2(data, decoded, width, supports_rgba);\n      return;\n#endif\n   }\n\n   bpp /= 8;\n\n   if (supports_rgba)\n   {\n      for (i = 0; i < (int)width; i++)\n      {\n         uint32_t r, g, b, a;\n         r        = *decoded;\n         decoded += bpp;\n         g        = *decoded;\n         decoded += bpp;\n         b        = *decoded;\n         decoded += bpp;\n         a        = *decoded;\n         decoded += bpp;\n         data[i]  = (a << 24) | (b << 16) | (g << 8) | (r << 0);\n      }\n   }\n   else\n   {\n      for (i = 0; i < (int)width; i++)\n      {\n         uint32_t r, g, b, a;\n         r        = *decoded;\n         decoded += bpp;\n         g        = *decoded;\n         decoded += bpp;\n         b        = *decoded;\n         decoded += bpp;\n         a        = *decoded;\n         decoded += bpp;\n         data[i]  = (a << 24) | (r << 16) | (g << 8) | (b << 0);\n      }\n   }\n}\n\nstatic void rpng_reverse_filter_copy_line_bw(uint32_t *data,\n      const uint8_t *decoded, unsigned width, unsigned depth)\n{\n   int i;\n   unsigned bit;\n   static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };\n   unsigned mul, mask;\n\n   if (depth == 16)\n   {\n      for (i = 0; i < (int)width; i++)\n      {\n         uint32_t val = decoded[i << 1];\n         data[i]      = (val * 0x010101) | (0xffu << 24);\n      }\n      return;\n   }\n\n   mul  = mul_table[depth];\n   mask = (1 << depth) - 1;\n   bit  = 0;\n\n   for (i = 0; i < (int)width; i++, bit += depth)\n   {\n      unsigned byte = bit >> 3;\n      unsigned val  = decoded[byte] >> (8 - depth - (bit & 7));\n\n      val          &= mask;\n      val          *= mul;\n      data[i]       = (val * 0x010101) | (0xffu << 24);\n   }\n}\n\nstatic void rpng_reverse_filter_copy_line_gray_alpha(uint32_t *data,\n      const uint8_t *decoded, unsigned width,\n      unsigned bpp)\n{\n   int i;\n\n   bpp /= 8;\n\n   for (i = 0; i < (int)width; i++)\n   {\n      uint32_t gray, alpha;\n\n      gray     = *decoded;\n      decoded += bpp;\n      alpha    = *decoded;\n      decoded += bpp;\n\n      data[i]  = (gray * 0x010101) | (alpha << 24);\n   }\n}\n\nstatic void rpng_reverse_filter_copy_line_plt(uint32_t *data,\n      const uint8_t *decoded, unsigned width,\n      unsigned depth, const uint32_t *palette)\n{\n   switch (depth)\n   {\n      case 1:\n         {\n            int i;\n            unsigned w = width / 8;\n            for (i = 0; i < (int)w; i++, decoded++)\n            {\n               *data++ = palette[(*decoded >> 7) & 1];\n               *data++ = palette[(*decoded >> 6) & 1];\n               *data++ = palette[(*decoded >> 5) & 1];\n               *data++ = palette[(*decoded >> 4) & 1];\n               *data++ = palette[(*decoded >> 3) & 1];\n               *data++ = palette[(*decoded >> 2) & 1];\n               *data++ = palette[(*decoded >> 1) & 1];\n               *data++ = palette[*decoded & 1];\n            }\n\n            switch (width & 7)\n            {\n               case 7:\n                  data[6] = palette[(*decoded >> 1) & 1];\n               case 6:\n                  data[5] = palette[(*decoded >> 2) & 1];\n               case 5:\n                  data[4] = palette[(*decoded >> 3) & 1];\n               case 4:\n                  data[3] = palette[(*decoded >> 4) & 1];\n               case 3:\n                  data[2] = palette[(*decoded >> 5) & 1];\n               case 2:\n                  data[1] = palette[(*decoded >> 6) & 1];\n               case 1:\n                  data[0] = palette[(*decoded >> 7) & 1];\n                  break;\n            }\n         }\n         break;\n\n      case 2:\n         {\n            int i;\n            unsigned w = width / 4;\n            for (i = 0; i < (int)w; i++, decoded++)\n            {\n               *data++ = palette[(*decoded >> 6) & 3];\n               *data++ = palette[(*decoded >> 4) & 3];\n               *data++ = palette[(*decoded >> 2) & 3];\n               *data++ = palette[*decoded & 3];\n            }\n\n            switch (width & 3)\n            {\n               case 3:\n                  data[2] = palette[(*decoded >> 2) & 3];\n               case 2:\n                  data[1] = palette[(*decoded >> 4) & 3];\n               case 1:\n                  data[0] = palette[(*decoded >> 6) & 3];\n                  break;\n            }\n         }\n         break;\n\n      case 4:\n         {\n            int i;\n            unsigned w = width / 2;\n            for (i = 0; i < (int)w; i++, decoded++)\n            {\n               *data++ = palette[*decoded >> 4];\n               *data++ = palette[*decoded & 0x0f];\n            }\n\n            if (width & 1)\n               *data = palette[*decoded >> 4];\n         }\n         break;\n\n      case 8:\n         {\n            int i;\n            for (i = 0; i < (int)width; i++, decoded++, data++)\n               *data = palette[*decoded];\n         }\n         break;\n   }\n}\n\nstatic void rpng_pass_geom(const struct png_ihdr *ihdr,\n      unsigned width, unsigned height,\n      unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)\n{\n   /* Perform pitch and pass_size arithmetic in size_t.  Previously these\n    * were done in unsigned int, which can silently wrap on 32-bit at a\n    * width of ~67M for 16bpc RGBA (pitch = width*8) or, more plausibly,\n    * at a pitch*height product exceeding ~4 GiB — reachable today with\n    * a 30000x30000 16bpc-RGBA image that passes the IHDR output-size\n    * cap (based on the RGBA-8 output buffer) but whose 16bpc intermediate\n    * scanline buffer is ~6.7 GiB.  A wrapped pass_size underallocates the\n    * inflate buffer and exposes a heap overflow during decode.\n    *\n    * The `(size_t)ihdr->width * ihdr->depth` leading term forces the\n    * whole expression to size_t width.  Callers with `unsigned *pitch_out`\n    * still receive a narrowed value — safe on 64-bit where size_t is 64\n    * bits, since realistic pitches fit comfortably.  On 32-bit targets\n    * pitch_out itself has no headroom beyond UINT32_MAX, but the caller\n    * won't reach any allocation using pitch if the IHDR check further\n    * down rejects such images for their overall size. */\n   size_t   bpp   = 0;\n   size_t   pitch = 0;\n\n   switch (ihdr->color_type)\n   {\n      case PNG_IHDR_COLOR_GRAY:\n         bpp   = ((size_t)ihdr->depth + 7) / 8;\n         pitch = ((size_t)ihdr->width * ihdr->depth + 7) / 8;\n         break;\n      case PNG_IHDR_COLOR_RGB:\n         bpp   = ((size_t)ihdr->depth * 3 + 7) / 8;\n         pitch = ((size_t)ihdr->width * ihdr->depth * 3 + 7) / 8;\n         break;\n      case PNG_IHDR_COLOR_PLT:\n         bpp   = ((size_t)ihdr->depth + 7) / 8;\n         pitch = ((size_t)ihdr->width * ihdr->depth + 7) / 8;\n         break;\n      case PNG_IHDR_COLOR_GRAY_ALPHA:\n         bpp   = ((size_t)ihdr->depth * 2 + 7) / 8;\n         pitch = ((size_t)ihdr->width * ihdr->depth * 2 + 7) / 8;\n         break;\n      case PNG_IHDR_COLOR_RGBA:\n         bpp   = ((size_t)ihdr->depth * 4 + 7) / 8;\n         pitch = ((size_t)ihdr->width * ihdr->depth * 4 + 7) / 8;\n         break;\n      default:\n         break;\n   }\n\n   if (pass_size)\n      *pass_size = (pitch + 1) * (size_t)ihdr->height;\n   if (bpp_out)\n      *bpp_out   = (unsigned)bpp;\n   if (pitch_out)\n      *pitch_out = (unsigned)pitch;\n}\n\nstatic void rpng_reverse_filter_adam7_deinterlace_pass(uint32_t *data,\n      const struct png_ihdr *ihdr,\n      const uint32_t *input, unsigned pass_width, unsigned pass_height,\n      const struct adam7_pass *pass)\n{\n   unsigned x, y;\n\n   data += pass->y * ihdr->width + pass->x;\n\n   for (y = 0; y < pass_height;\n         y++, data += ihdr->width * pass->stride_y, input += pass_width)\n   {\n      uint32_t *out = data;\n\n      for (x = 0; x < pass_width; x++, out += pass->stride_x)\n         *out = input[x];\n   }\n}\n\nstatic void rpng_reverse_filter_deinit(struct rpng_process *pngp)\n{\n   if (!pngp)\n      return;\n   if (pngp->decoded_scanline)\n      free(pngp->decoded_scanline);\n   pngp->decoded_scanline = NULL;\n   if (pngp->prev_scanline)\n      free(pngp->prev_scanline);\n   pngp->prev_scanline    = NULL;\n\n   pngp->flags           &= ~RPNG_PROCESS_FLAG_PASS_INITIALIZED;\n   pngp->h                = 0;\n}\n\nstatic int rpng_reverse_filter_init(const struct png_ihdr *ihdr,\n      struct rpng_process *pngp)\n{\n   size_t pass_size;\n\n   if (   !(pngp->flags & RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED)\n         && ihdr->interlace)\n   {\n      if (     ihdr->width  <= rpng_passes[pngp->pass_pos].x\n            || ihdr->height <= rpng_passes[pngp->pass_pos].y) /* Empty pass */\n         return 1;\n\n      pngp->pass_width  = (ihdr->width -\n            rpng_passes[pngp->pass_pos].x + rpng_passes[pngp->pass_pos].stride_x\n- 1) / rpng_passes[pngp->pass_pos].stride_x;\n      pngp->pass_height = (ihdr->height - rpng_passes[pngp->pass_pos].y +\n            rpng_passes[pngp->pass_pos].stride_y - 1) / rpng_passes[pngp->pass_pos].stride_y;\n\n      if (!(pngp->data = (uint32_t*)malloc(\n            (size_t)pngp->pass_width * (size_t)pngp->pass_height * sizeof(uint32_t))))\n         return -1;\n\n      pngp->ihdr        = *ihdr;\n      pngp->ihdr.width  = pngp->pass_width;\n      pngp->ihdr.height = pngp->pass_height;\n\n      rpng_pass_geom(&pngp->ihdr, pngp->pass_width,\n            pngp->pass_height, NULL, NULL, &pngp->pass_size);\n\n      if (pngp->pass_size > pngp->total_out)\n      {\n         free(pngp->data);\n         pngp->data = NULL;\n         return -1;\n      }\n\n      pngp->flags |= RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;\n\n      return 0;\n   }\n\n   if (pngp->flags & RPNG_PROCESS_FLAG_PASS_INITIALIZED)\n      return 0;\n\n   rpng_pass_geom(ihdr, ihdr->width, ihdr->height, &pngp->bpp, &pngp->pitch, &pass_size);\n\n   if (pngp->total_out < pass_size)\n      return -1;\n\n   pngp->restore_buf_size      = 0;\n   pngp->data_restore_buf_size = 0;\n   pngp->prev_scanline         = (uint8_t*)calloc(1, pngp->pitch);\n   pngp->decoded_scanline      = (uint8_t*)calloc(1, pngp->pitch);\n\n   if (!pngp->prev_scanline || !pngp->decoded_scanline)\n      goto error;\n\n   pngp->h                    = 0;\n   pngp->flags               |= RPNG_PROCESS_FLAG_PASS_INITIALIZED;\n\n   return 0;\n\nerror:\n   rpng_reverse_filter_deinit(pngp);\n   return -1;\n}\n\n/* ---------------------------------------------------------------------------*/\n\nstatic int rpng_reverse_filter_copy_line(uint32_t *data,\n      const struct png_ihdr *ihdr,\n      struct rpng_process *pngp, unsigned filter)\n{\n   unsigned i;\n\n   switch (filter)\n   {\n      case PNG_FILTER_NONE:\n         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);\n         break;\n      case PNG_FILTER_SUB:\n#if defined(RPNG_SIMD_SSE2) || defined(RPNG_SIMD_NEON)\n         if (pngp->bpp == 4)\n         {\n            rpng_filter_sub_rgba(pngp->decoded_scanline,\n                  pngp->inflate_buf, pngp->pitch);\n            break;\n         }\n#endif\n         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);\n         for (i = pngp->bpp; i < pngp->pitch; i++)\n            pngp->decoded_scanline[i] += pngp->decoded_scanline[i - pngp->bpp];\n         break;\n      case PNG_FILTER_UP:\n         /* Filter Up is a pure vector add—no inter-byte dependency. */\n         rpng_filter_up(pngp->decoded_scanline,\n               pngp->inflate_buf, pngp->prev_scanline, pngp->pitch);\n         break;\n      case PNG_FILTER_AVERAGE:\n#if defined(RPNG_SIMD_SSE2) || defined(RPNG_SIMD_NEON)\n         if (pngp->bpp == 4)\n         {\n            rpng_filter_avg_rgba(pngp->decoded_scanline,\n                  pngp->inflate_buf, pngp->prev_scanline, pngp->pitch);\n            break;\n         }\n#endif\n         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);\n         for (i = 0; i < pngp->bpp; i++)\n         {\n            uint8_t avg = pngp->prev_scanline[i] >> 1;\n            pngp->decoded_scanline[i] += avg;\n         }\n         for (i = pngp->bpp; i < pngp->pitch; i++)\n         {\n            uint8_t avg = (pngp->decoded_scanline[i - pngp->bpp] + pngp->prev_scanline[i]) >> 1;\n            pngp->decoded_scanline[i] += avg;\n         }\n         break;\n      case PNG_FILTER_PAETH:\n#if defined(RPNG_SIMD_SSE2) || defined(RPNG_SIMD_NEON)\n         if (pngp->bpp == 4)\n         {\n            rpng_filter_paeth_rgba(pngp->decoded_scanline,\n                  pngp->inflate_buf, pngp->prev_scanline, pngp->pitch);\n            break;\n         }\n#endif\n         memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);\n         for (i = 0; i < pngp->bpp; i++)\n            pngp->decoded_scanline[i] += pngp->prev_scanline[i];\n         for (i = pngp->bpp; i < pngp->pitch; i++)\n            pngp->decoded_scanline[i] += paeth(\n                  pngp->decoded_scanline[i - pngp->bpp],\n                  pngp->prev_scanline[i],\n                  pngp->prev_scanline[i - pngp->bpp]);\n         break;\n      default:\n         return IMAGE_PROCESS_ERROR_END;\n   }\n\n   switch (ihdr->color_type)\n   {\n      case PNG_IHDR_COLOR_GRAY:\n         rpng_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);\n         break;\n      case PNG_IHDR_COLOR_RGB:\n         rpng_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth,\n               pngp->supports_rgba);\n         break;\n      case PNG_IHDR_COLOR_PLT:\n         rpng_reverse_filter_copy_line_plt(\n               data, pngp->decoded_scanline, ihdr->width,\n               ihdr->depth, pngp->palette);\n         break;\n      case PNG_IHDR_COLOR_GRAY_ALPHA:\n         rpng_reverse_filter_copy_line_gray_alpha(\n               data, pngp->decoded_scanline, ihdr->width,\n               ihdr->depth);\n         break;\n      case PNG_IHDR_COLOR_RGBA:\n         rpng_reverse_filter_copy_line_rgba(\n               data, pngp->decoded_scanline, ihdr->width, ihdr->depth,\n               pngp->supports_rgba);\n         break;\n   }\n\n   /* Swap scanline pointers instead of copying — the current decoded\n    * scanline becomes the previous scanline for the next row.\n    * Both buffers are the same size (pitch bytes), allocated in\n    * rpng_reverse_filter_init, so swapping is always safe. */\n   {\n      uint8_t *tmp           = pngp->prev_scanline;\n      pngp->prev_scanline    = pngp->decoded_scanline;\n      pngp->decoded_scanline = tmp;\n   }\n\n   return IMAGE_PROCESS_NEXT;\n}\n\nstatic int rpng_reverse_filter_regular_iterate(\n      uint32_t **data, const struct png_ihdr *ihdr,\n      struct rpng_process *pngp)\n{\n   int ret = IMAGE_PROCESS_END;\n   if (pngp->h < ihdr->height)\n   {\n      unsigned filter         = *pngp->inflate_buf++;\n      pngp->restore_buf_size += 1;\n      ret                     = rpng_reverse_filter_copy_line(*data,\n            ihdr, pngp, filter);\n      if (ret == IMAGE_PROCESS_END || ret == IMAGE_PROCESS_ERROR_END)\n         goto end;\n   }\n   else\n      goto end;\n\n   pngp->h++;\n   pngp->inflate_buf           += pngp->pitch;\n   pngp->restore_buf_size      += pngp->pitch;\n\n   *data                       += ihdr->width;\n   pngp->data_restore_buf_size += ihdr->width;\n\n   return IMAGE_PROCESS_NEXT;\n\nend:\n   rpng_reverse_filter_deinit(pngp);\n\n   pngp->inflate_buf -= pngp->restore_buf_size;\n   *data             -= pngp->data_restore_buf_size;\n   pngp->data_restore_buf_size = 0;\n   return ret;\n}\n\nstatic int rpng_reverse_filter_adam7_iterate(uint32_t **data_,\n      const struct png_ihdr *ihdr,\n      struct rpng_process *pngp)\n{\n   int        ret = 0;\n   bool   to_next = pngp->pass_pos < ARRAY_SIZE(rpng_passes);\n   uint32_t *data = *data_;\n\n   if (!to_next)\n      return IMAGE_PROCESS_END;\n\n   if ((ret = rpng_reverse_filter_init(ihdr, pngp)) == 1)\n      return IMAGE_PROCESS_NEXT;\n   else if (ret == -1)\n      return IMAGE_PROCESS_ERROR_END;\n\n   if (rpng_reverse_filter_init(&pngp->ihdr, pngp) == -1)\n      return IMAGE_PROCESS_ERROR;\n\n   do\n   {\n      ret = rpng_reverse_filter_regular_iterate(&pngp->data,\n            &pngp->ihdr, pngp);\n   } while (ret == IMAGE_PROCESS_NEXT);\n\n   if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)\n      return IMAGE_PROCESS_ERROR;\n\n   pngp->inflate_buf            += pngp->pass_size;\n   pngp->adam7_restore_buf_size += pngp->pass_size;\n\n   pngp->total_out              -= pngp->pass_size;\n\n   rpng_reverse_filter_adam7_deinterlace_pass(data,\n         ihdr, pngp->data, pngp->pass_width, pngp->pass_height,\n         &rpng_passes[pngp->pass_pos]);\n\n   free(pngp->data);\n\n   pngp->data                   = NULL;\n   pngp->pass_width             = 0;\n   pngp->pass_height            = 0;\n   pngp->pass_size              = 0;\n   pngp->flags                 &= ~RPNG_PROCESS_FLAG_ADAM7_PASS_INITIALIZED;\n\n   return IMAGE_PROCESS_NEXT;\n}\n\nstatic int rpng_reverse_filter_adam7(uint32_t **data_,\n      const struct png_ihdr *ihdr,\n      struct rpng_process *pngp)\n{\n   int ret = rpng_reverse_filter_adam7_iterate(data_,\n         ihdr, pngp);\n\n   switch (ret)\n   {\n      case IMAGE_PROCESS_ERROR_END:\n      case IMAGE_PROCESS_END:\n         break;\n      case IMAGE_PROCESS_NEXT:\n         pngp->pass_pos++;\n         return 0;\n      case IMAGE_PROCESS_ERROR:\n         if (pngp->data)\n         {\n            free(pngp->data);\n            pngp->data = NULL;\n         }\n         pngp->inflate_buf -= pngp->adam7_restore_buf_size;\n         pngp->adam7_restore_buf_size = 0;\n         return -1;\n   }\n\n   pngp->inflate_buf            -= pngp->adam7_restore_buf_size;\n   pngp->adam7_restore_buf_size  = 0;\n   return ret;\n}\n\nstatic int rpng_load_image_argb_process_inflate_init(\n      rpng_t *rpng, uint32_t **data)\n{\n   bool zstatus;\n   enum trans_stream_error err;\n   uint32_t rd, wn;\n   struct rpng_process *process = (struct rpng_process*)rpng->process;\n   bool to_continue             = (process->avail_in  > 0\n                                && process->avail_out > 0);\n\n   if (!to_continue)\n      goto end;\n\n   zstatus = process->stream_backend->trans(\n      process->stream, false, &rd, &wn, &err);\n\n   if (!zstatus && err != TRANS_STREAM_ERROR_BUFFER_FULL)\n      goto error;\n\n   process->avail_in -= rd;\n   process->avail_out -= wn;\n   process->total_out += wn;\n\n   if (err)\n      return 0;\n\nend:\n   process->stream_backend->stream_free(process->stream);\n   process->stream = NULL;\n\n#ifdef GEKKO\n   /* We often use these in textures, make sure \n    * they're 32-byte aligned */\n   *data = (uint32_t*)memalign(32, (size_t)rpng->ihdr.width *\n         (size_t)rpng->ihdr.height * sizeof(uint32_t));\n#else\n   *data = (uint32_t*)malloc((size_t)rpng->ihdr.width *\n         (size_t)rpng->ihdr.height * sizeof(uint32_t));\n#endif\n   if (!*data)\n      goto false_end;\n\n   process->adam7_restore_buf_size = 0;\n   process->restore_buf_size       = 0;\n   process->palette                = rpng->palette;\n\n   if (rpng->ihdr.interlace != 1)\n      if (rpng_reverse_filter_init(&rpng->ihdr, process) == -1)\n         goto false_end;\n\n   process->flags |=  RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;\n   return 1;\n\nerror:\nfalse_end:\n   process->flags &= ~RPNG_PROCESS_FLAG_INFLATE_INITIALIZED;\n   return -1;\n}\n\n/* Cap on the accumulated IDAT stream.  The IHDR check rejects\n * images whose decoded output would exceed 4 GiB, so any legitimate\n * IDAT stream will be well under this ceiling.  256 MiB of\n * compressed IDAT is far larger than any realistic libretro asset\n * and small enough that even on 32-bit the doubling loop below\n * cannot overflow.  Rejecting here closes off a decompression-bomb\n * path where a hostile PNG streams many large IDAT chunks to force\n * the intermediate buffer to grow arbitrarily. */\n#define RPNG_IDAT_MAX ((size_t)256 * 1024 * 1024)\n\nstatic bool rpng_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)\n{\n   size_t required;\n\n   /* Pre-patch: buf->size + chunk_size was size_t + uint32_t.  On\n    * 32-bit size_t the sum could wrap (accumulated IDAT plus a\n    * near-UINT32_MAX chunk_size), making \"required > capacity\"\n    * false, the realloc skipped, and the subsequent memcpy writing\n    * past the existing buffer.  Detect overflow explicitly and\n    * cap total growth. */\n   if (chunk_size > RPNG_IDAT_MAX - buf->size)\n      return false;\n   required = buf->size + chunk_size;\n\n   if (required > buf->capacity)\n   {\n      uint8_t *new_buffer = NULL;\n      size_t new_cap      = buf->capacity ? buf->capacity : 4096;\n\n      /* Cap the doubling too so a malicious chunk at the edge of\n       * RPNG_IDAT_MAX cannot drive new_cap past SIZE_MAX / 2. */\n      while (new_cap < required)\n      {\n         if (new_cap > RPNG_IDAT_MAX / 2)\n         {\n            new_cap = RPNG_IDAT_MAX;\n            break;\n         }\n         new_cap *= 2;\n      }\n      if (new_cap < required)\n         return false;\n\n      new_buffer = (uint8_t*)realloc(buf->data, new_cap);\n\n      if (!new_buffer)\n         return false;\n\n      buf->data     = new_buffer;\n      buf->capacity = new_cap;\n   }\n\n   return true;\n}\n\nstatic struct rpng_process *rpng_process_init(rpng_t *rpng)\n{\n   uint8_t *inflate_buf            = NULL;\n   /* calloc zeroes all fields (pointers, integers, flags) in one call */\n   struct rpng_process *process    = (struct rpng_process*)calloc(1, sizeof(*process));\n\n   if (!process)\n      return NULL;\n\n   process->stream_backend         = trans_stream_get_zlib_inflate_backend();\n\n   rpng_pass_geom(&rpng->ihdr, rpng->ihdr.width,\n         rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size);\n   if (rpng->ihdr.interlace == 1) /* To be sure. */\n      process->inflate_buf_size *= 2;\n\n   process->stream = process->stream_backend->stream_new();\n\n   if (!process->stream)\n   {\n      free(process);\n      return NULL;\n   }\n\n   inflate_buf = (uint8_t*)malloc(process->inflate_buf_size);\n   if (!inflate_buf)\n      goto error;\n\n   process->inflate_buf = inflate_buf;\n   process->avail_in    = rpng->idat_buf.size;\n   process->avail_out   = process->inflate_buf_size;\n\n   process->stream_backend->set_in(\n         process->stream,\n         rpng->idat_buf.data,\n         (uint32_t)rpng->idat_buf.size);\n   process->stream_backend->set_out(\n         process->stream,\n         process->inflate_buf,\n         (uint32_t)process->inflate_buf_size);\n\n   return process;\n\nerror:\n   if (process)\n   {\n      if (process->stream)\n         process->stream_backend->stream_free(process->stream);\n      free(process);\n   }\n   return NULL;\n}\n\n/**\n * rpng_read_chunk_header:\n *\n * Leaf function.\n *\n * @return The PNG type of the memory chunk (i.e. IHDR, IDAT, IEND,\n   PLTE, and/or tRNS)\n **/\nstatic enum png_chunk_type rpng_read_chunk_header(\n      uint8_t *buf, uint32_t chunk_size)\n{\n   int i;\n   /* Read chunk type as a big-endian 32-bit word for fast comparison */\n   uint32_t tag = rpng_dword_be(buf + 4);\n\n   /* Validate: all four bytes must be ASCII letters (65-90 or 97-122) */\n   for (i = 0; i < 4; i++)\n   {\n      uint8_t byte = (uint8_t)(tag >> (24 - i * 8));\n      if ((byte < 65) || ((byte > 90) && (byte < 97)) || (byte > 122))\n         return PNG_CHUNK_ERROR;\n   }\n\n   /* IDAT is the most common chunk type — check it first */\n   if (tag == 0x49444154) /* \"IDAT\" */\n      return PNG_CHUNK_IDAT;\n   if (tag == 0x49484452) /* \"IHDR\" */\n      return PNG_CHUNK_IHDR;\n   if (tag == 0x49454E44) /* \"IEND\" */\n      return PNG_CHUNK_IEND;\n   if (tag == 0x504C5445) /* \"PLTE\" */\n      return PNG_CHUNK_PLTE;\n   if (tag == 0x74524E53) /* \"tRNS\" */\n      return PNG_CHUNK_tRNS;\n\n   return PNG_CHUNK_NOOP;\n}\n\nbool rpng_iterate_image(rpng_t *rpng)\n{\n   uint8_t *buf             = (uint8_t*)rpng->buff_data;\n   uint32_t chunk_size      = 0;\n   size_t   remaining;\n\n   /* Check whether data buffer pointer is valid */\n   if (buf > rpng->buff_end)\n      return false;\n\n   /* Check whether reading the header will overflow\n    * the data buffer.  buff_end points at the LAST byte of the\n    * input, so bytes-remaining = (buff_end - buf) + 1. */\n   if ((size_t)(rpng->buff_end - buf) + 1 < 8)\n      return false;\n\n   chunk_size = rpng_dword_be(buf);\n\n   /* Check whether chunk will overflow the data buffer.\n    *\n    * Pre-patch:\n    *    if (buf + 8 + chunk_size > rpng->buff_end) return false;\n    * is pointer arithmetic on a uint8_t * with an attacker-\n    * controlled 32-bit chunk_size.  For a value near UINT32_MAX\n    * the sum wraps the pointer address (UB per C99; on 32-bit the\n    * arithmetic genuinely rolls over and the compare defeats the\n    * check, letting the memcpy at the IDAT handler read ~4 GiB\n    * past the end of the input).  Compare sizes instead of\n    * pointers, and reject chunk_size that cannot possibly fit\n    * even before accounting for the type/CRC overhead. */\n   remaining = (size_t)(rpng->buff_end - buf) + 1;\n   if (chunk_size > remaining || remaining - chunk_size < 12)\n      return false;\n\n   switch (rpng_read_chunk_header(buf, chunk_size))\n   {\n      case PNG_CHUNK_NOOP:\n      default:\n         break;\n\n      case PNG_CHUNK_ERROR:\n         return false;\n\n      case PNG_CHUNK_IHDR:\n         if (rpng->flags & (\n                    RPNG_FLAG_HAS_IHDR \n                  | RPNG_FLAG_HAS_IDAT\n                  | RPNG_FLAG_HAS_IEND))\n            return false;\n\n         if (chunk_size != 13)\n            return false;\n\n         buf                    += 4 + 4;\n\n         rpng->ihdr.width        = rpng_dword_be(buf + 0);\n         rpng->ihdr.height       = rpng_dword_be(buf + 4);\n         rpng->ihdr.depth        = buf[8];\n         rpng->ihdr.color_type   = buf[9];\n         rpng->ihdr.compression  = buf[10];\n         rpng->ihdr.filter       = buf[11];\n         rpng->ihdr.interlace    = buf[12];\n\n         /* Validate color_type + depth combination before any size\n          * arithmetic; rpng_pass_geom's switch relies on color_type\n          * being one of the five legal values. */\n         if (!rpng_process_ihdr(&rpng->ihdr))\n            return false;\n\n         if (rpng->ihdr.width == 0 || rpng->ihdr.height == 0)\n            return false;\n\n         /* Two independent size caps, both at 4 GiB:\n          *\n          *   1) Output buffer — rpng always decodes to ARGB32 regardless\n          *      of the source depth, so the final buffer is always\n          *      width * height * 4 bytes.\n          *\n          *   2) Intermediate inflate buffer — sized by rpng_pass_geom\n          *      as (pitch + 1) * height.  For 8bpc RGBA this matches\n          *      the output (~4 bytes/pixel), but for 16bpc RGBA it is\n          *      2x (8 bytes/pixel), and palette/gray paths are smaller.\n          *      A 30000x30000 16bpc-RGBA image passes the output cap\n          *      (3.35 GiB) but needs a 7 GiB intermediate — reject it\n          *      here rather than relying on malloc to fail downstream.\n          *\n          * Both caps use 64-bit arithmetic; the ULL literal keeps the\n          * constant unambiguously 64-bit on LLP64 (Windows) where\n          * unsigned long is 32-bit.  rpng_pass_geom's arithmetic is\n          * itself size_t-wide after the prior widening commit, so the\n          * pass_size returned here is trustworthy.\n          *\n          * On ILP32 platforms (e.g. 32-bit PPC / i686), size_t is 32-bit\n          * and pass_size can never reach 2^32, so GCC warns that the\n          * pass_size cap is always false.  Preprocessor-gate it on\n          * 64-bit size_t; the output-size cap remains active on both\n          * 32-bit and 64-bit (width*height*4 can overflow 32-bit even\n          * when each factor is 32-bit). */\n         {\n            size_t pass_size = 0;\n            rpng_pass_geom(&rpng->ihdr, rpng->ihdr.width,\n                           rpng->ihdr.height, NULL, NULL, &pass_size);\n            if ((uint64_t)rpng->ihdr.width * rpng->ihdr.height\n                     * sizeof(uint32_t) >= 0x100000000ULL\n#if SIZE_MAX > 0xFFFFFFFFULL\n                  || (uint64_t)pass_size >= 0x100000000ULL\n#endif\n               )\n               return false;\n         }\n\n         if (rpng->ihdr.compression != 0)\n         {\n#if defined(DEBUG) || defined(RPNG_TEST)\n            fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__);\n#endif\n            return false;\n         }\n\n         rpng->flags   |= RPNG_FLAG_HAS_IHDR;\n         break;\n\n      case PNG_CHUNK_PLTE:\n         {\n            int i;\n            unsigned entries = chunk_size / 3;\n\n            if (entries > 256)\n               return false;\n            if (chunk_size % 3)\n               return false;\n\n            if (    !(rpng->flags & RPNG_FLAG_HAS_IHDR) \n                  || (rpng->flags & (\n                        RPNG_FLAG_HAS_PLTE \n                      | RPNG_FLAG_HAS_IEND \n                      | RPNG_FLAG_HAS_IDAT\n                      | RPNG_FLAG_HAS_TRNS)))\n               return false;\n\n            buf += 8;\n\n            for (i = 0; i < (int)entries; i++)\n            {\n               uint32_t r       = buf[3 * i + 0];\n               uint32_t g       = buf[3 * i + 1];\n               uint32_t b       = buf[3 * i + 2];\n               rpng->palette[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24);\n            }\n\n            rpng->flags        |= RPNG_FLAG_HAS_PLTE;\n         }\n         break;\n\n      case PNG_CHUNK_tRNS:\n         if (rpng->flags & RPNG_FLAG_HAS_IDAT)\n            return false;\n\n         if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)\n         {\n            int i;\n            uint32_t *palette;\n            /* we should compare with the number of palette entries */\n            if (chunk_size > 256)\n               return false;\n\n            buf    += 8;\n            palette = rpng->palette;\n\n            for (i = 0; i < (int)chunk_size; i++, buf++, palette++)\n               *palette = (*palette & 0x00ffffff) | (unsigned)*buf << 24;\n         }\n         /* TODO: support colorkey in grayscale and truecolor images */\n\n         rpng->flags         |= RPNG_FLAG_HAS_TRNS;\n         break;\n\n      case PNG_CHUNK_IDAT:\n         if (     !(rpng->flags & RPNG_FLAG_HAS_IHDR)\n               ||  (rpng->flags & RPNG_FLAG_HAS_IEND)\n               ||  (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT\n                  &&\n                  !(rpng->flags & RPNG_FLAG_HAS_PLTE)))\n            return false;\n\n         if (!rpng_realloc_idat(&rpng->idat_buf, chunk_size))\n            return false;\n\n         buf += 8;\n\n         memcpy(rpng->idat_buf.data + rpng->idat_buf.size, buf, chunk_size);\n\n         rpng->idat_buf.size += chunk_size;\n\n         rpng->flags         |= RPNG_FLAG_HAS_IDAT;\n         break;\n\n      case PNG_CHUNK_IEND:\n         if ((rpng->flags & (RPNG_FLAG_HAS_IHDR | RPNG_FLAG_HAS_IDAT)) != (RPNG_FLAG_HAS_IHDR | RPNG_FLAG_HAS_IDAT))\n            return false;\n\n         rpng->flags         |= RPNG_FLAG_HAS_IEND;\n         return false;\n   }\n\n   /* chunk_size + 12 is a uint32_t + int, promoted to uint32_t,\n    * which wraps for chunk_size near UINT32_MAX.  The\n    * per-chunk-size overflow guard at the top of this function\n    * already rejects values that large, but keep the arithmetic\n    * explicit in size_t here so readers (and future callers who\n    * might loosen that guard) don't trip the wrap. */\n   rpng->buff_data += (size_t)chunk_size + 12;\n\n   /* Check whether data buffer pointer is valid */\n   if (rpng->buff_data > rpng->buff_end)\n      return false;\n   return true;\n}\n\nint rpng_process_image(rpng_t *rpng,\n      void **_data, size_t len, unsigned *width, unsigned *height,\n      bool supports_rgba)\n{\n   uint32_t **data = (uint32_t**)_data;\n\n   rpng->supports_rgba = supports_rgba;\n\n   if (!rpng->process)\n   {\n      struct rpng_process *process;\n\n      /* Pre-swizzle palette entries for ABGR output.\n       * The palette was assembled as ARGB during PLTE chunk parsing;\n       * for supports_rgba we need ABGR. Swap R↔B once here (max 256\n       * entries) instead of per-pixel in the copy_line_plt path.\n       * Done inside the !process guard so it runs exactly once. */\n      if (supports_rgba && (rpng->flags & RPNG_FLAG_HAS_PLTE))\n      {\n         int pi;\n         for (pi = 0; pi < 256; pi++)\n         {\n            uint32_t c  = rpng->palette[pi];\n            rpng->palette[pi] = (c & 0xFF00FF00u)\n                               | ((c & 0x00FF0000u) >> 16)\n                               | ((c & 0x000000FFu) << 16);\n         }\n      }\n\n      process = rpng_process_init(rpng);\n\n      if (!process)\n         goto error;\n\n      rpng->process = process;\n      rpng->process->supports_rgba = supports_rgba;\n      return IMAGE_PROCESS_NEXT;\n   }\n\n   if (!(rpng->process->flags & RPNG_PROCESS_FLAG_INFLATE_INITIALIZED))\n   {\n      if (rpng_load_image_argb_process_inflate_init(rpng, data) == -1)\n         goto error;\n      return IMAGE_PROCESS_NEXT;\n   }\n\n   *width  = rpng->ihdr.width;\n   *height = rpng->ihdr.height;\n\n   if (rpng->ihdr.interlace && rpng->process)\n      return rpng_reverse_filter_adam7(data, &rpng->ihdr, rpng->process);\n   return rpng_reverse_filter_regular_iterate(data,\n      &rpng->ihdr, rpng->process);\n\nerror:\n   if (rpng->process)\n   {\n      if (rpng->process->inflate_buf)\n         free(rpng->process->inflate_buf);\n      if (rpng->process->stream)\n         rpng->process->stream_backend->stream_free(rpng->process->stream);\n      free(rpng->process);\n      rpng->process = NULL;\n   }\n   return IMAGE_PROCESS_ERROR;\n}\n\nvoid rpng_free(rpng_t *rpng)\n{\n   if (!rpng)\n      return;\n\n   if (rpng->idat_buf.data)\n      free(rpng->idat_buf.data);\n   if (rpng->process)\n   {\n      if (rpng->process->inflate_buf)\n         free(rpng->process->inflate_buf);\n      if (rpng->process->stream)\n      {\n         if (   rpng->process->stream_backend \n             && rpng->process->stream_backend->stream_free)\n            rpng->process->stream_backend->stream_free(rpng->process->stream);\n         else\n            free(rpng->process->stream);\n      }\n      free(rpng->process);\n   }\n\n   free(rpng);\n}\n\nbool rpng_start(rpng_t *rpng)\n{\n   if (!rpng)\n      return false;\n\n   /* Check whether reading the header will overflow\n    * the data buffer */\n   if (rpng->buff_end - rpng->buff_data < 8)\n      return false;\n\n   if (memcmp(rpng->buff_data, png_magic, sizeof(png_magic)) != 0)\n      return false;\n\n   rpng->buff_data += 8;\n\n   return true;\n}\n\n/**\n * rpng_is_valid:\n *\n * Check if @rpng is a valid PNG image.\n * Must contain an IHDR chunk, one or more IDAT\n * chunks, and an IEND chunk.\n *\n * Leaf function.\n *\n * @return true if it's a valid PNG image, otherwise false.\n **/\nbool rpng_is_valid(rpng_t *rpng)\n{\n   const uint8_t valid_mask = RPNG_FLAG_HAS_IHDR\n                            | RPNG_FLAG_HAS_IDAT\n                            | RPNG_FLAG_HAS_IEND;\n   return (rpng && ((rpng->flags & valid_mask) == valid_mask));\n}\n\nbool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len)\n{\n   if (!rpng || (len < 1))\n      return false;\n\n   rpng->buff_data = (uint8_t*)data;\n   rpng->buff_end  = rpng->buff_data + (len - 1);\n\n   return true;\n}\n\nrpng_t *rpng_alloc(void)\n{\n   rpng_t *rpng = (rpng_t*)calloc(1, sizeof(*rpng));\n   if (!rpng)\n      return NULL;\n   return rpng;\n}\n"
  },
  {
    "path": "formats/png/rpng_encode.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rpng_encode.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <libretro.h>\n#include <encodings/crc32.h>\n#include <streams/interface_stream.h>\n#include <streams/trans_stream.h>\n\n#include \"rpng_internal.h\"\n\n#undef GOTO_END_ERROR\n#define GOTO_END_ERROR() do { \\\n   fprintf(stderr, \"[RPNG] Error in line %d.\\n\", __LINE__); \\\n   ret = false; \\\n   goto end; \\\n} while (0)\n\nstatic const double DEFLATE_PADDING = 1.1;\nstatic const int PNG_ROUGH_HEADER  = 100;\n\nstatic void dword_write_be(uint8_t *buf, uint32_t val)\n{\n   *buf++ = (uint8_t)(val >> 24);\n   *buf++ = (uint8_t)(val >> 16);\n   *buf++ = (uint8_t)(val >>  8);\n   *buf++ = (uint8_t)(val >>  0);\n}\n\nstatic bool png_write_crc_string(intfstream_t *intf_s, const uint8_t *data, size_t len)\n{\n   uint8_t crc_raw[4] = {0};\n   uint32_t crc       = encoding_crc32(0, data, len);\n\n   dword_write_be(crc_raw, crc);\n   return intfstream_write(intf_s, crc_raw, sizeof(crc_raw)) == sizeof(crc_raw);\n}\n\nstatic bool png_write_ihdr_string(intfstream_t *intf_s, const struct png_ihdr *ihdr)\n{\n   uint8_t ihdr_raw[21];\n\n   ihdr_raw[0]  = '0';                 /* Size */\n   ihdr_raw[1]  = '0';\n   ihdr_raw[2]  = '0';\n   ihdr_raw[3]  = '0';\n   ihdr_raw[4]  = 'I';\n   ihdr_raw[5]  = 'H';\n   ihdr_raw[6]  = 'D';\n   ihdr_raw[7]  = 'R';\n   ihdr_raw[8]  =   0;                 /* Width */\n   ihdr_raw[9]  =   0;\n   ihdr_raw[10] =   0;\n   ihdr_raw[11] =   0;\n   ihdr_raw[12] =   0;                 /* Height */\n   ihdr_raw[13] =   0;\n   ihdr_raw[14] =   0;\n   ihdr_raw[15] =   0;\n   ihdr_raw[16] =   ihdr->depth;       /* Depth */\n   ihdr_raw[17] =   ihdr->color_type;\n   ihdr_raw[18] =   ihdr->compression;\n   ihdr_raw[19] =   ihdr->filter;\n   ihdr_raw[20] =   ihdr->interlace;\n\n   dword_write_be(ihdr_raw +  0, sizeof(ihdr_raw) - 8);\n   dword_write_be(ihdr_raw +  8, ihdr->width);\n   dword_write_be(ihdr_raw + 12, ihdr->height);\n   if (intfstream_write(intf_s, ihdr_raw, sizeof(ihdr_raw)) != sizeof(ihdr_raw))\n      return false;\n\n   return png_write_crc_string(intf_s, ihdr_raw + sizeof(uint32_t),\n         sizeof(ihdr_raw) - sizeof(uint32_t));\n}\n\nstatic bool png_write_idat_string(intfstream_t* intf_s, const uint8_t *data, size_t len)\n{\n   if (intfstream_write(intf_s, data, len) != (ssize_t)len)\n      return false;\n   return png_write_crc_string(intf_s, data + sizeof(uint32_t), len - sizeof(uint32_t));\n}\n\nstatic bool png_write_iend_string(intfstream_t* intf_s)\n{\n   const uint8_t data[] = {\n      0, 0, 0, 0,\n      'I', 'E', 'N', 'D',\n   };\n\n   if (intfstream_write(intf_s, data, sizeof(data)) != sizeof(data))\n      return false;\n\n   return png_write_crc_string(intf_s, data + sizeof(uint32_t),\n         sizeof(data) - sizeof(uint32_t));\n}\n\nstatic void copy_argb_line(uint8_t *dst, const uint32_t *src, unsigned width)\n{\n   unsigned i;\n   for (i = 0; i < width; i++)\n   {\n      uint32_t col = src[i];\n      *dst++ = (uint8_t)(col >> 16);\n      *dst++ = (uint8_t)(col >>  8);\n      *dst++ = (uint8_t)(col >>  0);\n      *dst++ = (uint8_t)(col >> 24);\n   }\n}\n\nstatic void copy_bgr24_line(uint8_t *dst, const uint8_t *src, unsigned width)\n{\n   unsigned i;\n   for (i = 0; i < width; i++, dst += 3, src += 3)\n   {\n      dst[2] = src[0];\n      dst[1] = src[1];\n      dst[0] = src[2];\n   }\n}\n\nstatic unsigned count_sad(const uint8_t *data, size_t len)\n{\n   size_t i;\n   unsigned cnt = 0;\n   for (i = 0; i < len; i++)\n   {\n      /* Use conditional instead of abs() to avoid undefined behaviour\n       * when the value is -128 (INT8_MIN). */\n      int8_t val = (int8_t)data[i];\n      cnt += val < 0 ? -val : val;\n   }\n   return cnt;\n}\n\nstatic unsigned filter_up(uint8_t *target, const uint8_t *line,\n      const uint8_t *prev, unsigned width, unsigned bpp)\n{\n   unsigned i;\n   width *= bpp;\n   for (i = 0; i < width; i++)\n      target[i] = line[i] - prev[i];\n\n   return count_sad(target, width);\n}\n\nstatic unsigned filter_sub(uint8_t *target, const uint8_t *line,\n      unsigned width, unsigned bpp)\n{\n   unsigned i;\n   width *= bpp;\n   for (i = 0; i < bpp; i++)\n      target[i] = line[i];\n   for (i = bpp; i < width; i++)\n      target[i] = line[i] - line[i - bpp];\n\n   return count_sad(target, width);\n}\n\nstatic unsigned filter_avg(uint8_t *target, const uint8_t *line,\n      const uint8_t *prev, unsigned width, unsigned bpp)\n{\n   unsigned i;\n   width *= bpp;\n   for (i = 0; i < bpp; i++)\n      target[i] = line[i] - (prev[i] >> 1);\n   for (i = bpp; i < width; i++)\n      target[i] = line[i] - ((line[i - bpp] + prev[i]) >> 1);\n\n   return count_sad(target, width);\n}\n\nstatic unsigned filter_paeth(uint8_t *target,\n      const uint8_t *line, const uint8_t *prev,\n      unsigned width, unsigned bpp)\n{\n   unsigned i;\n   width *= bpp;\n   for (i = 0; i < bpp; i++)\n      target[i] = line[i] - paeth(0, prev[i], 0);\n   for (i = bpp; i < width; i++)\n      target[i] = line[i] - paeth(line[i - bpp], prev[i], prev[i - bpp]);\n\n   return count_sad(target, width);\n}\n\n/* Size of the per-chunk deflate output buffer.  A screenshot-sized\n * encode will fill this many times over and produce multiple IDAT\n * chunks; smaller than zlib's default window (32 KiB) to keep\n * peak memory low while large enough to amortise chunk-header\n * overhead (12 bytes per IDAT). */\n#define IDAT_CHUNK_SIZE 16384\n\n/* Emit one IDAT chunk.  `chunk_buf` is laid out as:\n *     bytes [0..4): length field (filled in here, big-endian)\n *     bytes [4..8): literal \"IDAT\"\n *     bytes [8..8+payload_len): the deflate output produced by\n *                               this chunk's worth of trans() calls\n * Matches the layout png_write_idat_string expects. */\nstatic bool flush_idat_chunk(intfstream_t *intf_s,\n      uint8_t *chunk_buf, size_t payload_len)\n{\n   if (payload_len == 0)\n      return true; /* empty chunk -- nothing to emit, not an error */\n   dword_write_be(chunk_buf + 0, (uint32_t)payload_len);\n   memcpy(chunk_buf + 4, \"IDAT\", 4);\n   return png_write_idat_string(intf_s, chunk_buf, payload_len + 8);\n}\n\nbool rpng_save_image_stream(const uint8_t *data, intfstream_t* intf_s,\n      unsigned width, unsigned height, signed pitch, unsigned bpp)\n{\n   unsigned h;\n   struct png_ihdr ihdr = {0};\n   bool ret = true;\n   const struct trans_stream_backend *stream_backend = NULL;\n   uint8_t *rgba_line        = NULL;\n   uint8_t *up_filtered      = NULL;\n   uint8_t *sub_filtered     = NULL;\n   uint8_t *avg_filtered     = NULL;\n   uint8_t *paeth_filtered   = NULL;\n   uint8_t *prev_encoded     = NULL;\n   /* filter_line holds [filter_byte][filtered_row] and is what we\n    * feed into deflate one row at a time. */\n   uint8_t *filter_line      = NULL;\n   /* chunk_buf is the IDAT-chunk staging buffer:\n    *   [0..4):        length field (filled in at flush time)\n    *   [4..8):        \"IDAT\"\n    *   [8..8+IDAT_CHUNK_SIZE): deflate output */\n   uint8_t *chunk_buf        = NULL;\n   void *stream              = NULL;\n   size_t line_len           = (size_t)width * bpp;\n   /* How many bytes deflate has produced into the current chunk_buf\n    * since the last set_out.  Reset to 0 after every flush_idat_chunk. */\n   size_t chunk_fill         = 0;\n   enum trans_stream_error err = TRANS_STREAM_ERROR_NONE;\n\n   if (!intf_s)\n      GOTO_END_ERROR();\n\n   stream_backend = trans_stream_get_zlib_deflate_backend();\n\n   if (intfstream_write(intf_s, png_magic, sizeof(png_magic)) != sizeof(png_magic))\n      GOTO_END_ERROR();\n\n   ihdr.width      = width;\n   ihdr.height     = height;\n   ihdr.depth      = 8;\n   ihdr.color_type = bpp == sizeof(uint32_t) ? 6 : 2; /* RGBA or RGB */\n   if (!png_write_ihdr_string(intf_s, &ihdr))\n      GOTO_END_ERROR();\n\n   /* Per-row scratch.  ~width*bpp each -- trivial compared to the\n    * frame-sized encode_buf the old full-buffer path allocated. */\n   prev_encoded   = (uint8_t*)calloc(1, line_len);\n   rgba_line      = (uint8_t*)malloc(line_len);\n   up_filtered    = (uint8_t*)malloc(line_len);\n   sub_filtered   = (uint8_t*)malloc(line_len);\n   avg_filtered   = (uint8_t*)malloc(line_len);\n   paeth_filtered = (uint8_t*)malloc(line_len);\n   filter_line    = (uint8_t*)malloc(line_len + 1);\n   chunk_buf      = (uint8_t*)malloc(IDAT_CHUNK_SIZE + 8);\n   if (!prev_encoded || !rgba_line || !up_filtered || !sub_filtered\n         || !avg_filtered || !paeth_filtered || !filter_line\n         || !chunk_buf)\n      GOTO_END_ERROR();\n\n   stream = stream_backend->stream_new();\n   if (!stream)\n      GOTO_END_ERROR();\n\n   /* Point deflate's output at our chunk staging area (after the\n    * 8-byte chunk header).  We re-point it every time we flush\n    * a chunk so the driver doesn't need to know the chunk layout. */\n   stream_backend->set_out(stream,\n         chunk_buf + 8, (uint32_t)IDAT_CHUNK_SIZE);\n\n   for (h = 0; h < height; h++, data += pitch)\n   {\n      uint32_t rd, wn;\n      uint8_t filter;\n      unsigned none_score, up_score, sub_score, avg_score, paeth_score;\n      unsigned min_sad;\n      const uint8_t *chosen_filtered;\n\n      if (bpp == sizeof(uint32_t))\n         copy_argb_line(rgba_line, (const uint32_t*)data, width);\n      else\n         copy_bgr24_line(rgba_line, data, width);\n\n      /* Filter selection unchanged from the previous implementation:\n       * try every filter, pick the one with lowest sum-of-abs-deviation. */\n      none_score  = count_sad(rgba_line, line_len);\n      up_score    = filter_up   (up_filtered,    rgba_line, prev_encoded, width, bpp);\n      sub_score   = filter_sub  (sub_filtered,   rgba_line,               width, bpp);\n      avg_score   = filter_avg  (avg_filtered,   rgba_line, prev_encoded, width, bpp);\n      paeth_score = filter_paeth(paeth_filtered, rgba_line, prev_encoded, width, bpp);\n\n      filter          = 0;\n      min_sad         = none_score;\n      chosen_filtered = rgba_line;\n      if (sub_score < min_sad)   { filter = 1; chosen_filtered = sub_filtered;   min_sad = sub_score;   }\n      if (up_score < min_sad)    { filter = 2; chosen_filtered = up_filtered;    min_sad = up_score;    }\n      if (avg_score < min_sad)   { filter = 3; chosen_filtered = avg_filtered;   min_sad = avg_score;   }\n      if (paeth_score < min_sad) { filter = 4; chosen_filtered = paeth_filtered;                        }\n\n      filter_line[0] = filter;\n      memcpy(filter_line + 1, chosen_filtered, line_len);\n      memcpy(prev_encoded,    rgba_line,       line_len);\n\n      /* Feed this row into deflate. The loop handles the case where\n       * our chunk buffer fills mid-row (BUFFER_FULL): flush IDAT,\n       * point deflate at a fresh output buffer, and keep going.\n       *\n       * When trans() returns success with err=AGAIN, zlib has\n       * consumed what we gave it but hasn't finalized (no Z_FINISH\n       * was requested) -- that's the normal \"ok, send more data\n       * next time\" signal.  We break out and feed the next row. */\n      stream_backend->set_in(stream, filter_line, (uint32_t)(line_len + 1));\n      for (;;)\n      {\n         bool ok = stream_backend->trans(stream, false, &rd, &wn, &err);\n         chunk_fill += wn;\n\n         if (ok)\n         {\n            /* All input consumed.  If the output buffer also happens\n             * to be exactly full (avail_in=0 AND avail_out=0 on the\n             * same call, which the trans API reports as success\n             * with AGAIN rather than BUFFER_FULL), flush proactively\n             * -- otherwise the next row's trans() would find\n             * avail_out=0 and error out. */\n            if (chunk_fill >= IDAT_CHUNK_SIZE)\n            {\n               if (!flush_idat_chunk(intf_s, chunk_buf, chunk_fill))\n                  GOTO_END_ERROR();\n               chunk_fill = 0;\n               stream_backend->set_out(stream,\n                     chunk_buf + 8, (uint32_t)IDAT_CHUNK_SIZE);\n            }\n            break;\n         }\n\n         if (err != TRANS_STREAM_ERROR_BUFFER_FULL)\n            GOTO_END_ERROR();\n\n         /* Output filled mid-row.  chunk_fill should equal\n          * IDAT_CHUNK_SIZE.  Flush and re-point. */\n         if (!flush_idat_chunk(intf_s, chunk_buf, chunk_fill))\n            GOTO_END_ERROR();\n         chunk_fill = 0;\n         stream_backend->set_out(stream,\n               chunk_buf + 8, (uint32_t)IDAT_CHUNK_SIZE);\n      }\n   }\n\n   /* All rows consumed.  Drain deflate with Z_FINISH, emitting IDATs\n    * on BUFFER_FULL, final partial on NONE (Z_STREAM_END). */\n   stream_backend->set_in(stream, NULL, 0);\n   for (;;)\n   {\n      uint32_t rd = 0, wn = 0;\n      bool ok = stream_backend->trans(stream, true, &rd, &wn, &err);\n      chunk_fill += wn;\n\n      if (!ok)\n      {\n         /* BUFFER_FULL during flush-drain with avail_in=0 shouldn't\n          * strictly be reachable, but handle defensively. */\n         if (err != TRANS_STREAM_ERROR_BUFFER_FULL)\n            GOTO_END_ERROR();\n         if (!flush_idat_chunk(intf_s, chunk_buf, chunk_fill))\n            GOTO_END_ERROR();\n         chunk_fill = 0;\n         stream_backend->set_out(stream,\n               chunk_buf + 8, (uint32_t)IDAT_CHUNK_SIZE);\n         continue;\n      }\n      if (err == TRANS_STREAM_ERROR_AGAIN)\n      {\n         /* Z_OK during Z_FINISH with avail_in=0 means deflate has\n          * more output to emit but our buffer ran out of space.\n          * Flush the full chunk and give it more room. */\n         if (!flush_idat_chunk(intf_s, chunk_buf, chunk_fill))\n            GOTO_END_ERROR();\n         chunk_fill = 0;\n         stream_backend->set_out(stream,\n               chunk_buf + 8, (uint32_t)IDAT_CHUNK_SIZE);\n         continue;\n      }\n      /* err == NONE: Z_STREAM_END.  Flush whatever's in the buffer\n       * and we're done.  flush_idat_chunk tolerates chunk_fill==0. */\n      if (!flush_idat_chunk(intf_s, chunk_buf, chunk_fill))\n         GOTO_END_ERROR();\n      break;\n   }\n\n   if (!png_write_iend_string(intf_s))\n      GOTO_END_ERROR();\n\nend:\n   free(rgba_line);\n   free(prev_encoded);\n   free(up_filtered);\n   free(sub_filtered);\n   free(avg_filtered);\n   free(paeth_filtered);\n   free(filter_line);\n   free(chunk_buf);\n\n   if (stream_backend)\n   {\n      if (stream)\n      {\n         if (stream_backend->stream_free)\n            stream_backend->stream_free(stream);\n      }\n   }\n   return ret;\n}\n\nbool rpng_save_image_argb(const char *path, const uint32_t *data,\n      unsigned width, unsigned height, unsigned pitch)\n{\n   bool ret                      = false;\n   intfstream_t* intf_s          = NULL;\n\n   intf_s = intfstream_open_file(path,\n         RETRO_VFS_FILE_ACCESS_WRITE,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n   ret = rpng_save_image_stream((const uint8_t*) data, intf_s,\n                                width, height,\n                                (signed) pitch, sizeof(uint32_t));\n   intfstream_close(intf_s);\n   free(intf_s);\n   return ret;\n}\n\nbool rpng_save_image_bgr24(const char *path, const uint8_t *data,\n      unsigned width, unsigned height, unsigned pitch)\n{\n   bool ret                      = false;\n   intfstream_t* intf_s          = NULL;\n\n   intf_s = intfstream_open_file(path,\n         RETRO_VFS_FILE_ACCESS_WRITE,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   ret = rpng_save_image_stream(data, intf_s, width, height,\n                                (signed) pitch, 3);\n   intfstream_close(intf_s);\n   free(intf_s);\n   return ret;\n}\n\n\nuint8_t* rpng_save_image_bgr24_string(const uint8_t *data,\n      unsigned width, unsigned height, signed pitch, uint64_t* bytes)\n{\n   bool ret             = false;\n   intfstream_t *intf_s = NULL;\n   size_t _len          = (size_t)(width * height * 3 * DEFLATE_PADDING) + PNG_ROUGH_HEADER;\n   uint8_t *buf         = (uint8_t*)malloc(_len * sizeof(uint8_t));\n   if (!buf)\n      GOTO_END_ERROR();\n\n   intf_s = intfstream_open_memory(buf,\n         RETRO_VFS_FILE_ACCESS_WRITE,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE,\n         _len);\n\n   ret    = rpng_save_image_stream((const uint8_t*)data,\n            intf_s, width, height, pitch, 3);\n   *bytes = intfstream_get_ptr(intf_s);\n\n   /* Trim the buffer to the actual written size instead of\n    * allocating a second buffer and copying. */\n   if (ret && *bytes > 0)\n   {\n      uint8_t *trimmed = (uint8_t*)realloc(buf, (size_t)*bytes);\n      if (trimmed)\n         buf = trimmed;\n      /* If realloc fails, the original (oversized) buf is still valid */\n   }\n\nend:\n   if (intf_s)\n   {\n      intfstream_close(intf_s);\n      free(intf_s);\n   }\n   if (!ret)\n   {\n      if (buf)\n         free(buf);\n      return NULL;\n   }\n   return buf;\n}\n\n"
  },
  {
    "path": "formats/png/rpng_internal.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rpng_internal.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _RPNG_COMMON_H\n#define _RPNG_COMMON_H\n\n#include <stdint.h>\n#include <filters.h>\n#include <formats/rpng.h>\n\n#ifndef ARRAY_SIZE\n#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))\n#endif\n\nstatic const uint8_t png_magic[8] = {\n   0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a,\n};\n\nstruct png_ihdr\n{\n   uint32_t width;\n   uint32_t height;\n   uint8_t depth;\n   uint8_t color_type;\n   uint8_t compression;\n   uint8_t filter;\n   uint8_t interlace;\n};\n\n#endif\n"
  },
  {
    "path": "formats/tga/rtga.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rtga.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Modified version of stb_image's TGA sources. */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <stddef.h> /* ptrdiff_t on osx */\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h> /* INT_MAX, SIZE_MAX via stdint */\n\n#include <retro_inline.h>\n\n#include <formats/image.h>\n#include <formats/rtga.h>\n\nstruct rtga\n{\n   uint8_t *buff_data;\n   uint32_t *output_image;\n};\n\ntypedef struct\n{\n   uint8_t *img_buffer;\n   uint8_t *img_buffer_end;\n   uint8_t *img_buffer_original;\n   int buflen;\n   int img_n, img_out_n;\n   uint32_t img_x, img_y;\n   uint8_t buffer_start[128];\n} rtga_context;\n\nstatic INLINE uint8_t rtga_get8(rtga_context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n   return 0;\n}\n\nstatic void rtga_skip(rtga_context *s, int n)\n{\n   ptrdiff_t remaining;\n   if (n < 0)\n   {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   /* Clamp the advance to the remaining input.  Pre-patch a large\n    * attacker-supplied offset (TGA header byte 1, or palette\n    * start) pushed img_buffer past img_buffer_end, which is\n    * pointer arithmetic outside the allocated object (UB per C99).\n    * All callers of rtga_get8 check \"buffer < buffer_end\" so the\n    * clamped state parses as EOF and the subsequent header checks\n    * or indexed-palette code fail cleanly. */\n   remaining = s->img_buffer_end - s->img_buffer;\n   if ((ptrdiff_t)n > remaining)\n      s->img_buffer = s->img_buffer_end;\n   else\n      s->img_buffer += n;\n}\n\nstatic int rtga_get16le(rtga_context *s)\n{\n   return rtga_get8(s) + (rtga_get8(s) << 8);\n}\n\nstatic uint32_t *rtga_tga_load(rtga_context *s,\n      unsigned *x, unsigned *y, int *comp,\n      bool supports_rgba)\n{\n   /* Read in the TGA header stuff */\n   int tga_offset          = rtga_get8(s);\n   int tga_indexed         = rtga_get8(s);\n   int tga_image_type      = rtga_get8(s);\n   int tga_is_RLE          = 0;\n   int tga_palette_start   = rtga_get16le(s);\n   int tga_palette_len     = rtga_get16le(s);\n   int tga_palette_bits    = rtga_get8(s);\n   int tga_x_origin        = rtga_get16le(s);\n   int tga_y_origin        = rtga_get16le(s);\n   int tga_width           = rtga_get16le(s);\n   int tga_height          = rtga_get16le(s);\n   int tga_bits_per_pixel  = rtga_get8(s);\n   int tga_comp            = tga_bits_per_pixel / 8;\n   int tga_inverted        = rtga_get8(s);\n\n   /* Output buffer — always 32bpp ARGB or ABGR */\n   uint32_t *output        = NULL;\n\n   (void)tga_palette_start;\n   (void)tga_x_origin;\n   (void)tga_y_origin;\n\n   /*   do a tiny bit of precessing */\n   if (tga_image_type >= 8)\n   {\n      tga_image_type -= 8;\n      tga_is_RLE = 1;\n   }\n\n   /* int tga_alpha_bits = tga_inverted & 15; */\n   tga_inverted = 1 - ((tga_inverted >> 5) & 1);\n\n   /*   error check */\n   if (\n         (tga_width < 1) || (tga_height < 1) ||\n         (tga_image_type < 1) || (tga_image_type > 3) ||\n         (\n          (tga_bits_per_pixel != 8)  && (tga_bits_per_pixel != 16) &&\n          (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)\n         )\n      )\n      return NULL;\n\n   /*   If paletted, then we will use the number of bits from the palette.\n    *\n    *   tga_palette_bits is attacker-controlled (TGA byte 7, 0..255).\n    *   Pre-patch the indexed-read loop below did\n    *       for (j = 0; j * 8 < tga_palette_bits; ++j)\n    *           raw_data[j] = tga_palette[pal_idx + j];\n    *   raw_data is a 4-byte stack array, so tga_palette_bits > 32\n    *   wrote past the end of raw_data -- a stack buffer overflow of\n    *   up to 28 bytes, directly driven by the TGA header.  Reject\n    *   bogus palette_bits / empty palettes here and everything\n    *   downstream runs with bounded buffers. */\n   if (tga_indexed)\n   {\n      if (    tga_palette_len < 1\n           || (    tga_palette_bits != 15\n                && tga_palette_bits != 16\n                && tga_palette_bits != 24\n                && tga_palette_bits != 32))\n         return NULL;\n      tga_comp = tga_palette_bits / 8;\n   }\n\n   /*   TGA info */\n   *x = tga_width;\n   *y = tga_height;\n   if (comp)\n      *comp = tga_comp;\n\n   /* Bound the output allocation.  TGA dimensions are attacker-\n    * controlled 16-bit values (max 65535), so their product is\n    * up to ~4.29 G pixels.  Pre-patch a 32-bit build could wrap\n    * (size_t)w * h * sizeof(uint32_t) to a small positive size_t\n    * and the per-pixel decode ran off the undersized malloc.\n    * Reject dimensions beyond a sane ceiling so the allocation\n    * never grows anywhere near wrap territory and hostile\n    * headers cannot drive the client into a multi-GiB malloc\n    * attempt.  0x4000 x 0x4000 = 1 GiB of decoded RGBA,\n    * comfortably larger than any real-world libretro asset. */\n   if (tga_width > 0x4000 || tga_height > 0x4000)\n      return NULL;\n   output = (uint32_t*)malloc(\n         (size_t)tga_width * (size_t)tga_height * sizeof(uint32_t));\n   if (!output)\n      return NULL;\n\n   /* skip to the data's starting position (offset usually = 0) */\n   rtga_skip(s, tga_offset);\n\n   /* --- Decode all pixels directly into uint32 output --- */\n\n   if (!tga_indexed && !tga_is_RLE && tga_comp >= 3)\n   {\n      /* Fast path: uncompressed, non-indexed, 24/32-bit.\n       * Read entire rows via pointer arithmetic (no per-byte rtga_get8),\n       * assemble uint32 pixels directly, handle row flip by writing\n       * to the correct row offset. */\n      int row;\n\n      for (row = 0; row < tga_height; ++row)\n      {\n         int dst_row     = tga_inverted ? (tga_height - 1 - row) : row;\n         uint32_t *dst   = output + dst_row * tga_width;\n         int bytes_needed = tga_width * tga_comp;\n         int col;\n\n         if (s->img_buffer + bytes_needed > s->img_buffer_end)\n            break;\n\n         if (tga_comp == 4)\n         {\n            const uint8_t *src = s->img_buffer;\n            if (supports_rgba)\n            {\n               /* TGA BGRA bytes → ABGR uint32: just memcpy on little-endian\n                * since BGRA bytes = uint32 ARGB... no wait:\n                * bytes [B,G,R,A] as little-endian uint32 = A<<24|R<<16|G<<8|B = ARGB.\n                * We need ABGR = A<<24|B<<16|G<<8|R.\n                * So we still need to swap R and B. */\n               for (col = 0; col < tga_width; ++col)\n               {\n                  uint8_t b = src[0], g = src[1], r = src[2], a = src[3];\n                  dst[col] = ((uint32_t)a << 24) | ((uint32_t)b << 16)\n                           | ((uint32_t)g << 8)  | (uint32_t)r;\n                  src += 4;\n               }\n            }\n            else\n            {\n               /* Need ARGB = A<<24|R<<16|G<<8|B.\n                * TGA bytes [B,G,R,A] as little-endian uint32 is already ARGB.\n                * Direct memcpy! */\n               memcpy(dst, src, tga_width * 4);\n            }\n         }\n         else /* tga_comp == 3 */\n         {\n            const uint8_t *src = s->img_buffer;\n            if (supports_rgba)\n            {\n               for (col = 0; col < tga_width; ++col)\n               {\n                  uint8_t b = src[0], g = src[1], r = src[2];\n                  dst[col] = 0xFF000000u | ((uint32_t)b << 16)\n                           | ((uint32_t)g << 8)  | (uint32_t)r;\n                  src += 3;\n               }\n            }\n            else\n            {\n               for (col = 0; col < tga_width; ++col)\n               {\n                  uint8_t b = src[0], g = src[1], r = src[2];\n                  dst[col] = 0xFF000000u | ((uint32_t)r << 16)\n                           | ((uint32_t)g << 8)  | (uint32_t)b;\n                  src += 3;\n               }\n            }\n         }\n\n         s->img_buffer += bytes_needed;\n      }\n   }\n   else\n   {\n      /* Generic path: RLE, indexed, or grayscale.\n       * Per-pixel processing with row/column tracking. */\n      int i, j;\n      int RLE_repeating          = 0;\n      int RLE_count              = 0;\n      int read_next_pixel        = 1;\n      unsigned char raw_data[4]  = {0};\n      unsigned char *tga_palette = NULL;\n      int pixel_count            = tga_width * tga_height;\n      int cur_col                = 0;\n      int cur_row                = 0;\n\n      /* Load palette if indexed.  Header-level checks above have\n       * ensured tga_palette_len >= 1 and tga_palette_bits in\n       * {15,16,24,32}, so n is positive and bounded at\n       * 65535 * 32 / 8 = 262140 bytes -- fits comfortably in int\n       * and in the input length we've already accepted. */\n      if (tga_indexed)\n      {\n         int n;\n         rtga_skip(s, tga_palette_start);\n         n = tga_palette_len * tga_palette_bits / 8;\n         tga_palette = (unsigned char*)malloc((size_t)n);\n         if (!tga_palette)\n         {\n            free(output);\n            return NULL;\n         }\n         if (s->img_buffer_end - s->img_buffer >= (ptrdiff_t)n)\n         {\n            memcpy(tga_palette, s->img_buffer, n);\n            s->img_buffer += n;\n         }\n         else\n         {\n            free(output);\n            free(tga_palette);\n            return NULL;\n         }\n      }\n\n      for (i = 0; i < pixel_count; ++i)\n      {\n         int dst_row;\n         uint32_t pixel;\n         unsigned char b, g, r, a;\n\n         /* RLE handling */\n         if (tga_is_RLE)\n         {\n            if (RLE_count == 0)\n            {\n               int RLE_cmd     = rtga_get8(s);\n               RLE_count       = 1 + (RLE_cmd & 127);\n               RLE_repeating   = RLE_cmd >> 7;\n               read_next_pixel = 1;\n            }\n            else if (!RLE_repeating)\n               read_next_pixel = 1;\n         }\n         else\n            read_next_pixel = 1;\n\n         /* Read raw pixel data */\n         if (read_next_pixel)\n         {\n            if (tga_indexed)\n            {\n               int pal_idx = rtga_get8(s);\n               if (pal_idx >= tga_palette_len)\n                  pal_idx = 0;\n               pal_idx *= tga_palette_bits / 8;\n               for (j = 0; j * 8 < tga_palette_bits; ++j)\n                  raw_data[j] = tga_palette[pal_idx + j];\n            }\n            else\n            {\n               j = 0;\n               switch (tga_bits_per_pixel)\n               {\n                  case 32:\n                     raw_data[j++] = rtga_get8(s); /* fallthrough */\n                  case 24:\n                     raw_data[j++] = rtga_get8(s); /* fallthrough */\n                  case 16:\n                     raw_data[j++] = rtga_get8(s); /* fallthrough */\n                  case  8:\n                     raw_data[j++] = rtga_get8(s);\n               }\n            }\n            read_next_pixel = 0;\n         }\n\n         /* Assemble pixel in correct byte order */\n         if (tga_comp >= 3)\n         {\n            b = raw_data[0];\n            g = raw_data[1];\n            r = raw_data[2];\n            a = (tga_comp >= 4) ? raw_data[3] : 0xFF;\n         }\n         else\n         {\n            r = g = b = raw_data[0];\n            a = (tga_comp >= 2) ? raw_data[1] : 0xFF;\n         }\n\n         if (supports_rgba)\n            pixel = ((uint32_t)a << 24) | ((uint32_t)b << 16)\n                  | ((uint32_t)g << 8)  | (uint32_t)r;\n         else\n            pixel = ((uint32_t)a << 24) | ((uint32_t)r << 16)\n                  | ((uint32_t)g << 8)  | (uint32_t)b;\n\n         /* Write to correct position using tracked row/col\n          * (avoids per-pixel division and modulo).  Use size_t for\n          * the index so dst_row * tga_width does not overflow\n          * signed int for a legitimate 65535 x 65535 image. */\n         dst_row = tga_inverted ? (tga_height - 1 - cur_row) : cur_row;\n         output[(size_t)dst_row * (size_t)tga_width + (size_t)cur_col] = pixel;\n\n         if (++cur_col >= tga_width)\n         {\n            cur_col = 0;\n            ++cur_row;\n         }\n\n         --RLE_count;\n      }\n\n      if (tga_palette)\n         free(tga_palette);\n   }\n\n   return output;\n}\n\nstatic uint32_t *rtga_load_from_memory(uint8_t const *buffer, int len,\n      unsigned *x, unsigned *y, int *comp, bool supports_rgba)\n{\n   rtga_context s;\n\n   s.img_buffer          = (uint8_t *)buffer;\n   s.img_buffer_original = (uint8_t *) buffer;\n   s.img_buffer_end      = (uint8_t *) buffer+len;\n\n   return rtga_tga_load(&s, x, y, comp, supports_rgba);\n}\n\nint rtga_process_image(rtga_t *rtga, void **buf_data,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba)\n{\n   int comp;\n\n   if (!rtga)\n      return IMAGE_PROCESS_ERROR;\n\n   /* Reject sizes that don't fit in int before casting.  A TGA\n    * file larger than INT_MAX handed to an int-taking API would\n    * truncate, the truncated value (potentially negative)\n    * propagated to img_buffer_end = buffer + len, producing\n    * pointer arithmetic outside the source object (UB).  A 2 GiB\n    * TGA is unreasonable; reject early. */\n   if (size > (size_t)INT_MAX)\n      return IMAGE_PROCESS_ERROR;\n\n   rtga->output_image   = rtga_load_from_memory(rtga->buff_data,\n                           (int)size, width, height, &comp, supports_rgba);\n   *buf_data             = rtga->output_image;\n\n   if (!rtga->output_image)\n      return IMAGE_PROCESS_ERROR;\n\n   return IMAGE_PROCESS_END;\n}\n\nbool rtga_set_buf_ptr(rtga_t *rtga, void *data)\n{\n   if (!rtga)\n      return false;\n\n   rtga->buff_data = (uint8_t*)data;\n\n   return true;\n}\n\nvoid rtga_free(rtga_t *rtga)\n{\n   if (!rtga)\n      return;\n\n   free(rtga);\n}\n\nrtga_t *rtga_alloc(void)\n{\n   rtga_t *rtga = (rtga_t*)calloc(1, sizeof(*rtga));\n   if (!rtga)\n      return NULL;\n   return rtga;\n}\n"
  },
  {
    "path": "formats/wav/rwav.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rwav.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <stddef.h> /* ptrdiff_t on osx */\n#include <stdlib.h>\n#include <string.h>\n\n#include <formats/rwav.h>\n\nenum\n{\n   ITER_BEGIN,\n   ITER_COPY_SAMPLES,\n   ITER_COPY_SAMPLES_8,\n   ITER_COPY_SAMPLES_16\n};\n\nstruct rwav_iterator\n{\n   rwav_t *out;\n   const uint8_t *data;\n   size_t size;\n   size_t i, j;\n   int step;\n};\n\nvoid rwav_init(rwav_iterator_t* iter, rwav_t* out, const void *s, size_t len)\n{\n   iter->out    = out;\n   iter->data   = (const uint8_t*)s;\n   iter->size   = len;\n   iter->step   = ITER_BEGIN;\n\n   out->samples = NULL;\n}\n\nenum rwav_state rwav_iterate(rwav_iterator_t *iter)\n{\n   size_t s;\n   uint16_t *u16       = NULL;\n   void *samples       = NULL;\n   rwav_t *rwav        = iter->out;\n   const uint8_t *data = iter->data;\n\n   switch (iter->step)\n   {\n      case ITER_BEGIN:\n         if (iter->size < 44)\n            return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */\n\n         if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F')\n            return RWAV_ITERATE_ERROR;\n\n         if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E')\n            return RWAV_ITERATE_ERROR;\n\n         if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ')\n            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */\n\n         if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0)\n            return RWAV_ITERATE_ERROR;\n\n         if (data[20] != 1 || data[21] != 0)\n            return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */\n\n         if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a')\n            return RWAV_ITERATE_ERROR;\n\n         rwav->bitspersample = data[34] | data[35] << 8;\n\n         if (rwav->bitspersample != 8 && rwav->bitspersample != 16)\n            return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */\n\n         rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24;\n\n         if (   (rwav->subchunk2size < 1)\n             || (rwav->subchunk2size > iter->size - 44))\n            return RWAV_ITERATE_ERROR; /* too few bytes in buffer */\n\n         samples = malloc(rwav->subchunk2size);\n\n         if (!samples)\n            return RWAV_ITERATE_ERROR;\n\n         rwav->numchannels = data[22] | data[23] << 8;\n         rwav->numsamples  = rwav->subchunk2size * 8 / rwav->bitspersample / rwav->numchannels;\n         rwav->samplerate  = data[24] | data[25] << 8 | data[26] << 16 | data[27] << 24;\n         rwav->samples     = samples;\n\n         iter->step = ITER_COPY_SAMPLES;\n         return RWAV_ITERATE_MORE;\n\n      case ITER_COPY_SAMPLES:\n         iter->i = 0;\n\n         if (rwav->bitspersample == 8)\n         {\n            iter->step = ITER_COPY_SAMPLES_8;\n\n            /* TODO/FIXME - what is going on here? */\n            case ITER_COPY_SAMPLES_8:\n            s = rwav->subchunk2size - iter->i;\n\n            if (s > RWAV_ITERATE_BUF_SIZE)\n               s = RWAV_ITERATE_BUF_SIZE;\n\n            memcpy((void*)((uint8_t*)rwav->samples + iter->i), (void *)(iter->data + 44 + iter->i), s);\n            iter->i += s;\n         }\n         else\n         {\n            iter->step = ITER_COPY_SAMPLES_16;\n            iter->j    = 0;\n\n            /* TODO/FIXME - what is going on here? */\n            case ITER_COPY_SAMPLES_16:\n            s = rwav->subchunk2size - iter->i;\n\n            if (s > RWAV_ITERATE_BUF_SIZE)\n               s = RWAV_ITERATE_BUF_SIZE;\n\n            u16 = (uint16_t *)rwav->samples;\n\n            while (s != 0)\n            {\n               u16[iter->j++] = iter->data[44 + iter->i] | iter->data[45 + iter->i] << 8;\n               iter->i += 2;\n               s -= 2;\n            }\n         }\n\n         if (iter->i < rwav->subchunk2size)\n            return RWAV_ITERATE_MORE;\n         return RWAV_ITERATE_DONE;\n   }\n\n   return RWAV_ITERATE_ERROR;\n}\n\nenum rwav_state rwav_load(rwav_t* out, const void *s, size_t len)\n{\n   enum rwav_state res;\n   rwav_iterator_t iter;\n\n   iter.out             = NULL;\n   iter.data            = NULL;\n   iter.size            = 0;\n   iter.i               = 0;\n   iter.j               = 0;\n   iter.step            = 0;\n\n   rwav_init(&iter, out, s, len);\n\n   do\n   {\n      res = rwav_iterate(&iter);\n   }while (res == RWAV_ITERATE_MORE);\n\n   return res;\n}\n\nvoid rwav_free(rwav_t *rwav)\n{\n   free((void*)rwav->samples);\n}\n"
  },
  {
    "path": "formats/webp/rwebp.c",
    "content": "/* Copyright  (C) 2010-2024 The RetroArch team\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Self-contained WebP decoder for libretro. No external dependencies.\n * Supports VP8L (lossless, all 4 transforms) and VP8 (lossy, prediction-only). */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n#include <retro_inline.h>\n#include <formats/image.h>\n#include <formats/rwebp.h>\n\n/* ===== RIFF Container ===== */\n\nstatic uint32_t rw32(const uint8_t *p)\n{\n   return (uint32_t)p[0] | ((uint32_t)p[1]<<8) |\n          ((uint32_t)p[2]<<16) | ((uint32_t)p[3]<<24);\n}\n\n#define RW_CC(a,b,c,d) \\\n   ((uint32_t)(a)|((uint32_t)(b)<<8)|((uint32_t)(c)<<16)|((uint32_t)(d)<<24))\n\ntypedef struct\n{\n   const uint8_t *vp8;  size_t vp8s;\n   const uint8_t *vp8l; size_t vp8ls;\n   int lossless;\n} rw_ctr;\n\nstatic int rw_parse(const uint8_t *b, size_t l, rw_ctr *c)\n{\n   size_t p;\n   memset(c, 0, sizeof(*c));\n   if (l < 12 || rw32(b) != RW_CC('R','I','F','F')\n       || rw32(b+8) != RW_CC('W','E','B','P'))\n      return 0;\n   for (p = 12; p + 8 <= l; )\n   {\n      uint32_t tag = rw32(b+p);\n      uint32_t sz  = rw32(b+p+4);\n      const uint8_t *d = b + p + 8;\n      if (p + 8 + sz > l) break;\n      if (tag == RW_CC('V','P','8',' ') && !c->vp8)\n      { c->vp8 = d; c->vp8s = sz; c->lossless = 0; }\n      else if (tag == RW_CC('V','P','8','L') && !c->vp8l)\n      { c->vp8l = d; c->vp8ls = sz; c->lossless = 1; }\n      else if (tag == RW_CC('A','N','M','F') && sz >= 16)\n      {\n         size_t sp;\n         for (sp = 16; sp + 8 <= sz; )\n         {\n            uint32_t st = rw32(d+sp), ss = rw32(d+sp+4);\n            if (sp+8+ss > sz) break;\n            if (st == RW_CC('V','P','8',' ') && !c->vp8)\n            { c->vp8 = d+sp+8; c->vp8s = ss; c->lossless = 0; }\n            else if (st == RW_CC('V','P','8','L') && !c->vp8l)\n            { c->vp8l = d+sp+8; c->vp8ls = ss; c->lossless = 1; }\n            sp += 8 + ((ss+1) & ~(size_t)1);\n         }\n      }\n      p += 8 + ((sz+1) & ~(size_t)1);\n   }\n   return (c->vp8 || c->vp8l);\n}\n\n/* ===== VP8L LSB Bit Reader ===== */\n\ntypedef struct { const uint8_t *buf, *end; uint64_t val; int nb; } vbr;\n\nstatic void vbr_init(vbr *b, const uint8_t *d, size_t l)\n{ b->buf = d; b->end = d + l; b->val = 0; b->nb = 0; }\n\nstatic INLINE void vbr_fill(vbr *b)\n{ while (b->nb < 56 && b->buf < b->end)\n  { b->val |= (uint64_t)(*b->buf++) << b->nb; b->nb += 8; } }\n\nstatic INLINE uint32_t vbr_read(vbr *b, int n)\n{\n   uint32_t v;\n   if (b->nb < n) vbr_fill(b);\n   v = (uint32_t)(b->val & (((uint64_t)1 << n) - 1));\n   b->val >>= n; b->nb -= n;\n   return v;\n}\n\n/* ===== VP8L Huffman Tables ===== */\n\n#define VH_MAXCL 15\n#define VH_ROOT  8\n\ntypedef struct { uint32_t *t; int sz, rb; } vh;\n\nstatic void vh_free(vh *h) { free(h->t); h->t = NULL; }\n\nstatic int vh_build(vh *h, const uint8_t *lens, int ns, int root)\n{\n   int cnt[VH_MAXCL+1], off[VH_MAXCL+1], sorted[4096];\n   int i, len, key, sym, total, step, tc;\n   uint32_t *t;\n   if (ns > 4096) return -1;\n   memset(cnt, 0, sizeof(cnt));\n   for (i = 0; i < ns; i++)\n   {\n      if (lens[i] > VH_MAXCL) return -1;\n      cnt[lens[i]]++;\n   }\n   off[0] = 0; off[1] = 0;\n   for (i = 1; i < VH_MAXCL; i++) off[i+1] = off[i] + cnt[i];\n   for (i = 0; i < ns; i++) if (lens[i]) sorted[off[lens[i]]++] = i;\n\n   total = 1 << root;\n   for (len = root+1; len <= VH_MAXCL; len++)\n      total += cnt[len] << (len - root);\n   if (total < (1 << root)) total = 1 << root;\n\n   h->t = (uint32_t*)calloc(total + 64, sizeof(uint32_t));\n   if (!h->t) return -1;\n   h->sz = total; h->rb = root;\n   t = h->t; step = 1 << root;\n\n   /* Trivial tree: 0 or 1 symbols -> every entry returns that symbol, 0 bits consumed */\n   tc = 0;\n   for (i = 1; i <= VH_MAXCL; i++) tc += cnt[i];\n   if (tc <= 1)\n   {\n      int s = (tc == 1) ? sorted[0] : 0;\n      uint32_t e = (uint32_t)(s << 16); /* code_length = 0 */\n      for (i = 0; i < (1 << root); i++) t[i] = e;\n      return 0;\n   }\n\n   key = 0; sym = 0;\n   for (len = 1; len <= VH_MAXCL; len++)\n   {\n      for (i = 0; i < cnt[len]; i++, sym++)\n      {\n         int s = sorted[sym], j;\n         if (len <= root)\n         {\n            int rk = 0;\n            uint32_t e = (uint32_t)((s << 16) | len);\n            for (j = 0; j < len; j++) rk |= ((key >> j) & 1) << (len-1-j);\n            for (j = rk; j < (1 << root); j += (1 << len)) t[j] = e;\n         }\n         else\n         {\n            int rk2 = 0, sb = len - root, sk = 0, j2;\n            uint32_t e = (uint32_t)((s << 16) | sb);\n            for (j = 0; j < root; j++) rk2 |= ((key >> j) & 1) << (root-1-j);\n            if (!(t[rk2] & 0x80000000u))\n            {\n               t[rk2] = (uint32_t)((step << 16) | sb | 0x80000000u);\n               step += (1 << sb);\n            }\n            for (j = 0; j < sb; j++) sk |= ((key >> (root+j)) & 1) << (sb-1-j);\n            { int so = (t[rk2] >> 16) & 0x7FFF, stb = t[rk2] & 0x1F;\n              for (j2 = sk; j2 < (1 << stb); j2 += (1 << sb))\n                 if (so + j2 < total + 64) t[so + j2] = e; }\n         }\n         key++;\n      }\n      key <<= 1;\n   }\n   return 0;\n}\n\nstatic INLINE int vh_read(const vh *h, vbr *b)\n{\n   uint32_t e;\n   int idx;\n   vbr_fill(b);\n   idx = (int)(b->val & ((1u << h->rb) - 1));\n   e = h->t[idx];\n   if (e & 0x80000000u)\n   {\n      int sb = e & 0x1F, so = (e >> 16) & 0x7FFF;\n      b->val >>= h->rb; b->nb -= h->rb;\n      e = h->t[so + ((int)(b->val & ((1u << sb) - 1)))];\n      { int cl = e & 0xFFFF; b->val >>= cl; b->nb -= cl; }\n   }\n   else\n   {\n      int cl = e & 0xFFFF;\n      if (cl > 0) { b->val >>= cl; b->nb -= cl; }\n   }\n   return (int)(e >> 16);\n}\n\n/* Code-length alphabet order */\nstatic const uint8_t vh_cl_order[19] =\n   {17,18,0,1,2,3,4,5,16,6,7,8,9,10,11,12,13,14,15};\n\nstatic int vh_read_codes(vbr *br, int ns, uint8_t *lens)\n{\n   int i;\n   memset(lens, 0, ns);\n   if (vbr_read(br, 1)) /* simple */\n   {\n      int n = vbr_read(br, 1) + 1;\n      int f8 = vbr_read(br, 1);\n      int s0 = vbr_read(br, f8 ? 8 : 1);\n      if (s0 < ns) lens[s0] = 1;\n      if (n == 2)\n      {\n         int s1 = vbr_read(br, 8);\n         if (s1 < ns) lens[s1] = 1;\n      }\n   }\n   else\n   {\n      uint8_t cl[19];\n      vh clt;\n      int ncl, prev = 8, si, ms;\n      memset(&clt, 0, sizeof(clt));\n      memset(cl, 0, 19);\n      ncl = vbr_read(br, 4) + 4;\n      if (ncl > 19) ncl = 19;\n      for (i = 0; i < ncl; i++)\n         cl[vh_cl_order[i]] = (uint8_t)vbr_read(br, 3);\n      if (vh_build(&clt, cl, 19, 7) < 0) return -1;\n      ms = ns;\n      if (vbr_read(br, 1))\n      {\n         int nb = 2 + 2 * vbr_read(br, 3);\n         ms = 2 + vbr_read(br, nb);\n         if (ms > ns) ms = ns;\n      }\n      si = 0;\n      while (si < ms)\n      {\n         int c = vh_read(&clt, br);\n         if      (c < 16) { lens[si++] = (uint8_t)c; if (c) prev = c; }\n         else if (c == 16) { int r = vbr_read(br,2)+3; while (r-- > 0 && si < ms) lens[si++] = (uint8_t)prev; }\n         else if (c == 17) { int r = vbr_read(br,3)+3; while (r-- > 0 && si < ms) lens[si++] = 0; }\n         else if (c == 18) { int r = vbr_read(br,7)+11;while (r-- > 0 && si < ms) lens[si++] = 0; }\n         else break;\n      }\n      vh_free(&clt);\n   }\n   return 0;\n}\n\n/* ===== VP8L Pixel Math ===== */\n\nstatic INLINE uint32_t px_add(uint32_t a, uint32_t b)\n{\n   return ((((a>>8)&0xFF00FF)+((b>>8)&0xFF00FF))&0xFF00FF)<<8 |\n          (((a&0xFF00FF)+(b&0xFF00FF))&0xFF00FF);\n}\nstatic INLINE uint32_t px_avg2(uint32_t a, uint32_t b)\n{ return (((a^b)&0xFEFEFEFEu)>>1)+(a&b); }\nstatic INLINE int px_abs(int x) { return x<0?-x:x; }\nstatic INLINE int px_clb(int v) { return v<0?0:v>255?255:v; }\n\nstatic uint32_t px_select(uint32_t TL, uint32_t T, uint32_t L)\n{\n   int d = px_abs((int)((T>>24)&0xFF)-(int)((TL>>24)&0xFF)) - px_abs((int)((L>>24)&0xFF)-(int)((TL>>24)&0xFF))\n         + px_abs((int)((T>>16)&0xFF)-(int)((TL>>16)&0xFF)) - px_abs((int)((L>>16)&0xFF)-(int)((TL>>16)&0xFF))\n         + px_abs((int)((T>> 8)&0xFF)-(int)((TL>> 8)&0xFF)) - px_abs((int)((L>> 8)&0xFF)-(int)((TL>> 8)&0xFF))\n         + px_abs((int)( T     &0xFF)-(int)( TL     &0xFF)) - px_abs((int)( L     &0xFF)-(int)( TL     &0xFF));\n   return d <= 0 ? T : L;\n}\nstatic uint32_t px_casf(uint32_t a, uint32_t b, uint32_t c)\n{\n   return ((uint32_t)px_clb((int)((a>>24)&0xFF)+(int)((b>>24)&0xFF)-(int)((c>>24)&0xFF))<<24)\n        | ((uint32_t)px_clb((int)((a>>16)&0xFF)+(int)((b>>16)&0xFF)-(int)((c>>16)&0xFF))<<16)\n        | ((uint32_t)px_clb((int)((a>> 8)&0xFF)+(int)((b>> 8)&0xFF)-(int)((c>> 8)&0xFF))<< 8)\n        |  (uint32_t)px_clb((int)( a     &0xFF)+(int)( b     &0xFF)-(int)( c     &0xFF));\n}\nstatic uint32_t px_cash(uint32_t a, uint32_t b)\n{\n   return ((uint32_t)px_clb((int)((a>>24)&0xFF)+((int)((a>>24)&0xFF)-(int)((b>>24)&0xFF))/2)<<24)\n        | ((uint32_t)px_clb((int)((a>>16)&0xFF)+((int)((a>>16)&0xFF)-(int)((b>>16)&0xFF))/2)<<16)\n        | ((uint32_t)px_clb((int)((a>> 8)&0xFF)+((int)((a>> 8)&0xFF)-(int)((b>> 8)&0xFF))/2)<< 8)\n        |  (uint32_t)px_clb((int)( a     &0xFF)+((int)( a     &0xFF)-(int)( b     &0xFF))/2);\n}\n\nstatic uint32_t px_predict(int m, uint32_t L, uint32_t T, uint32_t TL, uint32_t TR)\n{\n   switch (m)\n   {\n      case 0: return 0xFF000000u;\n      case 1: return L;\n      case 2: return T;\n      case 3: return TR;\n      case 4: return TL;\n      case 5: return px_avg2(px_avg2(L,TR),T);\n      case 6: return px_avg2(L,TL);\n      case 7: return px_avg2(L,T);\n      case 8: return px_avg2(TL,T);\n      case 9: return px_avg2(T,TR);\n      case 10: return px_avg2(px_avg2(L,TL),px_avg2(T,TR));\n      case 11: return px_select(TL,T,L);\n      case 12: return px_casf(L,T,TL);\n      case 13: return px_cash(px_avg2(L,T),TL);\n      default: return 0xFF000000u;\n   }\n}\n\n/* Distance mapping */\nstatic const int8_t vl_dx[] = {0,1,1,1,0,-1,-1,-1,0,2,2,2,1,1,-1,-1,-2,-2,-2,0,3,3,3,3,2,2,1,-1,-2,-2,-3,-3,-3,-3,0,4};\nstatic const int8_t vl_dy[] = {1,0,1,-1,2,1,0,-1,2,0,1,-1,2,-2,2,-2,1,0,-1,2,0,1,-1,-2,2,-2,3,3,2,1,2,1,0,-1,3,0};\n\nstatic int vl_dist(int c, int xs)\n{\n   if (c < 4) return c + 1;\n   if (c < 40) { int d = vl_dy[c-4]*xs + vl_dx[c-4]; return d < 1 ? 1 : d; }\n   return c - 2 + 1;\n}\n\nstatic int vl_prefix(int c, vbr *br)\n{\n   int ri, extra, off;\n   if (c < 4) return c + 1;\n   ri = (c - 2) >> 1;\n   extra = ri;\n   if (extra > 24) extra = 24;\n   off = (2 + ((c - 2) & 1)) << ri;\n   return off + (int)vbr_read(br, extra) + 1;\n}\n\n/* ===== VP8L Pixel Decode ===== */\n\nstatic uint32_t *vl_decode_pixels(vbr *br, int w, int h)\n{\n   uint32_t *pix;\n   int ccb = 0, ccs = 0, ns[5], i, pi;\n   uint32_t *cc = NULL;\n   vh ht[5];\n   uint8_t *cl;\n\n   memset(ht, 0, sizeof(ht));\n   if (vbr_read(br, 1))\n   {\n      ccb = vbr_read(br, 4);\n      if (ccb < 1 || ccb > 11) return NULL;\n      ccs = 1 << ccb;\n      cc = (uint32_t*)calloc(ccs, sizeof(uint32_t));\n      if (!cc) return NULL;\n   }\n   ns[0] = 256 + 24 + ccs; ns[1] = 256; ns[2] = 256; ns[3] = 256; ns[4] = 40;\n   cl = (uint8_t*)malloc(4096);\n   if (!cl) { free(cc); return NULL; }\n   for (i = 0; i < 5; i++)\n   {\n      if (vh_read_codes(br, ns[i], cl) < 0) goto pfail;\n      if (vh_build(&ht[i], cl, ns[i], VH_ROOT) < 0) goto pfail;\n   }\n   pix = (uint32_t*)malloc((size_t)w * h * sizeof(uint32_t));\n   if (!pix) goto pfail;\n\n   pi = 0;\n   while (pi < w * h)\n   {\n      int g = vh_read(&ht[0], br);\n      if (g < 256)\n      {\n         int r = vh_read(&ht[1], br);\n         int b = vh_read(&ht[2], br);\n         int a = vh_read(&ht[3], br);\n         uint32_t argb = ((uint32_t)a<<24)|((uint32_t)r<<16)|((uint32_t)g<<8)|(uint32_t)b;\n         pix[pi++] = argb;\n         if (cc) cc[(0x1E35A7BDu * argb) >> (32 - ccb)] = argb;\n      }\n      else if (g < 256 + 24)\n      {\n         int lc = g - 256;\n         int length = vl_prefix(lc, br);\n         int dc = vh_read(&ht[4], br);\n         int dist = (dc < 40) ? vl_dist(dc, w) : vl_prefix(dc - 2, br) + 38;\n         int k;\n         if (dist < 1) dist = 1;\n         for (k = 0; k < length && pi < w * h; k++)\n         {\n            int src = pi - dist;\n            uint32_t argb = (src >= 0) ? pix[src] : 0xFF000000u;\n            pix[pi++] = argb;\n            if (cc) cc[(0x1E35A7BDu * argb) >> (32 - ccb)] = argb;\n         }\n      }\n      else\n      {\n         int ci = g - 256 - 24;\n         pix[pi++] = (cc && ci < ccs) ? cc[ci] : 0xFF000000u;\n      }\n   }\n   free(cl); free(cc);\n   for (i = 0; i < 5; i++) vh_free(&ht[i]);\n   return pix;\npfail:\n   free(cl); free(cc);\n   for (i = 0; i < 5; i++) vh_free(&ht[i]);\n   return NULL;\n}\n\n/* ===== VP8L Full Decode with Transforms ===== */\n\n#define XF_PRED 0\n#define XF_CCOL 1\n#define XF_SUBG 2\n#define XF_CIDX 3\n#define XF_MAX  4\n\ntypedef struct { int type, bits, dw, dh; uint32_t *data; } xf_t;\n\nstatic uint32_t *vl_decode_full(const uint8_t *data, size_t len,\n      unsigned *ow, unsigned *oh)\n{\n   vbr br;\n   uint32_t sig, width, height;\n   uint32_t *pix = NULL;\n   xf_t xf[XF_MAX];\n   int nxf = 0, i, cw, ch;\n\n   vbr_init(&br, data, len);\n   sig = vbr_read(&br, 8);\n   if (sig != 0x2F) return NULL;\n   width = vbr_read(&br, 14) + 1;\n   height = vbr_read(&br, 14) + 1;\n   vbr_read(&br, 1); /* alpha_is_used */\n   if (vbr_read(&br, 3) != 0) return NULL; /* version */\n   if (width > 16384 || height > 16384) return NULL;\n   memset(xf, 0, sizeof(xf));\n   cw = (int)width; ch = (int)height;\n\n   /* Read transforms */\n   while (vbr_read(&br, 1))\n   {\n      int tt = vbr_read(&br, 2);\n      xf_t *x;\n      if (nxf >= XF_MAX) goto xfail;\n      x = &xf[nxf++];\n      x->type = tt;\n\n      switch (tt)\n      {\n         case XF_PRED:\n         case XF_CCOL:\n         {\n            int bb = vbr_read(&br, 3) + 2;\n            int bw = ((cw-1) >> bb) + 1;\n            int bh = ((ch-1) >> bb) + 1;\n            x->bits = bb; x->dw = bw; x->dh = bh;\n            x->data = vl_decode_pixels(&br, bw, bh);\n            if (!x->data) goto xfail;\n            break;\n         }\n         case XF_SUBG:\n            break;\n         case XF_CIDX:\n         {\n            int nc = vbr_read(&br, 8) + 1, bits, pi2;\n            x->dw = nc; x->dh = 1;\n            x->data = vl_decode_pixels(&br, nc, 1);\n            if (!x->data) goto xfail;\n            /* Delta-decode palette */\n            for (pi2 = 1; pi2 < nc; pi2++)\n               x->data[pi2] = px_add(x->data[pi2], x->data[pi2-1]);\n            if      (nc <= 2)  bits = 3;\n            else if (nc <= 4)  bits = 2;\n            else if (nc <= 16) bits = 1;\n            else               bits = 0;\n            x->bits = bits;\n            if (bits > 0) cw = ((cw + (1 << bits) - 1) >> bits);\n            break;\n         }\n      }\n   }\n\n   /* Decode main image */\n   pix = vl_decode_pixels(&br, cw, ch);\n   if (!pix) goto xfail;\n\n   /* Inverse transforms in reverse order */\n   for (i = nxf - 1; i >= 0; i--)\n   {\n      xf_t *x = &xf[i];\n      switch (x->type)\n      {\n         case XF_CIDX:\n         {\n            uint32_t *pal = x->data;\n            int nc = x->dw, bits = x->bits, rw = (int)width;\n            uint32_t *out = (uint32_t*)malloc((size_t)rw * height * sizeof(uint32_t));\n            int px2, py2;\n            if (!out) goto xfail;\n            for (py2 = 0; py2 < (int)height; py2++)\n            {\n               for (px2 = 0; px2 < rw; px2++)\n               {\n                  int idx;\n                  if (bits > 0)\n                  {\n                     int pi2 = px2 >> bits;\n                     int si  = px2 & ((1 << bits) - 1);\n                     uint32_t raw = (pi2 < cw) ? pix[py2 * cw + pi2] : 0;\n                     idx = ((int)((raw >> 8) & 0xFF) >> (si * (8 >> bits))) & ((1 << (8 >> bits)) - 1);\n                  }\n                  else\n                  {\n                     uint32_t raw = (px2 < cw) ? pix[py2 * cw + px2] : 0;\n                     idx = (raw >> 8) & 0xFF;\n                  }\n                  if (idx >= nc) idx = 0;\n                  out[py2 * rw + px2] = pal[idx];\n               }\n            }\n            free(pix); pix = out; cw = rw;\n            break;\n         }\n         case XF_SUBG:\n         {\n            int j, n = cw * (int)height;\n            for (j = 0; j < n; j++)\n            {\n               uint32_t c = pix[j];\n               uint32_t g = (c >> 8) & 0xFF;\n               uint32_t r = (((c >> 16) & 0xFF) + g) & 0xFF;\n               uint32_t b2 = ((c & 0xFF) + g) & 0xFF;\n               pix[j] = (c & 0xFF00FF00u) | (r << 16) | b2;\n            }\n            break;\n         }\n         case XF_PRED:\n         {\n            int bw = x->dw;\n            uint32_t *td = x->data;\n            int px2, py2;\n            for (py2 = 0; py2 < (int)height; py2++)\n            {\n               for (px2 = 0; px2 < cw; px2++)\n               {\n                  uint32_t L  = (px2 > 0)            ? pix[py2*cw+px2-1]     : 0xFF000000u;\n                  uint32_t T  = (py2 > 0)             ? pix[(py2-1)*cw+px2]   : 0xFF000000u;\n                  uint32_t TL = (px2>0 && py2>0)      ? pix[(py2-1)*cw+px2-1] : 0xFF000000u;\n                  uint32_t TR = (px2<cw-1 && py2>0)   ? pix[(py2-1)*cw+px2+1] : 0xFF000000u;\n                  int bx = px2 >> x->bits, by = py2 >> x->bits;\n                  int mode;\n                  if (bx >= bw) bx = bw - 1;\n                  mode = (td[by * bw + bx] >> 8) & 0xF;\n                  if (px2 == 0 && py2 == 0) mode = 0;\n                  else if (px2 == 0) mode = 2;\n                  else if (py2 == 0) mode = 1;\n                  pix[py2*cw+px2] = px_add(pix[py2*cw+px2], px_predict(mode, L, T, TL, TR));\n               }\n            }\n            break;\n         }\n         case XF_CCOL:\n         {\n            int bw = x->dw;\n            uint32_t *td = x->data;\n            int px2, py2;\n            for (py2 = 0; py2 < (int)height; py2++)\n            {\n               for (px2 = 0; px2 < cw; px2++)\n               {\n                  int bx = px2 >> x->bits, by = py2 >> x->bits;\n                  uint32_t td2, c2;\n                  int8_t g2r, g2b, r2b;\n                  int r, g, b2;\n                  if (bx >= bw) bx = bw - 1;\n                  td2 = td[by * bw + bx];\n                  g2r = (int8_t)((td2 >> 16) & 0xFF);\n                  g2b = (int8_t)((td2 >>  8) & 0xFF);\n                  r2b = (int8_t)(td2 & 0xFF);\n                  c2 = pix[py2 * cw + px2];\n                  g = (int)((c2 >> 8) & 0xFF);\n                  r = (int)((c2 >> 16) & 0xFF);\n                  b2 = (int)(c2 & 0xFF);\n                  r = (r + ((g2r * g) >> 5)) & 0xFF;\n                  b2 = (b2 + ((g2b * g) >> 5) + ((r2b * r) >> 5)) & 0xFF;\n                  pix[py2*cw+px2] = (c2 & 0xFF00FF00u) | ((uint32_t)r << 16) | (uint32_t)b2;\n               }\n            }\n            break;\n         }\n      }\n   }\n\n   for (i = 0; i < nxf; i++) free(xf[i].data);\n   *ow = width; *oh = height;\n   return pix;\nxfail:\n   free(pix);\n   for (i = 0; i < nxf; i++) free(xf[i].data);\n   return NULL;\n}\n\n/* ===== VP8 Lossy — full decode with coefficients ===== */\n\ntypedef struct { const uint8_t *buf, *end; uint32_t range; uint64_t value; int count; } vp8b;\n\nstatic void vp8b_fill(vp8b *b)\n{\n   int shift = 48 - b->count;\n   while (shift >= 0 && b->buf < b->end)\n   {\n      b->count += 8;\n      b->value |= (uint64_t)(*b->buf++) << shift;\n      shift -= 8;\n   }\n}\n\nstatic void vp8b_init(vp8b *b, const uint8_t *d, size_t s)\n{\n   b->buf = d; b->end = d + s; b->range = 255;\n   b->value = 0; b->count = -8;\n   vp8b_fill(b);\n}\n\nstatic INLINE int vp8b_get(vp8b *b, int prob)\n{\n   uint32_t split = 1 + (((b->range - 1) * (uint32_t)prob) >> 8);\n   uint64_t bigsplit = (uint64_t)split << 56;\n   int bit, shift;\n   if (b->value >= bigsplit)\n   {\n      bit = 1; b->range -= split; b->value -= bigsplit;\n   }\n   else\n   {\n      bit = 0; b->range = split;\n   }\n   shift = 0;\n   while (b->range < 128) { b->range <<= 1; shift++; }\n   b->value <<= shift;\n   b->count -= shift;\n   if (b->count < 0) vp8b_fill(b);\n   return bit;\n}\n\n\nstatic INLINE int     vp8b_bit(vp8b *b)       { return vp8b_get(b, 128); }\nstatic INLINE uint32_t vp8b_lit(vp8b *b, int n)\n{ uint32_t v = 0; int i; for (i = n-1; i >= 0; i--) v |= (uint32_t)vp8b_get(b,128) << i; return v; }\nstatic INLINE int32_t vp8b_sig(vp8b *b, int n)\n{ int32_t v = (int32_t)vp8b_lit(b,n); return vp8b_bit(b) ? -v : v; }\n\nstatic INLINE uint8_t vp8_cl(int v) { return (uint8_t)(v<0?0:v>255?255:v); }\n\nstatic void vp8_yuv2rgb(int y, int u, int v, uint8_t *r, uint8_t *g, uint8_t *bo)\n{\n   int c = y - 16, d = u - 128, e = v - 128;\n   *r  = vp8_cl((298*c + 409*e + 128) >> 8);\n   *g  = vp8_cl((298*c - 100*d - 208*e + 128) >> 8);\n   *bo = vp8_cl((298*c + 516*d + 128) >> 8);\n}\n\n/* Coefficient tables */\nstatic const uint8_t vp8_bands[16 + 1] = {0,1,2,3,6,4,5,6,6,6,6,6,6,6,6,7, 0};\nstatic const uint8_t vp8_zigzag[16] = {0,1,4,8,5,2,3,6,9,12,13,10,7,11,14,15};\n\nstatic const int16_t vp8_dc_qlut[128] = {\n   4,5,6,7,8,9,10,10,11,12,13,14,15,16,17,17,18,19,20,20,21,21,22,22,23,23,24,25,25,26,27,28,\n   29,30,31,32,33,34,35,36,37,37,38,39,40,41,42,43,44,45,46,46,47,48,49,50,51,52,53,54,55,56,57,58,\n   59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,76,77,78,79,80,81,82,83,84,85,86,87,88,89,\n   91,93,95,96,98,100,101,102,104,106,108,110,112,114,116,118,122,124,126,128,130,132,134,136,138,140,143,145,148,151,154,157};\nstatic const int16_t vp8_ac_qlut[128] = {\n   4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,\n   36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,62,64,66,68,70,72,74,76,\n   78,80,82,84,86,88,90,92,94,96,98,100,102,104,106,108,110,112,114,116,119,122,125,128,131,134,137,140,143,146,149,152,\n   155,158,161,164,167,170,173,177,181,185,189,193,197,201,205,209,213,217,221,225,229,234,239,245,249,254,259,264,269,274,279,284};\n\n/* Default coefficient probabilities — simplified: using a representative subset\n * that covers the most common cases in typical WebP images.\n * Full tables are 4*8*3*11 = 1056 bytes. We embed them directly. */\nstatic uint8_t vp8_cprob[4][8][3][11];\n\nstatic void vp8_init_default_cprob(void)\n{\n   static const uint8_t def[4][8][3][11] = {\n   {\n    {{128,128,128,128,128,128,128,128,128,128,128},{128,128,128,128,128,128,128,128,128,128,128},{128,128,128,128,128,128,128,128,128,128,128}},\n    {{253,136,254,255,228,219,128,128,128,128,128},{189,129,242,255,227,213,255,219,128,128,128},{106,126,227,252,214,209,255,255,128,128,128}},\n    {{1,98,248,255,236,226,255,255,128,128,128},{181,133,238,254,221,234,255,154,128,128,128},{78,134,202,247,198,180,255,219,128,128,128}},\n    {{1,185,249,255,243,255,128,128,128,128,128},{184,150,247,255,236,224,128,128,128,128,128},{77,110,216,255,236,230,128,128,128,128,128}},\n    {{1,101,251,255,241,255,128,128,128,128,128},{170,139,241,252,236,209,255,255,128,128,128},{37,116,196,243,228,255,255,255,128,128,128}},\n    {{1,204,254,255,245,255,128,128,128,128,128},{207,160,250,255,238,128,128,128,128,128,128},{102,103,231,255,211,171,128,128,128,128,128}},\n    {{1,152,252,255,240,255,128,128,128,128,128},{177,135,243,255,234,225,128,128,128,128,128},{80,129,211,255,194,224,128,128,128,128,128}},\n    {{1,1,255,128,128,128,128,128,128,128,128},{246,1,255,128,128,128,128,128,128,128,128},{255,128,128,128,128,128,128,128,128,128,128}},\n   },\n   {\n    {{198,35,237,223,193,187,162,160,145,155,62},{131,45,198,221,172,176,220,157,252,221,1},{68,47,146,208,149,167,221,162,255,223,128}},\n    {{1,149,241,255,221,224,255,255,128,128,128},{184,141,234,253,222,220,255,199,128,128,128},{81,99,181,242,176,190,249,202,255,255,128}},\n    {{1,129,232,253,214,197,242,196,255,255,128},{99,121,210,250,201,198,255,202,128,128,128},{23,91,163,242,170,187,247,210,255,255,128}},\n    {{1,200,246,255,234,255,128,128,128,128,128},{109,178,241,255,231,245,255,255,128,128,128},{44,130,201,253,205,192,255,255,128,128,128}},\n    {{1,132,239,251,219,209,255,165,128,128,128},{94,136,225,251,218,190,255,255,128,128,128},{22,100,174,245,186,161,255,199,128,128,128}},\n    {{1,182,249,255,232,235,128,128,128,128,128},{124,143,241,255,227,234,128,128,128,128,128},{35,77,181,251,193,211,255,205,128,128,128}},\n    {{1,157,247,255,236,231,255,255,128,128,128},{121,141,235,255,225,227,255,255,128,128,128},{45,99,188,251,195,217,255,224,128,128,128}},\n    {{1,1,251,255,213,255,128,128,128,128,128},{203,1,248,255,255,128,128,128,128,128,128},{137,1,177,255,224,255,128,128,128,128,128}},\n   },\n   {\n    {{253,9,248,251,207,208,255,192,128,128,128},{175,13,224,243,193,185,249,198,255,255,128},{73,17,171,221,161,179,236,167,255,234,128}},\n    {{1,95,247,253,212,183,255,255,128,128,128},{239,90,244,250,211,209,255,255,128,128,128},{155,77,195,248,188,195,255,255,128,128,128}},\n    {{1,24,239,251,218,219,255,205,128,128,128},{201,51,219,255,196,186,128,128,128,128,128},{69,46,190,239,201,218,255,228,128,128,128}},\n    {{1,191,251,255,255,128,128,128,128,128,128},{223,165,249,255,213,255,128,128,128,128,128},{141,124,248,255,255,128,128,128,128,128,128}},\n    {{1,16,248,255,255,128,128,128,128,128,128},{190,36,230,255,236,255,128,128,128,128,128},{149,1,255,128,128,128,128,128,128,128,128}},\n    {{1,226,255,128,128,128,128,128,128,128,128},{247,192,255,128,128,128,128,128,128,128,128},{240,128,255,128,128,128,128,128,128,128,128}},\n    {{1,134,252,255,255,128,128,128,128,128,128},{213,62,250,255,255,128,128,128,128,128,128},{55,93,255,128,128,128,128,128,128,128,128}},\n    {{128,128,128,128,128,128,128,128,128,128,128},{128,128,128,128,128,128,128,128,128,128,128},{128,128,128,128,128,128,128,128,128,128,128}},\n   },\n   {\n    {{202,24,213,235,186,191,220,160,240,175,255},{126,38,182,232,169,184,228,174,255,187,128},{61,46,138,219,151,178,240,170,255,216,128}},\n    {{1,112,230,250,199,191,247,159,255,255,128},{166,109,228,252,211,215,255,174,128,128,128},{39,77,162,232,172,180,245,178,255,255,128}},\n    {{1,52,220,246,198,199,249,220,255,255,128},{124,74,191,243,183,193,250,221,255,255,128},{24,71,130,219,154,170,243,182,255,255,128}},\n    {{1,182,225,249,219,240,255,224,128,128,128},{149,150,226,252,216,205,255,171,128,128,128},{28,108,170,242,183,194,254,223,255,255,128}},\n    {{1,81,230,252,204,203,255,192,128,128,128},{123,102,209,247,188,196,255,233,128,128,128},{20,95,153,243,164,173,255,203,128,128,128}},\n    {{1,222,248,255,216,213,128,128,128,128,128},{168,175,246,252,235,205,255,255,128,128,128},{47,116,215,255,211,212,255,255,128,128,128}},\n    {{1,121,236,253,212,214,255,255,128,128,128},{141,84,213,252,201,202,255,219,128,128,128},{42,80,160,240,162,185,255,205,128,128,128}},\n    {{1,1,255,128,128,128,128,128,128,128,128},{244,1,255,128,128,128,128,128,128,128,128},{238,1,255,128,128,128,128,128,128,128,128}},\n   },\n   };\n   memcpy(vp8_cprob, def, sizeof(def));\n}\n\n/* Decode one 4x4 block of DCT coefficients (matching libvpx GetCoeffs).\n * init_ctx: initial probability context from neighbor non-zero status\n * Returns the position of the last non-zero coeff + 1 (0 if all zero). */\nstatic int vp8_decode_block(vp8b *br, int16_t coeffs[16], int type,\n      uint8_t probs[8][3][11], int start_at, int init_ctx)\n{\n   static const uint8_t kCat3[] = {173,148,140};\n   static const uint8_t kCat4[] = {176,155,140,135};\n   static const uint8_t kCat5[] = {180,157,141,134,130};\n   static const uint8_t kCat6[] = {254,254,243,230,196,177,153,140,133,130,129};\n   int n = start_at;\n   const uint8_t *p = probs[n][init_ctx];\n   memset(coeffs, 0, 16 * sizeof(int16_t));\n\n   /* First \"CBP\" bit: EOB for entire block */\n   if (!vp8b_get(br, p[0]))\n      return 0;\n\n   for (;;)\n   {\n      int v;\n      ++n;\n      if (!vp8b_get(br, p[1]))\n      {\n         /* zero coefficient */\n         p = probs[vp8_bands[n]][0];\n      }\n      else\n      {\n         /* non-zero coefficient */\n         if (!vp8b_get(br, p[2]))\n         {\n            v = 1;\n            p = probs[vp8_bands[n]][1];\n         }\n         else\n         {\n            if (!vp8b_get(br, p[3]))\n            {\n               if (!vp8b_get(br, p[4]))\n                  v = 2;\n               else\n                  v = 3 + vp8b_get(br, p[5]);\n            }\n            else\n            {\n               if (!vp8b_get(br, p[6]))\n               {\n                  if (!vp8b_get(br, p[7]))\n                     v = 5 + vp8b_get(br, 159);\n                  else\n                  {\n                     v = 7 + 2 * vp8b_get(br, 165);\n                     v += vp8b_get(br, 145);\n                  }\n               }\n               else\n               {\n                  int bit1 = vp8b_get(br, p[8]);\n                  int bit0 = vp8b_get(br, p[9 + bit1]);\n                  int cat = 2 * bit1 + bit0, k;\n                  v = 0;\n                  if (cat == 0) { for(k=0;k<3;k++) v = v*2 + vp8b_get(br, kCat3[k]); v += 11; }\n                  else if (cat == 1) { for(k=0;k<4;k++) v = v*2 + vp8b_get(br, kCat4[k]); v += 19; }\n                  else if (cat == 2) { for(k=0;k<5;k++) v = v*2 + vp8b_get(br, kCat5[k]); v += 35; }\n                  else { for(k=0;k<11;k++) v = v*2 + vp8b_get(br, kCat6[k]); v += 67; }\n               }\n            }\n            p = probs[vp8_bands[n]][2];\n         }\n         /* Sign bit and store */\n         coeffs[vp8_zigzag[n-1]] = (int16_t)(vp8b_get(br, 128) ? -v : v);\n\n         if (n == 16 || !vp8b_get(br, p[0])) /* EOB */\n            return n;\n      }\n      if (n == 16)\n         return 16;\n   }\n}\n\n/* VP8 4x4 inverse DCT (from RFC 6386 §14.3) */\nstatic void vp8_idct4x4_add(const int16_t in[16], uint8_t *dst, int stride)\n{\n   int i, tmp[16];\n   for (i = 0; i < 4; i++)\n   {\n      int a = in[i*4+0] + in[i*4+2];\n      int b = in[i*4+0] - in[i*4+2];\n      int c = (in[i*4+1] * 35468 >> 16) - (in[i*4+3] + (in[i*4+3] * 20091 >> 16));\n      int d = (in[i*4+1] + (in[i*4+1] * 20091 >> 16)) + (in[i*4+3] * 35468 >> 16);\n      tmp[i*4+0] = a + d; tmp[i*4+1] = b + c;\n      tmp[i*4+2] = b - c; tmp[i*4+3] = a - d;\n   }\n   for (i = 0; i < 4; i++)\n   {\n      int a = tmp[i] + tmp[8+i];\n      int b = tmp[i] - tmp[8+i];\n      int c = (tmp[4+i] * 35468 >> 16) - (tmp[12+i] + (tmp[12+i] * 20091 >> 16));\n      int d = (tmp[4+i] + (tmp[4+i] * 20091 >> 16)) + (tmp[12+i] * 35468 >> 16);\n      dst[0*stride+i] = vp8_cl(dst[0*stride+i] + ((a+d+4) >> 3));\n      dst[1*stride+i] = vp8_cl(dst[1*stride+i] + ((b+c+4) >> 3));\n      dst[2*stride+i] = vp8_cl(dst[2*stride+i] + ((b-c+4) >> 3));\n      dst[3*stride+i] = vp8_cl(dst[3*stride+i] + ((a-d+4) >> 3));\n   }\n}\n\n/* Inverse Walsh-Hadamard Transform for Y2 DC block.\n * Output goes directly as DC coefficients to the 4x4 IDCT,\n * so NO >>3 normalization here (IDCT applies its own). */\nstatic void vp8_iwht4x4(const int16_t in[16], int16_t out[16])\n{\n   int i, tmp[16];\n   for (i = 0; i < 4; i++)\n   {\n      int a = in[i*4+0]+in[i*4+3], b = in[i*4+1]+in[i*4+2];\n      int c = in[i*4+1]-in[i*4+2], d = in[i*4+0]-in[i*4+3];\n      tmp[i*4+0]=a+b; tmp[i*4+1]=c+d; tmp[i*4+2]=a-b; tmp[i*4+3]=d-c;\n   }\n   for (i = 0; i < 4; i++)\n   {\n      int a = tmp[i]+tmp[12+i], b = tmp[4+i]+tmp[8+i];\n      int c = tmp[4+i]-tmp[8+i], d = tmp[i]-tmp[12+i];\n      out[i]=(int16_t)(a+b); out[4+i]=(int16_t)(c+d);\n      out[8+i]=(int16_t)(a-b); out[12+i]=(int16_t)(d-c);\n   }\n}\n\nstatic const uint8_t vp8_ymp[4] = {145,156,163,128};\nstatic const uint8_t vp8_uvmp[3] = {142,114,183};\n\n/* Key-frame B_PRED sub-block mode probabilities (RFC 6386 §12.1)\n * Indexed by [above_bmode][left_bmode][tree_node 0..8] */\nstatic const uint8_t kf_bmode_prob[10][10][9] = {\n {{231,120,48,89,115,113,120,152,112},{152,179,64,126,170,118,46,70,95},{175,69,143,80,85,82,72,155,103},{56,58,10,171,218,189,17,13,152},{144,71,10,38,171,213,144,34,26},{114,26,17,163,44,195,21,10,173},{121,24,80,195,26,62,44,64,85},{170,46,55,19,136,160,33,206,71},{63,20,8,114,114,208,12,9,226},{81,40,11,96,182,84,29,16,36}},\n {{134,183,89,137,98,101,106,165,148},{72,187,100,130,157,111,32,75,80},{66,102,167,99,74,62,40,234,128},{41,53,9,178,241,141,26,8,107},{104,79,12,27,217,255,87,17,7},{74,43,26,146,73,166,49,23,157},{65,38,105,160,51,52,31,115,128},{87,68,71,44,114,51,15,186,23},{47,41,14,110,182,183,21,17,194},{66,45,25,102,197,189,23,18,22}},\n {{88,88,147,150,42,46,45,196,205},{43,97,183,117,85,38,35,179,61},{39,53,200,87,26,21,43,232,171},{56,34,51,104,114,102,29,93,77},{107,54,32,26,51,1,81,43,31},{39,28,85,171,58,165,90,98,64},{34,22,116,206,23,34,43,166,73},{68,25,106,22,64,171,36,225,114},{34,19,21,102,132,188,16,76,124},{62,18,78,95,85,57,50,48,51}},\n {{193,101,35,159,215,111,89,46,111},{60,148,31,172,219,228,21,18,111},{112,113,77,85,179,255,38,120,114},{40,42,1,196,245,209,10,25,109},{100,80,8,43,154,1,51,26,71},{88,43,29,140,166,213,37,43,154},{61,63,30,155,67,45,68,1,209},{142,78,78,16,255,128,34,197,171},{41,40,5,102,211,183,4,1,221},{51,50,17,168,209,192,23,25,82}},\n {{125,98,42,88,104,85,117,175,82},{95,84,53,89,128,100,113,101,45},{75,79,123,47,51,128,81,171,1},{57,17,5,71,102,57,53,41,49},{115,21,2,10,102,255,166,23,6},{38,33,13,121,57,73,26,1,85},{41,10,67,138,77,110,90,47,114},{101,29,16,10,85,128,101,196,26},{57,18,10,102,102,213,34,20,43},{117,20,15,36,163,128,68,1,26}},\n {{138,31,36,171,27,166,38,44,229},{67,87,58,169,82,115,26,59,179},{63,59,90,180,59,166,93,73,154},{40,40,21,116,143,209,34,39,175},{57,46,22,24,128,1,54,17,37},{47,15,16,183,34,223,49,45,183},{46,17,33,183,6,98,15,32,183},{65,32,73,115,28,128,23,128,205},{40,3,9,115,51,192,18,6,223},{87,37,9,115,59,77,64,21,47}},\n {{104,55,44,218,9,54,53,130,226},{64,90,70,205,40,41,23,26,57},{54,57,112,184,5,41,38,166,213},{30,34,26,133,152,116,10,32,134},{75,32,12,51,192,255,160,43,51},{39,19,53,221,26,114,32,73,255},{31,9,65,234,2,15,1,118,73},{88,31,35,67,102,85,55,186,85},{56,21,23,111,59,205,45,37,192},{55,38,70,124,73,102,1,34,98}},\n {{102,61,71,37,34,53,31,243,192},{69,60,71,38,73,119,28,222,37},{68,45,128,34,1,47,11,245,171},{62,17,19,70,146,85,55,62,70},{75,15,9,9,64,255,184,119,16},{37,43,37,154,100,163,85,160,1},{63,9,92,136,28,64,32,201,85},{86,6,28,5,64,255,25,248,1},{56,8,17,132,137,255,55,116,128},{58,15,20,82,135,57,26,121,40}},\n {{164,50,31,137,154,133,25,35,218},{51,103,44,131,131,123,31,6,158},{86,40,64,135,148,224,45,183,128},{22,26,17,131,240,154,14,1,209},{83,12,13,54,192,255,68,47,28},{45,16,21,91,64,222,7,1,197},{56,21,39,155,60,138,23,102,213},{85,26,85,85,128,128,32,146,171},{18,11,7,63,144,171,4,4,246},{35,27,10,146,174,171,12,26,128}},\n {{190,80,35,99,180,80,126,54,45},{85,126,47,87,176,51,41,20,32},{101,75,128,139,118,146,116,128,85},{56,41,15,176,236,85,37,9,62},{146,36,19,30,171,255,97,27,20},{71,30,17,119,118,255,17,18,138},{101,38,60,138,55,70,43,26,142},{138,45,61,62,219,1,81,188,64},{32,41,20,117,151,142,20,21,163},{112,19,12,61,195,128,48,4,24}}\n};\n\n/* Decode a B_PRED sub-block mode from the key-frame tree (RFC 6386 §12.1) */\nstatic int vp8_read_bmode(vp8b *br, int above, int left)\n{\n   const uint8_t *p = kf_bmode_prob[above][left];\n   if (!vp8b_get(br, p[0])) return 0; /* B_DC_PRED */\n   if (!vp8b_get(br, p[1])) return 1; /* B_TM_PRED */\n   if (!vp8b_get(br, p[2])) return 2; /* B_VE_PRED */\n   if (!vp8b_get(br, p[3])) {\n      if (!vp8b_get(br, p[4])) return 3; /* B_HE_PRED */\n      if (!vp8b_get(br, p[5])) return 5; /* B_LD_PRED */\n      return 6; /* B_RD_PRED */\n   } else {\n      if (!vp8b_get(br, p[6])) return 4; /* B_VR_PRED */\n      if (!vp8b_get(br, p[7])) return 7; /* B_VL_PRED */\n      if (!vp8b_get(br, p[8])) return 8; /* B_HD_PRED */\n      return 9; /* B_HU_PRED */\n   }\n}\n\n/* 4x4 sub-block intra prediction for B_PRED.\n * dst: output 4x4 block, stride s.\n * a[0..7]: 8 above pixels (a[0..3]=directly above, a[4..7]=above-right)\n * l[0..3]: left pixels, tl: top-left pixel */\nstatic void vp8_pred4x4(uint8_t *d, int s, int m,\n      const uint8_t *a, const uint8_t *l, uint8_t tl)\n{\n   int i, j;\n   switch (m)\n   {\n   case 0: /* B_DC_PRED */\n   {  int sum=0;\n      for(i=0;i<4;i++) sum+=a[i]+l[i];\n      { uint8_t dc=(uint8_t)((sum+4)>>3);\n        for(j=0;j<4;j++) memset(d+j*s,dc,4); }\n      break;\n   }\n   case 1: /* B_TM_PRED */\n      for(j=0;j<4;j++) for(i=0;i<4;i++)\n         d[j*s+i]=vp8_cl((int)a[i]+(int)l[j]-(int)tl);\n      break;\n   case 2: /* B_VE_PRED (vertical/above with smoothing) */\n      for(i=0;i<4;i++) {\n         int v = (i==0) ? (tl+2*a[0]+a[1]+2)>>2 : (a[i-1]+2*a[i]+a[i+1]+2)>>2;\n         for(j=0;j<4;j++) d[j*s+i]=(uint8_t)v;\n      }\n      break;\n   case 3: /* B_HE_PRED (horizontal/left with smoothing) */\n      for(j=0;j<4;j++) {\n         int v = (j==0) ? (tl+2*l[0]+l[1]+2)>>2 : (j==3) ? (l[2]+3*l[3]+2)>>2 : (l[j-1]+2*l[j]+l[j+1]+2)>>2;\n         memset(d+j*s,(uint8_t)v,4);\n      }\n      break;\n   case 4: /* B_VR_PRED */\n      d[3*s+0]=(uint8_t)((l[2]+2*l[1]+l[0]+2)>>2);\n      d[2*s+0]=(uint8_t)((l[1]+2*l[0]+tl+2)>>2);\n      d[1*s+0]=d[3*s+1]=(uint8_t)((l[0]+2*tl+a[0]+2)>>2);\n      d[0*s+0]=d[2*s+1]=(uint8_t)((tl+a[0]+1)>>1);\n      d[0*s+1]=d[2*s+2]=(uint8_t)((a[0]+a[1]+1)>>1);\n      d[1*s+1]=d[3*s+2]=(uint8_t)((tl+2*a[0]+a[1]+2)>>2);\n      d[0*s+2]=d[2*s+3]=(uint8_t)((a[1]+a[2]+1)>>1);\n      d[1*s+2]=d[3*s+3]=(uint8_t)((a[0]+2*a[1]+a[2]+2)>>2);\n      d[0*s+3]=(uint8_t)((a[2]+a[3]+1)>>1);\n      d[1*s+3]=(uint8_t)((a[1]+2*a[2]+a[3]+2)>>2);\n      break;\n   case 5: /* B_LD_PRED */\n      d[0*s+0]=(uint8_t)((a[0]+2*a[1]+a[2]+2)>>2);\n      d[0*s+1]=d[1*s+0]=(uint8_t)((a[1]+2*a[2]+a[3]+2)>>2);\n      d[0*s+2]=d[1*s+1]=d[2*s+0]=(uint8_t)((a[2]+2*a[3]+a[4]+2)>>2);\n      d[0*s+3]=d[1*s+2]=d[2*s+1]=d[3*s+0]=(uint8_t)((a[3]+2*a[4]+a[5]+2)>>2);\n      d[1*s+3]=d[2*s+2]=d[3*s+1]=(uint8_t)((a[4]+2*a[5]+a[6]+2)>>2);\n      d[2*s+3]=d[3*s+2]=(uint8_t)((a[5]+2*a[6]+a[7]+2)>>2);\n      d[3*s+3]=(uint8_t)((a[6]+2*a[7]+a[7]+2)>>2);\n      break;\n   case 6: /* B_RD_PRED */\n      d[3*s+0]=(uint8_t)((l[3]+2*l[2]+l[1]+2)>>2);\n      d[2*s+0]=d[3*s+1]=(uint8_t)((l[2]+2*l[1]+l[0]+2)>>2);\n      d[1*s+0]=d[2*s+1]=d[3*s+2]=(uint8_t)((l[1]+2*l[0]+tl+2)>>2);\n      d[0*s+0]=d[1*s+1]=d[2*s+2]=d[3*s+3]=(uint8_t)((l[0]+2*tl+a[0]+2)>>2);\n      d[0*s+1]=d[1*s+2]=d[2*s+3]=(uint8_t)((tl+2*a[0]+a[1]+2)>>2);\n      d[0*s+2]=d[1*s+3]=(uint8_t)((a[0]+2*a[1]+a[2]+2)>>2);\n      d[0*s+3]=(uint8_t)((a[1]+2*a[2]+a[3]+2)>>2);\n      break;\n   case 7: /* B_VL_PRED */\n      d[0*s+0]=(uint8_t)((a[0]+a[1]+1)>>1); d[1*s+0]=(uint8_t)((a[0]+2*a[1]+a[2]+2)>>2);\n      d[0*s+1]=d[2*s+0]=(uint8_t)((a[1]+a[2]+1)>>1); d[1*s+1]=d[3*s+0]=(uint8_t)((a[1]+2*a[2]+a[3]+2)>>2);\n      d[0*s+2]=d[2*s+1]=(uint8_t)((a[2]+a[3]+1)>>1); d[1*s+2]=d[3*s+1]=(uint8_t)((a[2]+2*a[3]+a[4]+2)>>2);\n      d[0*s+3]=d[2*s+2]=(uint8_t)((a[3]+a[4]+1)>>1); d[1*s+3]=d[3*s+2]=(uint8_t)((a[3]+2*a[4]+a[5]+2)>>2);\n      d[2*s+3]=(uint8_t)((a[4]+a[5]+1)>>1); d[3*s+3]=(uint8_t)((a[4]+2*a[5]+a[6]+2)>>2);\n      break;\n   case 8: /* B_HD_PRED */\n      d[3*s+0]=(uint8_t)((l[3]+l[2]+1)>>1); d[3*s+1]=(uint8_t)((l[3]+2*l[2]+l[1]+2)>>2);\n      d[2*s+0]=d[3*s+2]=(uint8_t)((l[2]+l[1]+1)>>1); d[2*s+1]=d[3*s+3]=(uint8_t)((l[2]+2*l[1]+l[0]+2)>>2);\n      d[1*s+0]=d[2*s+2]=(uint8_t)((l[1]+l[0]+1)>>1); d[1*s+1]=d[2*s+3]=(uint8_t)((l[1]+2*l[0]+tl+2)>>2);\n      d[0*s+0]=d[1*s+2]=(uint8_t)((l[0]+tl+1)>>1); d[0*s+1]=d[1*s+3]=(uint8_t)((l[0]+2*tl+a[0]+2)>>2);\n      d[0*s+2]=(uint8_t)((tl+2*a[0]+a[1]+2)>>2); d[0*s+3]=(uint8_t)((a[0]+2*a[1]+a[2]+2)>>2);\n      break;\n   case 9: /* B_HU_PRED */\n      d[0*s+0]=(uint8_t)((l[0]+l[1]+1)>>1); d[0*s+1]=(uint8_t)((l[0]+2*l[1]+l[2]+2)>>2);\n      d[0*s+2]=d[1*s+0]=(uint8_t)((l[1]+l[2]+1)>>1); d[0*s+3]=d[1*s+1]=(uint8_t)((l[1]+2*l[2]+l[3]+2)>>2);\n      d[1*s+2]=d[2*s+0]=(uint8_t)((l[2]+l[3]+1)>>1); d[1*s+3]=d[2*s+1]=(uint8_t)((l[2]+2*l[3]+l[3]+2)>>2);\n      d[2*s+2]=d[2*s+3]=d[3*s+0]=d[3*s+1]=d[3*s+2]=d[3*s+3]=(uint8_t)l[3];\n      break;\n   default:\n   {  int sum=0; for(i=0;i<4;i++) sum+=a[i]+l[i];\n      { uint8_t dc=(uint8_t)((sum+4)>>3); for(j=0;j<4;j++) memset(d+j*s,dc,4); } break; }\n   }\n}\n\n\n/* VP8 Simple Loop Filter (RFC 6386 §15.2) */\nstatic INLINE int vp8_sc(int v) { return v < -128 ? -128 : v > 127 ? 127 : v; }\n\nstatic void vp8_simple_filter(uint8_t *p, int stride, int count, int flimit)\n{\n   int i;\n   for (i = 0; i < count; i++)\n   {\n      int p1 = p[-2*stride], p0 = p[-1*stride], q0 = p[0], q1 = p[stride];\n      int a = vp8_sc(vp8_sc(3 * (q0 - p0) + vp8_sc(p1 - q1)) + 4) >> 3;\n      p[-1*stride] = vp8_cl(p0 + a);\n      p[0]         = vp8_cl(q0 - a);\n      p++;\n   }\n}\n\nstatic void vp8_loop_filter_simple(uint8_t *y, int ys, uint8_t *u, int uvs, uint8_t *v_plane,\n   int mbw, int mbh, int lf_level, int sharpness,\n   int seg_enabled, int seg_abs, const int *seg_lf, const uint8_t *seg_map)\n{\n   int mx, my, by, bx;\n   for (my = 0; my < mbh; my++)\n   {\n      for (mx = 0; mx < mbw; mx++)\n      {\n         int mb_lf = lf_level;\n         int seg_id = seg_map ? seg_map[my * mbw + mx] : 0;\n         int flimit;\n         if (seg_enabled && seg_abs)\n            mb_lf = seg_lf[seg_id];\n         else if (seg_enabled)\n            mb_lf = lf_level + seg_lf[seg_id];\n         if (mb_lf < 0) mb_lf = 0;\n         if (mb_lf > 63) mb_lf = 63;\n         if (mb_lf == 0) continue;\n         flimit = 2 * mb_lf + (sharpness > 0 ? (sharpness > 4 ? 2 : 1) : 0);\n         if (flimit > 63) flimit = 63;\n         /* Y: left MB edge only */\n         if (mx > 0) {\n            for (by = 0; by < 16; by++) {\n               uint8_t *row = y + (my*16+by)*ys + mx*16;\n               int p1=row[-2],p0=row[-1],q0=row[0],q1=row[1];\n               int a=vp8_sc(3*(q0-p0)+vp8_sc(p1-q1));\n               if ((a<0?-a:a)<=flimit) { int f=vp8_sc(a+4)>>3; row[-1]=vp8_cl(p0+f); row[0]=vp8_cl(q0-f); }\n            }\n         }\n         /* Y: top MB edge only */\n         if (my > 0) {\n            for (bx = 0; bx < 16; bx++) {\n               uint8_t *col = y + my*16*ys + mx*16 + bx;\n               int p1=col[-2*ys],p0=col[-ys],q0=col[0],q1=col[ys];\n               int a=vp8_sc(3*(q0-p0)+vp8_sc(p1-q1));\n               if ((a<0?-a:a)<=flimit) { int f=vp8_sc(a+4)>>3; col[-ys]=vp8_cl(p0+f); col[0]=vp8_cl(q0-f); }\n            }\n         }\n      }\n   }\n}\n\nstatic void vp8_pred16(uint8_t *d, int s, int m, const uint8_t *a, const uint8_t *l, uint8_t tl)\n{\n   int i, j;\n   switch (m) {\n   case 0: { int sum=0; for(i=0;i<16;i++) sum+=a[i]+l[i];\n             { uint8_t dc=(uint8_t)((sum+16)>>5); for(j=0;j<16;j++) memset(d+j*s,dc,16); } break; }\n   case 1: for(j=0;j<16;j++) memcpy(d+j*s,a,16); break;\n   case 2: for(j=0;j<16;j++) memset(d+j*s,l[j],16); break;\n   case 3: for(j=0;j<16;j++) for(i=0;i<16;i++) d[j*s+i]=vp8_cl((int)a[i]+(int)l[j]-(int)tl); break;\n   }\n}\n\nstatic void vp8_pred8(uint8_t *d, int s, int m, const uint8_t *a, const uint8_t *l, uint8_t tl)\n{\n   int i, j;\n   switch (m) {\n   case 0: { int sum=0; for(i=0;i<8;i++) sum+=a[i]+l[i];\n             { uint8_t dc=(uint8_t)((sum+8)>>4); for(j=0;j<8;j++) memset(d+j*s,dc,8); } break; }\n   case 1: for(j=0;j<8;j++) memcpy(d+j*s,a,8); break;\n   case 2: for(j=0;j<8;j++) memset(d+j*s,l[j],8); break;\n   case 3: for(j=0;j<8;j++) for(i=0;i<8;i++) d[j*s+i]=vp8_cl((int)a[i]+(int)l[j]-(int)tl); break;\n   }\n}\n\nstatic uint32_t *vp8_decode(const uint8_t *data, size_t len,\n      unsigned *ow, unsigned *oh)\n{\n   uint32_t ft;\n   int kf, w, h, mbw, mbh, ys, uvs, mx, my, i, j;\n   uint32_t p0s;\n   int base_qp, y1dc_dq, y2dc_dq, y2ac_dq, uvdc_dq, uvac_dq;\n   int qp, y1_dc_q, y1_ac_q, y2_dc_q, y2_ac_q, uv_dc_q, uv_ac_q;\n   int skip_enabled, prob_skip, log2parts, num_parts;\n   int filter_type, lf_level, sharpness;\n   int seg_enabled, seg_abs, seg_qp[4], seg_lf[4], seg_prob[3];\n   vp8b br;\n   vp8b tbr[8]; /* up to 8 token partitions */\n   const uint8_t *p0;\n   uint8_t *yb = NULL, *ub = NULL, *vb = NULL;\n   uint32_t *pix = NULL;\n\n   if (len < 10) return NULL;\n   ft = (uint32_t)data[0] | ((uint32_t)data[1]<<8) | ((uint32_t)data[2]<<16);\n   kf = !(ft & 1);\n   p0s = (ft >> 5) & 0x7FFFF;\n   if (!kf) return NULL;\n   if (data[3]!=0x9D || data[4]!=0x01 || data[5]!=0x2A) return NULL;\n   w = (data[6]|(data[7]<<8)) & 0x3FFF;\n   h = (data[8]|(data[9]<<8)) & 0x3FFF;\n   if (!w || !h || w > 16384 || h > 16384) return NULL;\n   mbw = (w+15) >> 4; mbh = (h+15) >> 4;\n   p0 = data + 10;\n   if ((size_t)(p0 - data) + p0s > len) return NULL;\n   vp8b_init(&br, p0, (size_t)(data + len - p0));\n\n   vp8b_bit(&br); vp8b_bit(&br); /* color_space, clamping */\n\n   /* Segmentation */\n   seg_enabled = vp8b_bit(&br);\n   seg_abs = 0;\n   seg_qp[0] = seg_qp[1] = seg_qp[2] = seg_qp[3] = 0;\n   seg_prob[0] = seg_prob[1] = seg_prob[2] = 255;\n   seg_lf[0] = seg_lf[1] = seg_lf[2] = seg_lf[3] = 0;\n   if (seg_enabled)\n   {\n      int um = vp8b_bit(&br), ud = vp8b_bit(&br);\n      if (ud) {\n         seg_abs = vp8b_bit(&br);\n         for (i=0;i<4;i++) seg_qp[i] = vp8b_bit(&br) ? vp8b_sig(&br,7) : 0;\n         for (i=0;i<4;i++) seg_lf[i] = vp8b_bit(&br) ? vp8b_sig(&br,6) : 0;\n      }\n      if (um) for (i=0;i<3;i++) { if (vp8b_bit(&br)) seg_prob[i] = (int)vp8b_lit(&br,8); }\n   }\n\n   filter_type = vp8b_bit(&br); lf_level = (int)vp8b_lit(&br,6); sharpness = (int)vp8b_lit(&br,3);\n   { int mrd = vp8b_bit(&br);\n     if (mrd && vp8b_bit(&br))\n     { for(i=0;i<4;i++) if(vp8b_bit(&br)) vp8b_sig(&br,6);\n       for(i=0;i<4;i++) if(vp8b_bit(&br)) vp8b_sig(&br,6); } }\n   log2parts = vp8b_lit(&br,2);\n   num_parts = 1 << log2parts;\n\n   /* Quantizer */\n   base_qp = vp8b_lit(&br,7);\n   y1dc_dq = vp8b_bit(&br) ? vp8b_sig(&br,4) : 0;\n   y2dc_dq = vp8b_bit(&br) ? vp8b_sig(&br,4) : 0;\n   y2ac_dq = vp8b_bit(&br) ? vp8b_sig(&br,4) : 0;\n   uvdc_dq = vp8b_bit(&br) ? vp8b_sig(&br,4) : 0;\n   uvac_dq = vp8b_bit(&br) ? vp8b_sig(&br,4) : 0;\n\n   /* refresh_entropy_probs (RFC 6386) */\n   (void)vp8b_bit(&br);\n\n   /* We'll compute per-MB quantizer in the loop using segment info */\n   qp = base_qp < 0 ? 0 : (base_qp > 127 ? 127 : base_qp);\n   { int q2 = qp + y1dc_dq; y1_dc_q = vp8_dc_qlut[q2<0?0:q2>127?127:q2]; }\n   y1_ac_q = vp8_ac_qlut[qp];\n   { int q2 = qp + y2dc_dq; y2_dc_q = vp8_dc_qlut[q2<0?0:q2>127?127:q2]; }\n   { int q2 = qp + y2ac_dq; y2_ac_q = vp8_ac_qlut[q2<0?0:q2>127?127:q2]; }\n   { int q2 = qp + uvdc_dq; uv_dc_q = vp8_dc_qlut[q2<0?0:q2>127?127:q2]; if(uv_dc_q>132)uv_dc_q=132; }\n   { int q2 = qp + uvac_dq; uv_ac_q = vp8_ac_qlut[q2<0?0:q2>127?127:q2]; }\n\n   /* Initialize coefficient probabilities */\n   vp8_init_default_cprob();\n\n   /* Read coefficient probability updates using the fixed update probabilities\n    * defined in RFC 6386 §13.4 (Table 2). Each prob may be updated if a flag\n    * is read with the corresponding update probability. */\n   {\n      static const uint8_t cup[4][8][3][11] = {\n      {{{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{176,246,255,255,255,255,255,255,255,255,255},{223,241,252,255,255,255,255,255,255,255,255},{249,253,253,255,255,255,255,255,255,255,255}},\n       {{255,244,252,255,255,255,255,255,255,255,255},{234,254,254,255,255,255,255,255,255,255,255},{253,255,255,255,255,255,255,255,255,255,255}},\n       {{255,246,254,255,255,255,255,255,255,255,255},{239,253,254,255,255,255,255,255,255,255,255},{254,255,254,255,255,255,255,255,255,255,255}},\n       {{255,248,254,255,255,255,255,255,255,255,255},{251,255,254,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,253,254,255,255,255,255,255,255,255,255},{251,254,254,255,255,255,255,255,255,255,255},{254,255,254,255,255,255,255,255,255,255,255}},\n       {{255,254,253,255,254,255,255,255,255,255,255},{250,255,254,255,254,255,255,255,255,255,255},{254,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}}},\n      {{{217,255,255,255,255,255,255,255,255,255,255},{225,252,241,253,255,255,254,255,255,255,255},{234,250,241,250,253,255,253,254,255,255,255}},\n       {{255,254,255,255,255,255,255,255,255,255,255},{223,254,254,255,255,255,255,255,255,255,255},{238,253,254,254,255,255,255,255,255,255,255}},\n       {{255,248,254,255,255,255,255,255,255,255,255},{249,254,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,253,255,255,255,255,255,255,255,255,255},{247,254,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,253,254,255,255,255,255,255,255,255,255},{252,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,254,254,255,255,255,255,255,255,255,255},{253,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,254,253,255,255,255,255,255,255,255,255},{250,255,255,255,255,255,255,255,255,255,255},{254,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}}},\n      {{{186,251,250,255,255,255,255,255,255,255,255},{234,251,244,254,255,255,255,255,255,255,255},{251,251,243,253,254,255,254,255,255,255,255}},\n       {{255,253,254,255,255,255,255,255,255,255,255},{236,253,254,255,255,255,255,255,255,255,255},{251,253,253,254,254,255,255,255,255,255,255}},\n       {{255,254,254,255,255,255,255,255,255,255,255},{254,254,254,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,254,255,255,255,255,255,255,255,255,255},{254,254,255,255,255,255,255,255,255,255,255},{254,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{254,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}}},\n      {{{248,255,255,255,255,255,255,255,255,255,255},{250,254,252,254,255,255,255,255,255,255,255},{248,254,249,253,255,255,255,255,255,255,255}},\n       {{255,253,253,255,255,255,255,255,255,255,255},{246,253,253,255,255,255,255,255,255,255,255},{252,254,251,254,254,255,255,255,255,255,255}},\n       {{255,254,252,255,255,255,255,255,255,255,255},{248,254,253,255,255,255,255,255,255,255,255},{253,255,254,254,255,255,255,255,255,255,255}},\n       {{255,251,254,255,255,255,255,255,255,255,255},{245,251,254,255,255,255,255,255,255,255,255},{253,253,254,255,255,255,255,255,255,255,255}},\n       {{255,251,253,255,255,255,255,255,255,255,255},{252,253,254,255,255,255,255,255,255,255,255},{255,254,255,255,255,255,255,255,255,255,255}},\n       {{255,252,255,255,255,255,255,255,255,255,255},{249,255,254,255,255,255,255,255,255,255,255},{255,255,254,255,255,255,255,255,255,255,255}},\n       {{255,255,253,255,255,255,255,255,255,255,255},{250,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}},\n       {{255,255,255,255,255,255,255,255,255,255,255},{254,255,255,255,255,255,255,255,255,255,255},{255,255,255,255,255,255,255,255,255,255,255}}}\n      };\n      int t, b, c, p;\n      for (t = 0; t < 4; t++)\n         for (b = 0; b < 8; b++)\n            for (c = 0; c < 3; c++)\n               for (p = 0; p < 11; p++)\n                  if (vp8b_get(&br, cup[t][b][c][p]))\n                     vp8_cprob[t][b][c][p] = (uint8_t)vp8b_lit(&br, 8);\n   }\n\n   /* Dump some probs */\n   skip_enabled = vp8b_bit(&br);\n   prob_skip = skip_enabled ? (int)vp8b_lit(&br, 8) : 0;\n\n   /* Initialize token partitions */\n   {\n      const uint8_t *tp_base = p0 + p0s;\n      const uint8_t *tp_sizes = tp_base; /* partition size bytes */\n      const uint8_t *tp_data;\n      size_t part_sizes[8];\n      int np;\n\n      if (num_parts > 8) num_parts = 8;\n      /* Read partition sizes: (num_parts - 1) * 3 bytes, little-endian 24-bit each */\n      tp_data = tp_base + 3 * (num_parts - 1);\n      for (np = 0; np < num_parts - 1; np++)\n      {\n         part_sizes[np] = (size_t)tp_sizes[np*3]\n                        | ((size_t)tp_sizes[np*3+1] << 8)\n                        | ((size_t)tp_sizes[np*3+2] << 16);\n      }\n      /* Last partition gets the remainder */\n      {\n         size_t used = 0;\n         for (np = 0; np < num_parts - 1; np++) used += part_sizes[np];\n         part_sizes[num_parts - 1] = (data + len) - tp_data - used;\n      }\n      /* Initialize each partition's bool decoder */\n      for (np = 0; np < num_parts; np++)\n      {\n         if (tp_data + part_sizes[np] > data + len)\n            part_sizes[np] = (data + len) - tp_data;\n         vp8b_init(&tbr[np], tp_data, part_sizes[np]);\n         tp_data += part_sizes[np];\n      }\n   }\n\n   uint8_t *seg_map_buf = NULL;\n   ys = mbw * 16; uvs = mbw * 8;\n   seg_map_buf = (uint8_t*)calloc(mbw * mbh, 1);\n   yb = (uint8_t*)calloc(ys * mbh * 16, 1);\n   ub = (uint8_t*)calloc(uvs * mbh * 8, 1);\n   vb = (uint8_t*)calloc(uvs * mbh * 8, 1);\n   if (!yb || !ub || !vb) goto lfail;\n   memset(yb, 127, ys * mbh * 16);\n   memset(ub, 127, uvs * mbh * 8);\n   memset(vb, 127, uvs * mbh * 8);\n\n   /* Non-zero coefficient context tracking (RFC 6386 §13.3).\n    * above_nz_*: one entry per sub-block column across the MB row.\n    * left_nz_*: one entry per sub-block row within current MB. */\n   {\n      uint8_t *above_nz_y  = (uint8_t*)calloc(mbw * 4, 1); /* 4 Y sub-block cols per MB */\n      uint8_t *above_nz_u  = (uint8_t*)calloc(mbw * 2, 1); /* 2 U sub-block cols per MB */\n      uint8_t *above_nz_v  = (uint8_t*)calloc(mbw * 2, 1);\n      uint8_t *above_nz_dc = (uint8_t*)calloc(mbw, 1);     /* Y2 DC block */\n      uint8_t *above_bmodes = (uint8_t*)calloc(mbw * 4, 1); /* B_PRED sub-block modes */\n      uint8_t left_nz_y[4], left_nz_u[2], left_nz_v[2];\n      uint8_t left_bmodes[4];\n      int left_nz_dc;\n\n      if (!above_nz_y || !above_nz_u || !above_nz_v || !above_nz_dc || !above_bmodes)\n      { free(above_nz_y); free(above_nz_u); free(above_nz_v); free(above_nz_dc); free(above_bmodes); goto lfail; }\n\n   for (my = 0; my < mbh; my++)\n   {\n      vp8b *tp = &tbr[my % num_parts]; /* token partition for this row */\n      /* Reset left context at start of each row */\n      memset(left_nz_y, 0, sizeof(left_nz_y));\n      memset(left_nz_u, 0, sizeof(left_nz_u));\n      memset(left_nz_v, 0, sizeof(left_nz_v));\n      memset(left_bmodes, 0, sizeof(left_bmodes));\n      left_nz_dc = 0;\n      for (mx = 0; mx < mbw; mx++)\n      {\n         int ym, uvm, is_skip = 0, seg_id = 0;\n         uint8_t ay[16], ly[16], au[8], lu[8], av[8], lv[8];\n         uint8_t tly=128, tlu=128, tlv=128;\n         int16_t coeffs[16], y2_block[16], dc_vals[16];\n         uint8_t bmodes[16]; /* B_PRED sub-block modes */\n         int bx, by;\n         int mb_qp;\n\n         /* Read segment ID if segmentation is enabled */\n         if (seg_enabled)\n         {\n            /* VP8 segment tree: prob[0] -> left(prob[1]->seg0/seg1) / right(prob[2]->seg2/seg3) */\n            if (vp8b_get(&br, seg_prob[0]))\n               seg_id = 2 + vp8b_get(&br, seg_prob[2]);\n            else\n               seg_id = vp8b_get(&br, seg_prob[1]);\n         }\n\n         if (seg_map_buf) seg_map_buf[my * mbw + mx] = (uint8_t)seg_id;\n         /* Compute per-MB quantizer based on segment */\n         if (seg_enabled && seg_abs)\n            mb_qp = seg_qp[seg_id];\n         else if (seg_enabled)\n            mb_qp = base_qp + seg_qp[seg_id];\n         else\n            mb_qp = base_qp;\n         if (mb_qp < 0) mb_qp = 0;\n         if (mb_qp > 127) mb_qp = 127;\n         /* Recompute quantizer tables for this MB's QP */\n         { int q2 = mb_qp + y1dc_dq; y1_dc_q = vp8_dc_qlut[q2<0?0:q2>127?127:q2]; }\n         y1_ac_q = vp8_ac_qlut[mb_qp];\n         { int q2 = mb_qp + y2dc_dq; y2_dc_q = vp8_dc_qlut[q2<0?0:q2>127?127:q2]; }\n         { int q2 = mb_qp + y2ac_dq; y2_ac_q = vp8_ac_qlut[q2<0?0:q2>127?127:q2]; }\n         { int q2 = mb_qp + uvdc_dq; uv_dc_q = vp8_dc_qlut[q2<0?0:q2>127?127:q2]; if(uv_dc_q>132)uv_dc_q=132; }\n         { int q2 = mb_qp + uvac_dq; uv_ac_q = vp8_ac_qlut[q2<0?0:q2>127?127:q2]; }\n\n         /* Skip flag (after segment, before y_mode — libvpx order) */\n         if (skip_enabled)\n            is_skip = vp8b_get(&br, prob_skip);\n\n         /* Y mode */\n         if (!vp8b_get(&br, vp8_ymp[0])) {\n            ym = 4; /* B_PRED */\n         } else if (!vp8b_get(&br, vp8_ymp[1])) {\n            /* Left subtree: DC, V */\n            ym = vp8b_get(&br, vp8_ymp[2]) ? 1 : 0;\n         } else {\n            /* Right subtree: H, TM */\n            ym = vp8b_get(&br, vp8_ymp[3]) ? 3 : 2;\n         }\n\n         if (ym == 4)\n         {\n            /* B_PRED: read 16 sub-block modes using key-frame context probs. */\n            for (i = 0; i < 16; i++)\n            {\n               int sb_row = i / 4, sb_col = i % 4;\n               int above_mode, left_mode;\n               /* Above mode: from previous MB row's bottom sub-block, or default 0 (DC) */\n               if (sb_row > 0)\n                  above_mode = bmodes[i - 4];\n               else if (my > 0)\n                  above_mode = above_bmodes[mx * 4 + sb_col];\n               else\n                  above_mode = 0;\n               /* Left mode: from left sub-block in this MB, or previous MB's right col */\n               if (sb_col > 0)\n                  left_mode = bmodes[i - 1];\n               else if (mx > 0)\n                  left_mode = left_bmodes[sb_row];\n               else\n                  left_mode = 0;\n               bmodes[i] = (uint8_t)vp8_read_bmode(&br, above_mode, left_mode);\n            }\n            /* Store bottom row for next MB row's above context */\n            for (i = 0; i < 4; i++)\n               above_bmodes[mx * 4 + i] = bmodes[12 + i];\n            /* Store right column for next MB's left context */\n            for (i = 0; i < 4; i++)\n               left_bmodes[i] = bmodes[i * 4 + 3];\n         }\n         else\n         {\n            /* Non B_PRED: clear bmode context (default DC=0 for neighbors) */\n            for (i = 0; i < 4; i++) above_bmodes[mx * 4 + i] = 0;\n            for (i = 0; i < 4; i++) left_bmodes[i] = 0;\n         }\n\n         /* UV mode */\n         if      (!vp8b_get(&br, vp8_uvmp[0])) uvm = 0;\n         else if (!vp8b_get(&br, vp8_uvmp[1])) uvm = 1;\n         else if (!vp8b_get(&br, vp8_uvmp[2])) uvm = 2;\n         else uvm = 3;\n\n         /* Gather prediction context */\n         if (my > 0) {\n            memcpy(ay, yb+(my*16-1)*ys+mx*16, 16);\n            memcpy(au, ub+(my*8-1)*uvs+mx*8, 8);\n            memcpy(av, vb+(my*8-1)*uvs+mx*8, 8);\n            if (mx > 0) { tly=yb[(my*16-1)*ys+mx*16-1]; tlu=ub[(my*8-1)*uvs+mx*8-1]; tlv=vb[(my*8-1)*uvs+mx*8-1]; }\n         } else { memset(ay,127,16); memset(au,127,8); memset(av,127,8); }\n         if (mx > 0) {\n            for(j=0;j<16;j++) ly[j]=yb[(my*16+j)*ys+mx*16-1];\n            for(j=0;j<8;j++) lu[j]=ub[(my*8+j)*uvs+mx*8-1];\n            for(j=0;j<8;j++) lv[j]=vb[(my*8+j)*uvs+mx*8-1];\n         } else { memset(ly,127,16); memset(lu,127,8); memset(lv,127,8); }\n\n         /* Predict */\n         if (ym != 4)\n            vp8_pred16(yb+my*16*ys+mx*16, ys, ym, ay, ly, tly);\n         /* B_PRED Y prediction is done per sub-block below */\n         vp8_pred8(ub+my*8*uvs+mx*8, uvs, uvm, au, lu, tlu);\n         vp8_pred8(vb+my*8*uvs+mx*8, uvs, uvm, av, lv, tlv);\n\n         /* Decode and add residual */\n         if (!is_skip)\n         {\n            /* Non-zero coefficient tracking for context. */\n            int nz_y2 = 0;\n\n            /* Y2 block (DC for 16x16 prediction) */\n            memset(dc_vals, 0, sizeof(dc_vals));\n            if (ym != 4) /* not B_PRED */\n            {\n               int y2_above = (my > 0) ? above_nz_dc[mx] : 0;\n               int y2_left  = (mx > 0) ? left_nz_dc : 0;\n               int y2_ctx   = (y2_above + y2_left > 1) ? 2 : (y2_above + y2_left);\n               memset(y2_block, 0, sizeof(y2_block));\n               nz_y2 = vp8_decode_block(tp, y2_block, 1, vp8_cprob[1], 0, y2_ctx);\n               above_nz_dc[mx] = (nz_y2 > 0) ? 1 : 0;\n               left_nz_dc = (nz_y2 > 0) ? 1 : 0;\n               /* Dequantize Y2 */\n               y2_block[0] = (int16_t)(y2_block[0] * y2_dc_q);\n               for (i = 1; i < 16; i++)\n                  y2_block[i] = (int16_t)(y2_block[i] * y2_ac_q);\n               /* Inverse WHT to get DC values for each sub-block */\n               vp8_iwht4x4(y2_block, dc_vals);\n            }\n\n            /* 16 Y sub-blocks */\n            for (by = 0; by < 4; by++)\n            {\n               for (bx = 0; bx < 4; bx++)\n               {\n                  int sb_above = (my > 0 || by > 0) ? above_nz_y[mx*4+bx] : 0;\n                  int sb_left  = (mx > 0 || bx > 0) ? left_nz_y[by] : 0;\n                  int sb_ctx   = (sb_above + sb_left > 1) ? 2 : (sb_above + sb_left);\n                  int start, nz_cnt;\n                  uint8_t *sb_dst = yb + (my*16 + by*4) * ys + mx*16 + bx*4;\n\n                  if (ym == 4) /* B_PRED: per-sub-block prediction */\n                  {\n                     uint8_t sa[8], sl[4]; uint8_t stl;\n                     int sb_idx = by * 4 + bx;\n                     /* Gather 4x4 context from already-reconstructed neighbors */\n                     if (by > 0) { for(i=0;i<4;i++) sa[i]=sb_dst[-ys+i]; }\n                     else if (my > 0) { for(i=0;i<4;i++) sa[i]=yb[(my*16-1)*ys+mx*16+bx*4+i]; }\n                     else { memset(sa,127,4); }\n                     /* Above-right: next 4 pixels */\n                     if (bx < 3 && by > 0) { for(i=0;i<4;i++) sa[4+i]=sb_dst[-ys+4+i]; }\n                     else if (bx < 3 && my > 0) { for(i=0;i<4;i++) sa[4+i]=yb[(my*16-1)*ys+mx*16+bx*4+4+i]; }\n                     else { for(i=0;i<4;i++) sa[4+i]=sa[3]; }\n                     if (bx > 0) { for(i=0;i<4;i++) sl[i]=sb_dst[i*ys-1]; }\n                     else if (mx > 0) { for(i=0;i<4;i++) sl[i]=yb[(my*16+by*4+i)*ys+mx*16-1]; }\n                     else { memset(sl,129,4); }\n                     if (bx > 0 && by > 0) stl = sb_dst[-ys-1];\n                     else if (by > 0 && mx > 0) stl = sb_dst[-ys-1];\n                     else if (bx > 0 && my > 0) stl = yb[(my*16-1)*ys+mx*16+bx*4-1];\n                     else if (by > 0) stl = 127; /* above border for first column */\n                     else if (bx > 0) stl = (my > 0) ? yb[(my*16-1)*ys+mx*16+bx*4-1] : 127;\n                     else stl = 127; /* top-left corner */\n                     vp8_pred4x4(sb_dst, ys, bmodes[sb_idx], sa, sl, stl);\n                     start = 0; /* B_PRED: decode DC from tokens (type 1) */\n                  }\n                  else\n                  {\n                     start = 1; /* non-B_PRED: DC comes from Y2 */\n                  }\n\n                  nz_cnt = vp8_decode_block(tp, coeffs, (ym == 4) ? 3 : 0,\n                        vp8_cprob[(ym == 4) ? 3 : 0], start, sb_ctx);\n                  /* Dequantize */\n                  if (ym != 4)\n                     coeffs[0] = dc_vals[by * 4 + bx]; /* DC from WHT */\n                  else\n                     coeffs[0] = (int16_t)(coeffs[0] * y1_dc_q);\n                  for (i = 1; i < 16; i++)\n                     coeffs[i] = (int16_t)(coeffs[i] * y1_ac_q);\n                  /* Inverse DCT + add to prediction */\n                  vp8_idct4x4_add(coeffs, sb_dst, ys);\n                  /* Update context tracking */\n                  above_nz_y[mx*4+bx] = (nz_cnt > 0) ? 1 : 0;\n                  left_nz_y[by] = (nz_cnt > 0) ? 1 : 0;\n               }\n            }\n\n            /* 4 U sub-blocks */\n            for (by = 0; by < 2; by++)\n            {\n               for (bx = 0; bx < 2; bx++)\n               {\n                  int sb_above = (my > 0 || by > 0) ? above_nz_u[mx*2+bx] : 0;\n                  int sb_left  = (mx > 0 || bx > 0) ? left_nz_u[by] : 0;\n                  int sb_ctx   = (sb_above + sb_left > 1) ? 2 : (sb_above + sb_left);\n                  int nz_cnt = vp8_decode_block(tp, coeffs, 2, vp8_cprob[2], 0, sb_ctx);\n                  coeffs[0] = (int16_t)(coeffs[0] * uv_dc_q);\n                  for (i = 1; i < 16; i++)\n                     coeffs[i] = (int16_t)(coeffs[i] * uv_ac_q);\n                  vp8_idct4x4_add(coeffs,\n                        ub + (my*8 + by*4) * uvs + mx*8 + bx*4, uvs);\n                  above_nz_u[mx*2+bx] = (nz_cnt > 0) ? 1 : 0;\n                  left_nz_u[by] = (nz_cnt > 0) ? 1 : 0;\n               }\n            }\n\n            /* 4 V sub-blocks */\n            for (by = 0; by < 2; by++)\n            {\n               for (bx = 0; bx < 2; bx++)\n               {\n                  int sb_above = (my > 0 || by > 0) ? above_nz_v[mx*2+bx] : 0;\n                  int sb_left  = (mx > 0 || bx > 0) ? left_nz_v[by] : 0;\n                  int sb_ctx   = (sb_above + sb_left > 1) ? 2 : (sb_above + sb_left);\n                  int nz_cnt = vp8_decode_block(tp, coeffs, 2, vp8_cprob[2], 0, sb_ctx);\n                  coeffs[0] = (int16_t)(coeffs[0] * uv_dc_q);\n                  for (i = 1; i < 16; i++)\n                     coeffs[i] = (int16_t)(coeffs[i] * uv_ac_q);\n                  vp8_idct4x4_add(coeffs,\n                        vb + (my*8 + by*4) * uvs + mx*8 + bx*4, uvs);\n                  above_nz_v[mx*2+bx] = (nz_cnt > 0) ? 1 : 0;\n                  left_nz_v[by] = (nz_cnt > 0) ? 1 : 0;\n               }\n            }\n         }\n         else\n         {\n            /* Skipped MB: clear all non-zero context */\n            for (bx = 0; bx < 4; bx++) above_nz_y[mx*4+bx] = 0;\n            for (bx = 0; bx < 2; bx++) { above_nz_u[mx*2+bx] = 0; above_nz_v[mx*2+bx] = 0; }\n            above_nz_dc[mx] = 0;\n            memset(left_nz_y, 0, sizeof(left_nz_y));\n            memset(left_nz_u, 0, sizeof(left_nz_u));\n            memset(left_nz_v, 0, sizeof(left_nz_v));\n            left_nz_dc = 0;\n         }\n\n      }\n   }\n\n   free(above_nz_y); free(above_nz_u); free(above_nz_v); free(above_nz_dc); free(above_bmodes);\n   } /* end context tracking block */\n\n   /* Apply post-decode simple loop filter */\n   if (filter_type == 1 && lf_level > 0)\n      vp8_loop_filter_simple(yb, ys, ub, uvs, vb, mbw, mbh, lf_level, sharpness, seg_enabled, seg_abs, seg_lf, seg_map_buf);\n\n   /* YUV -> ARGB */\n   pix = (uint32_t*)malloc((size_t)w * h * sizeof(uint32_t));\n   if (!pix) goto lfail;\n   for (j = 0; j < h; j++)\n      for (i = 0; i < w; i++)\n      {\n         uint8_t r, g, b2;\n         vp8_yuv2rgb(yb[j*ys+i], ub[(j>>1)*uvs+(i>>1)], vb[(j>>1)*uvs+(i>>1)], &r, &g, &b2);\n         pix[j*w+i] = 0xFF000000u | ((uint32_t)r<<16) | ((uint32_t)g<<8) | (uint32_t)b2;\n      }\n   free(yb); free(ub); free(vb); free(seg_map_buf);\n   *ow = (unsigned)w; *oh = (unsigned)h;\n   return pix;\nlfail:\n   free(yb); free(ub); free(vb); free(seg_map_buf); free(pix);\n   return NULL;\n}\n\n/* ===== Top-level ===== */\n\nstatic uint32_t *rwebp_do(const uint8_t *buf, size_t len,\n      unsigned *w, unsigned *h, bool rgba)\n{\n   rw_ctr c;\n   uint32_t *pix = NULL;\n   if (!rw_parse(buf, len, &c)) return NULL;\n   if (c.vp8l && c.vp8ls > 0) pix = vl_decode_full(c.vp8l, c.vp8ls, w, h);\n   if (!pix && c.vp8 && c.vp8s > 0) pix = vp8_decode(c.vp8, c.vp8s, w, h);\n   if (!pix) return NULL;\n   if (rgba)\n   {\n      unsigned i, n = (*w) * (*h);\n      for (i = 0; i < n; i++)\n      {\n         uint32_t p = pix[i];\n         pix[i] = (p & 0xFF00FF00u) | ((p & 0xFF) << 16) | ((p >> 16) & 0xFF);\n      }\n   }\n   return pix;\n}\n\n/* ===== Public API ===== */\n\nstruct rwebp { uint8_t *buff_data; size_t buff_len; uint32_t *output_image; };\n\nint rwebp_process_image(rwebp_t *rwebp, void **buf_data,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba)\n{\n   if (!rwebp || !rwebp->buff_data) return IMAGE_PROCESS_ERROR;\n   rwebp->output_image = rwebp_do(rwebp->buff_data,\n         rwebp->buff_len > 0 ? rwebp->buff_len : size,\n         width, height, supports_rgba);\n   *buf_data = rwebp->output_image;\n   return rwebp->output_image ? IMAGE_PROCESS_END : IMAGE_PROCESS_ERROR;\n}\n\nbool rwebp_set_buf_ptr(rwebp_t *rwebp, void *data, size_t len)\n{\n   if (!rwebp) return false;\n   rwebp->buff_data = (uint8_t*)data;\n   rwebp->buff_len = len;\n   return true;\n}\n\nvoid rwebp_free(rwebp_t *rwebp) { if (rwebp) free(rwebp); }\nrwebp_t *rwebp_alloc(void) { return (rwebp_t*)calloc(1, sizeof(rwebp_t)); }\n"
  },
  {
    "path": "formats/xml/rxml.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rxml.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n#include <stdint.h>\n\n#include <boolean.h>\n#include <streams/file_stream.h>\n#include <compat/posix_string.h>\n\n#include <formats/rxml.h>\n\n#include \"../../deps/yxml/yxml.h\"\n\n#define BUFSIZE 4096\n\nstruct rxml_parse_buffer\n{\n   rxml_node_t *stack[32];\n   char xml[BUFSIZE];\n   char val[BUFSIZE];\n};\n\nstruct rxml_document\n{\n   struct rxml_node *root_node;\n};\n\nstruct rxml_node *rxml_root_node(rxml_document_t *doc)\n{\n   if (doc)\n      return doc->root_node;\n   return NULL;\n}\n\nstatic void rxml_free_node(struct rxml_node *node)\n{\n   struct rxml_node *head = NULL;\n   struct rxml_attrib_node *attrib_node_head = NULL;\n\n   if (!node)\n      return;\n\n   for (head = node->children; head; )\n   {\n      struct rxml_node *next_node = (struct rxml_node*)head->next;\n      rxml_free_node(head);\n      head = next_node;\n   }\n\n   for (attrib_node_head = node->attrib; attrib_node_head; )\n   {\n      struct rxml_attrib_node *next_attrib =\n            (struct rxml_attrib_node*)attrib_node_head->next;\n\n      if (attrib_node_head->attrib)\n         free(attrib_node_head->attrib);\n      if (attrib_node_head->value)\n         free(attrib_node_head->value);\n      if (attrib_node_head)\n         free(attrib_node_head);\n\n      attrib_node_head = next_attrib;\n   }\n\n   if (node->name)\n      free(node->name);\n   if (node->data)\n      free(node->data);\n   if (node)\n      free(node);\n}\n\nrxml_document_t *rxml_load_document(const char *path)\n{\n   rxml_document_t *doc    = NULL;\n   char *memory_buffer     = NULL;\n   int64_t len             = 0;\n   RFILE *file             = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   if (!file)\n      return NULL;\n\n   len                     = filestream_get_size(file);\n   /* filestream_get_size returns -1 on error.  Pre-patch this\n    * flowed through (size_t)(len + 1) as malloc(0) on 64-bit\n    * (returning a tiny non-NULL block) or as a wrapped value on\n    * 32-bit; either way memory_buffer[len] = '\\0' wrote far\n    * out-of-bounds.  Reject negative sizes and any size that\n    * would not fit in size_t on this platform. */\n   if (len < 0 || (uint64_t)len >= (uint64_t)((size_t)-1))\n      goto error;\n   memory_buffer           = (char*)malloc((size_t)(len + 1));\n   if (!memory_buffer)\n      goto error;\n\n   memory_buffer[len]      = '\\0';\n   if (filestream_read(file, memory_buffer, len) != len)\n      goto error;\n\n   filestream_close(file);\n   file                    = NULL;\n\n   doc                     = rxml_load_document_string(memory_buffer);\n\n   free(memory_buffer);\n   return doc;\n\nerror:\n   free(memory_buffer);\n   if (file)\n      filestream_close(file);\n   return NULL;\n}\n\nrxml_document_t *rxml_load_document_string(const char *str)\n{\n   yxml_t x;\n   rxml_document_t *doc          = NULL;\n   size_t stack_i                = 0;\n   size_t level                  = 0;\n   int i                         = 0;\n   char *valptr                  = NULL;\n   rxml_node_t *node             = NULL;\n   struct rxml_attrib_node *attr = NULL;\n   struct rxml_parse_buffer *buf = (struct rxml_parse_buffer*)\n      malloc(sizeof(*buf));\n   if (!buf)\n      return NULL;\n\n   valptr                        = buf->val;\n   doc                           = (rxml_document_t*)malloc(sizeof(*doc));\n   if (!doc)\n      goto error;\n   doc->root_node                = NULL;\n\n   yxml_init(&x, buf->xml, BUFSIZE);\n\n   for (; *str; ++str)\n   {\n      yxml_ret_t r = yxml_parse(&x, *str);\n\n      if (r < 0)\n         goto error;\n\n      switch (r)\n      {\n\n         case YXML_ELEMSTART:\n            if (node)\n            {\n               if (level > stack_i)\n               {\n                  buf->stack[stack_i]      = node;\n                  ++stack_i;\n\n                  node->children           = (rxml_node_t*)\n                     malloc(sizeof(*node));\n\n                  node->children->name     = NULL;\n                  node->children->data     = NULL;\n                  node->children->attrib   = NULL;\n                  node->children->children = NULL;\n                  node->children->next     = NULL;\n\n                  node                     = node->children;\n               }\n               else\n               {\n                  node->next               = (rxml_node_t*)\n                     malloc(sizeof(*node));\n\n                  node->next->name         = NULL;\n                  node->next->data         = NULL;\n                  node->next->attrib       = NULL;\n                  node->next->children     = NULL;\n                  node->next->next         = NULL;\n\n                  node                     = node->next;\n               }\n            }\n            else\n               node = doc->root_node       = (rxml_node_t*)\n                  calloc(1, sizeof(*node));\n\n            if (node->name)\n               free(node->name);\n            node->name                     = strdup(x.elem);\n\n            attr                           = NULL;\n            valptr                         = buf->val;\n\n            ++level;\n            break;\n\n         case YXML_ELEMEND:\n            --level;\n\n            if (valptr > buf->val)\n            {\n               *valptr = '\\0';\n\n               /* Original code was broken here:\n                * > If an element ended on two successive\n                *   iterations, on the second iteration\n                *   the 'data' for the *previous* node would\n                *   get overwritten\n                * > This effectively erased the data for the\n                *   previous node, *and* caused a memory leak\n                *   (due to the double strdup())\n                * It seems the correct thing to do here is\n                * only copy the data if the current 'level'\n                * and 'stack index' are the same... */\n               if (level == stack_i)\n               {\n                  if (node->data)\n                     free(node->data);\n                  node->data = strdup(buf->val);\n               }\n\n               valptr = buf->val;\n            }\n\n            if (level < stack_i)\n            {\n               --stack_i;\n               node = buf->stack[stack_i];\n            }\n            break;\n\n         case YXML_CONTENT:\n            for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)\n            {\n               *valptr = x.data[i];\n               ++valptr;\n            }\n            break;\n\n         case YXML_ATTRSTART:\n            if (attr)\n               attr = attr->next   = (struct rxml_attrib_node*)\n                     calloc(1, sizeof(*attr));\n            else\n            {\n               attr = (struct rxml_attrib_node*)calloc(1, sizeof(*attr));\n               if (node && attr)\n                  node->attrib = attr;\n            }\n\n            if (attr)\n            {\n               if (attr->attrib)\n                  free(attr->attrib);\n               attr->attrib = strdup(x.attr);\n            }\n\n            valptr       = buf->val;\n            break;\n\n         case YXML_ATTRVAL:\n            for (i = 0; i < (int)sizeof(x.data) && x.data[i]; i++)\n            {\n               *valptr = x.data[i];\n               ++valptr;\n            }\n            break;\n\n         case YXML_ATTREND:\n            if (valptr > buf->val)\n            {\n               *valptr = '\\0';\n\n               if (attr)\n               {\n                  if (attr->value)\n                     free(attr->value);\n                  attr->value = strdup(buf->val);\n               }\n\n               valptr      = buf->val;\n            }\n            break;\n\n         default:\n            break;\n      }\n   }\n\n   free(buf);\n   return doc;\n\nerror:\n   rxml_free_document(doc);\n   free(buf);\n   return NULL;\n}\n\nvoid rxml_free_document(rxml_document_t *doc)\n{\n   if (!doc)\n      return;\n\n   if (doc->root_node)\n      rxml_free_node(doc->root_node);\n\n   free(doc);\n}\n\nconst char *rxml_node_attrib(struct rxml_node *node, const char *attrib)\n{\n   struct rxml_attrib_node *attribs = NULL;\n   for (attribs = node->attrib; attribs; attribs = attribs->next)\n   {\n      if (strcmp(attrib, attribs->attrib) == 0)\n         return attribs->value;\n   }\n\n   return NULL;\n}\n"
  },
  {
    "path": "gfx/gl_capabilities.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (gl_capabilities.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <string.h>\n#include <stdlib.h>\n\n#include <boolean.h>\n\n#include <glsym/glsym.h>\n\n#include <gfx/gl_capabilities.h>\n\nstatic bool gl_core_context       = false;\n\nbool gl_query_core_context_in_use(void)\n{\n   return gl_core_context;\n}\n\nvoid gl_query_core_context_set(bool set)\n{\n   gl_core_context     =  set;\n}\n\nvoid gl_query_core_context_unset(void)\n{\n   gl_core_context = false;\n}\n\nbool gl_query_extension(const char *ext)\n{\n   bool ret = false;\n\n   if (gl_query_core_context_in_use())\n   {\n#ifdef GL_NUM_EXTENSIONS\n      GLint i;\n      GLint exts = 0;\n      glGetIntegerv(GL_NUM_EXTENSIONS, &exts);\n      for (i = 0; i < exts; i++)\n      {\n         const char *str = (const char*)glGetStringi(GL_EXTENSIONS, i);\n         if (str && strstr(str, ext))\n         {\n            ret = true;\n            break;\n         }\n      }\n#endif\n   }\n   else\n   {\n      const char *str = (const char*)glGetString(GL_EXTENSIONS);\n      ret = str && strstr(str, ext);\n   }\n\n   return ret;\n}\n\nbool gl_check_error(char **err_string)\n{\n   int err = glGetError();\n   switch (err)\n   {\n      case GL_INVALID_ENUM:\n         *err_string = strdup(\"GL: Invalid enum.\");\n         break;\n      case GL_INVALID_VALUE:\n         *err_string = strdup(\"GL: Invalid value.\");\n         break;\n      case GL_INVALID_OPERATION:\n         *err_string = strdup(\"GL: Invalid operation.\");\n         break;\n      case GL_OUT_OF_MEMORY:\n         *err_string = strdup(\"GL: Out of memory.\");\n         break;\n      case GL_NO_ERROR:\n         return true;\n      default:\n         *err_string = strdup(\"Non specified GL error.\");\n         break;\n   }\n\n   return false;\n}\n\nbool gl_check_capability(enum gl_capability_enum enum_idx)\n{\n   unsigned major       = 0;\n   const char *vendor   = (const char*)glGetString(GL_VENDOR);\n   const char *renderer = (const char*)glGetString(GL_RENDERER);\n   const char *version  = (const char*)glGetString(GL_VERSION);\n#ifdef HAVE_OPENGLES\n   if (version)\n   {\n      /* Skip \"OpenGL ES \" prefix */\n      const char *v = strstr(version, \"OpenGL ES \");\n      if (v)\n      {\n         char *end  = NULL;\n         v         += sizeof(\"OpenGL ES \")-1;\n         major      = (unsigned)strtol(v, &end, 10);\n         if (end && *end == '.') { }\n         else\n            major   = 0;\n      }\n   }\n#else\n   if (version)\n   {\n      char *end  = NULL;\n      major      = (unsigned)strtol(version, &end, 10);\n      if (end && *end == '.') { }\n      else\n         major   = 0;\n   }\n#endif\n\n   (void)vendor;\n   (void)renderer;\n\n   switch (enum_idx)\n   {\n      case GL_CAPS_GLES3_SUPPORTED:\n#if defined(HAVE_OPENGLES)\n         if (major >= 3)\n            return true;\n#endif\n         break;\n      case GL_CAPS_EGLIMAGE:\n#if defined(HAVE_EGL) && defined(HAVE_OPENGLES)\n         if (glEGLImageTargetTexture2DOES != NULL)\n            return true;\n#endif\n         break;\n      case GL_CAPS_SYNC:\n#ifdef HAVE_OPENGLES\n         if (major >= 3)\n            return true;\n#else\n         if (gl_query_extension(\"ARB_sync\") &&\n               glFenceSync && glDeleteSync && glClientWaitSync)\n            return true;\n#endif\n         break;\n      case GL_CAPS_MIPMAP:\n         {\n            static bool extension_queried = false;\n            static bool extension         = false;\n\n            if (!extension_queried)\n            {\n               extension         = gl_query_extension(\"ARB_framebuffer_object\");\n               extension_queried = true;\n            }\n\n            if (extension)\n               return true;\n         }\n         break;\n      case GL_CAPS_VAO:\n#ifndef HAVE_OPENGLES\n         if (!gl_query_core_context_in_use() && !gl_query_extension(\"ARB_vertex_array_object\"))\n            return false;\n\n         if (glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays)\n            return true;\n#endif\n         break;\n      case GL_CAPS_FBO:\n#if defined(HAVE_PSGL) || defined(HAVE_OPENGLES2) || defined(HAVE_OPENGLES3) || defined(HAVE_OPENGLES_3_1) || defined(HAVE_OPENGLES_3_2)\n         return true;\n#else\n         if (     !gl_query_core_context_in_use()\n               && !gl_query_extension(\"ARB_framebuffer_object\")\n               && !gl_query_extension(\"EXT_framebuffer_object\"))\n            return false;\n\n         if (gl_query_extension(\"ARB_framebuffer_object\"))\n            return true;\n\n         if (gl_query_extension(\"EXT_framebuffer_object\"))\n            return true;\n\n         if (major >= 3)\n            return true;\n         break;\n#endif\n      case GL_CAPS_ARGB8:\n#if defined(HAVE_OPENGLES) && !defined(EMSCRIPTEN)\n         if (gl_query_extension(\"OES_rgb8_rgba8\")\n               || gl_query_extension(\"ARM_rgba8\")\n                  || major >= 3)\n            return true;\n#elif defined(HAVE_OPENGLES) && defined(EMSCRIPTEN)\n         if (gl_query_extension(\"EXT_sRGB\")\n               || major >= 3)\n            return true;\n#else\n         /* TODO/FIXME - implement this for non-GLES? */\n#endif\n         break;\n      case GL_CAPS_DEBUG:\n         if (gl_query_extension(\"KHR_debug\"))\n            return true;\n#ifndef HAVE_OPENGLES\n         if (gl_query_extension(\"ARB_debug_output\"))\n            return true;\n#endif\n         break;\n      case GL_CAPS_PACKED_DEPTH_STENCIL:\n         if (major >= 3)\n            return true;\n         if (gl_query_extension(\"OES_packed_depth_stencil\"))\n            return true;\n         if (gl_query_extension(\"EXT_packed_depth_stencil\"))\n            return true;\n         break;\n      case GL_CAPS_ES2_COMPAT:\n#ifndef HAVE_OPENGLES\n         /* ATI card detected, skipping check for GL_RGB565 support... */\n         if (vendor && renderer && (strstr(vendor, \"ATI\") || strstr(renderer, \"ATI\")))\n            return false;\n\n         if (gl_query_extension(\"ARB_ES2_compatibility\"))\n            return true;\n#endif\n         break;\n      case GL_CAPS_UNPACK_ROW_LENGTH:\n#ifdef HAVE_OPENGLES\n         if (major >= 3)\n            return true;\n\n         /* Extension GL_EXT_unpack_subimage, can copy textures faster\n          * than using UNPACK_ROW_LENGTH */\n         if (gl_query_extension(\"GL_EXT_unpack_subimage\"))\n            return true;\n#endif\n         break;\n      case GL_CAPS_FULL_NPOT_SUPPORT:\n         if (major >= 3)\n            return true;\n#ifdef HAVE_OPENGLES\n         if (gl_query_extension(\"ARB_texture_non_power_of_two\") ||\n               gl_query_extension(\"OES_texture_npot\"))\n            return true;\n#else\n         {\n            GLint max_texture_size = 0;\n            GLint max_native_instr = 0;\n            /* try to detect actual npot support. might fail for older cards. */\n            bool  arb_npot         = gl_query_extension(\"ARB_texture_non_power_of_two\");\n            bool  arb_frag_program = gl_query_extension(\"ARB_fragment_program\");\n\n            glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);\n\n#ifdef GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB\n            if (arb_frag_program && glGetProgramivARB)\n               glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB,\n                     GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &max_native_instr);\n#endif\n\n            if (arb_npot && arb_frag_program &&\n                  (max_texture_size >= 8192) && (max_native_instr >= 4096))\n               return true;\n         }\n#endif\n         break;\n      case GL_CAPS_SRGB_FBO_ES3:\n#ifdef HAVE_OPENGLES\n         if (major >= 3)\n            return true;\n#else\n         break;\n#endif\n      case GL_CAPS_SRGB_FBO:\n#if defined(HAVE_OPENGLES)\n         if (major >= 3 || gl_query_extension(\"EXT_sRGB\"))\n            return true;\n#endif\n         if (gl_check_capability(GL_CAPS_FBO))\n         {\n            if (   gl_query_core_context_in_use() ||\n                  (gl_query_extension(\"EXT_texture_sRGB\")\n                   && gl_query_extension(\"ARB_framebuffer_sRGB\"))\n               )\n               return true;\n         }\n         break;\n      case GL_CAPS_FP_FBO:\n         if (gl_check_capability(GL_CAPS_FBO))\n         {\n            /* Float FBO is core in 3.2. */\n            if (gl_query_core_context_in_use() || gl_query_extension(\"ARB_texture_float\") || gl_query_extension(\"OES_texture_float_linear\"))\n               return true;\n         }\n         break;\n      case GL_CAPS_BGRA8888:\n#ifdef HAVE_OPENGLES\n         /* There are both APPLE and EXT variants. */\n         if (gl_query_extension(\"BGRA8888\"))\n            return true;\n#else\n         return true;\n#endif\n         break;\n      case GL_CAPS_TEX_STORAGE:\n#ifdef HAVE_OPENGLES\n         if (major >= 3)\n            return true;\n#else\n         if (vendor && strstr(vendor, \"ATI Technologies\"))\n            return false;\n         if (gl_query_extension(\"ARB_texture_storage\"))\n            return true;\n#endif\n         break;\n      case GL_CAPS_TEX_STORAGE_EXT:\n#ifdef TARGET_OS_IPHONE\n           /* Not working on iOS */\n           return false;\n#else\n         if (gl_query_extension(\"EXT_texture_storage\"))\n            return true;\n#endif\n         break;\n      case GL_CAPS_NONE:\n      default:\n         break;\n   }\n\n   return false;\n}\n"
  },
  {
    "path": "gfx/scaler/pixconv.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (pixconv.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_inline.h>\n\n#include <gfx/scaler/pixconv.h>\n\n#if _MSC_VER && _MSC_VER <= 1800\n#define SCALER_NO_SIMD\n#endif\n\n#ifdef SCALER_NO_SIMD\n#undef __SSE2__\n#endif\n\n#if defined(__SSE2__)\n#include <emmintrin.h>\n#elif defined(__MMX__)\n#include <mmintrin.h>\n#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))\n#include <arm_neon.h>\n#endif\n\nvoid conv_rgb565_0rgb1555(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input   = (const uint16_t*)input_;\n   uint16_t *output        = (uint16_t*)output_;\n\n#if defined(__SSE2__)\n   int max_width           = width - 7;\n   const __m128i hi_mask   = _mm_set1_epi16(0x7fe0);\n   const __m128i lo_mask   = _mm_set1_epi16(0x1f);\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 1, input += in_stride >> 1)\n   {\n      int w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 8)\n      {\n         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));\n         __m128i hi = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);\n         __m128i lo = _mm_and_si128(in, lo_mask);\n         _mm_storeu_si128((__m128i*)(output + w), _mm_or_si128(hi, lo));\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint16_t col = input[w];\n         uint16_t hi  = (col >> 1) & 0x7fe0;\n         uint16_t lo  = col & 0x1f;\n         output[w]    = hi | lo;\n      }\n   }\n}\n\nvoid conv_0rgb1555_rgb565(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input   = (const uint16_t*)input_;\n   uint16_t *output        = (uint16_t*)output_;\n\n#if defined(__SSE2__)\n   int max_width           = width - 7;\n\n   const __m128i hi_mask   = _mm_set1_epi16(\n         (int16_t)((0x1f << 11) | (0x1f << 6)));\n   const __m128i lo_mask   = _mm_set1_epi16(0x1f);\n   const __m128i glow_mask = _mm_set1_epi16(1 << 5);\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 1, input += in_stride >> 1)\n   {\n      int w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 8)\n      {\n         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));\n         __m128i rg   = _mm_and_si128(_mm_slli_epi16(in, 1), hi_mask);\n         __m128i b    = _mm_and_si128(in, lo_mask);\n         __m128i glow = _mm_and_si128(_mm_srli_epi16(in, 4), glow_mask);\n         _mm_storeu_si128((__m128i*)(output + w),\n               _mm_or_si128(rg, _mm_or_si128(b, glow)));\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint16_t col  = input[w];\n         uint16_t rg   = (col << 1) & ((0x1f << 11) | (0x1f << 6));\n         uint16_t b    = col & 0x1f;\n         uint16_t glow = (col >> 4) & (1 << 5);\n         output[w]     = rg | b | glow;\n      }\n   }\n}\n\nvoid conv_0rgb1555_argb8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input = (const uint16_t*)input_;\n   uint32_t *output      = (uint32_t*)output_;\n\n#ifdef __SSE2__\n   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f << 10);\n   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f <<  5);\n   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);\n   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);\n   const __m128i a           = _mm_set1_epi16(0x00ff);\n\n   int max_width = width - 7;\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride >> 1)\n   {\n      int w = 0;\n#ifdef __SSE2__\n      for (; w < max_width; w += 8)\n      {\n         __m128i res_lo_bg, res_hi_bg;\n         __m128i res_lo_ra, res_hi_ra;\n         __m128i res_lo, res_hi;\n         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));\n         __m128i r = _mm_and_si128(in, pix_mask_r);\n         __m128i g = _mm_and_si128(in, pix_mask_gb);\n         __m128i b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_gb);\n\n         r = _mm_mulhi_epi16(r, mul15_hi);\n         g = _mm_mulhi_epi16(g, mul15_mid);\n         b = _mm_mulhi_epi16(b, mul15_mid);\n\n         res_lo_bg = _mm_unpacklo_epi8(b, g);\n         res_hi_bg = _mm_unpackhi_epi8(b, g);\n         res_lo_ra = _mm_unpacklo_epi8(r, a);\n         res_hi_ra = _mm_unpackhi_epi8(r, a);\n\n         res_lo = _mm_or_si128(res_lo_bg,\n               _mm_slli_si128(res_lo_ra, 2));\n         res_hi = _mm_or_si128(res_hi_bg,\n               _mm_slli_si128(res_hi_ra, 2));\n\n         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);\n         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 10) & 0x1f;\n         uint32_t g   = (col >>  5) & 0x1f;\n         uint32_t b   = (col >>  0) & 0x1f;\n         r            = (r << 3) | (r >> 2);\n         g            = (g << 3) | (g >> 2);\n         b            = (b << 3) | (b >> 2);\n\n         output[w]    = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);\n      }\n   }\n}\n\nvoid conv_rgb565_argb8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input    = (const uint16_t*)input_;\n   uint32_t *output         = (uint32_t*)output_;\n\n#if defined(__SSE2__)\n   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);\n   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);\n   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);\n   const __m128i mul16_r    = _mm_set1_epi16(0x0210);\n   const __m128i mul16_g    = _mm_set1_epi16(0x2080);\n   const __m128i mul16_b    = _mm_set1_epi16(0x4200);\n   const __m128i a          = _mm_set1_epi16(0x00ff);\n\n   int max_width            = width - 7;\n#elif defined(__MMX__)\n   const __m64 pix_mask_r = _mm_set1_pi16(0x1f << 10);\n   const __m64 pix_mask_g = _mm_set1_pi16(0x3f << 5);\n   const __m64 pix_mask_b = _mm_set1_pi16(0x1f << 5);\n   const __m64 mul16_r    = _mm_set1_pi16(0x0210);\n   const __m64 mul16_g    = _mm_set1_pi16(0x2080);\n   const __m64 mul16_b    = _mm_set1_pi16(0x4200);\n   const __m64 a          = _mm_set1_pi16(0x00ff);\n\n   int max_width            = width - 3;\n#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))\n   int max_width            = width - 7;\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride >> 1)\n   {\n      int w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 8)\n      {\n         __m128i res_lo, res_hi;\n         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;\n         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));\n         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);\n         __m128i        g = _mm_and_si128(in, pix_mask_g);\n         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);\n\n         r                = _mm_mulhi_epi16(r, mul16_r);\n         g                = _mm_mulhi_epi16(g, mul16_g);\n         b                = _mm_mulhi_epi16(b, mul16_b);\n\n         res_lo_bg        = _mm_unpacklo_epi8(b, g);\n         res_hi_bg        = _mm_unpackhi_epi8(b, g);\n         res_lo_ra        = _mm_unpacklo_epi8(r, a);\n         res_hi_ra        = _mm_unpackhi_epi8(r, a);\n\n         res_lo           = _mm_or_si128(res_lo_bg,\n               _mm_slli_si128(res_lo_ra, 2));\n         res_hi           = _mm_or_si128(res_hi_bg,\n               _mm_slli_si128(res_hi_ra, 2));\n\n         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);\n         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);\n      }\n#elif defined(__MMX__)\n      for (; w < max_width; w += 4)\n      {\n         __m64 res_lo, res_hi;\n         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;\n         const __m64 in = *((__m64*)(input + w));\n         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 1), pix_mask_r);\n         __m64          g = _mm_and_si64(in, pix_mask_g);\n         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 5), pix_mask_b);\n\n         r                = _mm_mulhi_pi16(r, mul16_r);\n         g                = _mm_mulhi_pi16(g, mul16_g);\n         b                = _mm_mulhi_pi16(b, mul16_b);\n\n         res_lo_bg        = _mm_unpacklo_pi8(b, g);\n         res_hi_bg        = _mm_unpackhi_pi8(b, g);\n         res_lo_ra        = _mm_unpacklo_pi8(r, a);\n         res_hi_ra        = _mm_unpackhi_pi8(r, a);\n\n         res_lo           = _mm_or_si64(res_lo_bg,\n               _mm_slli_si64(res_lo_ra, 16));\n         res_hi           = _mm_or_si64(res_hi_bg,\n               _mm_slli_si64(res_hi_ra, 16));\n\n         *((__m64*)(output + w + 0)) = res_lo;\n         *((__m64*)(output + w + 2)) = res_hi;\n      }\n\n      _mm_empty();\n#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))\n      for (; w < max_width; w += 8)\n      {\n         uint16x8_t in = vld1q_u16(input + w);\n\n         uint16x8_t r = vsriq_n_u16(in, in, 5);\n         uint16x8_t b = vsliq_n_u16(in, in, 5);\n         uint16x8_t g = vsriq_n_u16(b,  b,  6);\n\n         uint8x8x4_t res;\n         res.val[3] = vdup_n_u8(0xffu);\n         res.val[2] = vshrn_n_u16(r, 8);\n         res.val[1] = vshrn_n_u16(g, 8);\n         res.val[0] = vshrn_n_u16(b, 2);\n\n         vst4_u8((uint8_t*)(output + w), res);\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 11) & 0x1f;\n         uint32_t g   = (col >>  5) & 0x3f;\n         uint32_t b   = (col >>  0) & 0x1f;\n         r            = (r << 3) | (r >> 2);\n         g            = (g << 2) | (g >> 4);\n         b            = (b << 3) | (b >> 2);\n\n         output[w]    = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);\n      }\n   }\n}\n\nvoid conv_rgb565_abgr8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input    = (const uint16_t*)input_;\n   uint32_t *output         = (uint32_t*)output_;\n #if defined(__SSE2__)\n   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);\n   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);\n   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);\n   const __m128i mul16_r    = _mm_set1_epi16(0x0210);\n   const __m128i mul16_g    = _mm_set1_epi16(0x2080);\n   const __m128i mul16_b    = _mm_set1_epi16(0x4200);\n   const __m128i a          = _mm_set1_epi16(0x00ff);\n    int max_width            = width - 7;\n#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))\n   int max_width            = width - 7;\n#endif\n    for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride >> 1)\n   {\n      int w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 8)\n      {\n         __m128i res_lo, res_hi;\n         __m128i res_lo_rg, res_hi_rg, res_lo_ba, res_hi_ba;\n         const __m128i in = _mm_loadu_si128((const __m128i*)(input + w));\n         __m128i        r = _mm_and_si128(_mm_srli_epi16(in, 1), pix_mask_r);\n         __m128i        g = _mm_and_si128(in, pix_mask_g);\n         __m128i        b = _mm_and_si128(_mm_slli_epi16(in, 5), pix_mask_b);\n         r                = _mm_mulhi_epi16(r, mul16_r);\n         g                = _mm_mulhi_epi16(g, mul16_g);\n         b                = _mm_mulhi_epi16(b, mul16_b);\n         /* Output byte order [r g b a] per pixel == ABGR uint32 LE,\n          * matching the scalar fallback below.  Pair (r,g) into the\n          * low half and (b,a) into the high half (shifted up 2 bytes),\n          * not (b,g) and (r,a) which would produce ARGB byte order. */\n         res_lo_rg        = _mm_unpacklo_epi8(r, g);\n         res_hi_rg        = _mm_unpackhi_epi8(r, g);\n         res_lo_ba        = _mm_unpacklo_epi8(b, a);\n         res_hi_ba        = _mm_unpackhi_epi8(b, a);\n         res_lo           = _mm_or_si128(res_lo_rg,\n               _mm_slli_si128(res_lo_ba, 2));\n         res_hi           = _mm_or_si128(res_hi_rg,\n               _mm_slli_si128(res_hi_ba, 2));\n         _mm_storeu_si128((__m128i*)(output + w + 0), res_lo);\n         _mm_storeu_si128((__m128i*)(output + w + 4), res_hi);\n      }\n#elif (defined(__ARM_NEON__) || defined(__ARM_NEON))\n      for (; w < max_width; w += 8)\n      {\n         uint16x8_t in = vld1q_u16(input + w);\n\n         uint16x8_t r = vsriq_n_u16(in, in, 5);\n         uint16x8_t b = vsliq_n_u16(in, in, 5);\n         uint16x8_t g = vsriq_n_u16(b,  b,  6);\n\n         uint8x8x4_t res;\n         res.val[3] = vdup_n_u8(0xffu);\n         res.val[2] = vshrn_n_u16(b, 2);\n         res.val[1] = vshrn_n_u16(g, 8);\n         res.val[0] = vshrn_n_u16(r, 8);\n\n         vst4_u8((uint8_t*)(output + w), res);\n      }\n#endif\n       for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 11) & 0x1f;\n         uint32_t g   = (col >>  5) & 0x3f;\n         uint32_t b   = (col >>  0) & 0x1f;\n         r            = (r << 3) | (r >> 2);\n         g            = (g << 2) | (g >> 4);\n         b            = (b << 3) | (b >> 2);\n         output[w]    = (0xffu << 24) | (b << 16) | (g << 8) | (r << 0);\n      }\n   }\n}\n\nvoid conv_argb8888_rgba4444(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   const uint32_t *input = (const uint32_t*)input_;\n   uint16_t *output      = (uint16_t*)output_;\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride >> 1)\n   {\n      for (w = 0; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 16) & 0xf;\n         uint32_t g   = (col >>  8) & 0xf;\n         uint32_t b   = (col) & 0xf;\n         uint32_t a   = (col >>  24) & 0xf;\n         r            = (r >> 4) | r;\n         g            = (g >> 4) | g;\n         b            = (b >> 4) | b;\n         a            = (a >> 4) | a;\n\n         output[w]    = (r << 12) | (g << 8) | (b << 4) | a;\n      }\n   }\n}\n\nvoid conv_rgba4444_argb8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input = (const uint16_t*)input_;\n   uint32_t *output      = (uint32_t*)output_;\n\n#if defined(__MMX__)\n   const __m64 pix_mask_r = _mm_set1_pi16(0xf << 10);\n   const __m64 pix_mask_g = _mm_set1_pi16(0xf << 8);\n   const __m64 pix_mask_b = _mm_set1_pi16(0xf << 8);\n   const __m64 pix_mask_a = _mm_set1_pi16(0x000f);\n   const __m64 mul16_r    = _mm_set1_pi16(0x0440);\n   const __m64 mul16_g    = _mm_set1_pi16(0x1100);\n   const __m64 mul16_b    = _mm_set1_pi16(0x1100);\n   const __m64 mul_a      = _mm_set1_pi16(0x0011);\n\n   int max_width            = width - 3;\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride >> 1)\n   {\n      int w = 0;\n#if defined(__MMX__)\n      for (; w < max_width; w += 4)\n      {\n         __m64 res_lo, res_hi;\n         __m64 res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;\n         const __m64 in = *((__m64*)(input + w));\n         __m64          r = _mm_and_si64(_mm_srli_pi16(in, 2), pix_mask_r);\n         __m64          g = _mm_and_si64(in, pix_mask_g);\n         __m64          b = _mm_and_si64(_mm_slli_pi16(in, 4), pix_mask_b);\n         /* Source is rgba4444 -- alpha is the low nibble of each 16-bit\n          * input word.  Expand 4-bit -> 8-bit via a*0x11 (== a<<4 | a),\n          * matching the scalar fallback. */\n         __m64          a = _mm_and_si64(in, pix_mask_a);\n\n         r                = _mm_mulhi_pi16(r, mul16_r);\n         g                = _mm_mulhi_pi16(g, mul16_g);\n         b                = _mm_mulhi_pi16(b, mul16_b);\n         a                = _mm_mullo_pi16(a, mul_a);\n\n         res_lo_bg        = _mm_unpacklo_pi8(b, g);\n         res_hi_bg        = _mm_unpackhi_pi8(b, g);\n         res_lo_ra        = _mm_unpacklo_pi8(r, a);\n         res_hi_ra        = _mm_unpackhi_pi8(r, a);\n\n         res_lo           = _mm_or_si64(res_lo_bg,\n               _mm_slli_si64(res_lo_ra, 16));\n         res_hi           = _mm_or_si64(res_hi_bg,\n               _mm_slli_si64(res_hi_ra, 16));\n\n         *((__m64*)(output + w + 0)) = res_lo;\n         *((__m64*)(output + w + 2)) = res_hi;\n      }\n\n      _mm_empty();\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 12) & 0xf;\n         uint32_t g   = (col >>  8) & 0xf;\n         uint32_t b   = (col >>  4) & 0xf;\n         uint32_t a   = (col >>  0) & 0xf;\n         r            = (r << 4) | r;\n         g            = (g << 4) | g;\n         b            = (b << 4) | b;\n         a            = (a << 4) | a;\n\n         output[w]    = (a << 24) | (r << 16) | (g << 8) | (b << 0);\n      }\n   }\n}\n\nvoid conv_rgba4444_rgb565(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   const uint16_t *input = (const uint16_t*)input_;\n   uint16_t *output      = (uint16_t*)output_;\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 1, input += in_stride >> 1)\n   {\n      for (w = 0; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 12) & 0xf;\n         uint32_t g   = (col >>  8) & 0xf;\n         uint32_t b   = (col >>  4) & 0xf;\n\n         output[w]    = (r << 12) | (g << 7) | (b << 1);\n      }\n   }\n}\n\n#if defined(__SSE2__)\n/* :( TODO: Make this saner. */\nstatic INLINE void store_bgr24_sse2(void *output, __m128i a,\n      __m128i b, __m128i c, __m128i d)\n{\n   const __m128i mask_0 = _mm_set_epi32(0, 0, 0, 0x00ffffff);\n   const __m128i mask_1 = _mm_set_epi32(0, 0, 0x00ffffff, 0);\n   const __m128i mask_2 = _mm_set_epi32(0, 0x00ffffff, 0, 0);\n   const __m128i mask_3 = _mm_set_epi32(0x00ffffff, 0, 0, 0);\n\n   __m128i a0 = _mm_and_si128(a, mask_0);\n   __m128i a1 = _mm_srli_si128(_mm_and_si128(a, mask_1),  1);\n   __m128i a2 = _mm_srli_si128(_mm_and_si128(a, mask_2),  2);\n   __m128i a3 = _mm_srli_si128(_mm_and_si128(a, mask_3),  3);\n   __m128i a4 = _mm_slli_si128(_mm_and_si128(b, mask_0), 12);\n   __m128i a5 = _mm_slli_si128(_mm_and_si128(b, mask_1), 11);\n\n   __m128i b0 = _mm_srli_si128(_mm_and_si128(b, mask_1), 5);\n   __m128i b1 = _mm_srli_si128(_mm_and_si128(b, mask_2), 6);\n   __m128i b2 = _mm_srli_si128(_mm_and_si128(b, mask_3), 7);\n   __m128i b3 = _mm_slli_si128(_mm_and_si128(c, mask_0), 8);\n   __m128i b4 = _mm_slli_si128(_mm_and_si128(c, mask_1), 7);\n   __m128i b5 = _mm_slli_si128(_mm_and_si128(c, mask_2), 6);\n\n   __m128i c0 = _mm_srli_si128(_mm_and_si128(c, mask_2), 10);\n   __m128i c1 = _mm_srli_si128(_mm_and_si128(c, mask_3), 11);\n   __m128i c2 = _mm_slli_si128(_mm_and_si128(d, mask_0),  4);\n   __m128i c3 = _mm_slli_si128(_mm_and_si128(d, mask_1),  3);\n   __m128i c4 = _mm_slli_si128(_mm_and_si128(d, mask_2),  2);\n   __m128i c5 = _mm_slli_si128(_mm_and_si128(d, mask_3),  1);\n\n   __m128i *out = (__m128i*)output;\n\n   _mm_storeu_si128(out + 0,\n         _mm_or_si128(a0, _mm_or_si128(a1, _mm_or_si128(a2,\n                  _mm_or_si128(a3, _mm_or_si128(a4, a5))))));\n\n   _mm_storeu_si128(out + 1,\n         _mm_or_si128(b0, _mm_or_si128(b1, _mm_or_si128(b2,\n                  _mm_or_si128(b3, _mm_or_si128(b4, b5))))));\n\n   _mm_storeu_si128(out + 2,\n         _mm_or_si128(c0, _mm_or_si128(c1, _mm_or_si128(c2,\n                  _mm_or_si128(c3, _mm_or_si128(c4, c5))))));\n}\n#endif\n\nvoid conv_0rgb1555_bgr24(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input     = (const uint16_t*)input_;\n   uint8_t *output           = (uint8_t*)output_;\n\n#if defined(__SSE2__)\n   const __m128i pix_mask_r  = _mm_set1_epi16(0x1f << 10);\n   const __m128i pix_mask_gb = _mm_set1_epi16(0x1f <<  5);\n   const __m128i mul15_mid   = _mm_set1_epi16(0x4200);\n   const __m128i mul15_hi    = _mm_set1_epi16(0x0210);\n   const __m128i a           = _mm_set1_epi16(0x00ff);\n\n   int max_width             = width - 15;\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride, input += in_stride >> 1)\n   {\n      uint8_t *out = output;\n      int   w = 0;\n\n#if defined(__SSE2__)\n      for (; w < max_width; w += 16, out += 48)\n      {\n         __m128i res_lo_bg0, res_lo_bg1, res_hi_bg0, res_hi_bg1,\n                 res_lo_ra0, res_lo_ra1, res_hi_ra0, res_hi_ra1,\n                 res_lo0, res_lo1, res_hi0, res_hi1;\n         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w + 0));\n         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));\n         __m128i r0        = _mm_and_si128(in0, pix_mask_r);\n         __m128i r1        = _mm_and_si128(in1, pix_mask_r);\n         __m128i g0        = _mm_and_si128(in0, pix_mask_gb);\n         __m128i g1        = _mm_and_si128(in1, pix_mask_gb);\n         __m128i b0        = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_gb);\n         __m128i b1        = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_gb);\n\n         r0                = _mm_mulhi_epi16(r0, mul15_hi);\n         r1                = _mm_mulhi_epi16(r1, mul15_hi);\n         g0                = _mm_mulhi_epi16(g0, mul15_mid);\n         g1                = _mm_mulhi_epi16(g1, mul15_mid);\n         b0                = _mm_mulhi_epi16(b0, mul15_mid);\n         b1                = _mm_mulhi_epi16(b1, mul15_mid);\n\n         res_lo_bg0        = _mm_unpacklo_epi8(b0, g0);\n         res_lo_bg1        = _mm_unpacklo_epi8(b1, g1);\n         res_hi_bg0        = _mm_unpackhi_epi8(b0, g0);\n         res_hi_bg1        = _mm_unpackhi_epi8(b1, g1);\n         res_lo_ra0        = _mm_unpacklo_epi8(r0, a);\n         res_lo_ra1        = _mm_unpacklo_epi8(r1, a);\n         res_hi_ra0        = _mm_unpackhi_epi8(r0, a);\n         res_hi_ra1        = _mm_unpackhi_epi8(r1, a);\n\n         res_lo0           = _mm_or_si128(res_lo_bg0,\n               _mm_slli_si128(res_lo_ra0, 2));\n         res_lo1           = _mm_or_si128(res_lo_bg1,\n               _mm_slli_si128(res_lo_ra1, 2));\n         res_hi0           = _mm_or_si128(res_hi_bg0,\n               _mm_slli_si128(res_hi_ra0, 2));\n         res_hi1           = _mm_or_si128(res_hi_bg1,\n               _mm_slli_si128(res_hi_ra1, 2));\n\n         /* Non-POT pixel sizes for the loss */\n         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t b   = (col >>  0) & 0x1f;\n         uint32_t g   = (col >>  5) & 0x1f;\n         uint32_t r   = (col >> 10) & 0x1f;\n         b            = (b << 3) | (b >> 2);\n         g            = (g << 3) | (g >> 2);\n         r            = (r << 3) | (r >> 2);\n\n         *out++       = b;\n         *out++       = g;\n         *out++       = r;\n      }\n   }\n}\n\nvoid conv_rgb565_bgr24(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint16_t *input    = (const uint16_t*)input_;\n   uint8_t *output          = (uint8_t*)output_;\n\n#if defined(__SSE2__)\n   const __m128i pix_mask_r = _mm_set1_epi16(0x1f << 10);\n   const __m128i pix_mask_g = _mm_set1_epi16(0x3f <<  5);\n   const __m128i pix_mask_b = _mm_set1_epi16(0x1f <<  5);\n   const __m128i mul16_r    = _mm_set1_epi16(0x0210);\n   const __m128i mul16_g    = _mm_set1_epi16(0x2080);\n   const __m128i mul16_b    = _mm_set1_epi16(0x4200);\n   const __m128i a          = _mm_set1_epi16(0x00ff);\n\n   int max_width            = width - 15;\n#endif\n\n   for (h = 0; h < height; h++, output += out_stride, input += in_stride >> 1)\n   {\n      uint8_t *out = output;\n      int        w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 16, out += 48)\n      {\n         __m128i res_lo_bg0, res_hi_bg0, res_lo_ra0, res_hi_ra0;\n         __m128i res_lo_bg1, res_hi_bg1, res_lo_ra1, res_hi_ra1;\n         __m128i res_lo0, res_hi0, res_lo1, res_hi1;\n         const __m128i in0 = _mm_loadu_si128((const __m128i*)(input + w));\n         const __m128i in1 = _mm_loadu_si128((const __m128i*)(input + w + 8));\n         __m128i r0 = _mm_and_si128(_mm_srli_epi16(in0, 1), pix_mask_r);\n         __m128i g0 = _mm_and_si128(in0, pix_mask_g);\n         __m128i b0 = _mm_and_si128(_mm_slli_epi16(in0, 5), pix_mask_b);\n         __m128i r1 = _mm_and_si128(_mm_srli_epi16(in1, 1), pix_mask_r);\n         __m128i g1 = _mm_and_si128(in1, pix_mask_g);\n         __m128i b1 = _mm_and_si128(_mm_slli_epi16(in1, 5), pix_mask_b);\n\n         r0         = _mm_mulhi_epi16(r0, mul16_r);\n         g0         = _mm_mulhi_epi16(g0, mul16_g);\n         b0         = _mm_mulhi_epi16(b0, mul16_b);\n         r1         = _mm_mulhi_epi16(r1, mul16_r);\n         g1         = _mm_mulhi_epi16(g1, mul16_g);\n         b1         = _mm_mulhi_epi16(b1, mul16_b);\n\n         res_lo_bg0 = _mm_unpacklo_epi8(b0, g0);\n         res_hi_bg0 = _mm_unpackhi_epi8(b0, g0);\n         res_lo_ra0 = _mm_unpacklo_epi8(r0, a);\n         res_hi_ra0 = _mm_unpackhi_epi8(r0, a);\n         res_lo_bg1 = _mm_unpacklo_epi8(b1, g1);\n         res_hi_bg1 = _mm_unpackhi_epi8(b1, g1);\n         res_lo_ra1 = _mm_unpacklo_epi8(r1, a);\n         res_hi_ra1 = _mm_unpackhi_epi8(r1, a);\n\n         res_lo0    = _mm_or_si128(res_lo_bg0,\n               _mm_slli_si128(res_lo_ra0, 2));\n         res_hi0    = _mm_or_si128(res_hi_bg0,\n               _mm_slli_si128(res_hi_ra0, 2));\n         res_lo1    = _mm_or_si128(res_lo_bg1,\n               _mm_slli_si128(res_lo_ra1, 2));\n         res_hi1    = _mm_or_si128(res_hi_bg1,\n               _mm_slli_si128(res_hi_ra1, 2));\n\n         store_bgr24_sse2(out, res_lo0, res_hi0, res_lo1, res_hi1);\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint32_t r   = (col >> 11) & 0x1f;\n         uint32_t g   = (col >>  5) & 0x3f;\n         uint32_t b   = (col >>  0) & 0x1f;\n         r = (r << 3) | (r >> 2);\n         g = (g << 2) | (g >> 4);\n         b = (b << 3) | (b >> 2);\n\n         *out++ = b;\n         *out++ = g;\n         *out++ = r;\n      }\n   }\n}\n\nvoid conv_bgr24_argb8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   const uint8_t *input = (const uint8_t*)input_;\n   uint32_t *output     = (uint32_t*)output_;\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride)\n   {\n      const uint8_t *inp = input;\n      for (w = 0; w < width; w++)\n      {\n         uint32_t b = *inp++;\n         uint32_t g = *inp++;\n         uint32_t r = *inp++;\n         output[w]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);\n      }\n   }\n}\n\nvoid conv_bgr24_rgb565(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   const uint8_t *input = (const uint8_t*)input_;\n   uint16_t *output     = (uint16_t*)output_;\n   for (h = 0; h < height;\n         h++, output += out_stride, input += in_stride)\n   {\n      const uint8_t *inp = input;\n      for (w = 0; w < width; w++)\n      {\n         uint16_t b = *inp++;\n         uint16_t g = *inp++;\n         uint16_t r = *inp++;\n\n         output[w] = ((r & 0x00F8) << 8) | ((g&0x00FC) << 3) | ((b&0x00F8) >> 3);\n      }\n   }\n}\n\nvoid conv_argb8888_0rgb1555(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   const uint32_t *input = (const uint32_t*)input_;\n   uint16_t *output      = (uint16_t*)output_;\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 1, input += in_stride >> 2)\n   {\n      for (w = 0; w < width; w++)\n      {\n         uint32_t col = input[w];\n         uint16_t r   = (col >> 19) & 0x1f;\n         uint16_t g   = (col >> 11) & 0x1f;\n         uint16_t b   = (col >>  3) & 0x1f;\n         output[w]    = (r << 10) | (g << 5) | (b << 0);\n      }\n   }\n}\n\nvoid conv_argb8888_bgr24(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint32_t *input = (const uint32_t*)input_;\n   uint8_t *output       = (uint8_t*)output_;\n\n#if defined(__SSE2__)\n   int max_width = width - 15;\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride, input += in_stride >> 2)\n   {\n      uint8_t *out = output;\n      int        w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 16, out += 48)\n      {\n         __m128i l0 = _mm_loadu_si128((const __m128i*)(input + w +  0));\n         __m128i l1 = _mm_loadu_si128((const __m128i*)(input + w +  4));\n         __m128i l2 = _mm_loadu_si128((const __m128i*)(input + w +  8));\n         __m128i l3 = _mm_loadu_si128((const __m128i*)(input + w + 12));\n         store_bgr24_sse2(out, l0, l1, l2, l3);\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         *out++       = (uint8_t)(col >>  0);\n         *out++       = (uint8_t)(col >>  8);\n         *out++       = (uint8_t)(col >> 16);\n      }\n   }\n}\n\n#if defined(__SSE2__)\nstatic INLINE __m128i conv_shuffle_rb_epi32(__m128i c)\n{\n   /* SSSE3 plz */\n   const __m128i b_mask = _mm_set1_epi32(0x000000ff);\n   const __m128i g_mask = _mm_set1_epi32(0x0000ff00);\n   const __m128i r_mask = _mm_set1_epi32(0x00ff0000);\n   __m128i sl = _mm_and_si128(_mm_slli_epi32(c, 16), r_mask);\n   __m128i sr = _mm_and_si128(_mm_srli_epi32(c, 16), b_mask);\n   __m128i g  = _mm_and_si128(c, g_mask);\n   __m128i rb = _mm_or_si128(sl, sr);\n   return _mm_or_si128(g, rb);\n}\n#endif\n\nvoid conv_abgr8888_bgr24(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint32_t *input = (const uint32_t*)input_;\n   uint8_t *output       = (uint8_t*)output_;\n\n#if defined(__SSE2__)\n   int max_width = width - 15;\n#endif\n\n   for (h = 0; h < height;\n         h++, output += out_stride, input += in_stride >> 2)\n   {\n      uint8_t *out = output;\n      int        w = 0;\n#if defined(__SSE2__)\n      for (; w < max_width; w += 16, out += 48)\n      {\n\t\t __m128i a = _mm_loadu_si128((const __m128i*)(input + w +  0));\n\t\t __m128i b = _mm_loadu_si128((const __m128i*)(input + w +  4));\n\t\t __m128i c = _mm_loadu_si128((const __m128i*)(input + w +  8));\n\t\t __m128i d = _mm_loadu_si128((const __m128i*)(input + w + 12));\n         a = conv_shuffle_rb_epi32(a);\n         b = conv_shuffle_rb_epi32(b);\n         c = conv_shuffle_rb_epi32(c);\n         d = conv_shuffle_rb_epi32(d);\n         store_bgr24_sse2(out, a, b, c, d);\n      }\n#endif\n\n      for (; w < width; w++)\n      {\n         uint32_t col = input[w];\n         *out++       = (uint8_t)(col >> 16);\n         *out++       = (uint8_t)(col >>  8);\n         *out++       = (uint8_t)(col >>  0);\n      }\n   }\n}\n\nvoid conv_argb8888_abgr8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   const uint32_t *input = (const uint32_t*)input_;\n   uint32_t *output      = (uint32_t*)output_;\n\n   for (h = 0; h < height;\n         h++, output += out_stride >> 2, input += in_stride >> 2)\n   {\n      for (w = 0; w < width; w++)\n      {\n         uint32_t col = input[w];\n         output[w]    = ((col << 16) & 0xff0000) |\n            ((col >> 16) & 0xff) | (col & 0xff00ff00);\n      }\n   }\n}\n\n#define YUV_SHIFT 6\n#define YUV_OFFSET (1 << (YUV_SHIFT - 1))\n#define YUV_MAT_Y (1 << 6)\n#define YUV_MAT_U_G (-22)\n#define YUV_MAT_U_B (113)\n#define YUV_MAT_V_R (90)\n#define YUV_MAT_V_G (-46)\n\nvoid conv_yuyv_argb8888(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   const uint8_t *input        = (const uint8_t*)input_;\n   uint32_t *output            = (uint32_t*)output_;\n\n#if defined(__SSE2__)\n   const __m128i mask_y        = _mm_set1_epi16(0xffu);\n   const __m128i mask_u        = _mm_set1_epi32(0xffu << 8);\n   const __m128i mask_v        = _mm_set1_epi32(0xffu << 24);\n   const __m128i chroma_offset = _mm_set1_epi16(128);\n   const __m128i round_offset  = _mm_set1_epi16(YUV_OFFSET);\n\n   const __m128i yuv_mul       = _mm_set1_epi16(YUV_MAT_Y);\n   const __m128i u_g_mul       = _mm_set1_epi16(YUV_MAT_U_G);\n   const __m128i u_b_mul       = _mm_set1_epi16(YUV_MAT_U_B);\n   const __m128i v_r_mul       = _mm_set1_epi16(YUV_MAT_V_R);\n   const __m128i v_g_mul       = _mm_set1_epi16(YUV_MAT_V_G);\n   const __m128i a             = _mm_cmpeq_epi16(\n         _mm_setzero_si128(), _mm_setzero_si128());\n#endif\n\n   for (h = 0; h < height; h++, output += out_stride >> 2, input += in_stride)\n   {\n      const uint8_t *src = input;\n      uint32_t      *dst = output;\n      int              w = 0;\n\n#if defined(__SSE2__)\n      /* Each loop processes 16 pixels. */\n      for (; w + 16 <= width; w += 16, src += 32, dst += 16)\n      {\n         __m128i u, v, u0_g, u1_g, u0_b, u1_b, v0_r, v1_r, v0_g, v1_g,\n                 r0, g0, b0, r1, g1, b1;\n         __m128i res_lo_bg, res_hi_bg, res_lo_ra, res_hi_ra;\n         __m128i res0, res1, res2, res3;\n         __m128i yuv0 = _mm_loadu_si128((const __m128i*)(src +  0)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */\n         __m128i yuv1 = _mm_loadu_si128((const __m128i*)(src + 16)); /* [Y0, U0, Y1, V0, Y2, U1, Y3, V1, ...] */\n\n         __m128i _y0 = _mm_and_si128(yuv0, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */\n         __m128i u0 = _mm_and_si128(yuv0, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */\n         __m128i v0 = _mm_and_si128(yuv0, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */\n         __m128i _y1 = _mm_and_si128(yuv1, mask_y); /* [Y0, Y1, Y2, ...] (16-bit) */\n         __m128i u1 = _mm_and_si128(yuv1, mask_u); /* [0, U0, 0, 0, 0, U1, 0, 0, ...] */\n         __m128i v1 = _mm_and_si128(yuv1, mask_v); /* [0, 0, 0, V1, 0, , 0, V1, ...] */\n\n         /* Juggle around to get U and V in the same 16-bit format as Y. */\n         u0 = _mm_srli_si128(u0, 1);\n         v0 = _mm_srli_si128(v0, 3);\n         u1 = _mm_srli_si128(u1, 1);\n         v1 = _mm_srli_si128(v1, 3);\n         u = _mm_packs_epi32(u0, u1);\n         v = _mm_packs_epi32(v0, v1);\n\n         /* Apply YUV offsets (U, V) -= (-128, -128). */\n         u = _mm_sub_epi16(u, chroma_offset);\n         v = _mm_sub_epi16(v, chroma_offset);\n\n         /* Upscale chroma horizontally (nearest). */\n         u0 = _mm_unpacklo_epi16(u, u);\n         u1 = _mm_unpackhi_epi16(u, u);\n         v0 = _mm_unpacklo_epi16(v, v);\n         v1 = _mm_unpackhi_epi16(v, v);\n\n         /* Apply transformations. */\n         _y0 = _mm_mullo_epi16(_y0, yuv_mul);\n         _y1 = _mm_mullo_epi16(_y1, yuv_mul);\n         u0_g   = _mm_mullo_epi16(u0, u_g_mul);\n         u1_g   = _mm_mullo_epi16(u1, u_g_mul);\n         u0_b   = _mm_mullo_epi16(u0, u_b_mul);\n         u1_b   = _mm_mullo_epi16(u1, u_b_mul);\n         v0_r   = _mm_mullo_epi16(v0, v_r_mul);\n         v1_r   = _mm_mullo_epi16(v1, v_r_mul);\n         v0_g   = _mm_mullo_epi16(v0, v_g_mul);\n         v1_g   = _mm_mullo_epi16(v1, v_g_mul);\n\n         /* Add contibutions from the transformed components. */\n         r0 = _mm_srai_epi16(_mm_adds_epi16(_mm_adds_epi16(_y0, v0_r),\n                  round_offset), YUV_SHIFT);\n         g0 = _mm_srai_epi16(_mm_adds_epi16(\n                  _mm_adds_epi16(_mm_adds_epi16(_y0, v0_g), u0_g), round_offset), YUV_SHIFT);\n         b0 = _mm_srai_epi16(_mm_adds_epi16(\n                  _mm_adds_epi16(_y0, u0_b), round_offset), YUV_SHIFT);\n\n         r1 = _mm_srai_epi16(_mm_adds_epi16(\n                  _mm_adds_epi16(_y1, v1_r), round_offset), YUV_SHIFT);\n         g1 = _mm_srai_epi16(_mm_adds_epi16(\n                  _mm_adds_epi16(_mm_adds_epi16(_y1, v1_g), u1_g), round_offset), YUV_SHIFT);\n         b1 = _mm_srai_epi16(_mm_adds_epi16(\n                  _mm_adds_epi16(_y1, u1_b), round_offset), YUV_SHIFT);\n\n         /* Saturate into 8-bit. */\n         r0 = _mm_packus_epi16(r0, r1);\n         g0 = _mm_packus_epi16(g0, g1);\n         b0 = _mm_packus_epi16(b0, b1);\n\n         /* Interleave into ARGB. */\n         res_lo_bg = _mm_unpacklo_epi8(b0, g0);\n         res_hi_bg = _mm_unpackhi_epi8(b0, g0);\n         res_lo_ra = _mm_unpacklo_epi8(r0, a);\n         res_hi_ra = _mm_unpackhi_epi8(r0, a);\n         res0 = _mm_unpacklo_epi16(res_lo_bg, res_lo_ra);\n         res1 = _mm_unpackhi_epi16(res_lo_bg, res_lo_ra);\n         res2 = _mm_unpacklo_epi16(res_hi_bg, res_hi_ra);\n         res3 = _mm_unpackhi_epi16(res_hi_bg, res_hi_ra);\n\n         _mm_storeu_si128((__m128i*)(dst +  0), res0);\n         _mm_storeu_si128((__m128i*)(dst +  4), res1);\n         _mm_storeu_si128((__m128i*)(dst +  8), res2);\n         _mm_storeu_si128((__m128i*)(dst + 12), res3);\n      }\n#endif\n\n      /* Finish off the rest (if any) in C. */\n      for (; w < width; w += 2, src += 4, dst += 2)\n      {\n         int _y0    = src[0];\n         int  u     = src[1] - 128;\n         int _y1    = src[2];\n         int  v     = src[3] - 128;\n\n         uint8_t r0 = clamp_8bit((YUV_MAT_Y * _y0 +                   YUV_MAT_V_R * v + YUV_OFFSET) >> YUV_SHIFT);\n         uint8_t g0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) >> YUV_SHIFT);\n         uint8_t b0 = clamp_8bit((YUV_MAT_Y * _y0 + YUV_MAT_U_B * u                   + YUV_OFFSET) >> YUV_SHIFT);\n\n         uint8_t r1 = clamp_8bit((YUV_MAT_Y * _y1 +                   YUV_MAT_V_R * v + YUV_OFFSET) >> YUV_SHIFT);\n         uint8_t g1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_G * u + YUV_MAT_V_G * v + YUV_OFFSET) >> YUV_SHIFT);\n         uint8_t b1 = clamp_8bit((YUV_MAT_Y * _y1 + YUV_MAT_U_B * u                   + YUV_OFFSET) >> YUV_SHIFT);\n\n         dst[0]     = 0xff000000u | (r0 << 16) | (g0 << 8) | (b0 << 0);\n         dst[1]     = 0xff000000u | (r1 << 16) | (g1 << 8) | (b1 << 0);\n      }\n   }\n}\n\nvoid conv_copy(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride)\n{\n   int h;\n   int copy_len         = abs(out_stride);\n   const uint8_t *input = (const uint8_t*)input_;\n   uint8_t *output      = (uint8_t*)output_;\n\n   if (abs(in_stride) < copy_len)\n      copy_len          = abs(in_stride);\n\n   for (h = 0; h < height;\n         h++, output += out_stride, input += in_stride)\n      memcpy(output, input, copy_len);\n}\n"
  },
  {
    "path": "gfx/scaler/scaler.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (scaler.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#include <gfx/scaler/scaler.h>\n#include <gfx/scaler/scaler_int.h>\n#include <gfx/scaler/filter.h>\n#include <gfx/scaler/pixconv.h>\n\nstatic bool allocate_frames(struct scaler_ctx *ctx)\n{\n   uint64_t *scaled_frame = NULL;\n   ctx->scaled.stride     = ((ctx->out_width + 7) & ~7) * sizeof(uint64_t);\n   ctx->scaled.width      = ctx->out_width;\n   ctx->scaled.height     = ctx->in_height;\n   scaled_frame           = (uint64_t*)calloc(\n            (ctx->scaled.stride * ctx->scaled.height) >> 3,\n            sizeof(uint64_t));\n\n   if (!scaled_frame)\n      return false;\n\n   ctx->scaled.frame      = scaled_frame;\n\n   if (ctx->in_fmt != SCALER_FMT_ARGB8888)\n   {\n      uint32_t *input_frame = NULL;\n      ctx->input.stride     = ((ctx->in_width + 7) & ~7) * sizeof(uint32_t);\n      input_frame           = (uint32_t*)calloc(\n               (ctx->input.stride * ctx->in_height) >> 2,\n               sizeof(uint32_t));\n\n      if (!input_frame)\n         return false;\n\n      ctx->input.frame      = input_frame;\n   }\n\n   if (ctx->out_fmt != SCALER_FMT_ARGB8888)\n   {\n      uint32_t *output_frame = NULL;\n      ctx->output.stride     = ((ctx->out_width + 7) & ~7) * sizeof(uint32_t);\n\n      output_frame           = (uint32_t*)calloc(\n               (ctx->output.stride * ctx->out_height) >> 2,\n               sizeof(uint32_t));\n\n      if (!output_frame)\n         return false;\n\n      ctx->output.frame      = output_frame;\n   }\n\n   return true;\n}\n\nbool scaler_ctx_gen_filter(struct scaler_ctx *ctx)\n{\n   scaler_ctx_gen_reset(ctx);\n\n   ctx->scaler_special = NULL;\n   ctx->unscaled       = false;\n\n   if (!allocate_frames(ctx))\n      return false;\n\n   if (     ctx->in_width  == ctx->out_width\n         && ctx->in_height == ctx->out_height)\n   {\n      ctx->unscaled     = true; /* Only pixel format conversion ... */\n\n      if (ctx->in_fmt == ctx->out_fmt)\n         ctx->direct_pixconv = conv_copy;\n      else\n      {\n         /* Bind a pixel converter callback function to the\n          * 'direct_pixconv' function pointer of the scaler context object. */\n         switch (ctx->in_fmt)\n         {\n            case SCALER_FMT_0RGB1555:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_ARGB8888:\n                     ctx->direct_pixconv = conv_0rgb1555_argb8888;\n                     break;\n                  case SCALER_FMT_RGB565:\n                     ctx->direct_pixconv = conv_0rgb1555_rgb565;\n                     break;\n                  case SCALER_FMT_BGR24:\n                     ctx->direct_pixconv = conv_0rgb1555_bgr24;\n                     break;\n                  default:\n                     break;\n               }\n               break;\n            case SCALER_FMT_RGB565:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_ARGB8888:\n                     ctx->direct_pixconv = conv_rgb565_argb8888;\n                     break;\n                  case SCALER_FMT_ABGR8888:\n                     ctx->direct_pixconv = conv_rgb565_abgr8888;\n                     break;\n                  case SCALER_FMT_BGR24:\n                     ctx->direct_pixconv = conv_rgb565_bgr24;\n                     break;\n                  case SCALER_FMT_0RGB1555:\n                     ctx->direct_pixconv = conv_rgb565_0rgb1555;\n                     break;\n                  default:\n                     break;\n               }\n               break;\n            case SCALER_FMT_BGR24:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_ARGB8888:\n                     ctx->direct_pixconv = conv_bgr24_argb8888;\n                     break;\n                  case SCALER_FMT_RGB565:\n                     ctx->direct_pixconv = conv_bgr24_rgb565;\n                  default:\n                     break;\n               }\n               break;\n            case SCALER_FMT_ARGB8888:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_0RGB1555:\n                     ctx->direct_pixconv = conv_argb8888_0rgb1555;\n                     break;\n                  case SCALER_FMT_BGR24:\n                     ctx->direct_pixconv = conv_argb8888_bgr24;\n                     break;\n                  case SCALER_FMT_ABGR8888:\n                     ctx->direct_pixconv = conv_argb8888_abgr8888;\n                     break;\n                  case SCALER_FMT_RGBA4444:\n                     ctx->direct_pixconv = conv_argb8888_rgba4444;\n                     break;\n                  default:\n                     break;\n               }\n               break;\n            case SCALER_FMT_YUYV:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_ARGB8888:\n                     ctx->direct_pixconv = conv_yuyv_argb8888;\n                     break;\n                  default:\n                     break;\n               }\n               break;\n            case SCALER_FMT_RGBA4444:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_ARGB8888:\n                     ctx->direct_pixconv = conv_rgba4444_argb8888;\n                     break;\n                  case SCALER_FMT_RGB565:\n                     ctx->direct_pixconv = conv_rgba4444_rgb565;\n                     break;\n                  default:\n                     break;\n               }\n               break;\n            case SCALER_FMT_ABGR8888:\n               switch (ctx->out_fmt)\n               {\n                  case SCALER_FMT_BGR24:\n                     ctx->direct_pixconv = conv_abgr8888_bgr24;\n                     break;\n                  default:\n                     break;\n               }\n               break;\n         }\n\n         if (!ctx->direct_pixconv)\n            return false;\n      }\n   }\n   else\n   {\n      ctx->scaler_horiz = scaler_argb8888_horiz;\n      ctx->scaler_vert  = scaler_argb8888_vert;\n\n      switch (ctx->in_fmt)\n      {\n         case SCALER_FMT_ARGB8888:\n            /* No need to convert :D */\n            break;\n\n         case SCALER_FMT_0RGB1555:\n            ctx->in_pixconv = conv_0rgb1555_argb8888;\n            break;\n\n         case SCALER_FMT_RGB565:\n            ctx->in_pixconv = conv_rgb565_argb8888;\n            break;\n\n         case SCALER_FMT_BGR24:\n            ctx->in_pixconv = conv_bgr24_argb8888;\n            break;\n\n         case SCALER_FMT_RGBA4444:\n            ctx->in_pixconv = conv_rgba4444_argb8888;\n            break;\n\n         default:\n            return false;\n      }\n\n      switch (ctx->out_fmt)\n      {\n         case SCALER_FMT_ARGB8888:\n            /* No need to convert :D */\n            break;\n\n         case SCALER_FMT_RGBA4444:\n            ctx->out_pixconv = conv_argb8888_rgba4444;\n            break;\n\n         case SCALER_FMT_0RGB1555:\n            ctx->out_pixconv = conv_argb8888_0rgb1555;\n            break;\n\n         case SCALER_FMT_BGR24:\n            ctx->out_pixconv = conv_argb8888_bgr24;\n            break;\n\n         case SCALER_FMT_ABGR8888:\n            ctx->out_pixconv = conv_argb8888_abgr8888;\n            break;\n\n         default:\n            return false;\n      }\n\n      if (!scaler_gen_filter(ctx))\n         return false;\n   }\n\n   return true;\n}\n\nvoid scaler_ctx_gen_reset(struct scaler_ctx *ctx)\n{\n   if (ctx->horiz.filter)\n      free(ctx->horiz.filter);\n   if (ctx->horiz.filter_pos)\n      free(ctx->horiz.filter_pos);\n   if (ctx->vert.filter)\n      free(ctx->vert.filter);\n   if (ctx->vert.filter_pos)\n      free(ctx->vert.filter_pos);\n   if (ctx->scaled.frame)\n      free(ctx->scaled.frame);\n   if (ctx->input.frame)\n      free(ctx->input.frame);\n   if (ctx->output.frame)\n      free(ctx->output.frame);\n\n   ctx->horiz.filter        = NULL;\n   ctx->horiz.filter_len    = 0;\n   ctx->horiz.filter_stride = 0;\n   ctx->horiz.filter_pos    = NULL;\n\n   ctx->vert.filter         = NULL;\n   ctx->vert.filter_len     = 0;\n   ctx->vert.filter_stride  = 0;\n   ctx->vert.filter_pos     = NULL;\n\n   ctx->scaled.frame        = NULL;\n   ctx->scaled.width        = 0;\n   ctx->scaled.height       = 0;\n   ctx->scaled.stride       = 0;\n\n   ctx->input.frame         = NULL;\n   ctx->input.stride        = 0;\n\n   ctx->output.frame        = NULL;\n   ctx->output.stride       = 0;\n}\n\n/**\n * scaler_ctx_scale:\n * @ctx          : pointer to scaler context object.\n * @output       : pointer to output image.\n * @input        : pointer to input image.\n *\n * Scales an input image to an output image.\n **/\nvoid scaler_ctx_scale(struct scaler_ctx *ctx,\n      void *output, const void *input)\n{\n   const void *input_frame = input;\n   void *output_frame      = output;\n   int input_stride        = ctx->in_stride;\n   int output_stride       = ctx->out_stride;\n\n   if (ctx->in_fmt != SCALER_FMT_ARGB8888)\n   {\n      ctx->in_pixconv(ctx->input.frame, input,\n            ctx->in_width, ctx->in_height,\n            ctx->input.stride, ctx->in_stride);\n\n      input_frame       = ctx->input.frame;\n      input_stride      = ctx->input.stride;\n   }\n\n   if (ctx->out_fmt != SCALER_FMT_ARGB8888)\n   {\n      output_frame  = ctx->output.frame;\n      output_stride = ctx->output.stride;\n   }\n\n   /* Take some special, and (hopefully) more optimized path. */\n   if (ctx->scaler_special)\n      ctx->scaler_special(ctx, output_frame, input_frame,\n            ctx->out_width, ctx->out_height,\n            ctx->in_width, ctx->in_height,\n            output_stride, input_stride);\n   else\n   {\n      /* Take generic filter path. */\n      if (ctx->scaler_horiz)\n         ctx->scaler_horiz(ctx, input_frame, input_stride);\n      if (ctx->scaler_vert)\n         ctx->scaler_vert (ctx, output, output_stride);\n   }\n\n   if (ctx->out_fmt != SCALER_FMT_ARGB8888)\n      ctx->out_pixconv(output, ctx->output.frame,\n            ctx->out_width, ctx->out_height,\n            ctx->out_stride, ctx->output.stride);\n}\n"
  },
  {
    "path": "gfx/scaler/scaler_filter.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (scaler_filter.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n\n#include <gfx/scaler/filter.h>\n#include <gfx/scaler/scaler_int.h>\n#include <retro_inline.h>\n#include <filters.h>\n#include <retro_math.h>\n\n#define FILTER_UNITY (1 << 14)\n\nstatic INLINE void gen_filter_point_sub(struct scaler_filter *filter,\n      int len, int pos, int step)\n{\n   int i;\n   for (i = 0; i < len; i++, pos += step)\n   {\n      filter->filter_pos[i] = pos >> 16;\n      filter->filter[i]     = FILTER_UNITY;\n   }\n}\n\nstatic INLINE void gen_filter_bilinear_sub(struct scaler_filter *filter,\n      int len, int pos, int step)\n{\n   int i;\n   for (i = 0; i < len; i++, pos += step)\n   {\n      filter->filter_pos[i]     = pos >> 16;\n      filter->filter[i * 2 + 1] = (pos & 0xffff) >> 2;\n      filter->filter[i * 2 + 0] = FILTER_UNITY - filter->filter[i * 2 + 1];\n   }\n}\n\nstatic INLINE void gen_filter_sinc_sub(struct scaler_filter *filter,\n      int len, int pos, int step, double phase_mul)\n{\n   int i, j;\n   const int sinc_size = filter->filter_len;\n\n   for (i = 0; i < len; i++, pos += step)\n   {\n      filter->filter_pos[i] = pos >> 16;\n\n      for (j = 0; j < sinc_size; j++)\n      {\n         double sinc_phase    = M_PI * ((double)((sinc_size << 15) + (pos & 0xffff)) / 0x10000 - j);\n         double lanczos_phase = sinc_phase / ((sinc_size >> 1));\n         int16_t sinc_val     = FILTER_UNITY * sinc(sinc_phase * phase_mul) * sinc(lanczos_phase) * phase_mul;\n\n         filter->filter[i * sinc_size + j] = sinc_val;\n      }\n   }\n}\n\nstatic bool validate_filter(struct scaler_ctx *ctx)\n{\n   int i;\n   int max_h_pos;\n   int max_w_pos = ctx->in_width - ctx->horiz.filter_len;\n\n   for (i = 0; i < ctx->out_width; i++)\n   {\n      if (ctx->horiz.filter_pos[i] > max_w_pos || ctx->horiz.filter_pos[i] < 0)\n         return false;\n   }\n\n   max_h_pos = ctx->in_height - ctx->vert.filter_len;\n\n   for (i = 0; i < ctx->out_height; i++)\n   {\n      if (ctx->vert.filter_pos[i] > max_h_pos || ctx->vert.filter_pos[i] < 0)\n         return false;\n   }\n\n   return true;\n}\n\nstatic void fixup_filter_sub(struct scaler_filter *filter,\n      int out_len, int in_len)\n{\n   int i;\n   int max_pos = in_len - filter->filter_len;\n\n   for (i = 0; i < out_len; i++)\n   {\n      int postsample =  filter->filter_pos[i] - max_pos;\n      int presample  = -filter->filter_pos[i];\n\n      if (postsample > 0)\n      {\n         int16_t *base_filter   = NULL;\n\n         filter->filter_pos[i] -= postsample;\n\n         base_filter            = filter->filter + i * filter->filter_stride;\n\n         if (postsample > (int)filter->filter_len)\n            memset(base_filter, 0, filter->filter_len * sizeof(int16_t));\n         else\n         {\n            memmove(base_filter + postsample, base_filter,\n                  (filter->filter_len - postsample) * sizeof(int16_t));\n            memset(base_filter, 0, postsample * sizeof(int16_t));\n         }\n      }\n\n      if (presample > 0)\n      {\n         int16_t *base_filter   = NULL;\n\n         filter->filter_pos[i] += presample;\n         base_filter            = filter->filter + i * filter->filter_stride;\n\n         if (presample > (int)filter->filter_len)\n            memset(base_filter, 0, filter->filter_len * sizeof(int16_t));\n         else\n         {\n            memmove(base_filter, base_filter + presample,\n                  (filter->filter_len - presample) * sizeof(int16_t));\n            memset(base_filter + (filter->filter_len - presample),\n                  0, presample * sizeof(int16_t));\n         }\n      }\n   }\n}\n\nbool scaler_gen_filter(struct scaler_ctx *ctx)\n{\n   int x_pos, x_step, y_pos, y_step;\n   int sinc_size = 0;\n\n   switch (ctx->scaler_type)\n   {\n      case SCALER_TYPE_POINT:\n         ctx->horiz.filter_len    = 1;\n         ctx->horiz.filter_stride = 1;\n         ctx->vert.filter_len     = 1;\n         ctx->vert.filter_stride  = 1;\n         break;\n      case SCALER_TYPE_BILINEAR:\n         ctx->horiz.filter_len    = 2;\n         ctx->horiz.filter_stride = 2;\n         ctx->vert.filter_len     = 2;\n         ctx->vert.filter_stride  = 2;\n         break;\n      case SCALER_TYPE_SINC:\n         sinc_size                = 8 * ((ctx->in_width > ctx->out_width)\n               ? next_pow2(ctx->in_width / ctx->out_width) : 1);\n         ctx->horiz.filter_len    = sinc_size;\n         ctx->horiz.filter_stride = sinc_size;\n         ctx->vert.filter_len     = sinc_size;\n         ctx->vert.filter_stride  = sinc_size;\n         break;\n      case SCALER_TYPE_UNKNOWN:\n      default:\n         return false;\n   }\n\n   ctx->horiz.filter     = (int16_t*)calloc(ctx->horiz.filter_stride * ctx->out_width, sizeof(int16_t));\n   ctx->horiz.filter_pos = (int*)calloc(ctx->out_width, sizeof(int));\n\n   ctx->vert.filter      = (int16_t*)calloc(ctx->vert.filter_stride * ctx->out_height, sizeof(int16_t));\n   ctx->vert.filter_pos  = (int*)calloc(ctx->out_height, sizeof(int));\n\n   if (!ctx->horiz.filter || !ctx->vert.filter)\n      return false;\n\n   x_step = (1 << 16) * ctx->in_width  / ctx->out_width;\n   y_step = (1 << 16) * ctx->in_height / ctx->out_height;\n   x_pos  = (1 << 15) * ctx->in_width  / ctx->out_width  - (1 << 15);\n   y_pos  = (1 << 15) * ctx->in_height / ctx->out_height - (1 << 15);\n\n   switch (ctx->scaler_type)\n   {\n      case SCALER_TYPE_POINT:\n         gen_filter_point_sub(&ctx->horiz, ctx->out_width,  x_pos, x_step);\n         gen_filter_point_sub(&ctx->vert,  ctx->out_height, y_pos, y_step);\n\n         ctx->scaler_special = scaler_argb8888_point_special;\n         break;\n\n      case SCALER_TYPE_BILINEAR:\n         gen_filter_bilinear_sub(&ctx->horiz, ctx->out_width,  x_pos, x_step);\n         gen_filter_bilinear_sub(&ctx->vert,  ctx->out_height, y_pos, y_step);\n         break;\n\n      case SCALER_TYPE_SINC:\n         /* Need to expand the filter when downsampling\n          * to get a proper low-pass effect. */\n         x_pos  -= (sinc_size << 15);\n         y_pos  -= (sinc_size << 15);\n\n         gen_filter_sinc_sub(&ctx->horiz, ctx->out_width, x_pos, x_step,\n               ctx->in_width  > ctx->out_width  ? (double)ctx->out_width  / ctx->in_width  : 1.0);\n         gen_filter_sinc_sub(&ctx->vert, ctx->out_height, y_pos, y_step,\n               ctx->in_height > ctx->out_height ? (double)ctx->out_height / ctx->in_height : 1.0\n               );\n         break;\n      case SCALER_TYPE_UNKNOWN:\n         break;\n   }\n\n   /* Makes sure that we never sample outside our rectangle */\n   fixup_filter_sub(&ctx->horiz, ctx->out_width,  ctx->in_width);\n   fixup_filter_sub(&ctx->vert,  ctx->out_height, ctx->in_height);\n\n   return validate_filter(ctx);\n}\n"
  },
  {
    "path": "gfx/scaler/scaler_int.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (scaler_int.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <gfx/scaler/scaler_int.h>\n\n#include <retro_inline.h>\n\n#ifdef SCALER_NO_SIMD\n#undef __SSE2__\n#endif\n\n#if defined(__SSE2__)\n#include <emmintrin.h>\n#ifdef _WIN32\n#include <intrin.h>\n#endif\n#endif\n\n/* ARGB8888 scaler is split in two:\n *\n * First, horizontal scaler is applied.\n * Here, all 8-bit channels are expanded to 16-bit. Values are then shifted 7\n * to left to occupy 15 bits.\n *\n * The sign bit is kept empty as we have to do signed multiplication for the\n * filter.\n *\n * A mulhi [(a * b) >> 16] is applied which loses some precision, but is\n * very efficient for SIMD.\n * It is accurate enough for 8-bit purposes.\n *\n * The fixed point 1.0 for filter is (1 << 14). After horizontal scale,\n * the output is kept with 16-bit channels, and will now have 13 bits\n * of precision as [(a * (1 << 14)) >> 16] is effectively a right shift by 2.\n *\n * Vertical scaler takes the 13 bit channels, and performs the\n * same mulhi steps.\n * Another 2 bits of precision is lost, which ends up as 11 bits.\n * Scaling is now complete. Channels are shifted right by 3, and saturated\n * into 8-bit values.\n *\n * The C version of scalers perform the exact same operations as the\n * SIMD code for testing purposes.\n */\n\nvoid scaler_argb8888_vert(const struct scaler_ctx *ctx, void *output_, int stride)\n{\n   int h, w, y;\n   const uint64_t      *input = ctx->scaled.frame;\n   uint32_t           *output = (uint32_t*)output_;\n\n   const int16_t *filter_vert = ctx->vert.filter;\n\n   for (h = 0; h < ctx->out_height; h++,\n         filter_vert += ctx->vert.filter_stride, output += stride >> 2)\n   {\n      const uint64_t *input_base = input + ctx->vert.filter_pos[h]\n         * (ctx->scaled.stride >> 3);\n\n      for (w = 0; w < ctx->out_width; w++)\n      {\n         const uint64_t *input_base_y = input_base + w;\n#if defined(__SSE2__)\n         __m128i final;\n         __m128i res = _mm_setzero_si128();\n\n         for (y = 0; (y + 1) < ctx->vert.filter_len; y += 2,\n               input_base_y += (ctx->scaled.stride >> 2))\n         {\n            __m128i coeff = _mm_set_epi64x(filter_vert[y + 1] * 0x0001000100010001ll, filter_vert[y + 0] * 0x0001000100010001ll);\n            __m128i col   = _mm_set_epi64x(input_base_y[ctx->scaled.stride >> 3], input_base_y[0]);\n\n            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);\n         }\n\n         for (; y < ctx->vert.filter_len; y++, input_base_y += (ctx->scaled.stride >> 3))\n         {\n            __m128i coeff = _mm_set_epi64x(0, filter_vert[y] * 0x0001000100010001ll);\n            __m128i col   = _mm_set_epi64x(0, input_base_y[0]);\n\n            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);\n         }\n\n         res       = _mm_adds_epi16(_mm_srli_si128(res, 8), res);\n         res       = _mm_srai_epi16(res, (7 - 2 - 2));\n\n         final     = _mm_packus_epi16(res, res);\n\n         output[w] = _mm_cvtsi128_si32(final);\n#else\n         int16_t res_a = 0;\n         int16_t res_r = 0;\n         int16_t res_g = 0;\n         int16_t res_b = 0;\n\n         for (y = 0; y < ctx->vert.filter_len; y++,\n               input_base_y += (ctx->scaled.stride >> 3))\n         {\n            uint64_t col   = *input_base_y;\n\n            int16_t a      = (col >> 48) & 0xffff;\n            int16_t r      = (col >> 32) & 0xffff;\n            int16_t g      = (col >> 16) & 0xffff;\n            int16_t b      = (col >>  0) & 0xffff;\n\n            int16_t coeff  = filter_vert[y];\n\n            res_a         += (a * coeff) >> 16;\n            res_r         += (r * coeff) >> 16;\n            res_g         += (g * coeff) >> 16;\n            res_b         += (b * coeff) >> 16;\n         }\n\n         res_a           >>= (7 - 2 - 2);\n         res_r           >>= (7 - 2 - 2);\n         res_g           >>= (7 - 2 - 2);\n         res_b           >>= (7 - 2 - 2);\n\n         output[w]         =\n            (clamp_8bit(res_a) << 24) |\n            (clamp_8bit(res_r) << 16) |\n            (clamp_8bit(res_g) << 8)  |\n            (clamp_8bit(res_b) << 0);\n#endif\n      }\n   }\n}\n\nvoid scaler_argb8888_horiz(const struct scaler_ctx *ctx, const void *input_, int stride)\n{\n   int h, w, x;\n   const uint32_t *input = (uint32_t*)input_;\n   uint64_t *output      = ctx->scaled.frame;\n\n   for (h = 0; h < ctx->scaled.height; h++, input += stride >> 2,\n         output += ctx->scaled.stride >> 3)\n   {\n      const int16_t *filter_horiz = ctx->horiz.filter;\n\n      for (w = 0; w < ctx->scaled.width; w++,\n            filter_horiz += ctx->horiz.filter_stride)\n      {\n         const uint32_t *input_base_x = input + ctx->horiz.filter_pos[w];\n#if defined(__SSE2__)\n         __m128i res = _mm_setzero_si128();\n#ifndef __x86_64__\n         union\n         {\n            uint32_t *u32;\n            uint64_t *u64;\n         } u;\n#endif\n         for (x = 0; (x + 1) < ctx->horiz.filter_len; x += 2)\n         {\n            __m128i coeff = _mm_set_epi64x(filter_horiz[x + 1] * 0x0001000100010001ll, filter_horiz[x + 0] * 0x0001000100010001ll);\n\n            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi64x(0,\n                     ((uint64_t)input_base_x[x + 1] << 32) | input_base_x[x + 0]), _mm_setzero_si128());\n\n            col           = _mm_slli_epi16(col, 7);\n            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);\n         }\n\n         for (; x < ctx->horiz.filter_len; x++)\n         {\n            __m128i coeff = _mm_set_epi64x(0, filter_horiz[x] * 0x0001000100010001ll);\n            __m128i col   = _mm_unpacklo_epi8(_mm_set_epi32(0, 0, 0, input_base_x[x]), _mm_setzero_si128());\n\n            col           = _mm_slli_epi16(col, 7);\n            res           = _mm_adds_epi16(_mm_mulhi_epi16(col, coeff), res);\n         }\n\n         res              = _mm_adds_epi16(_mm_srli_si128(res, 8), res);\n\n#ifdef __x86_64__\n         output[w]        = _mm_cvtsi128_si64(res);\n#else /* 32-bit doesn't have si64. Do it in two steps. */\n         u.u64    = output + w;\n         u.u32[0] = _mm_cvtsi128_si32(res);\n         u.u32[1] = _mm_cvtsi128_si32(_mm_srli_si128(res, 4));\n#endif\n#else\n         int16_t res_a = 0;\n         int16_t res_r = 0;\n         int16_t res_g = 0;\n         int16_t res_b = 0;\n\n         for (x = 0; x < ctx->horiz.filter_len; x++)\n         {\n            uint32_t col   = input_base_x[x];\n\n            int16_t a      = (col >> (24 - 7)) & (0xff << 7);\n            int16_t r      = (col >> (16 - 7)) & (0xff << 7);\n            int16_t g      = (col >> ( 8 - 7)) & (0xff << 7);\n            int16_t b      = (col << ( 0 + 7)) & (0xff << 7);\n\n            int16_t coeff  = filter_horiz[x];\n\n            res_a         += (a * coeff) >> 16;\n            res_r         += (r * coeff) >> 16;\n            res_g         += (g * coeff) >> 16;\n            res_b         += (b * coeff) >> 16;\n         }\n\n         output[w]         = (\n               (uint64_t)res_a  << 48)  |\n               ((uint64_t)res_r << 32)  |\n               ((uint64_t)res_g << 16)  |\n               ((uint64_t)res_b << 0);\n#endif\n      }\n   }\n}\n\nvoid scaler_argb8888_point_special(const struct scaler_ctx *ctx,\n      void *output_, const void *input_,\n      int out_width, int out_height,\n      int in_width, int in_height,\n      int out_stride, int in_stride)\n{\n   int h, w;\n   int x_pos             = (1 << 15) * in_width / out_width - (1 << 15);\n   int x_step            = (1 << 16) * in_width / out_width;\n   int y_pos             = (1 << 15) * in_height / out_height - (1 << 15);\n   int y_step            = (1 << 16) * in_height / out_height;\n   const uint32_t *input = (const uint32_t*)input_;\n   uint32_t *output      = (uint32_t*)output_;\n\n   if (x_pos < 0)\n      x_pos = 0;\n   if (y_pos < 0)\n      y_pos = 0;\n\n   for (h = 0; h < out_height; h++, y_pos += y_step, output += out_stride >> 2)\n   {\n      int               x = x_pos;\n      const uint32_t *inp = input + (y_pos >> 16) * (in_stride >> 2);\n\n      for (w = 0; w < out_width; w++, x += x_step)\n         output[w] = inp[x >> 16];\n   }\n}\n"
  },
  {
    "path": "glsym/README.md",
    "content": "# Autogenerate GL extension loaders\n\n## OpenGL desktop\n\nUse Khronos' recent [header](www.opengl.org/registry/api/glext.h).\n\n    ./glgen.py /usr/include/GL/glext.h glsym_gl.h glsym_gl.c\n\n## OpenGL ES\n\n    ./glgen.py /usr/include/GLES2/gl2ext.h glsym_es2.h glsym_es2.c\n"
  },
  {
    "path": "glsym/glgen.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\n   License statement applies to this file (glgen.py) only.\n\n   Permission is hereby granted, free of charge,\n   to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n   to deal in the Software without restriction, including without limitation the rights to\n   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\n\nimport sys\nimport os\nimport re\n\nbanned_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' ]\n\ndef noext(sym):\n   for ext in banned_ext:\n      if sym.endswith(ext):\n         return False\n   return True\n\ndef fix_multiline_functions(lines):\n   fixed_lines = []\n   temp_lines = []\n   for line in lines:\n      if line.count('(') > line.count(')'):\n         temp_lines.append(line)\n      else:\n         if len(temp_lines) > 0:\n            if line.count(')') > line.count('('):\n               temp_lines.append(line)\n               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\\n','').replace('\\t',''))\n               fixed_lines.append(fixed_line)\n               temp_lines = []\n            else:\n               temp_lines.append(line)\n         else:\n            fixed_lines.append(line)\n   return fixed_lines\n\ndef find_gl_symbols(lines):\n   typedefs = []\n   syms = []\n   for line in lines:\n      m = re.search(r'^typedef.+PFN(\\S+)PROC.+$', line)\n      g = re.search(r'^.+(gl\\S+)\\W*\\(.+\\).*$', line)\n      if m and noext(m.group(1)):\n         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))\n      if g and noext(g.group(1)):\n         syms.append(g.group(1))\n   return (typedefs, syms)\n\ndef generate_defines(gl_syms):\n   res = []\n   for line in gl_syms:\n      res.append('#define {} __rglgen_{}'.format(line, line))\n   return res\n\ndef generate_declarations(gl_syms):\n   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]\n\ndef generate_macros(gl_syms):\n   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]\n\ndef dump(f, lines):\n   f.write('\\n'.join(lines))\n   f.write('\\n\\n')\n\nif __name__ == '__main__':\n\n   if len(sys.argv) > 4:\n      for banned in sys.argv[4:]:\n         banned_ext.append(banned)\n\n   with open(sys.argv[1], 'r') as f:\n      lines = fix_multiline_functions(f.readlines())\n      typedefs, syms = find_gl_symbols(lines)\n\n      overrides = generate_defines(syms)\n      declarations = generate_declarations(syms)\n      externs = ['extern ' + x for x in declarations]\n\n      macros = generate_macros(syms)\n\n   with open(sys.argv[2], 'w') as f:\n      f.write('#ifndef RGLGEN_DECL_H__\\n')\n      f.write('#define RGLGEN_DECL_H__\\n')\n\n      f.write('#ifdef __cplusplus\\n')\n      f.write('extern \"C\" {\\n')\n      f.write('#endif\\n')\n\n      f.write('#ifdef GL_APIENTRY\\n')\n      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('#else\\n')\n      f.write('#ifndef APIENTRY\\n')\n      f.write('#define APIENTRY\\n')\n      f.write('#endif\\n')\n      f.write('#ifndef APIENTRYP\\n')\n      f.write('#define APIENTRYP APIENTRY *\\n')\n      f.write('#endif\\n')\n      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('#endif\\n')\n\n      f.write('#ifndef GL_OES_EGL_image\\n')\n      f.write('typedef void *GLeglImageOES;\\n')\n      f.write('#endif\\n')\n\n      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\\n')\n      f.write('typedef GLint GLfixed;\\n')\n      f.write('#endif\\n')\n\n      f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\\n')\n      f.write('typedef long long int GLint64;\\n')\n      f.write('typedef unsigned long long int GLuint64;\\n')\n      f.write('typedef unsigned long long int GLuint64EXT;\\n')\n      f.write('typedef struct __GLsync *GLsync;\\n')\n      f.write('#endif\\n')\n\n      dump(f, typedefs)\n      dump(f, overrides)\n      dump(f, externs)\n\n      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\\n')\n      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\\n')\n\n      f.write('#ifdef __cplusplus\\n')\n      f.write('}\\n')\n      f.write('#endif\\n')\n\n      f.write('#endif\\n')\n\n   with open(sys.argv[3], 'w') as f:\n      f.write('#include \"glsym/glsym.h\"\\n')\n      f.write('#include <stddef.h>\\n')\n      f.write('#define SYM(x) { \"gl\" #x, &(gl##x) }\\n')\n      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\\n')\n      dump(f, macros)\n      f.write('    { NULL, NULL },\\n')\n      f.write('};\\n')\n      dump(f, declarations)\n"
  },
  {
    "path": "glsym/glsym_es2.c",
    "content": "#include \"glsym/glsym.h\"\n#include <stddef.h>\n#define SYM(x) { \"gl\" #x, &(gl##x) }\nconst struct rglgen_sym_map rglgen_symbol_map[] = {\n    SYM(BlendBarrierKHR),\n    SYM(DebugMessageControlKHR),\n    SYM(DebugMessageInsertKHR),\n    SYM(DebugMessageCallbackKHR),\n    SYM(GetDebugMessageLogKHR),\n    SYM(PushDebugGroupKHR),\n    SYM(PopDebugGroupKHR),\n    SYM(ObjectLabelKHR),\n    SYM(GetObjectLabelKHR),\n    SYM(ObjectPtrLabelKHR),\n    SYM(GetObjectPtrLabelKHR),\n    SYM(GetPointervKHR),\n    SYM(GetGraphicsResetStatusKHR),\n    SYM(ReadnPixelsKHR),\n    SYM(GetnUniformfvKHR),\n    SYM(GetnUniformivKHR),\n    SYM(GetnUniformuivKHR),\n    SYM(EGLImageTargetTexture2DOES),\n    SYM(EGLImageTargetRenderbufferStorageOES),\n    SYM(CopyImageSubDataOES),\n    SYM(EnableiOES),\n    SYM(DisableiOES),\n    SYM(BlendEquationiOES),\n    SYM(BlendEquationSeparateiOES),\n    SYM(BlendFunciOES),\n    SYM(BlendFuncSeparateiOES),\n    SYM(ColorMaskiOES),\n    SYM(IsEnablediOES),\n    SYM(DrawElementsBaseVertexOES),\n    SYM(DrawRangeElementsBaseVertexOES),\n    SYM(DrawElementsInstancedBaseVertexOES),\n    SYM(MultiDrawElementsBaseVertexOES),\n    SYM(FramebufferTextureOES),\n    SYM(GetProgramBinaryOES),\n    SYM(ProgramBinaryOES),\n    SYM(MapBufferOES),\n    SYM(UnmapBufferOES),\n    SYM(GetBufferPointervOES),\n    SYM(PrimitiveBoundingBoxOES),\n    SYM(MinSampleShadingOES),\n    SYM(PatchParameteriOES),\n    SYM(TexImage3DOES),\n    SYM(TexSubImage3DOES),\n    SYM(CopyTexSubImage3DOES),\n    SYM(CompressedTexImage3DOES),\n    SYM(CompressedTexSubImage3DOES),\n    SYM(FramebufferTexture3DOES),\n    SYM(TexParameterIivOES),\n    SYM(TexParameterIuivOES),\n    SYM(GetTexParameterIivOES),\n    SYM(GetTexParameterIuivOES),\n    SYM(SamplerParameterIivOES),\n    SYM(SamplerParameterIuivOES),\n    SYM(GetSamplerParameterIivOES),\n    SYM(GetSamplerParameterIuivOES),\n    SYM(TexBufferOES),\n    SYM(TexBufferRangeOES),\n    SYM(TexStorage3DMultisampleOES),\n    SYM(TextureViewOES),\n    SYM(BindVertexArrayOES),\n    SYM(DeleteVertexArraysOES),\n    SYM(GenVertexArraysOES),\n    SYM(IsVertexArrayOES),\n    SYM(ViewportArrayvOES),\n    SYM(ViewportIndexedfOES),\n    SYM(ViewportIndexedfvOES),\n    SYM(ScissorArrayvOES),\n    SYM(ScissorIndexedOES),\n    SYM(ScissorIndexedvOES),\n    SYM(DepthRangeArrayfvOES),\n    SYM(DepthRangeIndexedfOES),\n    SYM(GetFloati_vOES),\n    SYM(DrawArraysInstancedBaseInstanceEXT),\n    SYM(DrawElementsInstancedBaseInstanceEXT),\n    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),\n    SYM(BindFragDataLocationIndexedEXT),\n    SYM(BindFragDataLocationEXT),\n    SYM(GetProgramResourceLocationIndexEXT),\n    SYM(GetFragDataIndexEXT),\n    SYM(BufferStorageEXT),\n    SYM(ClearTexImageEXT),\n    SYM(ClearTexSubImageEXT),\n    SYM(CopyImageSubDataEXT),\n    SYM(LabelObjectEXT),\n    SYM(GetObjectLabelEXT),\n    SYM(InsertEventMarkerEXT),\n    SYM(PushGroupMarkerEXT),\n    SYM(PopGroupMarkerEXT),\n    SYM(DiscardFramebufferEXT),\n    SYM(GenQueriesEXT),\n    SYM(DeleteQueriesEXT),\n    SYM(IsQueryEXT),\n    SYM(BeginQueryEXT),\n    SYM(EndQueryEXT),\n    SYM(QueryCounterEXT),\n    SYM(GetQueryivEXT),\n    SYM(GetQueryObjectivEXT),\n    SYM(GetQueryObjectuivEXT),\n    SYM(DrawBuffersEXT),\n    SYM(EnableiEXT),\n    SYM(DisableiEXT),\n    SYM(BlendEquationiEXT),\n    SYM(BlendEquationSeparateiEXT),\n    SYM(BlendFunciEXT),\n    SYM(BlendFuncSeparateiEXT),\n    SYM(ColorMaskiEXT),\n    SYM(IsEnablediEXT),\n    SYM(DrawElementsBaseVertexEXT),\n    SYM(DrawRangeElementsBaseVertexEXT),\n    SYM(DrawElementsInstancedBaseVertexEXT),\n    SYM(MultiDrawElementsBaseVertexEXT),\n    SYM(DrawArraysInstancedEXT),\n    SYM(DrawElementsInstancedEXT),\n    SYM(FramebufferTextureEXT),\n    SYM(VertexAttribDivisorEXT),\n    SYM(MapBufferRangeEXT),\n    SYM(FlushMappedBufferRangeEXT),\n    SYM(MultiDrawArraysEXT),\n    SYM(MultiDrawElementsEXT),\n    SYM(MultiDrawArraysIndirectEXT),\n    SYM(MultiDrawElementsIndirectEXT),\n    SYM(RenderbufferStorageMultisampleEXT),\n    SYM(FramebufferTexture2DMultisampleEXT),\n    SYM(ReadBufferIndexedEXT),\n    SYM(DrawBuffersIndexedEXT),\n    SYM(GetIntegeri_vEXT),\n    SYM(PolygonOffsetClampEXT),\n    SYM(PrimitiveBoundingBoxEXT),\n    SYM(RasterSamplesEXT),\n    SYM(GetGraphicsResetStatusEXT),\n    SYM(ReadnPixelsEXT),\n    SYM(GetnUniformfvEXT),\n    SYM(GetnUniformivEXT),\n    SYM(ActiveShaderProgramEXT),\n    SYM(BindProgramPipelineEXT),\n    SYM(CreateShaderProgramvEXT),\n    SYM(DeleteProgramPipelinesEXT),\n    SYM(GenProgramPipelinesEXT),\n    SYM(GetProgramPipelineInfoLogEXT),\n    SYM(GetProgramPipelineivEXT),\n    SYM(IsProgramPipelineEXT),\n    SYM(ProgramParameteriEXT),\n    SYM(ProgramUniform1fEXT),\n    SYM(ProgramUniform1fvEXT),\n    SYM(ProgramUniform1iEXT),\n    SYM(ProgramUniform1ivEXT),\n    SYM(ProgramUniform2fEXT),\n    SYM(ProgramUniform2fvEXT),\n    SYM(ProgramUniform2iEXT),\n    SYM(ProgramUniform2ivEXT),\n    SYM(ProgramUniform3fEXT),\n    SYM(ProgramUniform3fvEXT),\n    SYM(ProgramUniform3iEXT),\n    SYM(ProgramUniform3ivEXT),\n    SYM(ProgramUniform4fEXT),\n    SYM(ProgramUniform4fvEXT),\n    SYM(ProgramUniform4iEXT),\n    SYM(ProgramUniform4ivEXT),\n    SYM(ProgramUniformMatrix2fvEXT),\n    SYM(ProgramUniformMatrix3fvEXT),\n    SYM(ProgramUniformMatrix4fvEXT),\n    SYM(UseProgramStagesEXT),\n    SYM(ValidateProgramPipelineEXT),\n    SYM(ProgramUniform1uiEXT),\n    SYM(ProgramUniform2uiEXT),\n    SYM(ProgramUniform3uiEXT),\n    SYM(ProgramUniform4uiEXT),\n    SYM(ProgramUniform1uivEXT),\n    SYM(ProgramUniform2uivEXT),\n    SYM(ProgramUniform3uivEXT),\n    SYM(ProgramUniform4uivEXT),\n    SYM(ProgramUniformMatrix2x3fvEXT),\n    SYM(ProgramUniformMatrix3x2fvEXT),\n    SYM(ProgramUniformMatrix2x4fvEXT),\n    SYM(ProgramUniformMatrix4x2fvEXT),\n    SYM(ProgramUniformMatrix3x4fvEXT),\n    SYM(ProgramUniformMatrix4x3fvEXT),\n    SYM(FramebufferPixelLocalStorageSizeEXT),\n    SYM(GetFramebufferPixelLocalStorageSizeEXT),\n    SYM(ClearPixelLocalStorageuiEXT),\n    SYM(TexPageCommitmentEXT),\n    SYM(PatchParameteriEXT),\n    SYM(TexParameterIivEXT),\n    SYM(TexParameterIuivEXT),\n    SYM(GetTexParameterIivEXT),\n    SYM(GetTexParameterIuivEXT),\n    SYM(SamplerParameterIivEXT),\n    SYM(SamplerParameterIuivEXT),\n    SYM(GetSamplerParameterIivEXT),\n    SYM(GetSamplerParameterIuivEXT),\n    SYM(TexBufferEXT),\n    SYM(TexBufferRangeEXT),\n    SYM(TexStorage1DEXT),\n    SYM(TexStorage2DEXT),\n    SYM(TexStorage3DEXT),\n    SYM(TextureStorage1DEXT),\n    SYM(TextureStorage2DEXT),\n    SYM(TextureStorage3DEXT),\n    SYM(TextureViewEXT),\n    SYM(FramebufferTextureMultiviewOVR),\n    SYM(FramebufferTextureMultisampleMultiviewOVR),\n\n    { NULL, NULL },\n};\nRGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;\nRGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;\nRGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;\nRGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;\nRGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;\nRGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;\nRGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;\nRGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;\nRGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;\nRGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;\nRGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;\nRGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;\nRGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;\nRGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;\nRGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;\nRGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;\nRGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;\nRGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;\nRGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;\nRGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;\nRGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;\nRGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;\nRGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;\nRGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;\nRGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;\nRGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;\nRGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;\nRGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;\nRGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;\nRGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;\nRGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;\nRGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;\nRGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;\nRGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;\nRGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;\nRGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;\nRGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;\nRGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;\nRGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;\nRGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;\nRGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;\nRGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;\nRGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;\nRGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;\nRGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;\nRGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;\nRGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;\nRGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;\nRGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;\nRGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;\nRGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;\nRGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;\nRGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;\nRGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;\nRGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;\nRGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;\nRGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;\nRGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;\nRGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;\nRGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;\nRGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;\nRGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;\nRGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;\nRGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;\nRGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;\nRGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;\nRGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;\nRGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;\nRGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;\nRGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;\nRGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;\nRGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;\nRGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;\nRGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;\nRGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;\nRGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;\nRGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;\nRGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;\nRGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;\nRGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;\nRGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;\nRGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;\nRGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;\nRGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;\nRGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;\nRGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;\nRGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;\nRGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;\nRGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;\nRGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;\nRGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;\nRGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;\nRGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;\nRGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;\nRGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;\nRGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;\nRGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;\nRGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;\nRGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;\nRGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;\nRGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;\nRGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;\nRGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;\nRGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;\nRGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;\nRGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;\nRGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;\nRGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;\nRGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;\nRGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;\nRGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;\nRGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;\nRGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;\nRGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;\nRGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;\nRGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;\nRGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;\nRGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;\nRGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;\nRGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;\nRGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;\nRGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;\nRGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;\nRGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;\nRGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;\nRGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;\nRGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;\nRGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;\nRGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;\nRGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;\nRGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;\nRGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;\nRGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;\nRGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;\nRGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;\nRGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;\nRGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;\nRGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;\nRGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;\nRGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;\nRGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;\nRGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;\nRGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;\nRGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;\nRGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;\nRGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;\nRGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;\nRGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;\nRGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;\nRGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;\nRGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;\nRGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;\nRGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;\nRGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;\nRGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;\nRGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;\nRGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;\nRGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;\nRGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;\nRGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;\nRGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;\nRGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;\nRGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;\nRGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;\nRGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;\nRGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;\nRGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;\nRGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;\nRGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;\nRGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;\nRGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;\nRGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;\nRGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;\nRGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;\nRGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;\nRGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;\nRGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;\nRGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;\nRGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;\nRGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;\nRGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;\nRGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;\nRGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;\nRGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;\nRGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;\nRGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;\n"
  },
  {
    "path": "glsym/glsym_es3.c",
    "content": "#include \"glsym/glsym.h\"\n#include <stddef.h>\n#define SYM(x) { \"gl\" #x, &(gl##x) }\nconst struct rglgen_sym_map rglgen_symbol_map[] = {\n    SYM(BlendBarrierKHR),\n    SYM(DebugMessageControlKHR),\n    SYM(DebugMessageInsertKHR),\n    SYM(DebugMessageCallbackKHR),\n    SYM(GetDebugMessageLogKHR),\n    SYM(PushDebugGroupKHR),\n    SYM(PopDebugGroupKHR),\n    SYM(ObjectLabelKHR),\n    SYM(GetObjectLabelKHR),\n    SYM(ObjectPtrLabelKHR),\n    SYM(GetObjectPtrLabelKHR),\n    SYM(GetPointervKHR),\n    SYM(GetGraphicsResetStatusKHR),\n    SYM(ReadnPixelsKHR),\n    SYM(GetnUniformfvKHR),\n    SYM(GetnUniformivKHR),\n    SYM(GetnUniformuivKHR),\n    SYM(EGLImageTargetTexture2DOES),\n    SYM(EGLImageTargetRenderbufferStorageOES),\n    SYM(CopyImageSubDataOES),\n    SYM(EnableiOES),\n    SYM(DisableiOES),\n    SYM(BlendEquationiOES),\n    SYM(BlendEquationSeparateiOES),\n    SYM(BlendFunciOES),\n    SYM(BlendFuncSeparateiOES),\n    SYM(ColorMaskiOES),\n    SYM(IsEnablediOES),\n    SYM(DrawElementsBaseVertexOES),\n    SYM(DrawRangeElementsBaseVertexOES),\n    SYM(DrawElementsInstancedBaseVertexOES),\n    SYM(MultiDrawElementsBaseVertexOES),\n    SYM(FramebufferTextureOES),\n    SYM(GetProgramBinaryOES),\n    SYM(ProgramBinaryOES),\n    SYM(MapBufferOES),\n    SYM(UnmapBufferOES),\n    SYM(GetBufferPointervOES),\n    SYM(PrimitiveBoundingBoxOES),\n    SYM(MinSampleShadingOES),\n    SYM(PatchParameteriOES),\n    SYM(TexImage3DOES),\n    SYM(TexSubImage3DOES),\n    SYM(CopyTexSubImage3DOES),\n    SYM(CompressedTexImage3DOES),\n    SYM(CompressedTexSubImage3DOES),\n    SYM(FramebufferTexture3DOES),\n    SYM(TexParameterIivOES),\n    SYM(TexParameterIuivOES),\n    SYM(GetTexParameterIivOES),\n    SYM(GetTexParameterIuivOES),\n    SYM(SamplerParameterIivOES),\n    SYM(SamplerParameterIuivOES),\n    SYM(GetSamplerParameterIivOES),\n    SYM(GetSamplerParameterIuivOES),\n    SYM(TexBufferOES),\n    SYM(TexBufferRangeOES),\n    SYM(TexStorage3DMultisampleOES),\n    SYM(TextureViewOES),\n    SYM(BindVertexArrayOES),\n    SYM(DeleteVertexArraysOES),\n    SYM(GenVertexArraysOES),\n    SYM(IsVertexArrayOES),\n    SYM(ViewportArrayvOES),\n    SYM(ViewportIndexedfOES),\n    SYM(ViewportIndexedfvOES),\n    SYM(ScissorArrayvOES),\n    SYM(ScissorIndexedOES),\n    SYM(ScissorIndexedvOES),\n    SYM(DepthRangeArrayfvOES),\n    SYM(DepthRangeIndexedfOES),\n    SYM(GetFloati_vOES),\n    SYM(DrawArraysInstancedBaseInstanceEXT),\n    SYM(DrawElementsInstancedBaseInstanceEXT),\n    SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),\n    SYM(BindFragDataLocationIndexedEXT),\n    SYM(BindFragDataLocationEXT),\n    SYM(GetProgramResourceLocationIndexEXT),\n    SYM(GetFragDataIndexEXT),\n    SYM(BufferStorageEXT),\n    SYM(ClearTexImageEXT),\n    SYM(ClearTexSubImageEXT),\n    SYM(CopyImageSubDataEXT),\n    SYM(LabelObjectEXT),\n    SYM(GetObjectLabelEXT),\n    SYM(InsertEventMarkerEXT),\n    SYM(PushGroupMarkerEXT),\n    SYM(PopGroupMarkerEXT),\n    SYM(DiscardFramebufferEXT),\n    SYM(GenQueriesEXT),\n    SYM(DeleteQueriesEXT),\n    SYM(IsQueryEXT),\n    SYM(BeginQueryEXT),\n    SYM(EndQueryEXT),\n    SYM(QueryCounterEXT),\n    SYM(GetQueryivEXT),\n    SYM(GetQueryObjectivEXT),\n    SYM(GetQueryObjectuivEXT),\n    SYM(GetQueryObjecti64vEXT),\n    SYM(GetQueryObjectui64vEXT),\n    SYM(DrawBuffersEXT),\n    SYM(EnableiEXT),\n    SYM(DisableiEXT),\n    SYM(BlendEquationiEXT),\n    SYM(BlendEquationSeparateiEXT),\n    SYM(BlendFunciEXT),\n    SYM(BlendFuncSeparateiEXT),\n    SYM(ColorMaskiEXT),\n    SYM(IsEnablediEXT),\n    SYM(DrawElementsBaseVertexEXT),\n    SYM(DrawRangeElementsBaseVertexEXT),\n    SYM(DrawElementsInstancedBaseVertexEXT),\n    SYM(MultiDrawElementsBaseVertexEXT),\n    SYM(DrawArraysInstancedEXT),\n    SYM(DrawElementsInstancedEXT),\n    SYM(FramebufferTextureEXT),\n    SYM(VertexAttribDivisorEXT),\n    SYM(MapBufferRangeEXT),\n    SYM(FlushMappedBufferRangeEXT),\n    SYM(MultiDrawArraysEXT),\n    SYM(MultiDrawElementsEXT),\n    SYM(MultiDrawArraysIndirectEXT),\n    SYM(MultiDrawElementsIndirectEXT),\n    SYM(RenderbufferStorageMultisampleEXT),\n    SYM(FramebufferTexture2DMultisampleEXT),\n    SYM(ReadBufferIndexedEXT),\n    SYM(DrawBuffersIndexedEXT),\n    SYM(GetIntegeri_vEXT),\n    SYM(PolygonOffsetClampEXT),\n    SYM(PrimitiveBoundingBoxEXT),\n    SYM(RasterSamplesEXT),\n    SYM(GetGraphicsResetStatusEXT),\n    SYM(ReadnPixelsEXT),\n    SYM(GetnUniformfvEXT),\n    SYM(GetnUniformivEXT),\n    SYM(ActiveShaderProgramEXT),\n    SYM(BindProgramPipelineEXT),\n    SYM(CreateShaderProgramvEXT),\n    SYM(DeleteProgramPipelinesEXT),\n    SYM(GenProgramPipelinesEXT),\n    SYM(GetProgramPipelineInfoLogEXT),\n    SYM(GetProgramPipelineivEXT),\n    SYM(IsProgramPipelineEXT),\n    SYM(ProgramParameteriEXT),\n    SYM(ProgramUniform1fEXT),\n    SYM(ProgramUniform1fvEXT),\n    SYM(ProgramUniform1iEXT),\n    SYM(ProgramUniform1ivEXT),\n    SYM(ProgramUniform2fEXT),\n    SYM(ProgramUniform2fvEXT),\n    SYM(ProgramUniform2iEXT),\n    SYM(ProgramUniform2ivEXT),\n    SYM(ProgramUniform3fEXT),\n    SYM(ProgramUniform3fvEXT),\n    SYM(ProgramUniform3iEXT),\n    SYM(ProgramUniform3ivEXT),\n    SYM(ProgramUniform4fEXT),\n    SYM(ProgramUniform4fvEXT),\n    SYM(ProgramUniform4iEXT),\n    SYM(ProgramUniform4ivEXT),\n    SYM(ProgramUniformMatrix2fvEXT),\n    SYM(ProgramUniformMatrix3fvEXT),\n    SYM(ProgramUniformMatrix4fvEXT),\n    SYM(UseProgramStagesEXT),\n    SYM(ValidateProgramPipelineEXT),\n    SYM(ProgramUniform1uiEXT),\n    SYM(ProgramUniform2uiEXT),\n    SYM(ProgramUniform3uiEXT),\n    SYM(ProgramUniform4uiEXT),\n    SYM(ProgramUniform1uivEXT),\n    SYM(ProgramUniform2uivEXT),\n    SYM(ProgramUniform3uivEXT),\n    SYM(ProgramUniform4uivEXT),\n    SYM(ProgramUniformMatrix2x3fvEXT),\n    SYM(ProgramUniformMatrix3x2fvEXT),\n    SYM(ProgramUniformMatrix2x4fvEXT),\n    SYM(ProgramUniformMatrix4x2fvEXT),\n    SYM(ProgramUniformMatrix3x4fvEXT),\n    SYM(ProgramUniformMatrix4x3fvEXT),\n    SYM(FramebufferPixelLocalStorageSizeEXT),\n    SYM(GetFramebufferPixelLocalStorageSizeEXT),\n    SYM(ClearPixelLocalStorageuiEXT),\n    SYM(TexPageCommitmentEXT),\n    SYM(PatchParameteriEXT),\n    SYM(TexParameterIivEXT),\n    SYM(TexParameterIuivEXT),\n    SYM(GetTexParameterIivEXT),\n    SYM(GetTexParameterIuivEXT),\n    SYM(SamplerParameterIivEXT),\n    SYM(SamplerParameterIuivEXT),\n    SYM(GetSamplerParameterIivEXT),\n    SYM(GetSamplerParameterIuivEXT),\n    SYM(TexBufferEXT),\n    SYM(TexBufferRangeEXT),\n    SYM(TexStorage1DEXT),\n    SYM(TexStorage2DEXT),\n    SYM(TexStorage3DEXT),\n    SYM(TextureStorage1DEXT),\n    SYM(TextureStorage2DEXT),\n    SYM(TextureStorage3DEXT),\n    SYM(TextureViewEXT),\n    SYM(FramebufferTextureMultiviewOVR),\n    SYM(FramebufferTextureMultisampleMultiviewOVR),\n\n    { NULL, NULL },\n};\nRGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;\nRGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;\nRGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;\nRGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;\nRGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;\nRGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;\nRGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;\nRGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;\nRGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;\nRGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;\nRGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;\nRGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;\nRGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;\nRGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;\nRGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;\nRGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;\nRGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;\nRGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;\nRGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;\nRGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;\nRGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;\nRGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;\nRGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;\nRGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;\nRGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;\nRGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;\nRGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;\nRGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;\nRGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;\nRGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;\nRGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;\nRGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;\nRGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;\nRGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;\nRGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;\nRGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;\nRGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;\nRGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;\nRGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;\nRGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;\nRGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;\nRGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;\nRGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;\nRGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;\nRGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;\nRGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;\nRGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;\nRGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;\nRGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;\nRGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;\nRGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;\nRGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;\nRGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;\nRGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;\nRGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;\nRGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;\nRGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;\nRGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;\nRGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;\nRGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;\nRGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;\nRGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;\nRGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;\nRGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;\nRGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;\nRGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;\nRGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;\nRGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;\nRGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;\nRGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;\nRGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;\nRGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;\nRGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;\nRGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;\nRGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;\nRGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;\nRGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;\nRGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;\nRGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;\nRGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;\nRGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;\nRGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;\nRGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;\nRGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;\nRGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;\nRGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;\nRGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;\nRGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;\nRGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;\nRGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;\nRGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;\nRGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;\nRGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;\nRGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;\nRGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;\nRGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;\nRGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;\nRGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;\nRGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;\nRGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;\nRGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;\nRGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;\nRGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;\nRGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;\nRGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;\nRGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;\nRGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;\nRGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;\nRGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;\nRGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;\nRGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;\nRGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;\nRGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;\nRGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;\nRGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;\nRGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;\nRGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;\nRGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;\nRGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;\nRGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;\nRGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;\nRGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;\nRGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;\nRGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;\nRGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;\nRGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;\nRGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;\nRGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;\nRGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;\nRGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;\nRGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;\nRGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;\nRGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;\nRGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;\nRGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;\nRGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;\nRGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;\nRGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;\nRGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;\nRGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;\nRGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;\nRGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;\nRGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;\nRGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;\nRGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;\nRGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;\nRGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;\nRGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;\nRGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;\nRGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;\nRGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;\nRGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;\nRGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;\nRGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;\nRGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;\nRGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;\nRGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;\nRGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;\nRGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;\nRGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;\nRGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;\nRGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;\nRGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;\nRGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;\nRGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;\nRGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;\nRGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;\nRGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;\nRGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;\nRGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;\nRGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;\nRGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;\nRGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;\nRGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;\nRGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;\nRGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;\nRGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;\nRGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;\nRGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;\nRGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;\nRGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;\nRGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;\nRGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;\nRGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;\nRGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;\nRGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;\nRGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;\nRGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;\nRGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;\n"
  },
  {
    "path": "glsym/glsym_gl.c",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (glsym).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stddef.h>\n\n#include <glsym/glsym.h>\n\n#define SYM(x) { \"gl\" #x, (void*)&(gl##x) }\n\nconst struct rglgen_sym_map rglgen_symbol_map[] = {\n#ifdef HAVE_LIBNX\n    SYM(ClearIndex),\n    SYM(ClearColor),\n    SYM(Clear),\n    SYM(IndexMask),\n    SYM(ColorMask),\n    SYM(AlphaFunc),\n    SYM(BlendFunc),\n    SYM(LogicOp),\n    SYM(CullFace),\n    SYM(FrontFace),\n    SYM(PointSize),\n    SYM(LineWidth),\n    SYM(LineStipple),\n    SYM(PolygonMode),\n    SYM(PolygonOffset),\n    SYM(PolygonStipple),\n    SYM(GetPolygonStipple),\n    SYM(EdgeFlag),\n    SYM(EdgeFlagv),\n    SYM(Scissor),\n    SYM(ClipPlane),\n    SYM(GetClipPlane),\n    SYM(DrawBuffer),\n    SYM(ReadBuffer),\n    SYM(Enable),\n    SYM(Disable),\n    SYM(IsEnabled),\n    SYM(EnableClientState),\n    SYM(DisableClientState),\n    SYM(GetBooleanv),\n    SYM(GetDoublev),\n    SYM(GetFloatv),\n    SYM(GetIntegerv),\n    SYM(PushAttrib),\n    SYM(PopAttrib),\n    SYM(PushClientAttrib),\n    SYM(PopClientAttrib),\n    SYM(RenderMode),\n    SYM(GetError),\n    SYM(GetString),\n    SYM(Finish),\n    SYM(Flush),\n    SYM(Hint),\n    SYM(ClearDepth),\n    SYM(DepthFunc),\n    SYM(DepthMask),\n    SYM(DepthRange),\n    SYM(ClearAccum),\n    SYM(Accum),\n    SYM(MatrixMode),\n    SYM(Ortho),\n    SYM(Frustum),\n    SYM(Viewport),\n    SYM(PushMatrix),\n    SYM(PopMatrix),\n    SYM(LoadIdentity),\n    SYM(LoadMatrixd),\n    SYM(LoadMatrixf),\n    SYM(MultMatrixd),\n    SYM(MultMatrixf),\n    SYM(Rotated),\n    SYM(Rotatef),\n    SYM(Scaled),\n    SYM(Scalef),\n    SYM(Translated),\n    SYM(Translatef),\n    SYM(IsList),\n    SYM(DeleteLists),\n    SYM(GenLists),\n    SYM(NewList),\n    SYM(EndList),\n    SYM(CallList),\n    SYM(CallLists),\n    SYM(ListBase),\n    SYM(Begin),\n    SYM(End),\n    SYM(Vertex2d),\n    SYM(Vertex2f),\n    SYM(Vertex2i),\n    SYM(Vertex2s),\n    SYM(Vertex3d),\n    SYM(Vertex3f),\n    SYM(Vertex3i),\n    SYM(Vertex3s),\n    SYM(Vertex4d),\n    SYM(Vertex4f),\n    SYM(Vertex4i),\n    SYM(Vertex4s),\n    SYM(Vertex2dv),\n    SYM(Vertex2fv),\n    SYM(Vertex2iv),\n    SYM(Vertex2sv),\n    SYM(Vertex3dv),\n    SYM(Vertex3fv),\n    SYM(Vertex3iv),\n    SYM(Vertex3sv),\n    SYM(Vertex4dv),\n    SYM(Vertex4fv),\n    SYM(Vertex4iv),\n    SYM(Vertex4sv),\n    SYM(Normal3b),\n    SYM(Normal3d),\n    SYM(Normal3f),\n    SYM(Normal3i),\n    SYM(Normal3s),\n    SYM(Normal3bv),\n    SYM(Normal3dv),\n    SYM(Normal3fv),\n    SYM(Normal3iv),\n    SYM(Normal3sv),\n    SYM(Indexd),\n    SYM(Indexf),\n    SYM(Indexi),\n    SYM(Indexs),\n    SYM(Indexub),\n    SYM(Indexdv),\n    SYM(Indexfv),\n    SYM(Indexiv),\n    SYM(Indexsv),\n    SYM(Indexubv),\n    SYM(Color3b),\n    SYM(Color3d),\n    SYM(Color3f),\n    SYM(Color3i),\n    SYM(Color3s),\n    SYM(Color3ub),\n    SYM(Color3ui),\n    SYM(Color3us),\n    SYM(Color4b),\n    SYM(Color4d),\n    SYM(Color4f),\n    SYM(Color4i),\n    SYM(Color4s),\n    SYM(Color4ub),\n    SYM(Color4ui),\n    SYM(Color4us),\n    SYM(Color3bv),\n    SYM(Color3dv),\n    SYM(Color3fv),\n    SYM(Color3iv),\n    SYM(Color3sv),\n    SYM(Color3ubv),\n    SYM(Color3uiv),\n    SYM(Color3usv),\n    SYM(Color4bv),\n    SYM(Color4dv),\n    SYM(Color4fv),\n    SYM(Color4iv),\n    SYM(Color4sv),\n    SYM(Color4ubv),\n    SYM(Color4uiv),\n    SYM(Color4usv),\n    SYM(TexCoord1d),\n    SYM(TexCoord1f),\n    SYM(TexCoord1i),\n    SYM(TexCoord1s),\n    SYM(TexCoord2d),\n    SYM(TexCoord2f),\n    SYM(TexCoord2i),\n    SYM(TexCoord2s),\n    SYM(TexCoord3d),\n    SYM(TexCoord3f),\n    SYM(TexCoord3i),\n    SYM(TexCoord3s),\n    SYM(TexCoord4d),\n    SYM(TexCoord4f),\n    SYM(TexCoord4i),\n    SYM(TexCoord4s),\n    SYM(TexCoord1dv),\n    SYM(TexCoord1fv),\n    SYM(TexCoord1iv),\n    SYM(TexCoord1sv),\n    SYM(TexCoord2dv),\n    SYM(TexCoord2fv),\n    SYM(TexCoord2iv),\n    SYM(TexCoord2sv),\n    SYM(TexCoord3dv),\n    SYM(TexCoord3fv),\n    SYM(TexCoord3iv),\n    SYM(TexCoord3sv),\n    SYM(TexCoord4dv),\n    SYM(TexCoord4fv),\n    SYM(TexCoord4iv),\n    SYM(TexCoord4sv),\n    SYM(RasterPos2d),\n    SYM(RasterPos2f),\n    SYM(RasterPos2i),\n    SYM(RasterPos2s),\n    SYM(RasterPos3d),\n    SYM(RasterPos3f),\n    SYM(RasterPos3i),\n    SYM(RasterPos3s),\n    SYM(RasterPos4d),\n    SYM(RasterPos4f),\n    SYM(RasterPos4i),\n    SYM(RasterPos4s),\n    SYM(RasterPos2dv),\n    SYM(RasterPos2fv),\n    SYM(RasterPos2iv),\n    SYM(RasterPos2sv),\n    SYM(RasterPos3dv),\n    SYM(RasterPos3fv),\n    SYM(RasterPos3iv),\n    SYM(RasterPos3sv),\n    SYM(RasterPos4dv),\n    SYM(RasterPos4fv),\n    SYM(RasterPos4iv),\n    SYM(RasterPos4sv),\n    SYM(Rectd),\n    SYM(Rectf),\n    SYM(Recti),\n    SYM(Rects),\n    SYM(Rectdv),\n    SYM(Rectfv),\n    SYM(Rectiv),\n    SYM(Rectsv),\n    SYM(VertexPointer),\n    SYM(NormalPointer),\n    SYM(ColorPointer),\n    SYM(IndexPointer),\n    SYM(TexCoordPointer),\n    SYM(EdgeFlagPointer),\n    SYM(GetPointerv),\n    SYM(ArrayElement),\n    SYM(DrawArrays),\n    SYM(DrawElements),\n    SYM(InterleavedArrays),\n    SYM(ShadeModel),\n    SYM(Lightf),\n    SYM(Lighti),\n    SYM(Lightfv),\n    SYM(Lightiv),\n    SYM(GetLightfv),\n    SYM(GetLightiv),\n    SYM(LightModelf),\n    SYM(LightModeli),\n    SYM(LightModelfv),\n    SYM(LightModeliv),\n    SYM(Materialf),\n    SYM(Materiali),\n    SYM(Materialfv),\n    SYM(Materialiv),\n    SYM(GetMaterialfv),\n    SYM(GetMaterialiv),\n    SYM(ColorMaterial),\n    SYM(PixelZoom),\n    SYM(PixelStoref),\n    SYM(PixelStorei),\n    SYM(PixelTransferf),\n    SYM(PixelTransferi),\n    SYM(PixelMapfv),\n    SYM(PixelMapuiv),\n    SYM(PixelMapusv),\n    SYM(GetPixelMapfv),\n    SYM(GetPixelMapuiv),\n    SYM(GetPixelMapusv),\n    SYM(Bitmap),\n    SYM(ReadPixels),\n    SYM(DrawPixels),\n    SYM(CopyPixels),\n    SYM(StencilFunc),\n    SYM(StencilMask),\n    SYM(StencilOp),\n    SYM(ClearStencil),\n    SYM(TexGend),\n    SYM(TexGenf),\n    SYM(TexGeni),\n    SYM(TexGendv),\n    SYM(TexGenfv),\n    SYM(TexGeniv),\n    SYM(GetTexGendv),\n    SYM(GetTexGenfv),\n    SYM(GetTexGeniv),\n    SYM(TexEnvf),\n    SYM(TexEnvi),\n    SYM(TexEnvfv),\n    SYM(TexEnviv),\n    SYM(GetTexEnvfv),\n    SYM(GetTexEnviv),\n    SYM(TexParameterf),\n    SYM(TexParameteri),\n    SYM(TexParameterfv),\n    SYM(TexParameteriv),\n    SYM(GetTexParameterfv),\n    SYM(GetTexParameteriv),\n    SYM(GetTexLevelParameterfv),\n    SYM(GetTexLevelParameteriv),\n    SYM(TexImage1D),\n    SYM(TexImage2D),\n    SYM(GetTexImage),\n    SYM(GenTextures),\n    SYM(DeleteTextures),\n    SYM(BindTexture),\n    SYM(PrioritizeTextures),\n    SYM(AreTexturesResident),\n    SYM(IsTexture),\n    SYM(TexSubImage1D),\n    SYM(TexSubImage2D),\n    SYM(CopyTexImage1D),\n    SYM(CopyTexImage2D),\n    SYM(CopyTexSubImage1D),\n    SYM(CopyTexSubImage2D),\n    SYM(Map1d),\n    SYM(Map1f),\n    SYM(Map2d),\n    SYM(Map2f),\n    SYM(GetMapdv),\n    SYM(GetMapfv),\n    SYM(GetMapiv),\n    SYM(EvalCoord1d),\n    SYM(EvalCoord1f),\n    SYM(EvalCoord1dv),\n    SYM(EvalCoord1fv),\n    SYM(EvalCoord2d),\n    SYM(EvalCoord2f),\n    SYM(EvalCoord2dv),\n    SYM(EvalCoord2fv),\n    SYM(MapGrid1d),\n    SYM(MapGrid1f),\n    SYM(MapGrid2d),\n    SYM(MapGrid2f),\n    SYM(EvalPoint1),\n    SYM(EvalPoint2),\n    SYM(EvalMesh1),\n    SYM(EvalMesh2),\n    SYM(Fogf),\n    SYM(Fogi),\n    SYM(Fogfv),\n    SYM(Fogiv),\n    SYM(FeedbackBuffer),\n    SYM(PassThrough),\n    SYM(SelectBuffer),\n    SYM(InitNames),\n    SYM(LoadName),\n    SYM(PushName),\n    SYM(PopName),\n    SYM(DrawRangeElements),\n    SYM(TexImage3D),\n    SYM(TexSubImage3D),\n    SYM(CopyTexSubImage3D),\n    SYM(ColorTable),\n    SYM(ColorSubTable),\n    SYM(ColorTableParameteriv),\n    SYM(ColorTableParameterfv),\n    SYM(CopyColorSubTable),\n    SYM(CopyColorTable),\n    SYM(GetColorTable),\n    SYM(GetColorTableParameterfv),\n    SYM(GetColorTableParameteriv),\n    SYM(BlendEquation),\n    SYM(BlendColor),\n    SYM(Histogram),\n    SYM(ResetHistogram),\n    SYM(GetHistogram),\n    SYM(GetHistogramParameterfv),\n    SYM(GetHistogramParameteriv),\n    SYM(Minmax),\n    SYM(ResetMinmax),\n    SYM(GetMinmax),\n    SYM(GetMinmaxParameterfv),\n    SYM(GetMinmaxParameteriv),\n    SYM(ConvolutionFilter1D),\n    SYM(ConvolutionFilter2D),\n    SYM(ConvolutionParameterf),\n    SYM(ConvolutionParameterfv),\n    SYM(ConvolutionParameteri),\n    SYM(ConvolutionParameteriv),\n    SYM(CopyConvolutionFilter1D),\n    SYM(CopyConvolutionFilter2D),\n    SYM(GetConvolutionFilter),\n    SYM(GetConvolutionParameterfv),\n    SYM(GetConvolutionParameteriv),\n    SYM(SeparableFilter2D),\n    SYM(GetSeparableFilter),\n    SYM(ActiveTexture),\n    SYM(ClientActiveTexture),\n    SYM(CompressedTexImage1D),\n    SYM(CompressedTexImage2D),\n    SYM(CompressedTexImage3D),\n    SYM(CompressedTexSubImage1D),\n    SYM(CompressedTexSubImage2D),\n    SYM(CompressedTexSubImage3D),\n    SYM(GetCompressedTexImage),\n    SYM(MultiTexCoord1d),\n    SYM(MultiTexCoord1dv),\n    SYM(MultiTexCoord1f),\n    SYM(MultiTexCoord1fv),\n    SYM(MultiTexCoord1i),\n    SYM(MultiTexCoord1iv),\n    SYM(MultiTexCoord1s),\n    SYM(MultiTexCoord1sv),\n    SYM(MultiTexCoord2d),\n    SYM(MultiTexCoord2dv),\n    SYM(MultiTexCoord2f),\n    SYM(MultiTexCoord2fv),\n    SYM(MultiTexCoord2i),\n    SYM(MultiTexCoord2iv),\n    SYM(MultiTexCoord2s),\n    SYM(MultiTexCoord2sv),\n    SYM(MultiTexCoord3d),\n    SYM(MultiTexCoord3dv),\n    SYM(MultiTexCoord3f),\n    SYM(MultiTexCoord3fv),\n    SYM(MultiTexCoord3i),\n    SYM(MultiTexCoord3iv),\n    SYM(MultiTexCoord3s),\n    SYM(MultiTexCoord3sv),\n    SYM(MultiTexCoord4d),\n    SYM(MultiTexCoord4dv),\n    SYM(MultiTexCoord4f),\n    SYM(MultiTexCoord4fv),\n    SYM(MultiTexCoord4i),\n    SYM(MultiTexCoord4iv),\n    SYM(MultiTexCoord4s),\n    SYM(MultiTexCoord4sv),\n    SYM(LoadTransposeMatrixd),\n    SYM(LoadTransposeMatrixf),\n    SYM(MultTransposeMatrixd),\n    SYM(MultTransposeMatrixf),\n    SYM(SampleCoverage),\n    SYM(ActiveTextureARB),\n    SYM(ClientActiveTextureARB),\n    SYM(MultiTexCoord1dARB),\n    SYM(MultiTexCoord1dvARB),\n    SYM(MultiTexCoord1fARB),\n    SYM(MultiTexCoord1fvARB),\n    SYM(MultiTexCoord1iARB),\n    SYM(MultiTexCoord1ivARB),\n    SYM(MultiTexCoord1sARB),\n    SYM(MultiTexCoord1svARB),\n    SYM(MultiTexCoord2dARB),\n    SYM(MultiTexCoord2dvARB),\n    SYM(MultiTexCoord2fARB),\n    SYM(MultiTexCoord2fvARB),\n    SYM(MultiTexCoord2iARB),\n    SYM(MultiTexCoord2ivARB),\n    SYM(MultiTexCoord2sARB),\n    SYM(MultiTexCoord2svARB),\n    SYM(MultiTexCoord3dARB),\n    SYM(MultiTexCoord3dvARB),\n    SYM(MultiTexCoord3fARB),\n    SYM(MultiTexCoord3fvARB),\n    SYM(MultiTexCoord3iARB),\n    SYM(MultiTexCoord3ivARB),\n    SYM(MultiTexCoord3sARB),\n    SYM(MultiTexCoord3svARB),\n    SYM(MultiTexCoord4dARB),\n    SYM(MultiTexCoord4dvARB),\n    SYM(MultiTexCoord4fARB),\n    SYM(MultiTexCoord4fvARB),\n    SYM(MultiTexCoord4iARB),\n    SYM(MultiTexCoord4ivARB),\n    SYM(MultiTexCoord4sARB),\n    SYM(MultiTexCoord4svARB),\n    SYM(EGLImageTargetTexture2DOES),\n    SYM(EGLImageTargetRenderbufferStorageOES),\n#endif\n\n    SYM(DrawRangeElements),\n    SYM(TexImage3D),\n    SYM(TexSubImage3D),\n    SYM(CopyTexSubImage3D),\n    SYM(ActiveTexture),\n    SYM(SampleCoverage),\n    SYM(CompressedTexImage3D),\n    SYM(CompressedTexImage2D),\n    SYM(CompressedTexImage1D),\n    SYM(CompressedTexSubImage3D),\n    SYM(CompressedTexSubImage2D),\n    SYM(CompressedTexSubImage1D),\n    SYM(GetCompressedTexImage),\n    SYM(ClientActiveTexture),\n    SYM(MultiTexCoord1d),\n    SYM(MultiTexCoord1dv),\n    SYM(MultiTexCoord1f),\n    SYM(MultiTexCoord1fv),\n    SYM(MultiTexCoord1i),\n    SYM(MultiTexCoord1iv),\n    SYM(MultiTexCoord1s),\n    SYM(MultiTexCoord1sv),\n    SYM(MultiTexCoord2d),\n    SYM(MultiTexCoord2dv),\n    SYM(MultiTexCoord2f),\n    SYM(MultiTexCoord2fv),\n    SYM(MultiTexCoord2i),\n    SYM(MultiTexCoord2iv),\n    SYM(MultiTexCoord2s),\n    SYM(MultiTexCoord2sv),\n    SYM(MultiTexCoord3d),\n    SYM(MultiTexCoord3dv),\n    SYM(MultiTexCoord3f),\n    SYM(MultiTexCoord3fv),\n    SYM(MultiTexCoord3i),\n    SYM(MultiTexCoord3iv),\n    SYM(MultiTexCoord3s),\n    SYM(MultiTexCoord3sv),\n    SYM(MultiTexCoord4d),\n    SYM(MultiTexCoord4dv),\n    SYM(MultiTexCoord4f),\n    SYM(MultiTexCoord4fv),\n    SYM(MultiTexCoord4i),\n    SYM(MultiTexCoord4iv),\n    SYM(MultiTexCoord4s),\n    SYM(MultiTexCoord4sv),\n    SYM(LoadTransposeMatrixf),\n    SYM(LoadTransposeMatrixd),\n    SYM(MultTransposeMatrixf),\n    SYM(MultTransposeMatrixd),\n    SYM(BlendFuncSeparate),\n    SYM(MultiDrawArrays),\n    SYM(MultiDrawElements),\n    SYM(PointParameterf),\n    SYM(PointParameterfv),\n    SYM(PointParameteri),\n    SYM(PointParameteriv),\n    SYM(FogCoordf),\n    SYM(FogCoordfv),\n    SYM(FogCoordd),\n    SYM(FogCoorddv),\n    SYM(FogCoordPointer),\n    SYM(SecondaryColor3b),\n    SYM(SecondaryColor3bv),\n    SYM(SecondaryColor3d),\n    SYM(SecondaryColor3dv),\n    SYM(SecondaryColor3f),\n    SYM(SecondaryColor3fv),\n    SYM(SecondaryColor3i),\n    SYM(SecondaryColor3iv),\n    SYM(SecondaryColor3s),\n    SYM(SecondaryColor3sv),\n    SYM(SecondaryColor3ub),\n    SYM(SecondaryColor3ubv),\n    SYM(SecondaryColor3ui),\n    SYM(SecondaryColor3uiv),\n    SYM(SecondaryColor3us),\n    SYM(SecondaryColor3usv),\n    SYM(SecondaryColorPointer),\n    SYM(WindowPos2d),\n    SYM(WindowPos2dv),\n    SYM(WindowPos2f),\n    SYM(WindowPos2fv),\n    SYM(WindowPos2i),\n    SYM(WindowPos2iv),\n    SYM(WindowPos2s),\n    SYM(WindowPos2sv),\n    SYM(WindowPos3d),\n    SYM(WindowPos3dv),\n    SYM(WindowPos3f),\n    SYM(WindowPos3fv),\n    SYM(WindowPos3i),\n    SYM(WindowPos3iv),\n    SYM(WindowPos3s),\n    SYM(WindowPos3sv),\n    SYM(BlendColor),\n    SYM(BlendEquation),\n    SYM(GenQueries),\n    SYM(DeleteQueries),\n    SYM(IsQuery),\n    SYM(BeginQuery),\n    SYM(EndQuery),\n    SYM(GetQueryiv),\n    SYM(GetQueryObjectiv),\n    SYM(GetQueryObjectuiv),\n    SYM(BindBuffer),\n    SYM(DeleteBuffers),\n    SYM(GenBuffers),\n    SYM(IsBuffer),\n    SYM(BufferData),\n    SYM(BufferSubData),\n    SYM(GetBufferSubData),\n    SYM(MapBuffer),\n    SYM(UnmapBuffer),\n    SYM(GetBufferParameteriv),\n    SYM(GetBufferPointerv),\n    SYM(BlendEquationSeparate),\n    SYM(DrawBuffers),\n    SYM(StencilOpSeparate),\n    SYM(StencilFuncSeparate),\n    SYM(StencilMaskSeparate),\n    SYM(AttachShader),\n    SYM(BindAttribLocation),\n    SYM(CompileShader),\n    SYM(CreateProgram),\n    SYM(CreateShader),\n    SYM(DeleteProgram),\n    SYM(DeleteShader),\n    SYM(DetachShader),\n    SYM(DisableVertexAttribArray),\n    SYM(EnableVertexAttribArray),\n    SYM(GetActiveAttrib),\n    SYM(GetActiveUniform),\n    SYM(GetAttachedShaders),\n    SYM(GetAttribLocation),\n    SYM(GetProgramiv),\n    SYM(GetProgramInfoLog),\n    SYM(GetShaderiv),\n    SYM(GetShaderInfoLog),\n    SYM(GetShaderSource),\n    SYM(GetUniformLocation),\n    SYM(GetUniformfv),\n    SYM(GetUniformiv),\n    SYM(GetVertexAttribdv),\n    SYM(GetVertexAttribfv),\n    SYM(GetVertexAttribiv),\n    SYM(GetVertexAttribPointerv),\n    SYM(IsProgram),\n    SYM(IsShader),\n    SYM(LinkProgram),\n    SYM(ShaderSource),\n    SYM(UseProgram),\n    SYM(Uniform1f),\n    SYM(Uniform2f),\n    SYM(Uniform3f),\n    SYM(Uniform4f),\n    SYM(Uniform1i),\n    SYM(Uniform2i),\n    SYM(Uniform3i),\n    SYM(Uniform4i),\n    SYM(Uniform1fv),\n    SYM(Uniform2fv),\n    SYM(Uniform3fv),\n    SYM(Uniform4fv),\n    SYM(Uniform1iv),\n    SYM(Uniform2iv),\n    SYM(Uniform3iv),\n    SYM(Uniform4iv),\n    SYM(UniformMatrix2fv),\n    SYM(UniformMatrix3fv),\n    SYM(UniformMatrix4fv),\n    SYM(ValidateProgram),\n    SYM(VertexAttrib1d),\n    SYM(VertexAttrib1dv),\n    SYM(VertexAttrib1f),\n    SYM(VertexAttrib1fv),\n    SYM(VertexAttrib1s),\n    SYM(VertexAttrib1sv),\n    SYM(VertexAttrib2d),\n    SYM(VertexAttrib2dv),\n    SYM(VertexAttrib2f),\n    SYM(VertexAttrib2fv),\n    SYM(VertexAttrib2s),\n    SYM(VertexAttrib2sv),\n    SYM(VertexAttrib3d),\n    SYM(VertexAttrib3dv),\n    SYM(VertexAttrib3f),\n    SYM(VertexAttrib3fv),\n    SYM(VertexAttrib3s),\n    SYM(VertexAttrib3sv),\n    SYM(VertexAttrib4Nbv),\n    SYM(VertexAttrib4Niv),\n    SYM(VertexAttrib4Nsv),\n    SYM(VertexAttrib4Nub),\n    SYM(VertexAttrib4Nubv),\n    SYM(VertexAttrib4Nuiv),\n    SYM(VertexAttrib4Nusv),\n    SYM(VertexAttrib4bv),\n    SYM(VertexAttrib4d),\n    SYM(VertexAttrib4dv),\n    SYM(VertexAttrib4f),\n    SYM(VertexAttrib4fv),\n    SYM(VertexAttrib4iv),\n    SYM(VertexAttrib4s),\n    SYM(VertexAttrib4sv),\n    SYM(VertexAttrib4ubv),\n    SYM(VertexAttrib4uiv),\n    SYM(VertexAttrib4usv),\n    SYM(VertexAttribPointer),\n    SYM(UniformMatrix2x3fv),\n    SYM(UniformMatrix3x2fv),\n    SYM(UniformMatrix2x4fv),\n    SYM(UniformMatrix4x2fv),\n    SYM(UniformMatrix3x4fv),\n    SYM(UniformMatrix4x3fv),\n    SYM(ColorMaski),\n    SYM(GetBooleani_v),\n    SYM(GetIntegeri_v),\n    SYM(Enablei),\n    SYM(Disablei),\n    SYM(IsEnabledi),\n    SYM(BeginTransformFeedback),\n    SYM(EndTransformFeedback),\n    SYM(BindBufferRange),\n    SYM(BindBufferBase),\n    SYM(TransformFeedbackVaryings),\n    SYM(GetTransformFeedbackVarying),\n    SYM(ClampColor),\n    SYM(BeginConditionalRender),\n    SYM(EndConditionalRender),\n    SYM(VertexAttribIPointer),\n    SYM(GetVertexAttribIiv),\n    SYM(GetVertexAttribIuiv),\n    SYM(VertexAttribI1i),\n    SYM(VertexAttribI2i),\n    SYM(VertexAttribI3i),\n    SYM(VertexAttribI4i),\n    SYM(VertexAttribI1ui),\n    SYM(VertexAttribI2ui),\n    SYM(VertexAttribI3ui),\n    SYM(VertexAttribI4ui),\n    SYM(VertexAttribI1iv),\n    SYM(VertexAttribI2iv),\n    SYM(VertexAttribI3iv),\n    SYM(VertexAttribI4iv),\n    SYM(VertexAttribI1uiv),\n    SYM(VertexAttribI2uiv),\n    SYM(VertexAttribI3uiv),\n    SYM(VertexAttribI4uiv),\n    SYM(VertexAttribI4bv),\n    SYM(VertexAttribI4sv),\n    SYM(VertexAttribI4ubv),\n    SYM(VertexAttribI4usv),\n    SYM(GetUniformuiv),\n    SYM(BindFragDataLocation),\n    SYM(GetFragDataLocation),\n    SYM(Uniform1ui),\n    SYM(Uniform2ui),\n    SYM(Uniform3ui),\n    SYM(Uniform4ui),\n    SYM(Uniform1uiv),\n    SYM(Uniform2uiv),\n    SYM(Uniform3uiv),\n    SYM(Uniform4uiv),\n    SYM(TexParameterIiv),\n    SYM(TexParameterIuiv),\n    SYM(GetTexParameterIiv),\n    SYM(GetTexParameterIuiv),\n    SYM(ClearBufferiv),\n    SYM(ClearBufferuiv),\n    SYM(ClearBufferfv),\n    SYM(ClearBufferfi),\n    SYM(GetStringi),\n    SYM(IsRenderbuffer),\n    SYM(BindRenderbuffer),\n    SYM(DeleteRenderbuffers),\n    SYM(GenRenderbuffers),\n    SYM(RenderbufferStorage),\n    SYM(GetRenderbufferParameteriv),\n    SYM(IsFramebuffer),\n    SYM(BindFramebuffer),\n    SYM(DeleteFramebuffers),\n    SYM(GenFramebuffers),\n    SYM(CheckFramebufferStatus),\n    SYM(FramebufferTexture1D),\n    SYM(FramebufferTexture2D),\n    SYM(FramebufferTexture3D),\n    SYM(FramebufferRenderbuffer),\n    SYM(GetFramebufferAttachmentParameteriv),\n    SYM(GenerateMipmap),\n    SYM(BlitFramebuffer),\n    SYM(RenderbufferStorageMultisample),\n    SYM(FramebufferTextureLayer),\n    SYM(MapBufferRange),\n    SYM(FlushMappedBufferRange),\n    SYM(BindVertexArray),\n    SYM(DeleteVertexArrays),\n    SYM(GenVertexArrays),\n    SYM(IsVertexArray),\n    SYM(DrawArraysInstanced),\n    SYM(DrawElementsInstanced),\n    SYM(TexBuffer),\n    SYM(PrimitiveRestartIndex),\n    SYM(CopyBufferSubData),\n    SYM(GetUniformIndices),\n    SYM(GetActiveUniformsiv),\n    SYM(GetActiveUniformName),\n    SYM(GetUniformBlockIndex),\n    SYM(GetActiveUniformBlockiv),\n    SYM(GetActiveUniformBlockName),\n    SYM(UniformBlockBinding),\n    SYM(DrawElementsBaseVertex),\n    SYM(DrawRangeElementsBaseVertex),\n    SYM(DrawElementsInstancedBaseVertex),\n    SYM(MultiDrawElementsBaseVertex),\n    SYM(ProvokingVertex),\n    SYM(FenceSync),\n    SYM(IsSync),\n    SYM(DeleteSync),\n    SYM(ClientWaitSync),\n    SYM(WaitSync),\n    SYM(GetInteger64v),\n    SYM(GetSynciv),\n    SYM(GetInteger64i_v),\n    SYM(GetBufferParameteri64v),\n    SYM(FramebufferTexture),\n    SYM(TexImage2DMultisample),\n    SYM(TexImage3DMultisample),\n    SYM(GetMultisamplefv),\n    SYM(SampleMaski),\n    SYM(BindFragDataLocationIndexed),\n    SYM(GetFragDataIndex),\n    SYM(GenSamplers),\n    SYM(DeleteSamplers),\n    SYM(IsSampler),\n    SYM(BindSampler),\n    SYM(SamplerParameteri),\n    SYM(SamplerParameteriv),\n    SYM(SamplerParameterf),\n    SYM(SamplerParameterfv),\n    SYM(SamplerParameterIiv),\n    SYM(SamplerParameterIuiv),\n    SYM(GetSamplerParameteriv),\n    SYM(GetSamplerParameterIiv),\n    SYM(GetSamplerParameterfv),\n    SYM(GetSamplerParameterIuiv),\n    SYM(QueryCounter),\n    SYM(GetQueryObjecti64v),\n    SYM(GetQueryObjectui64v),\n    SYM(VertexAttribDivisor),\n    SYM(VertexAttribP1ui),\n    SYM(VertexAttribP1uiv),\n    SYM(VertexAttribP2ui),\n    SYM(VertexAttribP2uiv),\n    SYM(VertexAttribP3ui),\n    SYM(VertexAttribP3uiv),\n    SYM(VertexAttribP4ui),\n    SYM(VertexAttribP4uiv),\n    SYM(VertexP2ui),\n    SYM(VertexP2uiv),\n    SYM(VertexP3ui),\n    SYM(VertexP3uiv),\n    SYM(VertexP4ui),\n    SYM(VertexP4uiv),\n    SYM(TexCoordP1ui),\n    SYM(TexCoordP1uiv),\n    SYM(TexCoordP2ui),\n    SYM(TexCoordP2uiv),\n    SYM(TexCoordP3ui),\n    SYM(TexCoordP3uiv),\n    SYM(TexCoordP4ui),\n    SYM(TexCoordP4uiv),\n    SYM(MultiTexCoordP1ui),\n    SYM(MultiTexCoordP1uiv),\n    SYM(MultiTexCoordP2ui),\n    SYM(MultiTexCoordP2uiv),\n    SYM(MultiTexCoordP3ui),\n    SYM(MultiTexCoordP3uiv),\n    SYM(MultiTexCoordP4ui),\n    SYM(MultiTexCoordP4uiv),\n    SYM(NormalP3ui),\n    SYM(NormalP3uiv),\n    SYM(ColorP3ui),\n    SYM(ColorP3uiv),\n    SYM(ColorP4ui),\n    SYM(ColorP4uiv),\n    SYM(SecondaryColorP3ui),\n    SYM(SecondaryColorP3uiv),\n    SYM(MinSampleShading),\n    SYM(BlendEquationi),\n    SYM(BlendEquationSeparatei),\n    SYM(BlendFunci),\n    SYM(BlendFuncSeparatei),\n    SYM(DrawArraysIndirect),\n    SYM(DrawElementsIndirect),\n    SYM(Uniform1d),\n    SYM(Uniform2d),\n    SYM(Uniform3d),\n    SYM(Uniform4d),\n    SYM(Uniform1dv),\n    SYM(Uniform2dv),\n    SYM(Uniform3dv),\n    SYM(Uniform4dv),\n    SYM(UniformMatrix2dv),\n    SYM(UniformMatrix3dv),\n    SYM(UniformMatrix4dv),\n    SYM(UniformMatrix2x3dv),\n    SYM(UniformMatrix2x4dv),\n    SYM(UniformMatrix3x2dv),\n    SYM(UniformMatrix3x4dv),\n    SYM(UniformMatrix4x2dv),\n    SYM(UniformMatrix4x3dv),\n    SYM(GetUniformdv),\n    SYM(GetSubroutineUniformLocation),\n    SYM(GetSubroutineIndex),\n    SYM(GetActiveSubroutineUniformiv),\n    SYM(GetActiveSubroutineUniformName),\n    SYM(GetActiveSubroutineName),\n    SYM(UniformSubroutinesuiv),\n    SYM(GetUniformSubroutineuiv),\n    SYM(GetProgramStageiv),\n    SYM(PatchParameteri),\n    SYM(PatchParameterfv),\n    SYM(BindTransformFeedback),\n    SYM(DeleteTransformFeedbacks),\n    SYM(GenTransformFeedbacks),\n    SYM(IsTransformFeedback),\n    SYM(PauseTransformFeedback),\n    SYM(ResumeTransformFeedback),\n    SYM(DrawTransformFeedback),\n    SYM(DrawTransformFeedbackStream),\n    SYM(BeginQueryIndexed),\n    SYM(EndQueryIndexed),\n    SYM(GetQueryIndexediv),\n    SYM(ReleaseShaderCompiler),\n    SYM(ShaderBinary),\n    SYM(GetShaderPrecisionFormat),\n    SYM(DepthRangef),\n    SYM(ClearDepthf),\n    SYM(GetProgramBinary),\n    SYM(ProgramBinary),\n    SYM(ProgramParameteri),\n    SYM(UseProgramStages),\n    SYM(ActiveShaderProgram),\n    SYM(CreateShaderProgramv),\n    SYM(BindProgramPipeline),\n    SYM(DeleteProgramPipelines),\n    SYM(GenProgramPipelines),\n    SYM(IsProgramPipeline),\n    SYM(GetProgramPipelineiv),\n    SYM(ProgramUniform1i),\n    SYM(ProgramUniform1iv),\n    SYM(ProgramUniform1f),\n    SYM(ProgramUniform1fv),\n    SYM(ProgramUniform1d),\n    SYM(ProgramUniform1dv),\n    SYM(ProgramUniform1ui),\n    SYM(ProgramUniform1uiv),\n    SYM(ProgramUniform2i),\n    SYM(ProgramUniform2iv),\n    SYM(ProgramUniform2f),\n    SYM(ProgramUniform2fv),\n    SYM(ProgramUniform2d),\n    SYM(ProgramUniform2dv),\n    SYM(ProgramUniform2ui),\n    SYM(ProgramUniform2uiv),\n    SYM(ProgramUniform3i),\n    SYM(ProgramUniform3iv),\n    SYM(ProgramUniform3f),\n    SYM(ProgramUniform3fv),\n    SYM(ProgramUniform3d),\n    SYM(ProgramUniform3dv),\n    SYM(ProgramUniform3ui),\n    SYM(ProgramUniform3uiv),\n    SYM(ProgramUniform4i),\n    SYM(ProgramUniform4iv),\n    SYM(ProgramUniform4f),\n    SYM(ProgramUniform4fv),\n    SYM(ProgramUniform4d),\n    SYM(ProgramUniform4dv),\n    SYM(ProgramUniform4ui),\n    SYM(ProgramUniform4uiv),\n    SYM(ProgramUniformMatrix2fv),\n    SYM(ProgramUniformMatrix3fv),\n    SYM(ProgramUniformMatrix4fv),\n    SYM(ProgramUniformMatrix2dv),\n    SYM(ProgramUniformMatrix3dv),\n    SYM(ProgramUniformMatrix4dv),\n    SYM(ProgramUniformMatrix2x3fv),\n    SYM(ProgramUniformMatrix3x2fv),\n    SYM(ProgramUniformMatrix2x4fv),\n    SYM(ProgramUniformMatrix4x2fv),\n    SYM(ProgramUniformMatrix3x4fv),\n    SYM(ProgramUniformMatrix4x3fv),\n    SYM(ProgramUniformMatrix2x3dv),\n    SYM(ProgramUniformMatrix3x2dv),\n    SYM(ProgramUniformMatrix2x4dv),\n    SYM(ProgramUniformMatrix4x2dv),\n    SYM(ProgramUniformMatrix3x4dv),\n    SYM(ProgramUniformMatrix4x3dv),\n    SYM(ValidateProgramPipeline),\n    SYM(GetProgramPipelineInfoLog),\n    SYM(VertexAttribL1d),\n    SYM(VertexAttribL2d),\n    SYM(VertexAttribL3d),\n    SYM(VertexAttribL4d),\n    SYM(VertexAttribL1dv),\n    SYM(VertexAttribL2dv),\n    SYM(VertexAttribL3dv),\n    SYM(VertexAttribL4dv),\n    SYM(VertexAttribLPointer),\n    SYM(GetVertexAttribLdv),\n    SYM(ViewportArrayv),\n    SYM(ViewportIndexedf),\n    SYM(ViewportIndexedfv),\n    SYM(ScissorArrayv),\n    SYM(ScissorIndexed),\n    SYM(ScissorIndexedv),\n    SYM(DepthRangeArrayv),\n    SYM(DepthRangeIndexed),\n    SYM(GetFloati_v),\n    SYM(GetDoublei_v),\n    SYM(DrawArraysInstancedBaseInstance),\n    SYM(DrawElementsInstancedBaseInstance),\n    SYM(DrawElementsInstancedBaseVertexBaseInstance),\n    SYM(GetInternalformativ),\n    SYM(GetActiveAtomicCounterBufferiv),\n    SYM(BindImageTexture),\n    SYM(MemoryBarrier),\n    SYM(TexStorage1D),\n    SYM(TexStorage2D),\n    SYM(TexStorage3D),\n    SYM(DrawTransformFeedbackInstanced),\n    SYM(DrawTransformFeedbackStreamInstanced),\n    SYM(ClearBufferData),\n    SYM(ClearBufferSubData),\n    SYM(DispatchCompute),\n    SYM(DispatchComputeIndirect),\n    SYM(CopyImageSubData),\n    SYM(FramebufferParameteri),\n    SYM(GetFramebufferParameteriv),\n    SYM(GetInternalformati64v),\n    SYM(InvalidateTexSubImage),\n    SYM(InvalidateTexImage),\n    SYM(InvalidateBufferSubData),\n    SYM(InvalidateBufferData),\n    SYM(InvalidateFramebuffer),\n    SYM(InvalidateSubFramebuffer),\n    SYM(MultiDrawArraysIndirect),\n    SYM(MultiDrawElementsIndirect),\n    SYM(GetProgramInterfaceiv),\n    SYM(GetProgramResourceIndex),\n    SYM(GetProgramResourceName),\n    SYM(GetProgramResourceiv),\n    SYM(GetProgramResourceLocation),\n    SYM(GetProgramResourceLocationIndex),\n    SYM(ShaderStorageBlockBinding),\n    SYM(TexBufferRange),\n    SYM(TexStorage2DMultisample),\n    SYM(TexStorage3DMultisample),\n    SYM(TextureView),\n    SYM(BindVertexBuffer),\n    SYM(VertexAttribFormat),\n    SYM(VertexAttribIFormat),\n    SYM(VertexAttribLFormat),\n    SYM(VertexAttribBinding),\n    SYM(VertexBindingDivisor),\n    SYM(DebugMessageControl),\n    SYM(DebugMessageInsert),\n    SYM(DebugMessageCallback),\n    SYM(GetDebugMessageLog),\n    SYM(PushDebugGroup),\n    SYM(PopDebugGroup),\n    SYM(ObjectLabel),\n    SYM(GetObjectLabel),\n    SYM(ObjectPtrLabel),\n    SYM(GetObjectPtrLabel),\n    SYM(BufferStorage),\n    SYM(ClearTexImage),\n    SYM(ClearTexSubImage),\n    SYM(BindBuffersBase),\n    SYM(BindBuffersRange),\n    SYM(BindTextures),\n    SYM(BindSamplers),\n    SYM(BindImageTextures),\n    SYM(BindVertexBuffers),\n    SYM(GetTextureHandleARB),\n    SYM(GetTextureSamplerHandleARB),\n    SYM(MakeTextureHandleResidentARB),\n    SYM(MakeTextureHandleNonResidentARB),\n    SYM(GetImageHandleARB),\n    SYM(MakeImageHandleResidentARB),\n    SYM(MakeImageHandleNonResidentARB),\n    SYM(UniformHandleui64ARB),\n    SYM(UniformHandleui64vARB),\n    SYM(ProgramUniformHandleui64ARB),\n    SYM(ProgramUniformHandleui64vARB),\n    SYM(IsTextureHandleResidentARB),\n    SYM(IsImageHandleResidentARB),\n    SYM(VertexAttribL1ui64ARB),\n    SYM(VertexAttribL1ui64vARB),\n    SYM(GetVertexAttribLui64vARB),\n    SYM(CreateSyncFromCLeventARB),\n    SYM(ClampColorARB),\n    SYM(DispatchComputeGroupSizeARB),\n    SYM(DebugMessageControlARB),\n    SYM(DebugMessageInsertARB),\n    SYM(DebugMessageCallbackARB),\n    SYM(GetDebugMessageLogARB),\n    SYM(DrawBuffersARB),\n    SYM(BlendEquationiARB),\n    SYM(BlendEquationSeparateiARB),\n    SYM(BlendFunciARB),\n    SYM(BlendFuncSeparateiARB),\n    SYM(DrawArraysInstancedARB),\n    SYM(DrawElementsInstancedARB),\n    SYM(ProgramStringARB),\n    SYM(BindProgramARB),\n    SYM(DeleteProgramsARB),\n    SYM(GenProgramsARB),\n    SYM(ProgramEnvParameter4dARB),\n    SYM(ProgramEnvParameter4dvARB),\n    SYM(ProgramEnvParameter4fARB),\n    SYM(ProgramEnvParameter4fvARB),\n    SYM(ProgramLocalParameter4dARB),\n    SYM(ProgramLocalParameter4dvARB),\n    SYM(ProgramLocalParameter4fARB),\n    SYM(ProgramLocalParameter4fvARB),\n    SYM(GetProgramEnvParameterdvARB),\n    SYM(GetProgramEnvParameterfvARB),\n    SYM(GetProgramLocalParameterdvARB),\n    SYM(GetProgramLocalParameterfvARB),\n    SYM(GetProgramivARB),\n    SYM(GetProgramStringARB),\n    SYM(IsProgramARB),\n    SYM(ProgramParameteriARB),\n    SYM(FramebufferTextureARB),\n    SYM(FramebufferTextureLayerARB),\n    SYM(FramebufferTextureFaceARB),\n    SYM(ColorTable),\n    SYM(ColorTableParameterfv),\n    SYM(ColorTableParameteriv),\n    SYM(CopyColorTable),\n    SYM(GetColorTable),\n    SYM(GetColorTableParameterfv),\n    SYM(GetColorTableParameteriv),\n    SYM(ColorSubTable),\n    SYM(CopyColorSubTable),\n    SYM(ConvolutionFilter1D),\n    SYM(ConvolutionFilter2D),\n    SYM(ConvolutionParameterf),\n    SYM(ConvolutionParameterfv),\n    SYM(ConvolutionParameteri),\n    SYM(ConvolutionParameteriv),\n    SYM(CopyConvolutionFilter1D),\n    SYM(CopyConvolutionFilter2D),\n    SYM(GetConvolutionFilter),\n    SYM(GetConvolutionParameterfv),\n    SYM(GetConvolutionParameteriv),\n    SYM(GetSeparableFilter),\n    SYM(SeparableFilter2D),\n    SYM(GetHistogram),\n    SYM(GetHistogramParameterfv),\n    SYM(GetHistogramParameteriv),\n    SYM(GetMinmax),\n    SYM(GetMinmaxParameterfv),\n    SYM(GetMinmaxParameteriv),\n    SYM(Histogram),\n    SYM(Minmax),\n    SYM(ResetHistogram),\n    SYM(ResetMinmax),\n    SYM(MultiDrawArraysIndirectCountARB),\n    SYM(MultiDrawElementsIndirectCountARB),\n    SYM(VertexAttribDivisorARB),\n    SYM(CurrentPaletteMatrixARB),\n    SYM(MatrixIndexubvARB),\n    SYM(MatrixIndexusvARB),\n    SYM(MatrixIndexuivARB),\n    SYM(MatrixIndexPointerARB),\n    SYM(SampleCoverageARB),\n    SYM(ActiveTextureARB),\n    SYM(ClientActiveTextureARB),\n    SYM(MultiTexCoord1dARB),\n    SYM(MultiTexCoord1dvARB),\n    SYM(MultiTexCoord1fARB),\n    SYM(MultiTexCoord1fvARB),\n    SYM(MultiTexCoord1iARB),\n    SYM(MultiTexCoord1ivARB),\n    SYM(MultiTexCoord1sARB),\n    SYM(MultiTexCoord1svARB),\n    SYM(MultiTexCoord2dARB),\n    SYM(MultiTexCoord2dvARB),\n    SYM(MultiTexCoord2fARB),\n    SYM(MultiTexCoord2fvARB),\n    SYM(MultiTexCoord2iARB),\n    SYM(MultiTexCoord2ivARB),\n    SYM(MultiTexCoord2sARB),\n    SYM(MultiTexCoord2svARB),\n    SYM(MultiTexCoord3dARB),\n    SYM(MultiTexCoord3dvARB),\n    SYM(MultiTexCoord3fARB),\n    SYM(MultiTexCoord3fvARB),\n    SYM(MultiTexCoord3iARB),\n    SYM(MultiTexCoord3ivARB),\n    SYM(MultiTexCoord3sARB),\n    SYM(MultiTexCoord3svARB),\n    SYM(MultiTexCoord4dARB),\n    SYM(MultiTexCoord4dvARB),\n    SYM(MultiTexCoord4fARB),\n    SYM(MultiTexCoord4fvARB),\n    SYM(MultiTexCoord4iARB),\n    SYM(MultiTexCoord4ivARB),\n    SYM(MultiTexCoord4sARB),\n    SYM(MultiTexCoord4svARB),\n    SYM(GenQueriesARB),\n    SYM(DeleteQueriesARB),\n    SYM(IsQueryARB),\n    SYM(BeginQueryARB),\n    SYM(EndQueryARB),\n    SYM(GetQueryivARB),\n    SYM(GetQueryObjectivARB),\n    SYM(GetQueryObjectuivARB),\n    SYM(PointParameterfARB),\n    SYM(PointParameterfvARB),\n    SYM(GetGraphicsResetStatusARB),\n    SYM(GetnTexImageARB),\n    SYM(ReadnPixelsARB),\n    SYM(GetnCompressedTexImageARB),\n    SYM(GetnUniformfvARB),\n    SYM(GetnUniformivARB),\n    SYM(GetnUniformuivARB),\n    SYM(GetnUniformdvARB),\n    SYM(GetnMapdvARB),\n    SYM(GetnMapfvARB),\n    SYM(GetnMapivARB),\n    SYM(GetnPixelMapfvARB),\n    SYM(GetnPixelMapuivARB),\n    SYM(GetnPixelMapusvARB),\n    SYM(GetnPolygonStippleARB),\n    SYM(GetnColorTableARB),\n    SYM(GetnConvolutionFilterARB),\n    SYM(GetnSeparableFilterARB),\n    SYM(GetnHistogramARB),\n    SYM(GetnMinmaxARB),\n    SYM(MinSampleShadingARB),\n    SYM(DeleteObjectARB),\n    SYM(GetHandleARB),\n    SYM(DetachObjectARB),\n    SYM(CreateShaderObjectARB),\n    SYM(ShaderSourceARB),\n    SYM(CompileShaderARB),\n    SYM(CreateProgramObjectARB),\n    SYM(AttachObjectARB),\n    SYM(LinkProgramARB),\n    SYM(UseProgramObjectARB),\n    SYM(ValidateProgramARB),\n    SYM(Uniform1fARB),\n    SYM(Uniform2fARB),\n    SYM(Uniform3fARB),\n    SYM(Uniform4fARB),\n    SYM(Uniform1iARB),\n    SYM(Uniform2iARB),\n    SYM(Uniform3iARB),\n    SYM(Uniform4iARB),\n    SYM(Uniform1fvARB),\n    SYM(Uniform2fvARB),\n    SYM(Uniform3fvARB),\n    SYM(Uniform4fvARB),\n    SYM(Uniform1ivARB),\n    SYM(Uniform2ivARB),\n    SYM(Uniform3ivARB),\n    SYM(Uniform4ivARB),\n    SYM(UniformMatrix2fvARB),\n    SYM(UniformMatrix3fvARB),\n    SYM(UniformMatrix4fvARB),\n    SYM(GetObjectParameterfvARB),\n    SYM(GetObjectParameterivARB),\n    SYM(GetInfoLogARB),\n    SYM(GetAttachedObjectsARB),\n    SYM(GetUniformLocationARB),\n    SYM(GetActiveUniformARB),\n    SYM(GetUniformfvARB),\n    SYM(GetUniformivARB),\n    SYM(GetShaderSourceARB),\n    SYM(NamedStringARB),\n    SYM(DeleteNamedStringARB),\n    SYM(CompileShaderIncludeARB),\n    SYM(IsNamedStringARB),\n    SYM(GetNamedStringARB),\n    SYM(GetNamedStringivARB),\n    SYM(TexPageCommitmentARB),\n    SYM(TexBufferARB),\n    SYM(CompressedTexImage3DARB),\n    SYM(CompressedTexImage2DARB),\n    SYM(CompressedTexImage1DARB),\n    SYM(CompressedTexSubImage3DARB),\n    SYM(CompressedTexSubImage2DARB),\n    SYM(CompressedTexSubImage1DARB),\n    SYM(GetCompressedTexImageARB),\n    SYM(LoadTransposeMatrixfARB),\n    SYM(LoadTransposeMatrixdARB),\n    SYM(MultTransposeMatrixfARB),\n    SYM(MultTransposeMatrixdARB),\n    SYM(WeightbvARB),\n    SYM(WeightsvARB),\n    SYM(WeightivARB),\n    SYM(WeightfvARB),\n    SYM(WeightdvARB),\n    SYM(WeightubvARB),\n    SYM(WeightusvARB),\n    SYM(WeightuivARB),\n    SYM(WeightPointerARB),\n    SYM(VertexBlendARB),\n    SYM(BindBufferARB),\n    SYM(DeleteBuffersARB),\n    SYM(GenBuffersARB),\n    SYM(IsBufferARB),\n    SYM(BufferDataARB),\n    SYM(BufferSubDataARB),\n    SYM(GetBufferSubDataARB),\n    SYM(MapBufferARB),\n    SYM(UnmapBufferARB),\n    SYM(GetBufferParameterivARB),\n    SYM(GetBufferPointervARB),\n    SYM(VertexAttrib1dARB),\n    SYM(VertexAttrib1dvARB),\n    SYM(VertexAttrib1fARB),\n    SYM(VertexAttrib1fvARB),\n    SYM(VertexAttrib1sARB),\n    SYM(VertexAttrib1svARB),\n    SYM(VertexAttrib2dARB),\n    SYM(VertexAttrib2dvARB),\n    SYM(VertexAttrib2fARB),\n    SYM(VertexAttrib2fvARB),\n    SYM(VertexAttrib2sARB),\n    SYM(VertexAttrib2svARB),\n    SYM(VertexAttrib3dARB),\n    SYM(VertexAttrib3dvARB),\n    SYM(VertexAttrib3fARB),\n    SYM(VertexAttrib3fvARB),\n    SYM(VertexAttrib3sARB),\n    SYM(VertexAttrib3svARB),\n    SYM(VertexAttrib4NbvARB),\n    SYM(VertexAttrib4NivARB),\n    SYM(VertexAttrib4NsvARB),\n    SYM(VertexAttrib4NubARB),\n    SYM(VertexAttrib4NubvARB),\n    SYM(VertexAttrib4NuivARB),\n    SYM(VertexAttrib4NusvARB),\n    SYM(VertexAttrib4bvARB),\n    SYM(VertexAttrib4dARB),\n    SYM(VertexAttrib4dvARB),\n    SYM(VertexAttrib4fARB),\n    SYM(VertexAttrib4fvARB),\n    SYM(VertexAttrib4ivARB),\n    SYM(VertexAttrib4sARB),\n    SYM(VertexAttrib4svARB),\n    SYM(VertexAttrib4ubvARB),\n    SYM(VertexAttrib4uivARB),\n    SYM(VertexAttrib4usvARB),\n    SYM(VertexAttribPointerARB),\n    SYM(EnableVertexAttribArrayARB),\n    SYM(DisableVertexAttribArrayARB),\n    SYM(GetVertexAttribdvARB),\n    SYM(GetVertexAttribfvARB),\n    SYM(GetVertexAttribivARB),\n    SYM(GetVertexAttribPointervARB),\n    SYM(BindAttribLocationARB),\n    SYM(GetActiveAttribARB),\n    SYM(GetAttribLocationARB),\n    SYM(WindowPos2dARB),\n    SYM(WindowPos2dvARB),\n    SYM(WindowPos2fARB),\n    SYM(WindowPos2fvARB),\n    SYM(WindowPos2iARB),\n    SYM(WindowPos2ivARB),\n    SYM(WindowPos2sARB),\n    SYM(WindowPos2svARB),\n    SYM(WindowPos3dARB),\n    SYM(WindowPos3dvARB),\n    SYM(WindowPos3fARB),\n    SYM(WindowPos3fvARB),\n    SYM(WindowPos3iARB),\n    SYM(WindowPos3ivARB),\n    SYM(WindowPos3sARB),\n    SYM(WindowPos3svARB),\n    SYM(MultiTexCoord1bOES),\n    SYM(MultiTexCoord1bvOES),\n    SYM(MultiTexCoord2bOES),\n    SYM(MultiTexCoord2bvOES),\n    SYM(MultiTexCoord3bOES),\n    SYM(MultiTexCoord3bvOES),\n    SYM(MultiTexCoord4bOES),\n    SYM(MultiTexCoord4bvOES),\n    SYM(TexCoord1bOES),\n    SYM(TexCoord1bvOES),\n    SYM(TexCoord2bOES),\n    SYM(TexCoord2bvOES),\n    SYM(TexCoord3bOES),\n    SYM(TexCoord3bvOES),\n    SYM(TexCoord4bOES),\n    SYM(TexCoord4bvOES),\n    SYM(Vertex2bOES),\n    SYM(Vertex2bvOES),\n    SYM(Vertex3bOES),\n    SYM(Vertex3bvOES),\n    SYM(Vertex4bOES),\n    SYM(Vertex4bvOES),\n    SYM(AlphaFuncxOES),\n    SYM(ClearColorxOES),\n    SYM(ClearDepthxOES),\n    SYM(ClipPlanexOES),\n    SYM(Color4xOES),\n    SYM(DepthRangexOES),\n    SYM(FogxOES),\n    SYM(FogxvOES),\n    SYM(FrustumxOES),\n    SYM(GetClipPlanexOES),\n    SYM(GetFixedvOES),\n    SYM(GetTexEnvxvOES),\n    SYM(GetTexParameterxvOES),\n    SYM(LightModelxOES),\n    SYM(LightModelxvOES),\n    SYM(LightxOES),\n    SYM(LightxvOES),\n    SYM(LineWidthxOES),\n    SYM(LoadMatrixxOES),\n    SYM(MaterialxOES),\n    SYM(MaterialxvOES),\n    SYM(MultMatrixxOES),\n    SYM(MultiTexCoord4xOES),\n    SYM(Normal3xOES),\n    SYM(OrthoxOES),\n    SYM(PointParameterxvOES),\n    SYM(PointSizexOES),\n    SYM(PolygonOffsetxOES),\n    SYM(RotatexOES),\n    SYM(SampleCoverageOES),\n    SYM(ScalexOES),\n    SYM(TexEnvxOES),\n    SYM(TexEnvxvOES),\n    SYM(TexParameterxOES),\n    SYM(TexParameterxvOES),\n    SYM(TranslatexOES),\n    SYM(AccumxOES),\n    SYM(BitmapxOES),\n    SYM(BlendColorxOES),\n    SYM(ClearAccumxOES),\n    SYM(Color3xOES),\n    SYM(Color3xvOES),\n    SYM(Color4xvOES),\n    SYM(ConvolutionParameterxOES),\n    SYM(ConvolutionParameterxvOES),\n    SYM(EvalCoord1xOES),\n    SYM(EvalCoord1xvOES),\n    SYM(EvalCoord2xOES),\n    SYM(EvalCoord2xvOES),\n    SYM(FeedbackBufferxOES),\n    SYM(GetConvolutionParameterxvOES),\n    SYM(GetHistogramParameterxvOES),\n    SYM(GetLightxOES),\n    SYM(GetMapxvOES),\n    SYM(GetMaterialxOES),\n    SYM(GetPixelMapxv),\n    SYM(GetTexGenxvOES),\n    SYM(GetTexLevelParameterxvOES),\n    SYM(IndexxOES),\n    SYM(IndexxvOES),\n    SYM(LoadTransposeMatrixxOES),\n    SYM(Map1xOES),\n    SYM(Map2xOES),\n    SYM(MapGrid1xOES),\n    SYM(MapGrid2xOES),\n    SYM(MultTransposeMatrixxOES),\n    SYM(MultiTexCoord1xOES),\n    SYM(MultiTexCoord1xvOES),\n    SYM(MultiTexCoord2xOES),\n    SYM(MultiTexCoord2xvOES),\n    SYM(MultiTexCoord3xOES),\n    SYM(MultiTexCoord3xvOES),\n    SYM(MultiTexCoord4xvOES),\n    SYM(Normal3xvOES),\n    SYM(PassThroughxOES),\n    SYM(PixelMapx),\n    SYM(PixelStorex),\n    SYM(PixelTransferxOES),\n    SYM(PixelZoomxOES),\n    SYM(PrioritizeTexturesxOES),\n    SYM(RasterPos2xOES),\n    SYM(RasterPos2xvOES),\n    SYM(RasterPos3xOES),\n    SYM(RasterPos3xvOES),\n    SYM(RasterPos4xOES),\n    SYM(RasterPos4xvOES),\n    SYM(RectxOES),\n    SYM(RectxvOES),\n    SYM(TexCoord1xOES),\n    SYM(TexCoord1xvOES),\n    SYM(TexCoord2xOES),\n    SYM(TexCoord2xvOES),\n    SYM(TexCoord3xOES),\n    SYM(TexCoord3xvOES),\n    SYM(TexCoord4xOES),\n    SYM(TexCoord4xvOES),\n    SYM(TexGenxOES),\n    SYM(TexGenxvOES),\n    SYM(Vertex2xOES),\n    SYM(Vertex2xvOES),\n    SYM(Vertex3xOES),\n    SYM(Vertex3xvOES),\n    SYM(Vertex4xOES),\n    SYM(Vertex4xvOES),\n    SYM(QueryMatrixxOES),\n    SYM(ClearDepthfOES),\n    SYM(ClipPlanefOES),\n    SYM(DepthRangefOES),\n    SYM(FrustumfOES),\n    SYM(GetClipPlanefOES),\n    SYM(OrthofOES),\n    SYM(ImageTransformParameteriHP),\n    SYM(ImageTransformParameterfHP),\n    SYM(ImageTransformParameterivHP),\n    SYM(ImageTransformParameterfvHP),\n    SYM(GetImageTransformParameterivHP),\n    SYM(GetImageTransformParameterfvHP),\n\n    { NULL, NULL },\n};\nRGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;\nRGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;\nRGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;\nRGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;\nRGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;\nRGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;\nRGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;\nRGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;\nRGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;\nRGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;\nRGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;\nRGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;\nRGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;\nRGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;\nRGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;\nRGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;\nRGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;\nRGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;\nRGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;\nRGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;\nRGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;\nRGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;\nRGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;\nRGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;\nRGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;\nRGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;\nRGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;\nRGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;\nRGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;\nRGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;\nRGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;\nRGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;\nRGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;\nRGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;\nRGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;\nRGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;\nRGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;\nRGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;\nRGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;\nRGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;\nRGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;\nRGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;\nRGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;\nRGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;\nRGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;\nRGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;\nRGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;\nRGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;\nRGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;\nRGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;\nRGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;\nRGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;\nRGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;\nRGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;\nRGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;\nRGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;\nRGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;\nRGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;\nRGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;\nRGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;\nRGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;\nRGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;\nRGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;\nRGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;\nRGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;\nRGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;\nRGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;\nRGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;\nRGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;\nRGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;\nRGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;\nRGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;\nRGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;\nRGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;\nRGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;\nRGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;\nRGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;\nRGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;\nRGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;\nRGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;\nRGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;\nRGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;\nRGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;\nRGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;\nRGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;\nRGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;\nRGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;\nRGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;\nRGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;\nRGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;\nRGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;\nRGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;\nRGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;\nRGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;\nRGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;\nRGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;\nRGLSYMGLISQUERYPROC __rglgen_glIsQuery;\nRGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;\nRGLSYMGLENDQUERYPROC __rglgen_glEndQuery;\nRGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;\nRGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;\nRGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;\nRGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;\nRGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;\nRGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;\nRGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;\nRGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;\nRGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;\nRGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;\nRGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;\nRGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;\nRGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;\nRGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;\nRGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;\nRGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;\nRGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;\nRGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;\nRGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;\nRGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;\nRGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;\nRGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;\nRGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;\nRGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;\nRGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;\nRGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;\nRGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;\nRGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;\nRGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;\nRGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;\nRGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;\nRGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;\nRGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;\nRGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;\nRGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;\nRGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;\nRGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;\nRGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;\nRGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;\nRGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;\nRGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;\nRGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;\nRGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;\nRGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;\nRGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;\nRGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;\nRGLSYMGLISSHADERPROC __rglgen_glIsShader;\nRGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;\nRGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;\nRGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;\nRGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;\nRGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;\nRGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;\nRGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;\nRGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;\nRGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;\nRGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;\nRGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;\nRGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;\nRGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;\nRGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;\nRGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;\nRGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;\nRGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;\nRGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;\nRGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;\nRGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;\nRGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;\nRGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;\nRGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;\nRGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;\nRGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;\nRGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;\nRGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;\nRGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;\nRGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;\nRGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;\nRGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;\nRGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;\nRGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;\nRGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;\nRGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;\nRGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;\nRGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;\nRGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;\nRGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;\nRGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;\nRGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;\nRGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;\nRGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;\nRGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;\nRGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;\nRGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;\nRGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;\nRGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;\nRGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;\nRGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;\nRGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;\nRGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;\nRGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;\nRGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;\nRGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;\nRGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;\nRGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;\nRGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;\nRGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;\nRGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;\nRGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;\nRGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;\nRGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;\nRGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;\nRGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;\nRGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;\nRGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;\nRGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;\nRGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;\nRGLSYMGLENABLEIPROC __rglgen_glEnablei;\nRGLSYMGLDISABLEIPROC __rglgen_glDisablei;\nRGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;\nRGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;\nRGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;\nRGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;\nRGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;\nRGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;\nRGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;\nRGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;\nRGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;\nRGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;\nRGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;\nRGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;\nRGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;\nRGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;\nRGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;\nRGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;\nRGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;\nRGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;\nRGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;\nRGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;\nRGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;\nRGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;\nRGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;\nRGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;\nRGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;\nRGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;\nRGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;\nRGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;\nRGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;\nRGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;\nRGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;\nRGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;\nRGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;\nRGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;\nRGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;\nRGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;\nRGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;\nRGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;\nRGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;\nRGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;\nRGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;\nRGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;\nRGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;\nRGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;\nRGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;\nRGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;\nRGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;\nRGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;\nRGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;\nRGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;\nRGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;\nRGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;\nRGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;\nRGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;\nRGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;\nRGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;\nRGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;\nRGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;\nRGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;\nRGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;\nRGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;\nRGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;\nRGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;\nRGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;\nRGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;\nRGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;\nRGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;\nRGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;\nRGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;\nRGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;\nRGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;\nRGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;\nRGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;\nRGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;\nRGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;\nRGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;\nRGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;\nRGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;\nRGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;\nRGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;\nRGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;\nRGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;\nRGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;\nRGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;\nRGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;\nRGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;\nRGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;\nRGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;\nRGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;\nRGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;\nRGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;\nRGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;\nRGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;\nRGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;\nRGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;\nRGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;\nRGLSYMGLISSYNCPROC __rglgen_glIsSync;\nRGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;\nRGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;\nRGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;\nRGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;\nRGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;\nRGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;\nRGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;\nRGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;\nRGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;\nRGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;\nRGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;\nRGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;\nRGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;\nRGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;\nRGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;\nRGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;\nRGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;\nRGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;\nRGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;\nRGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;\nRGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;\nRGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;\nRGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;\nRGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;\nRGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;\nRGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;\nRGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;\nRGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;\nRGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;\nRGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;\nRGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;\nRGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;\nRGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;\nRGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;\nRGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;\nRGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;\nRGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;\nRGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;\nRGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;\nRGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;\nRGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;\nRGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;\nRGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;\nRGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;\nRGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;\nRGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;\nRGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;\nRGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;\nRGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;\nRGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;\nRGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;\nRGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;\nRGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;\nRGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;\nRGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;\nRGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;\nRGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;\nRGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;\nRGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;\nRGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;\nRGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;\nRGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;\nRGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;\nRGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;\nRGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;\nRGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;\nRGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;\nRGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;\nRGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;\nRGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;\nRGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;\nRGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;\nRGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;\nRGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;\nRGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;\nRGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;\nRGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;\nRGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;\nRGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;\nRGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;\nRGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;\nRGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;\nRGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;\nRGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;\nRGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;\nRGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;\nRGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;\nRGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;\nRGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;\nRGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;\nRGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;\nRGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;\nRGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;\nRGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;\nRGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;\nRGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;\nRGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;\nRGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;\nRGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;\nRGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;\nRGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;\nRGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;\nRGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;\nRGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;\nRGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;\nRGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;\nRGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;\nRGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;\nRGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;\nRGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;\nRGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;\nRGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;\nRGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;\nRGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;\nRGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;\nRGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;\nRGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;\nRGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;\nRGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;\nRGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;\nRGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;\nRGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;\nRGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;\nRGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;\nRGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;\nRGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;\nRGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;\nRGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;\nRGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;\nRGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;\nRGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;\nRGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;\nRGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;\nRGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;\nRGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;\nRGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;\nRGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;\nRGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;\nRGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;\nRGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;\nRGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;\nRGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;\nRGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;\nRGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;\nRGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;\nRGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;\nRGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;\nRGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;\nRGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;\nRGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;\nRGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;\nRGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;\nRGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;\nRGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;\nRGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;\nRGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;\nRGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;\nRGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;\nRGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;\nRGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;\nRGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;\nRGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;\nRGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;\nRGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;\nRGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;\nRGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;\nRGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;\nRGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;\nRGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;\nRGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;\nRGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;\nRGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;\nRGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;\nRGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;\nRGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;\nRGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;\nRGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;\nRGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;\nRGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;\nRGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;\nRGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;\nRGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;\nRGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;\nRGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;\nRGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;\nRGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;\nRGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;\nRGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;\nRGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;\nRGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;\nRGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;\nRGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;\nRGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;\nRGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;\nRGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;\nRGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;\nRGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;\nRGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;\nRGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;\nRGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;\nRGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;\nRGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;\nRGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;\nRGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;\nRGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;\nRGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;\nRGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;\nRGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;\nRGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;\nRGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;\nRGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;\nRGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;\nRGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;\nRGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;\nRGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;\nRGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;\nRGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;\nRGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;\nRGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;\nRGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;\nRGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;\nRGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;\nRGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;\nRGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;\nRGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;\nRGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;\nRGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;\nRGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;\nRGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;\nRGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;\nRGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;\nRGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;\nRGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;\nRGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;\nRGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;\nRGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;\nRGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;\nRGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;\nRGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;\nRGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;\nRGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;\nRGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;\nRGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;\nRGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;\nRGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;\nRGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;\nRGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;\nRGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;\nRGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;\nRGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;\nRGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;\nRGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;\nRGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;\nRGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;\nRGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;\nRGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;\nRGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;\nRGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;\nRGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;\nRGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;\nRGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;\nRGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;\nRGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;\nRGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;\nRGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;\nRGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;\nRGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;\nRGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;\nRGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;\nRGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;\nRGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;\nRGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;\nRGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;\nRGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;\nRGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;\nRGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;\nRGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;\nRGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;\nRGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;\nRGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;\nRGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;\nRGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;\nRGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;\nRGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;\nRGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;\nRGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;\nRGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;\nRGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;\nRGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;\nRGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;\nRGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;\nRGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;\nRGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;\nRGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;\nRGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;\nRGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;\nRGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;\nRGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;\nRGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;\nRGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;\nRGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;\nRGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;\nRGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;\nRGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;\nRGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;\nRGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;\nRGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;\nRGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;\nRGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;\nRGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;\nRGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;\nRGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;\nRGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;\nRGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;\nRGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;\nRGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;\nRGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;\nRGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;\nRGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;\nRGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;\nRGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;\nRGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;\nRGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;\nRGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;\nRGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;\nRGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;\nRGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;\nRGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;\nRGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;\nRGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;\nRGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;\nRGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;\nRGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;\nRGLSYMGLMINMAXPROC __rglgen_glMinmax;\nRGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;\nRGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;\nRGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;\nRGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;\nRGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;\nRGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;\nRGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;\nRGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;\nRGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;\nRGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;\nRGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;\nRGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;\nRGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;\nRGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;\nRGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;\nRGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;\nRGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;\nRGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;\nRGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;\nRGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;\nRGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;\nRGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;\nRGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;\nRGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;\nRGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;\nRGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;\nRGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;\nRGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;\nRGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;\nRGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;\nRGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;\nRGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;\nRGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;\nRGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;\nRGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;\nRGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;\nRGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;\nRGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;\nRGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;\nRGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;\nRGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;\nRGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;\nRGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;\nRGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;\nRGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;\nRGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;\nRGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;\nRGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;\nRGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;\nRGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;\nRGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;\nRGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;\nRGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;\nRGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;\nRGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;\nRGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;\nRGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;\nRGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;\nRGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;\nRGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;\nRGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;\nRGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;\nRGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;\nRGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;\nRGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;\nRGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;\nRGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;\nRGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;\nRGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;\nRGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;\nRGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;\nRGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;\nRGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;\nRGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;\nRGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;\nRGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;\nRGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;\nRGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;\nRGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;\nRGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;\nRGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;\nRGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;\nRGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;\nRGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;\nRGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;\nRGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;\nRGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;\nRGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;\nRGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;\nRGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;\nRGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;\nRGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;\nRGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;\nRGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;\nRGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;\nRGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;\nRGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;\nRGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;\nRGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;\nRGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;\nRGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;\nRGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;\nRGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;\nRGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;\nRGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;\nRGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;\nRGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;\nRGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;\nRGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;\nRGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;\nRGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;\nRGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;\nRGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;\nRGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;\nRGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;\nRGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;\nRGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;\nRGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;\nRGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;\nRGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;\nRGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;\nRGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;\nRGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;\nRGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;\nRGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;\nRGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;\nRGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;\nRGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;\nRGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;\nRGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;\nRGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;\nRGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;\nRGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;\nRGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;\nRGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;\nRGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;\nRGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;\nRGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;\nRGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;\nRGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;\nRGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;\nRGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;\nRGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;\nRGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;\nRGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;\nRGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;\nRGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;\nRGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;\nRGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;\nRGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;\nRGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;\nRGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;\nRGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;\nRGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;\nRGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;\nRGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;\nRGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;\nRGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;\nRGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;\nRGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;\nRGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;\nRGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;\nRGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;\nRGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;\nRGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;\nRGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;\nRGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;\nRGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;\nRGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;\nRGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;\nRGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;\nRGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;\nRGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;\nRGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;\nRGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;\nRGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;\nRGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;\nRGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;\nRGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;\nRGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;\nRGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;\nRGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;\nRGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;\nRGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;\nRGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;\nRGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;\nRGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;\nRGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;\nRGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;\nRGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;\nRGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;\nRGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;\nRGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;\nRGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;\nRGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;\nRGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;\nRGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;\nRGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;\nRGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;\nRGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;\nRGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;\nRGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;\nRGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;\nRGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;\nRGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;\nRGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;\nRGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;\nRGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;\nRGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;\nRGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;\nRGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;\nRGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;\nRGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;\nRGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;\nRGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;\nRGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;\nRGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;\nRGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;\nRGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;\nRGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;\nRGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;\nRGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;\nRGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;\nRGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;\nRGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;\nRGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;\nRGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;\nRGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;\nRGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;\nRGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;\nRGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;\nRGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;\nRGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;\nRGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;\nRGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;\nRGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;\nRGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;\nRGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;\nRGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;\nRGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;\nRGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;\nRGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;\nRGLSYMGLFOGXOESPROC __rglgen_glFogxOES;\nRGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;\nRGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;\nRGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;\nRGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;\nRGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;\nRGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;\nRGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;\nRGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;\nRGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;\nRGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;\nRGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;\nRGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;\nRGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;\nRGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;\nRGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;\nRGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;\nRGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;\nRGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;\nRGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;\nRGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;\nRGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;\nRGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;\nRGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;\nRGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;\nRGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;\nRGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;\nRGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;\nRGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;\nRGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;\nRGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;\nRGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;\nRGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;\nRGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;\nRGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;\nRGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;\nRGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;\nRGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;\nRGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;\nRGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;\nRGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;\nRGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;\nRGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;\nRGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;\nRGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;\nRGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;\nRGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;\nRGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;\nRGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;\nRGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;\nRGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;\nRGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;\nRGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;\nRGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;\nRGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;\nRGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;\nRGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;\nRGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;\nRGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;\nRGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;\nRGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;\nRGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;\nRGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;\nRGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;\nRGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;\nRGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;\nRGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;\nRGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;\nRGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;\nRGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;\nRGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;\nRGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;\nRGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;\nRGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;\nRGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;\nRGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;\nRGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;\nRGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;\nRGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;\nRGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;\nRGLSYMGLRECTXOESPROC __rglgen_glRectxOES;\nRGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;\nRGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;\nRGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;\nRGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;\nRGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;\nRGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;\nRGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;\nRGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;\nRGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;\nRGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;\nRGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;\nRGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;\nRGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;\nRGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;\nRGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;\nRGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;\nRGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;\nRGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;\nRGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;\nRGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;\nRGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;\nRGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;\nRGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;\nRGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;\nRGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;\nRGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;\nRGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;\nRGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;\nRGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;\nRGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;\n"
  },
  {
    "path": "glsym/rglgen.c",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (glsym).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <string.h>\n\n#include <glsym/rglgen.h>\n#include <glsym/glsym.h>\n\nvoid rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,\n      const struct rglgen_sym_map *map)\n{\n   for (; map->sym; map++)\n   {\n      rglgen_func_t func = proc(map->sym);\n      memcpy(map->ptr, &func, sizeof(func));\n   }\n}\n\nvoid rglgen_resolve_symbols(rglgen_proc_address_t proc)\n{\n   if (!proc)\n      return;\n\n   rglgen_resolve_symbols_custom(proc, rglgen_symbol_map);\n}\n"
  },
  {
    "path": "glsym/rglgen.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\n   License statement applies to this file (glgen.py) only.\n\n   Permission is hereby granted, free of charge,\n   to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n   to deal in the Software without restriction, including without limitation the rights to\n   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\n\nimport sys\nimport os\nimport re\n\nbanned_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' ]\n\ndef noext(sym):\n   for ext in banned_ext:\n      if sym.endswith(ext):\n         return False\n   return True\n\ndef fix_multiline_functions(lines):\n   fixed_lines = []\n   temp_lines = []\n   for line in lines:\n      if line.count('(') > line.count(')'):\n         temp_lines.append(line)\n      else:\n         if len(temp_lines) > 0:\n            if line.count(')') > line.count('('):\n               temp_lines.append(line)\n               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\\n','').replace('\\t',''))\n               fixed_lines.append(fixed_line)\n               temp_lines = []\n            else:\n               temp_lines.append(line)\n         else:\n            fixed_lines.append(line)\n   return fixed_lines\n\ndef find_gl_symbols(lines):\n   typedefs = []\n   syms = []\n   for line in lines:\n      m = re.search(r'^typedef.+PFN(\\S+)PROC.+$', line)\n      g = re.search(r'^.+(gl\\S+)\\W*\\(.+\\).*$', line)\n      if m and noext(m.group(1)):\n         typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))\n      if g and noext(g.group(1)):\n         syms.append(g.group(1))\n   return (typedefs, syms)\n\ndef generate_defines(gl_syms):\n   res = []\n   for line in gl_syms:\n      res.append('#define {} __rglgen_{}'.format(line, line))\n   return res\n\ndef generate_declarations(gl_syms):\n   return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]\n\ndef generate_macros(gl_syms):\n   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]\n\ndef dump(f, lines):\n   f.write('\\n'.join(lines))\n   f.write('\\n\\n')\n\nif __name__ == '__main__':\n\n   if len(sys.argv) > 4:\n      for banned in sys.argv[4:]:\n         banned_ext.append(banned)\n\n   with open(sys.argv[1], 'r') as f:\n      lines = fix_multiline_functions(f.readlines())\n      typedefs, syms = find_gl_symbols(lines)\n\n      overrides = generate_defines(syms)\n      declarations = generate_declarations(syms)\n      externs = ['extern ' + x for x in declarations]\n\n      macros = generate_macros(syms)\n\n   with open(sys.argv[2], 'w') as f:\n      f.write('#ifndef RGLGEN_DECL_H__\\n')\n      f.write('#define RGLGEN_DECL_H__\\n')\n\n      f.write('#ifdef __cplusplus\\n')\n      f.write('extern \"C\" {\\n')\n      f.write('#endif\\n')\n\n      f.write('#ifdef GL_APIENTRY\\n')\n      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('#else\\n')\n      f.write('#ifndef APIENTRY\\n')\n      f.write('#define APIENTRY\\n')\n      f.write('#endif\\n')\n      f.write('#ifndef APIENTRYP\\n')\n      f.write('#define APIENTRYP APIENTRY *\\n')\n      f.write('#endif\\n')\n      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('#endif\\n')\n\n      f.write('#ifndef GL_OES_EGL_image\\n')\n      f.write('typedef void *GLeglImageOES;\\n')\n      f.write('#endif\\n')\n\n      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\\n')\n      f.write('typedef GLint GLfixed;\\n')\n      f.write('#endif\\n')\n\n      dump(f, typedefs)\n      dump(f, overrides)\n      dump(f, externs)\n\n      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\\n')\n      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\\n')\n\n      f.write('#ifdef __cplusplus\\n')\n      f.write('}\\n')\n      f.write('#endif\\n')\n\n      f.write('#endif\\n')\n\n   with open(sys.argv[3], 'w') as f:\n      f.write('#include \"glsym/glsym.h\"\\n')\n      f.write('#include <stddef.h>\\n')\n      f.write('#define SYM(x) { \"gl\" #x, &(gl##x) }\\n')\n      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\\n')\n      dump(f, macros)\n      f.write('    { NULL, NULL },\\n')\n      f.write('};\\n')\n      dump(f, declarations)\n"
  },
  {
    "path": "glsym/xglgen.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"\n   License statement applies to this file (xglgen.py) only.\n\n   Permission is hereby granted, free of charge,\n   to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n   to deal in the Software without restriction, including without limitation the rights to\n   use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n   and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\"\"\"\n\nimport sys\nimport os\nimport re\n\nbanned_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' ]\n\ndef noext(sym):\n   for ext in banned_ext:\n      if sym.endswith(ext):\n         return False\n   return True\n\ndef fix_multiline_functions(lines):\n   fixed_lines = []\n   temp_lines = []\n   for line in lines:\n      if line.count('(') > line.count(')'):\n         temp_lines.append(line)\n      else:\n         if len(temp_lines) > 0:\n            if line.count(')') > line.count('('):\n               temp_lines.append(line)\n               fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\\n','').replace('\\t',''))\n               fixed_lines.append(fixed_line)\n               temp_lines = []\n            else:\n               temp_lines.append(line)\n         else:\n            fixed_lines.append(line)\n   return fixed_lines\n\ndef find_gl_symbols(lines):\n   typedefs = []\n   syms = []\n   for line in lines:\n      # Note this doesn't work automated; this script is designed as a helper\n      m = re.search(r'^typedef.+PFN(\\S+)PROC.+$', line)\n      g = re.search(r'^GLAPI\\s(.+)\\s(.+)\\s(gl\\S+)\\W*\\((.+)\\).*', line)\n      if g and noext(g.group(3)):\n         typedefs.append('typedef ' + g.group(1) + ' (APIENTRYP RGLSYM' + g.group(3).upper() + 'PROC) (' + g.group(4) + ');')\n         syms.append(g.group(3))\n\n   return (typedefs, syms)\n\ndef generate_defines(gl_syms):\n   res = []\n   for line in gl_syms:\n      res.append('#define {} __rglgen_{}'.format(line, line))\n   return res\n\ndef generate_declarations(gl_syms):\n   return ['RGLSYM' + x.upper() + 'PROC ' + x + ';' for x in gl_syms]\n\ndef generate_macros(gl_syms):\n   return ['    SYM(' + x.replace('gl', '') + '),' for x in gl_syms]\n\ndef dump(f, lines):\n   f.write('\\n'.join(lines))\n   f.write('\\n\\n')\n\nif __name__ == '__main__':\n\n   if len(sys.argv) > 4:\n      for banned in sys.argv[4:]:\n         banned_ext.append(banned)\n\n   with open(sys.argv[1], 'r') as f:\n      lines = fix_multiline_functions(f.readlines())\n      typedefs, syms = find_gl_symbols(lines)\n\n      overrides = generate_defines(syms)\n      declarations = generate_declarations(syms)\n      externs = ['extern ' + x for x in declarations]\n\n      macros = generate_macros(syms)\n\n   with open(sys.argv[2], 'w') as f:\n      f.write('#ifndef RGLGEN_DECL_H__\\n')\n      f.write('#define RGLGEN_DECL_H__\\n')\n\n      f.write('#ifdef __cplusplus\\n')\n      f.write('extern \"C\" {\\n')\n      f.write('#endif\\n')\n\n      f.write('#ifdef GL_APIENTRY\\n')\n      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('#else\\n')\n      f.write('#ifndef APIENTRY\\n')\n      f.write('#define APIENTRY\\n')\n      f.write('#endif\\n')\n      f.write('#ifndef APIENTRYP\\n')\n      f.write('#define APIENTRYP APIENTRY *\\n')\n      f.write('#endif\\n')\n      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\\n')\n      f.write('#endif\\n')\n\n      f.write('#ifndef GL_OES_EGL_image\\n')\n      f.write('typedef void *GLeglImageOES;\\n')\n      f.write('#endif\\n')\n\n      f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\\n')\n      f.write('typedef GLint GLfixed;\\n')\n      f.write('#endif\\n')\n\n      f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\\n')\n      f.write('typedef long long int GLint64;\\n')\n      f.write('typedef unsigned long long int GLuint64;\\n')\n      f.write('typedef unsigned long long int GLuint64EXT;\\n')\n      f.write('typedef struct __GLsync *GLsync;\\n')\n      f.write('#endif\\n')\n\n      dump(f, typedefs)\n      dump(f, overrides)\n      dump(f, externs)\n\n      f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\\n')\n      f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\\n')\n\n      f.write('#ifdef __cplusplus\\n')\n      f.write('}\\n')\n      f.write('#endif\\n')\n\n      f.write('#endif\\n')\n\n   with open(sys.argv[3], 'w') as f:\n      f.write('#include \"glsym/glsym.h\"\\n')\n      f.write('#include <stddef.h>\\n')\n      f.write('#define SYM(x) { \"gl\" #x, &(gl##x) }\\n')\n      f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\\n')\n      dump(f, macros)\n      f.write('    { NULL, NULL },\\n')\n      f.write('};\\n')\n      dump(f, declarations)\n"
  },
  {
    "path": "hash/lrc_hash.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (lrc_hash.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n#include <stdio.h>\n\n#ifdef _WIN32\n#include <io.h>\n#else\n#include <unistd.h>\n#endif\n\n#if defined(__SSE2__) || (defined(_MSC_VER) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))\n#ifdef _MSC_VER\n#include <intrin.h>\n#else\n#include <emmintrin.h>\n#endif\n#endif\n\n#include <lrc_hash.h>\n#include <retro_miscellaneous.h>\n#include <retro_endianness.h>\n#include <streams/file_stream.h>\n\n#define LSL32(x, n) ((uint32_t)(x) << (n))\n#define LSR32(x, n) ((uint32_t)(x) >> (n))\n#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))\n\n/* First 32 bits of the fractional parts of the square roots of the first 8 primes 2..19 */\nstatic const uint32_t T_H[8] = {\n   0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,\n};\n\n/* First 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311 */\nstatic const uint32_t T_K[64] = {\n   0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n   0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n   0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n   0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n   0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n   0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n   0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n   0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n};\n\n/* SHA256 implementation from bSNES. Written by valditx. */\n\nstruct sha256_ctx\n{\n   union\n   {\n      uint8_t u8[64];\n      uint32_t u32[16];\n   } in;\n   unsigned inlen;\n\n   uint32_t w[64];\n   uint32_t h[8];\n   uint64_t len;\n};\n\nstatic void sha256_init(struct sha256_ctx *p)\n{\n   memset(p, 0, sizeof(struct sha256_ctx));\n   memcpy(p->h, T_H, sizeof(T_H));\n}\n\nstatic void sha256_block(struct sha256_ctx *p)\n{\n   unsigned i;\n   uint32_t s0, s1;\n   uint32_t a, b, c, d, e, f, g, h;\n\n   for (i = 0; i < 16; i++)\n      p->w[i] = load32be(p->in.u32 + i);\n\n   for (i = 16; i < 64; i++)\n   {\n      s0 = ROR32(p->w[i - 15],  7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15],  3);\n      s1 = ROR32(p->w[i -  2], 17) ^ ROR32(p->w[i -  2], 19) ^ LSR32(p->w[i -  2], 10);\n      p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;\n   }\n\n   a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];\n   e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];\n\n   for (i = 0; i < 64; i++)\n   {\n      uint32_t t1, t2, maj, ch;\n\n      s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);\n      maj = (a & b) ^ (a & c) ^ (b & c);\n      t2  = s0 + maj;\n      s1  = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);\n      ch  = (e & f) ^ (~e & g);\n      t1  = h + s1 + ch + T_K[i] + p->w[i];\n\n      h   = g;\n      g   = f;\n      f   = e;\n      e   = d + t1;\n      d   = c;\n      c   = b;\n      b   = a;\n      a   = t1 + t2;\n   }\n\n   p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;\n   p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;\n\n   /* Next block */\n   p->inlen = 0;\n}\n\nstatic void sha256_chunk(struct sha256_ctx *p,\n      const uint8_t *s, size_t len)\n{\n   p->len += len;\n\n   while (len)\n   {\n      size_t l   = 64 - p->inlen;\n\n      if (len < l)\n         l       = len;\n\n      memcpy(p->in.u8 + p->inlen, s, l);\n\n      s         += l;\n      p->inlen  += l;\n      len       -= l;\n\n      if (p->inlen == 64)\n         sha256_block(p);\n   }\n}\n\nstatic void sha256_final(struct sha256_ctx *p)\n{\n   uint64_t len;\n   p->in.u8[p->inlen++] = 0x80;\n\n   if (p->inlen > 56)\n   {\n      memset(p->in.u8 + p->inlen, 0, 64 - p->inlen);\n      sha256_block(p);\n   }\n\n   memset(p->in.u8 + p->inlen, 0, 56 - p->inlen);\n\n   len = p->len << 3;\n   store32be(p->in.u32 + 14, (uint32_t)(len >> 32));\n   store32be(p->in.u32 + 15, (uint32_t)len);\n   sha256_block(p);\n}\n\nstatic void sha256_subhash(struct sha256_ctx *p, uint32_t *t)\n{\n   unsigned i;\n   for (i = 0; i < 8; i++)\n      store32be(t++, p->h[i]);\n}\n\n/**\n * sha256_hash:\n * @s                 : Output.\n * @in                : Input.\n * @size              : Size of @s.\n *\n * Hashes SHA256 and outputs a human readable string.\n **/\nvoid sha256_hash(char *s, const uint8_t *in, size_t len)\n{\n   unsigned i;\n   struct sha256_ctx sha;\n\n   union\n   {\n      uint32_t u32[8];\n      uint8_t u8[32];\n   } shahash;\n\n   sha256_init(&sha);\n   sha256_chunk(&sha, in, len);\n   sha256_final(&sha);\n   sha256_subhash(&sha, shahash.u32);\n\n   for (i = 0; i < 32; i++)\n      snprintf(s + 2 * i, 3, \"%02x\", (unsigned)shahash.u8[i]);\n}\n\n#ifndef HAVE_ZLIB\n/* Zlib CRC32. */\nstatic const uint32_t crc32_hash_table[256] = {\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\n    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\n    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\n    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\n    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\n    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\n    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\n    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\n    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\n    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\n    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\n    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\n    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\n    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\n    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\n    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\n    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\n    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\n    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\n    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\n    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\n    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n};\n\nuint32_t crc32_adjust(uint32_t checksum, uint8_t input)\n{\n   return ((checksum >> 8) & 0x00ffffff) ^ crc32_hash_table[(checksum ^ input) & 0xff];\n}\n\nuint32_t crc32_calculate(const uint8_t *data, size_t len)\n{\n   size_t i;\n   uint32_t checksum = ~0;\n   for (i = 0; i < len; i++)\n      checksum = crc32_adjust(checksum, data[i]);\n   return ~checksum;\n}\n#endif\n\n/* SHA-1 implementation. */\n\n/*\n *  sha1.c\n *\n *  Copyright (C) 1998, 2009\n *  Paul E. Jones <paulej@packetizer.com>\n *  All Rights Reserved\n *\n *****************************************************************************\n *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $\n *****************************************************************************\n *\n *  Description:\n *      This file implements the Secure Hashing Standard as defined\n *      in FIPS PUB 180-1 published April 17, 1995.\n *\n *      The Secure Hashing Standard, which uses the Secure Hashing\n *      Algorithm (SHA), produces a 160-bit message digest for a\n *      given data stream.  In theory, it is highly improbable that\n *      two messages will produce the same message digest.  Therefore,\n *      this algorithm can serve as a means of providing a \"fingerprint\"\n *      for a message.\n *\n *  Portability Issues:\n *      SHA-1 is defined in terms of 32-bit \"words\".  This code was\n *      written with the expectation that the processor has at least\n *      a 32-bit machine word size.  If the machine word size is larger,\n *      the code should still function properly.  One caveat to that\n *      is that the input functions taking characters and character\n *      arrays assume that only 8 bits of information are stored in each\n *      character.\n *\n *  Caveats:\n *      SHA-1 is designed to work with messages less than 2^64 bits\n *      long. Although SHA-1 allows a message digest to be generated for\n *      messages of any number of bits less than 2^64, this\n *      implementation only works with messages with a length that is a\n *      multiple of the size of an 8-bit character.\n *\n */\n\n/* Define the circular shift macro */\n#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))\n\nstruct sha1_context\n{\n   unsigned Message_Digest[5]; /* Message Digest (output)          */\n\n   unsigned Length_Low;        /* Message length in bits           */\n   unsigned Length_High;       /* Message length in bits           */\n\n   unsigned char Message_Block[64]; /* 512-bit message blocks      */\n   int Message_Block_Index;    /* Index into message block array   */\n\n   int Computed;               /* Is the digest computed?          */\n   int Corrupted;              /* Is the message digest corruped?  */\n};\n\n\nstatic void SHA1Reset(struct sha1_context *context)\n{\n   if (!context)\n      return;\n\n   context->Length_Low             = 0;\n   context->Length_High            = 0;\n   context->Message_Block_Index    = 0;\n\n   context->Message_Digest[0]      = 0x67452301;\n   context->Message_Digest[1]      = 0xEFCDAB89;\n   context->Message_Digest[2]      = 0x98BADCFE;\n   context->Message_Digest[3]      = 0x10325476;\n   context->Message_Digest[4]      = 0xC3D2E1F0;\n\n   context->Computed   = 0;\n   context->Corrupted  = 0;\n}\n\nstatic void SHA1ProcessMessageBlock(struct sha1_context *context)\n{\n   const unsigned K[] =            /* Constants defined in SHA-1   */\n   {\n      0x5A827999,\n      0x6ED9EBA1,\n      0x8F1BBCDC,\n      0xCA62C1D6\n   };\n   int         t;                  /* Loop counter                 */\n   unsigned    temp;               /* Temporary word value         */\n   unsigned    W[80];              /* Word sequence                */\n   unsigned    A, B, C, D, E;      /* Word buffers                 */\n\n   /* Initialize the first 16 words in the array W */\n   for (t = 0; t < 16; t++)\n   {\n      W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;\n      W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;\n      W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;\n      W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);\n   }\n\n   for (t = 16; t < 80; t++)\n      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);\n\n   A = context->Message_Digest[0];\n   B = context->Message_Digest[1];\n   C = context->Message_Digest[2];\n   D = context->Message_Digest[3];\n   E = context->Message_Digest[4];\n\n   for (t = 0; t < 20; t++)\n   {\n      temp  =  SHA1CircularShift(5,A) +\n         ((B & C) | ((~B) & D)) + E + W[t] + K[0];\n      temp &= 0xFFFFFFFF;\n      E     = D;\n      D     = C;\n      C     = SHA1CircularShift(30,B);\n      B     = A;\n      A     = temp;\n   }\n\n   for (t = 20; t < 40; t++)\n   {\n      temp  = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];\n      temp &= 0xFFFFFFFF;\n      E     = D;\n      D     = C;\n      C     = SHA1CircularShift(30,B);\n      B     = A;\n      A     = temp;\n   }\n\n   for (t = 40; t < 60; t++)\n   {\n      temp  = SHA1CircularShift(5,A) +\n         ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];\n      temp &= 0xFFFFFFFF;\n      E     = D;\n      D     = C;\n      C     = SHA1CircularShift(30,B);\n      B     = A;\n      A     = temp;\n   }\n\n   for (t = 60; t < 80; t++)\n   {\n      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];\n      temp &= 0xFFFFFFFF;\n      E = D;\n      D = C;\n      C = SHA1CircularShift(30,B);\n      B = A;\n      A = temp;\n   }\n\n   context->Message_Digest[0] =\n      (context->Message_Digest[0] + A) & 0xFFFFFFFF;\n   context->Message_Digest[1] =\n      (context->Message_Digest[1] + B) & 0xFFFFFFFF;\n   context->Message_Digest[2] =\n      (context->Message_Digest[2] + C) & 0xFFFFFFFF;\n   context->Message_Digest[3] =\n      (context->Message_Digest[3] + D) & 0xFFFFFFFF;\n   context->Message_Digest[4] =\n      (context->Message_Digest[4] + E) & 0xFFFFFFFF;\n\n   context->Message_Block_Index = 0;\n}\n\nstatic void SHA1PadMessage(struct sha1_context *context)\n{\n   if (!context)\n      return;\n\n   /*\n    *  Check to see if the current message block is too small to hold\n    *  the initial padding bits and length.  If so, we will pad the\n    *  block, process it, and then continue padding into a second\n    *  block.\n    */\n   context->Message_Block[context->Message_Block_Index++] = 0x80;\n\n   if (context->Message_Block_Index > 55)\n   {\n      while (context->Message_Block_Index < 64)\n         context->Message_Block[context->Message_Block_Index++] = 0;\n\n      SHA1ProcessMessageBlock(context);\n   }\n\n   while (context->Message_Block_Index < 56)\n      context->Message_Block[context->Message_Block_Index++] = 0;\n\n   /*  Store the message length as the last 8 octets */\n   context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;\n   context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;\n   context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;\n   context->Message_Block[59] = (context->Length_High) & 0xFF;\n   context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;\n   context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;\n   context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;\n   context->Message_Block[63] = (context->Length_Low) & 0xFF;\n\n   SHA1ProcessMessageBlock(context);\n}\n\nstatic int SHA1Result(struct sha1_context *context, unsigned char digest[20])\n{\n   unsigned i;\n\n   if (context->Corrupted)\n      return 0;\n\n   if (!context->Computed)\n   {\n      SHA1PadMessage(context);\n      context->Computed = 1;\n   }\n\n   if (digest)\n   {\n      /* Convert Message_Digest to byte array */\n      for (i = 0; i < 20; i++)\n      {\n         digest[i] = (unsigned char)\n            ((context->Message_Digest[i>>2] >> 8 * (3 - (i & 0x03))) & 0xFF);\n      }\n   }\n\n   return 1;\n}\n\nstatic void SHA1Input(struct sha1_context *context,\n      const unsigned char *message_array,\n      unsigned len)\n{\n   if (!len)\n      return;\n\n   if (context->Computed || context->Corrupted)\n   {\n      context->Corrupted = 1;\n      return;\n   }\n\n   while (len-- && !context->Corrupted)\n   {\n      context->Message_Block[context->Message_Block_Index++] =\n         (*message_array & 0xFF);\n\n      context->Length_Low += 8;\n      /* Force it to 32 bits */\n      context->Length_Low &= 0xFFFFFFFF;\n      if (context->Length_Low == 0)\n      {\n         context->Length_High++;\n         /* Force it to 32 bits */\n         context->Length_High &= 0xFFFFFFFF;\n         if (context->Length_High == 0)\n            context->Corrupted = 1; /* Message is too long */\n      }\n\n      if (context->Message_Block_Index == 64)\n         SHA1ProcessMessageBlock(context);\n\n      message_array++;\n   }\n}\n\nvoid SHA1Digest(const uint8_t* data, size_t len, uint8_t digest[20])\n{\n#ifdef __APPLE__\n   CC_SHA1(data, (CC_LONG)len, digest);\n#else\n   struct sha1_context sha;\n\n   SHA1Reset(&sha);\n   SHA1Input(&sha, data, len);\n\n   if (!SHA1Result(&sha, digest))\n      memset(digest, 0, 20);\n#endif\n}\n\nint sha1_calculate(const char *path, char *result)\n{\n   struct sha1_context sha;\n   unsigned char buff[4096];\n   int rv    = 1;\n   RFILE *fd = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n   if (!fd)\n      goto error;\n\n   buff[0] = '\\0';\n\n   SHA1Reset(&sha);\n\n   do\n   {\n      rv = (int)filestream_read(fd, buff, 4096);\n      if (rv < 0)\n         goto error;\n\n      SHA1Input(&sha, buff, rv);\n   } while (rv);\n\n   if (!SHA1Result(&sha, NULL))\n      goto error;\n\n   sprintf(result, \"%08X%08X%08X%08X%08X\",\n         sha.Message_Digest[0],\n         sha.Message_Digest[1],\n         sha.Message_Digest[2],\n         sha.Message_Digest[3], sha.Message_Digest[4]);\n\n   filestream_close(fd);\n   return 0;\n\nerror:\n   if (fd)\n      filestream_close(fd);\n   return -1;\n}\n\n#if defined(__SSE2__) || (defined(_MSC_VER) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))\n\n#if _MSC_VER\n#define DJB2_ALIGN(x) __declspec(align(x))\n#else\n#define DJB2_ALIGN(x) __attribute__((aligned(x)))\n#endif\n\nstatic const DJB2_ALIGN(16) uint32_t DJB2_W8[8] = {\n   0xEC41D4E1, /* 33^7 */\n   0x4CFA3CC1, /* 33^6 */\n   0x025528A1, /* 33^5 */\n   0x00121881, /* 33^4 */\n   0x00008C61, /* 33^3 */\n   0x00000441, /* 33^2 */\n   0x00000021, /* 33^1 */\n   0x00000001, /* 33^0 */\n};\n#endif\n\nuint32_t djb2_calculate(const char *str)\n{\n   uint32_t h = 5381;\n   const unsigned char *p = (const unsigned char*)str;\n#if defined(__SSE2__) || (defined(_MSC_VER) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)))\n   __m128i w_lo = _mm_load_si128((const __m128i *)&DJB2_W8[0]);\n   __m128i w_hi = _mm_load_si128((const __m128i *)&DJB2_W8[4]);\n   size_t len   = strlen((const char*)p);\n   const unsigned char *end8 = p + (len & ~(size_t)7);\n\n   while (p < end8)\n   {\n      uint32_t sum = 0;\n      __m128i raw  = _mm_loadl_epi64((const __m128i *)p);\n      __m128i zero = _mm_setzero_si128();\n      __m128i b16  = _mm_unpacklo_epi8(raw, zero);\n      __m128i b_lo = _mm_unpacklo_epi16(b16, zero);\n      __m128i b_hi = _mm_unpackhi_epi16(b16, zero);\n\n     /* _mm_mul_epu32 multiplies lanes 0,2 → 64-bit results.\n      * Shuffle to access lanes 1,3. */\n      __m128i p02_lo = _mm_mul_epu32(b_lo, w_lo);\n      __m128i p13_lo = _mm_mul_epu32(_mm_shuffle_epi32(b_lo, 0xF5),\n                                     _mm_shuffle_epi32(w_lo, 0xF5));\n      __m128i p02_hi = _mm_mul_epu32(b_hi, w_hi);\n      __m128i p13_hi = _mm_mul_epu32(_mm_shuffle_epi32(b_hi, 0xF5),\n                                     _mm_shuffle_epi32(w_hi, 0xF5));\n      sum += (uint32_t)_mm_cvtsi128_si32(p02_lo);\n      sum += (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(p02_lo, 8));\n      sum += (uint32_t)_mm_cvtsi128_si32(p13_lo);\n      sum += (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(p13_lo, 8));\n      sum += (uint32_t)_mm_cvtsi128_si32(p02_hi);\n      sum += (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(p02_hi, 8));\n      sum += (uint32_t)_mm_cvtsi128_si32(p13_hi);\n      sum += (uint32_t)_mm_cvtsi128_si32(_mm_srli_si128(p13_hi, 8));\n\n      h    = h * UINT32_C(0x747C7101) + sum;\n      p   += 8;\n    }\n#endif\n    while (*p)\n        h = (h << 5) + h + *p++;\n    return h;\n}\n"
  },
  {
    "path": "include/array/rbuf.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rbuf.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_ARRAY_RBUF_H__\n#define __LIBRETRO_SDK_ARRAY_RBUF_H__\n\n/*\n * This file implements stretchy buffers as invented (?) by Sean Barrett.\n * Based on the implementation from the public domain Bitwise project\n * by Per Vognsen - https://github.com/pervognsen/bitwise\n *\n * It's a super simple type safe dynamic array for C with no need\n * to predeclare any type or anything.\n * The first time an element is added, memory for 16 elements are allocated.\n * Then every time length is about to exceed capacity, capacity is doubled.\n *\n * Be careful not to supply modifying statements to the macro arguments.\n * Something like RBUF_REMOVE(buf, i--); would have unintended results.\n *\n * Sample usage:\n *\n * mytype_t* buf = NULL;\n * RBUF_PUSH(buf, some_element);\n * RBUF_PUSH(buf, other_element);\n * -- now RBUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element\n *\n * -- Free allocated memory:\n * RBUF_FREE(buf);\n * -- now buf == NULL, RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 0\n *\n * -- Explicitly increase allocated memory and set capacity:\n * RBUF_FIT(buf, 100);\n * -- now RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 100\n *\n * -- Resize buffer (does not initialize or zero memory!)\n * RBUF_RESIZE(buf, 200);\n * -- now RBUF_LEN(buf) == 200, RBUF_CAP(buf) == 200\n *\n * -- To handle running out of memory:\n * bool ran_out_of_memory = !RBUF_TRYFIT(buf, 1000);\n * -- before RESIZE or PUSH. When out of memory, buf will stay unmodified.\n *\n * -- OOM behaviour of RBUF_PUSH / RBUF_RESIZE without explicit\n *    RBUF_TRYFIT:\n *    Both macros are safe against allocation failure.  If the\n *    underlying realloc / malloc fails, buf is left at its\n *    previous address (the old allocation remains valid and\n *    unfreed - realloc contract) and len is NOT advanced.  PUSH\n *    is a silent no-op on OOM; RESIZE leaves len unchanged.\n *    Callers that need to detect OOM explicitly should use\n *    RBUF_TRYFIT up-front as shown above.\n */\n\n#include <retro_math.h> /* for MAX */\n#include <stdlib.h> /* for malloc, realloc */\n\n#define RBUF__HDR(b) (((struct rbuf__hdr *)(b))-1)\n\n#define RBUF_LEN(b) ((b) ? RBUF__HDR(b)->len : 0)\n#define RBUF_CAP(b) ((b) ? RBUF__HDR(b)->cap : 0)\n#define RBUF_END(b) ((b) + RBUF_LEN(b))\n#define RBUF_SIZEOF(b) ((b) ? RBUF_LEN(b)*sizeof(*b) : 0)\n\n#define RBUF_FREE(b) ((b) ? (free(RBUF__HDR(b)), (b) = NULL) : 0)\n#define RBUF_FIT(b, n) ((size_t)(n) <= RBUF_CAP(b) ? 0 : (*(void**)(&(b)) = rbuf__grow((b), (n), sizeof(*(b)))))\n/* RBUF_PUSH: safe against OOM.\n *\n * Pre-patch this was:\n *   (RBUF_FIT((b), 1+LEN), (b)[HDR(b)->len++] = (val))\n * which on OOM would (a) NULL-deref when b was NULL and grow's\n * malloc failed, or (b) write past the end of the existing\n * allocation and corrupt the header's len past cap when\n * realloc failed on a non-NULL buf.\n *\n * The fix: re-check 'RBUF_CAP(b) >= 1 + RBUF_LEN(b)' after\n * RBUF_FIT returns.  If cap didn't grow (meaning grow failed),\n * the cap check is false and we skip the write + len bump\n * entirely.  The old buffer (if any) remains valid - realloc\n * contract guarantees the original allocation is intact on\n * failure. */\n#define RBUF_PUSH(b, val) \\\n   do { \\\n      RBUF_FIT((b), 1 + RBUF_LEN(b)); \\\n      if (RBUF_CAP(b) >= 1 + RBUF_LEN(b)) \\\n         (b)[RBUF__HDR(b)->len++] = (val); \\\n   } while (0)\n#define RBUF_POP(b) (b)[--RBUF__HDR(b)->len]\n/* RBUF_RESIZE: safe against OOM.\n *\n * Pre-patch: (RBUF_FIT((b), sz), ((b) ? HDR(b)->len = sz : 0))\n * would set len = sz even when grow failed and cap stayed below\n * sz, leaving len > cap.  Subsequent iteration of 0..LEN would\n * then read past the allocation.\n *\n * Fix: gate the len assignment on cap >= sz.  On OOM len stays\n * at its pre-RESIZE value; buf remains valid. */\n#define RBUF_RESIZE(b, sz) \\\n   (RBUF_FIT((b), (sz)), \\\n    ((b) && RBUF_CAP(b) >= (size_t)(sz) ? RBUF__HDR(b)->len = (sz) : 0))\n#define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)->len = 0 : 0)\n#define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) && RBUF_CAP(b) >= (size_t)(n)) || !(n)))\n#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)->len - (idx)) * sizeof(*(b)))\n\nstruct rbuf__hdr\n{\n   size_t len;\n   size_t cap;\n};\n\n#ifdef __GNUC__\n__attribute__((__unused__))\n#elif defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4505) /* Unreferenced local function has been removed */\n#endif\nstatic void *rbuf__grow(void *buf,\n      size_t new_len, size_t elem_size)\n{\n   struct rbuf__hdr *new_hdr;\n   size_t new_cap  = MAX(2 * RBUF_CAP(buf), MAX(new_len, 16));\n   size_t new_size = sizeof(struct rbuf__hdr) + new_cap*elem_size;\n   if (buf)\n   {\n      new_hdr      = (struct rbuf__hdr *)realloc(RBUF__HDR(buf), new_size);\n      if (!new_hdr)\n         return buf; /* out of memory, return unchanged */\n   }\n   else\n   {\n      new_hdr      = (struct rbuf__hdr *)malloc(new_size);\n      if (!new_hdr)\n         return NULL; /* out of memory */\n      new_hdr->len = 0;\n   }\n   new_hdr->cap    = new_cap;\n   return new_hdr + 1;\n}\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n#endif\n"
  },
  {
    "path": "include/array/rhmap.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rhmap.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_ARRAY_RHMAP_H__\n#define __LIBRETRO_SDK_ARRAY_RHMAP_H__\n\n/*\n * This file implements a hash map with 32-bit keys.\n * Based on the implementation from the public domain Bitwise project\n * by Per Vognsen - https://github.com/pervognsen/bitwise\n *\n * It's a super simple type safe hash map for C with no need\n * to predeclare any type or anything.\n * Will always allocate memory for twice the amount of max elements\n * so larger structs should be stored as pointers or indices to an array.\n * Can be used in C++ with POD types (without any constructor/destructor).\n *\n * Be careful not to supply modifying statements to the macro arguments.\n * Something like RHMAP_FIT(map, i++); would have unintended results.\n *\n * Sample usage:\n *\n * -- Set 2 elements with string keys and mytype_t values:\n * mytype_t* map = NULL;\n * RHMAP_SET_STR(map, \"foo\", foo_element);\n * RHMAP_SET_STR(map, \"bar\", bar_element);\n * -- now RHMAP_LEN(map) == 2, RHMAP_GET_STR(map, \"foo\") == foo_element\n *\n * -- Check if keys exist:\n * bool has_foo = RHMAP_HAS_STR(map, \"foo\");\n * bool has_baz = RHMAP_HAS_STR(map, \"baz\");\n * -- now has_foo == true, has_baz == false\n *\n * -- Removing a key:\n * bool removed = RHMAP_DEL_STR(map, \"bar\");\n * bool removed_again = RHMAP_DEL_STR(map, \"bar\");\n * -- now RHMAP_LEN(map) == 1, removed == true, removed_again == false\n *\n * -- Add/modify via pointer:\n * mytype_t* p_elem = RHMAP_PTR_STR(map, \"qux\");\n * p_elem->a = 123;\n * -- New keys initially have memory uninitialized\n * -- Pointers can get invalidated when a key is added/removed\n *\n * -- Looking up the index for a given key:\n * ptrdiff_t idx_foo = RHMAP_IDX_STR(map, \"foo\");\n * ptrdiff_t idx_invalid = RHMAP_IDX_STR(map, \"invalid\");\n * -- now idx_foo >= 0, idx_invalid == -1, map[idx_foo] == foo_element\n * -- Indices can change when a key is added/removed\n *\n * -- Clear all elements (keep memory allocated):\n * RHMAP_CLEAR(map);\n * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 16\n *\n * -- Reserve memory for at least N elements:\n * RHMAP_FIT(map, 30);\n * -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 64\n *\n * -- Add elements with custom hash keys:\n * RHMAP_SET(map, my_uint32_hash(key1), some_element);\n * RHMAP_SET(map, my_uint32_hash(key2), other_element);\n * -- now RHMAP_LEN(map) == 2, _GET/_HAS/_DEL/_PTR/_IDX also exist\n *\n * -- Iterate elements (random order, order can change on insert):\n * for (size_t i = 0, cap = RHMAP_CAP(map); i != cap, i++)\n *   if (RHMAP_KEY(map, i))\n * ------ here map[i] is the value of key RHMAP_KEY(map, i)\n *\n * -- Set a custom null value (is zeroed by default):\n * RHMAP_SETNULLVAL(map, map_null);\n * -- now RHMAP_GET_STR(map, \"invalid\") == map_null\n *\n * -- Free allocated memory:\n * RHMAP_FREE(map);\n * -- now map == NULL, RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 0\n *\n * -- To handle running out of memory:\n * bool ran_out_of_memory = !RHMAP_TRYFIT(map, 1000);\n * -- before setting an element (with SET, PTR or NULLVAL).\n * -- When out of memory, map will stay unmodified.\n *\n */\n\n#include <stdlib.h> /* for malloc, realloc */\n#include <string.h> /* for memcpy, memset */\n#include <stddef.h> /* for ptrdiff_t, size_t */\n#include <stdint.h> /* for uint32_t */\n\n#define RHMAP_LEN(b) ((b) ? RHMAP__HDR(b)->len : 0)\n#define RHMAP_MAX(b) ((b) ? RHMAP__HDR(b)->maxlen : 0)\n#define RHMAP_CAP(b) ((b) ? RHMAP__HDR(b)->maxlen + 1 : 0)\n#define RHMAP_KEY(b, idx) (RHMAP__HDR(b)->keys[idx])\n#define RHMAP_KEY_STR(b, idx) (RHMAP__HDR(b)->key_strs[idx])\n#define RHMAP_SETNULLVAL(b, val) (RHMAP__FIT1(b), b[-1] = (val))\n#define RHMAP_CLEAR(b) ((b) ? (memset(RHMAP__HDR(b)->keys, 0, RHMAP_CAP(b) * sizeof(uint32_t)), RHMAP__HDR(b)->len = 0) : 0)\n#define RHMAP_FREE(b) ((b) ? (rhmap__free(RHMAP__HDR(b)), (b) = NULL) : 0)\n#define RHMAP_FIT(b, n) ((!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))) ? 0 : RHMAP__GROW(b, n))\n#define RHMAP_TRYFIT(b, n) (RHMAP_FIT((b), (n)), (!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))))\n\n#define RHMAP_SET(b, key, val) RHMAP_SET_FULL(b, key, NULL, val)\n#define RHMAP_GET(b, key)      RHMAP_GET_FULL(b, key, NULL)\n#define RHMAP_HAS(b, key)      RHMAP_HAS_FULL(b, key, NULL)\n#define RHMAP_DEL(b, key)      RHMAP_DEL_FULL(b, key, NULL)\n#define RHMAP_PTR(b, key)      RHMAP_PTR_FULL(b, key, NULL)\n#define RHMAP_IDX(b, key)      RHMAP_IDX_FULL(b, key, NULL)\n\n#ifdef __GNUC__\n#define RHMAP__UNUSED __attribute__((__unused__))\n#else\n#define RHMAP__UNUSED\n#endif\n\n#if defined(_MSC_VER)\n#pragma warning(push)\n#pragma warning(disable:4505) /* Unreferenced local function has been removed */\n#endif\n\n#define RHMAP_SET_FULL(b, key, str, val) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)] = (val))\n#define RHMAP_GET_FULL(b, key, str) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0)])\n#define RHMAP_HAS_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) != -1 : 0)\n#define RHMAP_DEL_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, sizeof(*(b))) != -1 : 0)\n#define RHMAP_PTR_FULL(b, key, str) (RHMAP__FIT1(b), &b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)])\n#define RHMAP_IDX_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) : -1)\n\n#define RHMAP_SET_STR(b, string_key, val) RHMAP_SET_FULL(b, rhmap_hash_string(string_key), string_key, val)\n#define RHMAP_GET_STR(b, string_key)      RHMAP_GET_FULL(b, rhmap_hash_string(string_key), string_key)\n#define RHMAP_HAS_STR(b, string_key)      RHMAP_HAS_FULL(b, rhmap_hash_string(string_key), string_key)\n#define RHMAP_DEL_STR(b, string_key)      RHMAP_DEL_FULL(b, rhmap_hash_string(string_key), string_key)\n#define RHMAP_PTR_STR(b, string_key)      RHMAP_PTR_FULL(b, rhmap_hash_string(string_key), string_key)\n#define RHMAP_IDX_STR(b, string_key)      RHMAP_IDX_FULL(b, rhmap_hash_string(string_key), string_key)\n\nRHMAP__UNUSED static uint32_t rhmap_hash_string(const char* str)\n{\n   unsigned char c;\n   uint32_t hash = (uint32_t)0x811c9dc5;\n   while ((c = (unsigned char)*(str++)) != '\\0')\n      hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);\n   return (hash ? hash : 1);\n}\n\nstruct rhmap__hdr { size_t len, maxlen; uint32_t *keys; char** key_strs; };\n#define RHMAP__HDR(b) (((struct rhmap__hdr *)&(b)[-1])-1)\n#define RHMAP__GROW(b, n) (*(void**)(&(b)) = rhmap__grow((void*)(b), sizeof(*(b)), (size_t)(n)))\n#define RHMAP__FIT1(b) ((b) && RHMAP_LEN(b) * 2 <= RHMAP_MAX(b) ? 0 : RHMAP__GROW(b, 0))\n\nRHMAP__UNUSED static void* rhmap__grow(void* old_ptr, size_t elem_size, size_t reserve)\n{\n   struct rhmap__hdr *old_hdr = (old_ptr ? ((struct rhmap__hdr *)((char*)old_ptr-elem_size))-1 : NULL);\n   struct rhmap__hdr *new_hdr;\n   char *new_vals;\n   size_t new_max = (old_ptr ? old_hdr->maxlen * 2 + 1 : 15);\n   for (; new_max / 2 <= reserve; new_max = new_max * 2 + 1)\n      if (new_max == (size_t)-1)\n         return old_ptr; /* overflow */\n\n   new_hdr = (struct rhmap__hdr *)malloc(sizeof(struct rhmap__hdr) + (new_max + 2) * elem_size);\n   if (!new_hdr)\n      return old_ptr; /* out of memory */\n\n   new_hdr->maxlen = new_max;\n   new_hdr->keys = (uint32_t *)calloc(new_max + 1, sizeof(uint32_t));\n   if (!new_hdr->keys)\n   {\n      /* out of memory */\n      free(new_hdr);\n      return old_ptr;\n   }\n   new_hdr->key_strs = (char**)calloc(new_max + 1, sizeof(char*));\n   if (!new_hdr->key_strs)\n   {\n      /* out of memory */\n      free(new_hdr->keys);\n      free(new_hdr);\n      return old_ptr;\n   }\n\n   new_vals = ((char*)(new_hdr + 1)) + elem_size;\n   if (old_ptr)\n   {\n      size_t i;\n      char* old_vals = ((char*)(old_hdr + 1)) + elem_size;\n      for (i = 0; i <= old_hdr->maxlen; i++)\n      {\n         uint32_t key, j;\n         if (!old_hdr->keys[i])\n            continue;\n         for (key = old_hdr->keys[i], j = key;; j++)\n         {\n            if (!new_hdr->keys[j &= new_hdr->maxlen])\n            {\n               new_hdr->keys[j] = key;\n               new_hdr->key_strs[j] = old_hdr->key_strs[i];\n               memcpy(new_vals + j * elem_size, old_vals + i * elem_size, elem_size);\n               break;\n            }\n         }\n      }\n      memcpy(new_vals - elem_size, old_vals - elem_size, elem_size);\n      new_hdr->len = old_hdr->len;\n      free(old_hdr->keys);\n      free(old_hdr->key_strs);\n      free(old_hdr);\n   }\n   else\n   {\n      memset(new_vals - elem_size, 0, elem_size);\n      new_hdr->len = 0;\n   }\n   return new_vals;\n}\n\n/* This is just a custom version of strdup so we don't have an inherent\n * dependency on strdup for this file. It is functionally equivalent to\n * a system-provided strdup */\nstatic char *rhmap_strdup(const char *s)\n{\n    char *out;\n    int count = 0;\n    while (s[count])\n        ++count;\n    ++count;\n    out = (char*)malloc(sizeof(char) * count);\n    out[--count] = 0;\n    while (--count >= 0)\n        out[count] = s[count];\n    return out;\n}\n\nRHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)\n{\n   uint32_t i;\n\n   if (!key)\n      return (ptrdiff_t)-1;\n\n   for (i = key;; i++)\n   {\n      if (hdr->keys[i &= hdr->maxlen] == key && (!hdr->key_strs[i] || !str || !strcmp(hdr->key_strs[i], str)))\n      {\n         if (del)\n         {\n            hdr->len--;\n            hdr->keys[i] = 0;\n            free(hdr->key_strs[i]);\n            hdr->key_strs[i] = NULL;\n            while ((key = hdr->keys[i = (i + 1) & hdr->maxlen]) != 0)\n            {\n               if ((key = (uint32_t)rhmap__idx(hdr, key, hdr->key_strs[i], 1, 0)) == i) continue;\n               hdr->len--;\n               hdr->keys[i] = 0;\n               free(hdr->key_strs[i]);\n               hdr->key_strs[i] = NULL;\n               memcpy(((char*)(hdr + 1)) + (key + 1) * del,\n                     ((char*)(hdr + 1)) + (i + 1) * del, del);\n            }\n         }\n         return (ptrdiff_t)i;\n      }\n      if (!hdr->keys[i])\n      {\n         if (add)\n         {\n            hdr->len++;\n            hdr->keys[i] = key;\n            if (str)\n               hdr->key_strs[i] = rhmap_strdup(str);\n            return (ptrdiff_t)i;\n         }\n         return (ptrdiff_t)-1;\n      }\n   }\n}\n\nRHMAP__UNUSED static void rhmap__free(struct rhmap__hdr* hdr)\n{\n   size_t i;\n   for (i=0;i<hdr->maxlen+1;i++)\n   {\n      free(hdr->key_strs[i]);\n   }\n   free(hdr->key_strs);\n   free(hdr->keys);\n   free(hdr);\n}\n\n#if defined(_MSC_VER)\n#pragma warning(pop)\n#endif\n\n#endif\n"
  },
  {
    "path": "include/audio/audio_mix.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (audio_mix.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_AUDIO_MIX_H__\n#define __LIBRETRO_SDK_AUDIO_MIX_H__\n\n#include <retro_common_api.h>\n\n#include <stdint.h>\n#include <stddef.h>\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\n#include <formats/rwav.h>\n#include <audio/audio_resampler.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct\n{\n   double ratio;\n   void *buf;\n   int16_t *upsample_buf;\n   float *float_buf;\n   float *float_resample_buf;\n   int16_t *resample_buf;\n   const retro_resampler_t *resampler;\n   void *resampler_data;\n   rwav_t *rwav;\n   ssize_t len;\n   size_t resample_len;\n   int sample_rate;\n   bool resample;\n} audio_chunk_t;\n\n#if defined(__SSE2__)\n#define audio_mix_volume           audio_mix_volume_SSE2\n\nvoid audio_mix_volume_SSE2(float *out,\n      const float *in, float vol, size_t samples);\n#else\n#define audio_mix_volume           audio_mix_volume_C\n#endif\n\nvoid audio_mix_volume_C(float *dst, const float *src, float vol, size_t samples);\n\nvoid audio_mix_free_chunk(audio_chunk_t *chunk);\n\naudio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate,\n      const char *resampler_ident, enum resampler_quality quality);\n\nsize_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk);\n\n/**\n * audio_mix_get_chunk_sample:\n * @chunk              : audio chunk instance\n * @channel            : channel of the sample (0=left, 1=right)\n * @index              : index of the sample\n *\n * Get a sample from an audio chunk.\n *\n * Returns: A signed 16-bit audio sample, (if necessary) resampled into the desired output rate.\n **/\nint16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t sample);\n\nint16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk);\n\nint audio_mix_get_chunk_num_channels(audio_chunk_t *chunk);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/audio/audio_mixer.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (audio_mixer.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_AUDIO_MIXER__H\n#define __LIBRETRO_SDK_AUDIO_MIXER__H\n\n#include <stdint.h>\n#include <stddef.h>\n#include <stdlib.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <boolean.h>\n#include <retro_common_api.h>\n\n#include <audio/audio_resampler.h>\n\nRETRO_BEGIN_DECLS\n\nenum audio_mixer_type\n{\n   AUDIO_MIXER_TYPE_NONE = 0,\n   AUDIO_MIXER_TYPE_WAV,\n   AUDIO_MIXER_TYPE_OGG,\n   AUDIO_MIXER_TYPE_MOD,\n   AUDIO_MIXER_TYPE_FLAC,\n   AUDIO_MIXER_TYPE_MP3\n};\n\ntypedef struct audio_mixer_sound audio_mixer_sound_t;\ntypedef struct audio_mixer_voice audio_mixer_voice_t;\n\ntypedef void (*audio_mixer_stop_cb_t)(audio_mixer_sound_t* sound, unsigned reason);\n\n/* Reasons passed to the stop callback. */\n#define AUDIO_MIXER_SOUND_FINISHED 0\n#define AUDIO_MIXER_SOUND_STOPPED  1\n#define AUDIO_MIXER_SOUND_REPEATED 2\n\nvoid audio_mixer_init(unsigned rate);\n\nvoid audio_mixer_done(void);\n\naudio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size,\n      const char *resampler_ident, enum resampler_quality quality);\naudio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size);\naudio_mixer_sound_t* audio_mixer_load_mod(void *buffer, int32_t size);\naudio_mixer_sound_t* audio_mixer_load_flac(void *buffer, int32_t size);\naudio_mixer_sound_t* audio_mixer_load_mp3(void *buffer, int32_t size);\n\nvoid audio_mixer_destroy(audio_mixer_sound_t* sound);\n\naudio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound,\n      bool repeat, float volume,\n      const char *resampler_ident,\n      enum resampler_quality quality,\n      audio_mixer_stop_cb_t stop_cb);\n\nvoid audio_mixer_stop(audio_mixer_voice_t* voice);\n\nfloat audio_mixer_voice_get_volume(audio_mixer_voice_t *voice);\n\nvoid audio_mixer_voice_set_volume(audio_mixer_voice_t *voice, float val);\n\nvoid audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bool override);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/audio/audio_resampler.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (audio_resampler.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H\n#define __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <boolean.h>\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#define RESAMPLER_SIMD_SSE      (1 << 0)\n#define RESAMPLER_SIMD_SSE2     (1 << 1)\n#define RESAMPLER_SIMD_VMX      (1 << 2)\n#define RESAMPLER_SIMD_VMX128   (1 << 3)\n#define RESAMPLER_SIMD_AVX      (1 << 4)\n#define RESAMPLER_SIMD_NEON     (1 << 5)\n#define RESAMPLER_SIMD_SSE3     (1 << 6)\n#define RESAMPLER_SIMD_SSSE3    (1 << 7)\n#define RESAMPLER_SIMD_MMX      (1 << 8)\n#define RESAMPLER_SIMD_MMXEXT   (1 << 9)\n#define RESAMPLER_SIMD_SSE4     (1 << 10)\n#define RESAMPLER_SIMD_SSE42    (1 << 11)\n#define RESAMPLER_SIMD_AVX2     (1 << 12)\n#define RESAMPLER_SIMD_VFPU     (1 << 13)\n#define RESAMPLER_SIMD_PS       (1 << 14)\n\nenum resampler_quality\n{\n   RESAMPLER_QUALITY_DONTCARE = 0,\n   RESAMPLER_QUALITY_LOWEST,\n   RESAMPLER_QUALITY_LOWER,\n   RESAMPLER_QUALITY_NORMAL,\n   RESAMPLER_QUALITY_HIGHER,\n   RESAMPLER_QUALITY_HIGHEST\n};\n\n/* A bit-mask of all supported SIMD instruction sets.\n * Allows an implementation to pick different\n * resampler_implementation structs.\n */\ntypedef unsigned resampler_simd_mask_t;\n\n#define RESAMPLER_API_VERSION 1\n\n/**\n * A struct that groups the input and output of a resampler.\n */\nstruct resampler_data\n{\n   /**\n    * The buffer containing the data to be resampled.\n    */\n   const float *data_in;\n\n   /**\n    * The buffer that will be used to store resampled output.\n    * Must be allocated in advance, and must not be the same as data_in.\n    */\n   float *data_out;\n\n   /**\n    * The size of ::data_in, in frames (\\em not bytes or samples).\n    * For example, 32-bit stereo frames would consist of 8 bytes\n    * (two 4-byte floats per frame).\n    */\n   size_t input_frames;\n\n   /**\n    * The number of frames (\\em not bytes or samples) that the resampler produced.\n    * This value is set by the resampler.\n    * The resampler may not provide the same number of frames with each use,\n    * so be sure to check this value.\n    */\n   size_t output_frames;\n\n   /**\n    * The desired ratio of output_frames to input_frames.\n    * This value is used to determine the number of frames written to \\c data_out.\n    * If this value is (almost) equal to 1,\n    * then resampling may be skipped.\n    */\n   double ratio;\n};\n\n/* Returns true if config key was found. Otherwise,\n * returns false, and sets value to default value.\n */\ntypedef int (*resampler_config_get_float_t)(void *userdata,\n      const char *key, float *value, float default_value);\n\ntypedef int (*resampler_config_get_int_t)(void *userdata,\n      const char *key, int *value, int default_value);\n\n/* Allocates an array with values. free() with resampler_config_free_t. */\ntypedef int (*resampler_config_get_float_array_t)(void *userdata,\n      const char *key, float **values, unsigned *out_num_values,\n      const float *default_values, unsigned num_default_values);\n\ntypedef int (*resampler_config_get_int_array_t)(void *userdata,\n      const char *key, int **values, unsigned *out_num_values,\n      const int *default_values, unsigned num_default_values);\n\ntypedef int (*resampler_config_get_string_t)(void *userdata,\n      const char *key, char **output, const char *default_output);\n\n/* Calls free() in host runtime. Sometimes needed on Windows.\n * free() on NULL is fine. */\ntypedef void (*resampler_config_free_t)(void *ptr);\n\nstruct resampler_config\n{\n   resampler_config_get_float_t get_float;\n   resampler_config_get_int_t get_int;\n\n   resampler_config_get_float_array_t get_float_array;\n   resampler_config_get_int_array_t get_int_array;\n\n   resampler_config_get_string_t get_string;\n   /* Avoid problems where resampler plug and host are\n    * linked against different C runtimes. */\n   resampler_config_free_t free;\n};\n\n/* Bandwidth factor. Will be < 1.0 for downsampling, > 1.0 for upsampling.\n * Corresponds to expected resampling ratio. */\ntypedef void *(*resampler_init_t)(const struct resampler_config *config,\n      double bandwidth_mod, enum resampler_quality quality,\n      resampler_simd_mask_t mask);\n\n/* Frees the handle. */\ntypedef void (*resampler_free_t)(void *data);\n\n/* Processes input data. */\ntypedef void (*resampler_process_t)(void *_data, struct resampler_data *data);\n\ntypedef struct retro_resampler\n{\n   resampler_init_t     init;\n   resampler_process_t  process;\n   resampler_free_t     free;\n\n   /* Must be RESAMPLER_API_VERSION */\n   unsigned api_version;\n\n   /* Human readable identifier of implementation. */\n   const char *ident;\n\n   /* Computer-friendly short version of ident.\n    * Lower case, no spaces and special characters, etc. */\n   const char *short_ident;\n} retro_resampler_t;\n\ntypedef struct audio_frame_float\n{\n   float l;\n   float r;\n} audio_frame_float_t;\n\nextern retro_resampler_t sinc_resampler;\n#ifdef HAVE_CC_RESAMPLER\nextern retro_resampler_t CC_resampler;\n#endif\nextern retro_resampler_t nearest_resampler;\n\n/**\n * audio_resampler_driver_find_handle:\n * @index              : index of driver to get handle to.\n *\n * Returns: handle to audio resampler driver at index. Can be NULL\n * if nothing found.\n **/\nconst void *audio_resampler_driver_find_handle(int index);\n\n/**\n * audio_resampler_driver_find_ident:\n * @index              : index of driver to get handle to.\n *\n * Returns: Human-readable identifier of audio resampler driver at index.\n * Can be NULL if nothing found.\n **/\nconst char *audio_resampler_driver_find_ident(int index);\n\n/**\n * retro_resampler_realloc:\n * @re                         : Resampler handle\n * @backend                    : Resampler backend that is about to be set.\n * @ident                      : Identifier name for resampler we want.\n * @bw_ratio                   : Bandwidth ratio.\n *\n * Reallocates resampler. Will free previous handle before\n * allocating a new one. If ident is NULL, first resampler will be used.\n *\n * Returns: true (1) if successful, otherwise false (0).\n **/\nbool retro_resampler_realloc(void **re, const retro_resampler_t **backend,\n      const char *ident, enum resampler_quality quality, double bw_ratio);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/audio/conversion/dual_mono.h",
    "content": "/* Copyright  (C) 2010-2023 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (s16_to_float.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#ifndef __LIBRETRO_SDK_CONVERSION_DUAL_MONO__\n#define __LIBRETRO_SDK_CONVERSION_DUAL_MONO__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Duplicates 1-channel (mono) frames into 2-channel (stereo) frames.\n * The resulting array is suitable for use in the resampler,\n * or for any use case that demands stereo input.\n * This version operates on 32-bit floating-point samples.\n *\n * May use SIMD intrinsics on supported platforms,\n * but will work without them.\n *\n * Will do nothing if \\c out or \\c in are \\c NULL.\n *\n * @param[out] out The location in which the converted frames will be stored.\n * Must have enough room for twice the value of \\c frames.\n * @param[in] in The location of the frames to convert.\n * @param[in] frames The number of frames to convert.\n */\nvoid convert_to_dual_mono_float(float *out, const float *in, size_t frames);\n\n/**\n * Downmixes 2-channel (stereo) frames into 1-channel (mono) frames.\n * This is intended for dual-mono audio (i.e. where both channels are identical),\n * but it will work if both channels are different.\n *\n * This version operates on 32-bit floating-point samples.\n * It preserves the left channel and ignores the right channel.\n *\n * Will do nothing if \\c out or \\c in are \\c NULL.\n *\n * @param[out] out The location in which the converted frames will be stored.\n * Must have enough room for half the value of <code>frames * sizeof(float)</code>.\n * @param[in] in The location of the frames to convert.\n * @param[in] frames The number of frames to convert.\n */\nvoid convert_to_mono_float_left(float *out, const float *in, size_t frames);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/audio/conversion/float_to_s16.h",
    "content": "/* Copyright  (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (float_to_s16.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__\n#define __LIBRETRO_SDK_CONVERSION_FLOAT_TO_S16_H__\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#include <stdint.h>\n#include <stddef.h>\n\n/**\n * Converts an array of floating-point audio samples\n * to signed integer 16-bit audio samples,\n * possibly using SIMD intrinsics.\n *\n * @param out The buffer that will be used to store the converted samples.\n * @param in The buffer containing the samples to convert.\n * Any number of channels is supported.\n * @param samples The length of \\c in in samples, \\em not bytes or frames.\n * \\c out must be as large as <tt>sizeof(int16_t) * samples</tt>.\n * @see convert_s16_to_float\n **/\nvoid convert_float_to_s16(int16_t *out,\n      const float *in, size_t samples);\n\n/**\n * Initializes any prerequisites for\n * using SIMD implementations of \\c convert_float_to_s16.\n *\n * If SIMD intrinsics are not available or no initialization is required,\n * this function does nothing.\n *\n * @see convert_float_to_s16\n **/\nvoid convert_float_to_s16_init_simd(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/audio/conversion/s16_to_float.h",
    "content": "/* Copyright  (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (s16_to_float.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#ifndef __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__\n#define __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Converts an array of signed integer 16-bit audio samples\n * to floating-point format,\n * possibly using SIMD intrinsics.\n *\n * @param out The buffer that will be used to store the converted samples.\n * @param in The buffer containing the samples to convert.\n * Any number of channels is supported.\n * @param samples The length of \\c in in samples, \\em not bytes or frames.\n * \\c out must be as large as <tt>sizeof(float) * samples</tt>.\n * @param gain The gain (audio volume) to apply to the samples.\n * Pass a value of 1.0 to not apply any gain.\n * @see convert_float_to_s16\n **/\nvoid convert_s16_to_float(float *out,\n      const int16_t *in, size_t samples, float gain);\n\n/**\n * Initializes any prerequisites for\n * using SIMD implementations of \\c convert_s16_to_float.\n *\n * If SIMD intrinsics are not available or no initialization is required,\n * this function does nothing.\n *\n * @see convert_s16_to_float\n **/\nvoid convert_s16_to_float_init_simd(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/audio/dsp_filter.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (dsp_filter.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_AUDIO_DSP_FILTER_H\n#define __LIBRETRO_SDK_AUDIO_DSP_FILTER_H\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct retro_dsp_filter retro_dsp_filter_t;\n\nretro_dsp_filter_t *retro_dsp_filter_new(const char *filter_config,\n      void *string_data, float sample_rate);\n\nvoid retro_dsp_filter_free(retro_dsp_filter_t *dsp);\n\n/**\n * A struct that groups the input and output of a DSP filter.\n */\nstruct retro_dsp_data\n{\n   float *input;\n   unsigned input_frames;\n\n   /* Set by retro_dsp_filter_process(). */\n   float *output;\n   unsigned output_frames;\n};\n\nvoid retro_dsp_filter_process(retro_dsp_filter_t *dsp,\n      struct retro_dsp_data *data);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/boolean.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (boolean.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_BOOLEAN_H\n#define __LIBRETRO_SDK_BOOLEAN_H\n\n#ifndef __cplusplus\n\n#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)\n/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */\n#define bool unsigned char\n#define true 1\n#define false 0\n#else\n#include <stdbool.h>\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/cdrom/cdrom.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (cdrom.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_CDROM_H\n#define __LIBRETRO_SDK_CDROM_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <sys/types.h>\n\n#include <vfs/vfs.h>\n#include <libretro.h>\n#include <retro_common_api.h>\n#include <retro_inline.h>\n\n#include <boolean.h>\n\nstruct string_list;\n\nRETRO_BEGIN_DECLS\n\ntypedef struct\n{\n   unsigned short g1_timeout;\n   unsigned short g2_timeout;\n   unsigned short g3_timeout;\n} cdrom_group_timeouts_t;\n\ntypedef struct\n{\n   unsigned lba_start; /* start of pregap */\n   unsigned lba; /* start of data */\n   unsigned track_size; /* in LBAs */\n   unsigned track_bytes;\n   unsigned char track_num;\n   unsigned char min; /* start of data */\n   unsigned char sec;\n   unsigned char frame;\n   unsigned char mode;\n   bool audio;\n} cdrom_track_t;\n\ntypedef struct\n{\n   cdrom_track_t track[99];         /* unsigned alignment */\n   cdrom_group_timeouts_t timeouts; /* unsigned short alignment */\n   unsigned char num_tracks;\n   char drive;\n} cdrom_toc_t;\n\nvoid cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);\n\nunsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame);\n\nvoid increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame);\n\nint cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *s, size_t len);\n\nint 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);\n\n/* needs 32 bytes for full vendor, product and version */\nint cdrom_get_inquiry(libretro_vfs_implementation_file *stream, char *s, size_t len, bool *is_cdrom);\n\nint 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);\n\nint cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed);\n\nint cdrom_stop(libretro_vfs_implementation_file *stream);\n\nint cdrom_unlock(libretro_vfs_implementation_file *stream);\n\nint cdrom_open_tray(libretro_vfs_implementation_file *stream);\n\nint cdrom_close_tray(libretro_vfs_implementation_file *stream);\n\n/* must be freed by the caller */\nstruct string_list* cdrom_get_available_drives(void);\n\nbool cdrom_is_media_inserted(libretro_vfs_implementation_file *stream);\n\nbool cdrom_drive_has_media(const char drive);\n\nvoid cdrom_get_current_config_core(libretro_vfs_implementation_file *stream);\n\nvoid cdrom_get_current_config_profiles(libretro_vfs_implementation_file *stream);\n\nvoid cdrom_get_current_config_cdread(libretro_vfs_implementation_file *stream);\n\nvoid cdrom_get_current_config_multiread(libretro_vfs_implementation_file *stream);\n\nvoid cdrom_get_current_config_random_readable(libretro_vfs_implementation_file *stream);\n\nint cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len);\n\nbool cdrom_set_read_cache(libretro_vfs_implementation_file *stream, bool enabled);\n\nbool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts);\n\nbool cdrom_has_atip(libretro_vfs_implementation_file *stream);\n\nsize_t cdrom_device_fillpath(char *s, size_t len, char drive, unsigned char track, bool is_cue);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/clamping.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (clamping.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_CLAMPING_H\n#define _LIBRETRO_SDK_CLAMPING_H\n\n#include <stdint.h>\n#include <retro_inline.h>\n\n/**\n * Clamps a floating-point value to the specified range.\n *\n * @param val The value to clamp.\n * @param lower The minimum possible value.\n * @param upper The maximum possible value.\n *\n * @returns \\c val clamped to between \\c lower and \\c upper (inclusive).\n */\nstatic INLINE float clamp_float(float val, float lower, float upper)\n{\n   if (val < lower)\n      return lower;\n   if (val > upper)\n      return upper;\n   return val;\n}\n\n/**\n * Clamps an integer to fit in 8 bits.\n *\n * @param val The value to clamp.\n * @return \\c val clamped to between 0 and 255 (inclusive).\n */\nstatic INLINE uint8_t clamp_8bit(int val)\n{\n   if (val > 255)\n      return 255;\n   if (val < 0)\n      return 0;\n   return (uint8_t)val;\n}\n\n#endif\n"
  },
  {
    "path": "include/compat/apple_compat.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (apple_compat.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __APPLE_COMPAT_H\n#define __APPLE_COMPAT_H\n\n#ifdef __APPLE__\n#include <AvailabilityMacros.h>\n#include <CoreFoundation/CoreFoundation.h>\n#endif\n\n#ifdef __OBJC__\n\n#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4)\ntypedef int NSInteger;\ntypedef unsigned NSUInteger;\ntypedef float CGFloat;\n#endif\n\n#ifndef __has_feature\n/* Compatibility with non-Clang compilers. */\n#define __has_feature(x) 0\n#endif\n\n#ifndef CF_RETURNS_RETAINED\n#if __has_feature(attribute_cf_returns_retained)\n#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))\n#else\n#define CF_RETURNS_RETAINED\n#endif\n#endif\n\n#ifndef NS_INLINE\n#define NS_INLINE inline\n#endif\n\nNS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)\n{\n#if __has_feature(objc_arc)\n   return (__bridge_retained CFTypeRef)X;\n#else\n   return X;\n#endif\n}\n\n#endif\n\n#ifdef IOS\n#ifndef __IPHONE_5_0\n#warning \"This project uses features only available in iOS SDK 5.0 and later.\"\n#endif\n\n#ifdef __OBJC__\n#import <UIKit/UIKit.h>\n#import <GLKit/GLKit.h>\n#import <Foundation/Foundation.h>\n#endif\n\n#else\n\n#ifdef __OBJC__\n#include <objc/objc-runtime.h>\n#endif\n#endif\n\n#endif\n"
  },
  {
    "path": "include/compat/fnmatch.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fnmatch.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_FNMATCH_H__\n#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__\n\n#define\tFNM_NOMATCH\t1\n\n/**\n * Portable implementation of \\c fnmatch(3),\n * except \\c flags is not implemented.\n * @see https://man7.org/linux/man-pages/man3/fnmatch.3.html\n */\nint rl_fnmatch(const char *pattern, const char *string, int flags);\n\n#endif\n"
  },
  {
    "path": "include/compat/fopen_utf8.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fopen_utf8.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H\n#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H\n\n#ifdef _WIN32\n/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */\n/* TODO: enable */\n/* #define fopen (use fopen_utf8 instead) */\nvoid *fopen_utf8(const char * filename, const char * mode);\n#else\n#define fopen_utf8 fopen\n#endif\n#endif\n"
  },
  {
    "path": "include/compat/getopt.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (getopt.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_GETOPT_H\n#define __LIBRETRO_SDK_COMPAT_GETOPT_H\n\n#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)\n#include \"../../../config.h\"\n#endif\n\n/**\n * @file getopt.h\n *\n * Portable reimplementation of a subset of libc's \\c getopt_long.\n * Not designed to be fully compatible,\n * but it's enough for RetroArch's purposes.\n *\n * If \\c getopt_long is available (as determined by \\c HAVE_GETOPT_LONG), it will be used instead.\n *\n * @see https://man7.org/linux/man-pages/man3/getopt.3.html\n */\n\n#ifdef HAVE_GETOPT_LONG\n#include <getopt.h>\n#else\n/* Avoid possible naming collisions during link since we\n * prefer to use the actual name. */\n#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nstruct option\n{\n   const char *name;\n   int has_arg;\n   int *flag;\n   int val;\n};\n\n/* argv[] is declared with char * const argv[] in GNU,\n * but this makes no sense, as non-POSIX getopt_long\n * mutates argv (non-opts are moved to the end). */\nint getopt_long(int argc, char *argv[],\n      const char *optstring, const struct option *longopts, int *longindex);\nextern char *optarg;\nextern int optind, opterr, optopt;\n\nRETRO_END_DECLS\n\n/* If these are variously #defined, then we have bigger problems */\n#ifndef no_argument\n   #define no_argument 0\n   #define required_argument 1\n   #define optional_argument 2\n#endif\n\n/* HAVE_GETOPT_LONG */\n#endif\n\n/* pragma once */\n#endif\n"
  },
  {
    "path": "include/compat/ifaddrs.h",
    "content": "/*\n * Copyright (c) 1995, 1999\n *\tBerkeley Software Design, Inc.  All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tBSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp\n */\n\n#ifndef\t_IFADDRS_H_\n#define\t_IFADDRS_H_\n\nstruct ifaddrs\n{\n   struct ifaddrs  *ifa_next;\n   char\t\t*ifa_name;\n   unsigned int\t ifa_flags;\n   struct sockaddr\t*ifa_addr;\n   struct sockaddr\t*ifa_netmask;\n   struct sockaddr\t*ifa_dstaddr;\n   void\t\t*ifa_data;\n};\n\n/*\n * This may have been defined in <net/if.h>.  Note that if <net/if.h> is\n * to be included it must be included before this header file.\n */\n#ifndef\tifa_broadaddr\n#define\tifa_broadaddr\tifa_dstaddr\t/* broadcast address interface */\n#endif\n\n#include <sys/cdefs.h>\n\n/**\n * Portable reimplementation of \\c getifaddrs().\n * The original function will be used if it's available.\n *\n * @see https://man7.org/linux/man-pages/man3/getifaddrs.3.html\n */\nextern int getifaddrs(struct ifaddrs **ifap);\n\n/**\n * Portable reimplementation of \\c freeifaddrs().\n * The original function will be used if it's available.\n *\n * @see https://man7.org/linux/man-pages/man3/getifaddrs.3.html\n */\nextern void freeifaddrs(struct ifaddrs *ifa);\n\n#endif\n"
  },
  {
    "path": "include/compat/intrinsics.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (intrinsics.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_INTRINSICS_H\n#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H\n\n#include <stdint.h>\n#include <stddef.h>\n#include <string.h>\n\n#include <retro_common_api.h>\n#include <retro_inline.h>\n\n#if defined(_MSC_VER) && !defined(_XBOX)\n#if (_MSC_VER > 1310)\n#include <intrin.h>\n#endif\n#endif\n\nRETRO_BEGIN_DECLS\n\n/**\n * Counts the leading zero bits in a \\c uint16_t.\n * Uses compiler intrinsics if available, or a standard C implementation if not.\n *\n * @param val Value to count leading zeroes in.\n * @return Number of leading zeroes in \\c val.\n */\nstatic INLINE unsigned compat_clz_u16(uint16_t val)\n{\n#if defined(__GNUC__)\n   return __builtin_clz(val << 16 | 0x8000);\n#else\n   unsigned ret = 0;\n\n   while(!(val & 0x8000) && ret < 16)\n   {\n      val <<= 1;\n      ret++;\n   }\n\n   return ret;\n#endif\n}\n\n/**\n * Counts the trailing zero bits in a \\c uint16_t.\n * Uses compiler intrinsics if available, or a standard C implementation if not.\n *\n * @param val Value to count trailing zeroes in.\n * @return Number of trailing zeroes in \\c val.\n */\nstatic INLINE int compat_ctz(unsigned x)\n{\n#if defined(__GNUC__) && !defined(RARCH_CONSOLE)\n   return __builtin_ctz(x);\n#elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__)\n   unsigned long r = 0;\n   _BitScanForward((unsigned long*)&r, x);\n   return (int)r;\n#else\n   int count = 0;\n   if (!(x & 0xffff))\n   {\n      x >>= 16;\n      count |= 16;\n   }\n   if (!(x & 0xff))\n   {\n      x >>= 8;\n      count |= 8;\n   }\n   if (!(x & 0xf))\n   {\n      x >>= 4;\n      count |= 4;\n   }\n   if (!(x & 0x3))\n   {\n      x >>= 2;\n      count |= 2;\n   }\n   if (!(x & 0x1))\n      count |= 1;\n\n   return count;\n#endif\n}\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/compat/msvc/stdint.h",
    "content": "/* ISO C9x  compliant stdint.h for Microsoft Visual Studio\n * Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124\n *\n * Copyright (c) 2006-2008 Alexander Chemeris\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n *\n * 3. The name of the author may be used to endorse or promote products\n * derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef __RARCH_STDINT_H\n#define __RARCH_STDINT_H\n\n#if _MSC_VER && (_MSC_VER < 1600)\n/* Pre-MSVC 2010 needs an implementation of stdint.h. */\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n#include <limits.h>\n\n/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when\n * compiling for ARM we should wrap <wchar.h> include with 'extern \"C++\" {}'\n * or compiler give many errors like this:\n *\n * error C2733: second C linkage of overloaded function 'wmemchr' not allowed\n */\n#ifdef __cplusplus\n#if _MSC_VER <= 1200\nextern \"C++\" {\n#else\nextern \"C\" {\n#endif\n#endif\n#  include <wchar.h>\n#ifdef __cplusplus\n}\n#endif\n\n/* Define _W64 macros to mark types changing their size, like intptr_t. */\n#ifndef _W64\n#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300\n#     define _W64 __w64\n#  else\n#     define _W64\n#  endif\n#endif\n\n/* 7.18.1 Integer types. */\n\n/* 7.18.1.1 Exact-width integer types. */\n\n/* Visual Studio 6 and Embedded Visual C++ 4 doesn't\n * realize that, e.g. char has the same size as __int8\n * so we give up on __intX for them.\n */\n#if (_MSC_VER < 1300)\n   typedef signed char       int8_t;\n   typedef signed short      int16_t;\n   typedef signed int        int32_t;\n   typedef unsigned char     uint8_t;\n   typedef unsigned short    uint16_t;\n   typedef unsigned int      uint32_t;\n#else\n   typedef signed __int8     int8_t;\n   typedef signed __int16    int16_t;\n   typedef signed __int32    int32_t;\n   typedef unsigned __int8   uint8_t;\n   typedef unsigned __int16  uint16_t;\n   typedef unsigned __int32  uint32_t;\n#endif\ntypedef signed __int64       int64_t;\ntypedef unsigned __int64     uint64_t;\n\n/* 7.18.1.2 Minimum-width integer types. */\ntypedef int8_t    int_least8_t;\ntypedef int16_t   int_least16_t;\ntypedef int32_t   int_least32_t;\ntypedef int64_t   int_least64_t;\ntypedef uint8_t   uint_least8_t;\ntypedef uint16_t  uint_least16_t;\ntypedef uint32_t  uint_least32_t;\ntypedef uint64_t  uint_least64_t;\n\n/* 7.18.1.3 Fastest minimum-width integer types. */\ntypedef int8_t    int_fast8_t;\ntypedef int16_t   int_fast16_t;\ntypedef int32_t   int_fast32_t;\ntypedef int64_t   int_fast64_t;\ntypedef uint8_t   uint_fast8_t;\ntypedef uint16_t  uint_fast16_t;\ntypedef uint32_t  uint_fast32_t;\ntypedef uint64_t  uint_fast64_t;\n\n/* 7.18.1.4 Integer types capable of holding object pointers. */\n#ifdef _WIN64 /* [ */\n   typedef signed __int64    intptr_t;\n   typedef unsigned __int64  uintptr_t;\n#else /* _WIN64 ][ */\n   typedef _W64 signed int   intptr_t;\n   typedef _W64 unsigned int uintptr_t;\n#endif /* _WIN64 ] */\n\n/* 7.18.1.5 Greatest-width integer types. */\ntypedef int64_t   intmax_t;\ntypedef uint64_t  uintmax_t;\n\n/* 7.18.2 Limits of specified-width integer types. */\n\n#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)\n/* [   See footnote 220 at page 257 and footnote 221 at page 259. */\n\n/* 7.18.2.1 Limits of exact-width integer types. */\n#define INT8_MIN     ((int8_t)_I8_MIN)\n#define INT8_MAX     _I8_MAX\n#define INT16_MIN    ((int16_t)_I16_MIN)\n#define INT16_MAX    _I16_MAX\n#define INT32_MIN    ((int32_t)_I32_MIN)\n#define INT32_MAX    _I32_MAX\n#define INT64_MIN    ((int64_t)_I64_MIN)\n#define INT64_MAX    _I64_MAX\n#define UINT8_MAX    _UI8_MAX\n#define UINT16_MAX   _UI16_MAX\n#define UINT32_MAX   _UI32_MAX\n#define UINT64_MAX   _UI64_MAX\n\n/* 7.18.2.2 Limits of minimum-width integer types. */\n#define INT_LEAST8_MIN    INT8_MIN\n#define INT_LEAST8_MAX    INT8_MAX\n#define INT_LEAST16_MIN   INT16_MIN\n#define INT_LEAST16_MAX   INT16_MAX\n#define INT_LEAST32_MIN   INT32_MIN\n#define INT_LEAST32_MAX   INT32_MAX\n#define INT_LEAST64_MIN   INT64_MIN\n#define INT_LEAST64_MAX   INT64_MAX\n#define UINT_LEAST8_MAX   UINT8_MAX\n#define UINT_LEAST16_MAX  UINT16_MAX\n#define UINT_LEAST32_MAX  UINT32_MAX\n#define UINT_LEAST64_MAX  UINT64_MAX\n\n/* 7.18.2.3 Limits of fastest minimum-width integer types. */\n#define INT_FAST8_MIN    INT8_MIN\n#define INT_FAST8_MAX    INT8_MAX\n#define INT_FAST16_MIN   INT16_MIN\n#define INT_FAST16_MAX   INT16_MAX\n#define INT_FAST32_MIN   INT32_MIN\n#define INT_FAST32_MAX   INT32_MAX\n#define INT_FAST64_MIN   INT64_MIN\n#define INT_FAST64_MAX   INT64_MAX\n#define UINT_FAST8_MAX   UINT8_MAX\n#define UINT_FAST16_MAX  UINT16_MAX\n#define UINT_FAST32_MAX  UINT32_MAX\n#define UINT_FAST64_MAX  UINT64_MAX\n\n/* 7.18.2.4 Limits of integer types capable of holding object pointers. */\n#ifdef _WIN64 /* [ */\n#  define INTPTR_MIN   INT64_MIN\n#  define INTPTR_MAX   INT64_MAX\n#  define UINTPTR_MAX  UINT64_MAX\n#else /* _WIN64 ][ */\n#  define INTPTR_MIN   INT32_MIN\n#  define INTPTR_MAX   INT32_MAX\n#  define UINTPTR_MAX  UINT32_MAX\n#endif /* _WIN64 ] */\n\n/* 7.18.2.5 Limits of greatest-width integer types */\n#define INTMAX_MIN   INT64_MIN\n#define INTMAX_MAX   INT64_MAX\n#define UINTMAX_MAX  UINT64_MAX\n\n/* 7.18.3 Limits of other integer types */\n\n#ifdef _WIN64 /* [ */\n#  define PTRDIFF_MIN  _I64_MIN\n#  define PTRDIFF_MAX  _I64_MAX\n#else  /* _WIN64 ][ */\n#  define PTRDIFF_MIN  _I32_MIN\n#  define PTRDIFF_MAX  _I32_MAX\n#endif  /* _WIN64 ] */\n\n#define SIG_ATOMIC_MIN  INT_MIN\n#define SIG_ATOMIC_MAX  INT_MAX\n\n#ifndef SIZE_MAX /* [ */\n#  ifdef _WIN64 /* [ */\n#     define SIZE_MAX  _UI64_MAX\n#  else /* _WIN64 ][ */\n#     define SIZE_MAX  _UI32_MAX\n#  endif /* _WIN64 ] */\n#endif /* SIZE_MAX ] */\n\n/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */\n#ifndef WCHAR_MIN /* [ */\n#  define WCHAR_MIN  0\n#endif  /* WCHAR_MIN ] */\n#ifndef WCHAR_MAX // [\n#  define WCHAR_MAX  _UI16_MAX\n#endif  /* WCHAR_MAX ] */\n\n#define WINT_MIN  0\n#define WINT_MAX  _UI16_MAX\n\n#endif /* __STDC_LIMIT_MACROS ] */\n\n/* 7.18.4 Limits of other integer types */\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)\n/* [   See footnote 224 at page 260 */\n\n/* 7.18.4.1 Macros for minimum-width integer constants */\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n/* 7.18.4.2 Macros for greatest-width integer constants */\n#define INTMAX_C   INT64_C\n#define UINTMAX_C  UINT64_C\n\n#endif\n/* __STDC_CONSTANT_MACROS ] */\n\n#else\n/* Sanity for everything else. */\n#include <stdint.h>\n#endif\n\n#endif\n"
  },
  {
    "path": "include/compat/msvc.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (msvc.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_MSVC_H\n#define __LIBRETRO_SDK_COMPAT_MSVC_H\n\n#ifdef _MSC_VER\n\n#ifdef __cplusplus\nextern \"C\"  {\n#endif\n\n/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */\n#if _MSC_VER < 1900\n   #include <stdio.h>\n   #include <stdarg.h>\n   #include <stdlib.h>\n\n   #ifndef snprintf\n      #define snprintf c99_snprintf_retro__\n   #endif\n   int c99_snprintf_retro__(char *s, size_t len, const char *format, ...);\n\n   #ifndef vsnprintf\n      #define vsnprintf c99_vsnprintf_retro__\n   #endif\n   int c99_vsnprintf_retro__(char *s, size_t len, const char *format, va_list ap);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#undef UNICODE /* Do not bother with UNICODE at this time. */\n#include <direct.h>\n#include <stddef.h>\n\n#define _USE_MATH_DEFINES\n#include <math.h>\n\n/* Python headers defines ssize_t and sets HAVE_SSIZE_T.\n * Cannot duplicate these efforts.\n */\n#ifndef HAVE_SSIZE_T\n#if defined(_WIN64)\ntypedef __int64 ssize_t;\n#elif defined(_WIN32)\ntypedef int ssize_t;\n#endif\n#endif\n\n#define mkdir(dirname, unused) _mkdir(dirname)\n#define strtoull _strtoui64\n#undef strcasecmp\n#define strcasecmp _stricmp\n#undef strncasecmp\n#define strncasecmp _strnicmp\n\n/* Disable some of the annoying warnings. */\n#pragma warning(disable : 4800)\n#pragma warning(disable : 4805)\n#pragma warning(disable : 4244)\n#pragma warning(disable : 4305)\n#pragma warning(disable : 4146)\n#pragma warning(disable : 4267)\n#pragma warning(disable : 4723)\n#pragma warning(disable : 4996)\n\n/* roundf and va_copy is available since MSVC 2013 */\n#if _MSC_VER < 1800\n#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))\n#define va_copy(x, y) ((x) = (y))\n#endif\n\n#if _MSC_VER <= 1310\n   #ifndef __cplusplus\n      /* VC6 math.h doesn't define some functions when in C mode.\n       * Trying to define a prototype gives \"undefined reference\".\n       * But providing an implementation then gives \"function already has body\".\n       * So the equivalent of the implementations from math.h are used as\n       * defines here instead, and it seems to work.\n       */\n      #define cosf(x) ((float)cos((double)x))\n      #define powf(x, y) ((float)pow((double)x, (double)y))\n      #define sinf(x) ((float)sin((double)x))\n      #define ceilf(x) ((float)ceil((double)x))\n      #define floorf(x) ((float)floor((double)x))\n      #define sqrtf(x) ((float)sqrt((double)x))\n      #define fabsf(x)    ((float)fabs((double)(x)))\n   #endif\n\n   #ifndef _strtoui64\n      #define _strtoui64(x, y, z) (_atoi64(x))\n   #endif\n\n#endif\n\n#ifndef PATH_MAX\n#define PATH_MAX _MAX_PATH\n#endif\n\n#ifndef SIZE_MAX\n#define SIZE_MAX _UI32_MAX\n#endif\n\n#endif\n#endif\n"
  },
  {
    "path": "include/compat/posix_string.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (posix_string.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H\n#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H\n\n#include <retro_common_api.h>\n\n/**\n * @file posix_string.h\n *\n * Portable reimplementations of various string functions\n * that are normally provided by libc or POSIX.\n */\n\n#ifdef _MSC_VER\n#include <compat/msvc.h>\n#endif\n\nRETRO_BEGIN_DECLS\n\n#if defined(_WIN32) || defined(DOXYGEN)\n#undef strtok_r\n#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)\n\n/**\n * Portable reimplementation of \\c strtok_r().\n * The original function will be used if it's available.\n *\n * @see https://man7.org/linux/man-pages/man3/strtok.3.html\n */\nchar *strtok_r(char *str, const char *delim, char **saveptr);\n#endif\n\n#if defined(_MSC_VER) || defined(DOXYGEN)\n#undef strcasecmp\n#undef strdup\n\n#define strcasecmp(a, b) retro_strcasecmp__(a, b)\n#define strdup(orig)     retro_strdup__(orig)\n/**\n * Portable reimplementation of \\c strcasecmp().\n * The original function will be used if it's available.\n *\n * @see https://man7.org/linux/man-pages/man3/strcasecmp.3.html\n */\nint strcasecmp(const char *a, const char *b);\n\n/**\n * Portable reimplementation of \\c strdup().\n * The original function will be used if it's available.\n *\n * @see https://man7.org/linux/man-pages/man3/strdup.3.html\n */\nchar *strdup(const char *orig);\n\n/* isblank is available since MSVC 2013 */\n#if _MSC_VER < 1800\n#undef isblank\n#define isblank(c)       retro_isblank__(c)\n/**\n * Portable reimplementation of \\c isblank().\n * The original function will be used if it's available.\n *\n * @see https://en.cppreference.com/w/c/string/byte/isblank\n */\nint isblank(int c);\n#endif\n\n#endif\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/compat/strcasestr.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (strcasestr.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H\n#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H\n\n#include <string.h>\n\n#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)\n#include \"../../../config.h\"\n#endif\n\n#ifndef HAVE_STRCASESTR\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/* Avoid possible naming collisions during link\n * since we prefer to use the actual name. */\n#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)\n\n/**\n * Portable reimplementation of \\c strcasestr(3).\n * If the original function is available\n * (as determined by the presence of \\c HAVE_STRCASESTR),\n * it will be used instead.\n *\n * @see https://man7.org/linux/man-pages/man3/strstr.3.html\n */\nchar *strcasestr(const char *haystack, const char *needle);\n\nRETRO_END_DECLS\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/compat/strl.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (strl.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_COMPAT_STRL_H\n#define __LIBRETRO_SDK_COMPAT_STRL_H\n\n/**\n * @file strl.h\n *\n * Portable implementation of \\c strlcpy(3) and \\c strlcat(3).\n * If these functions are available on the target platform,\n * then the originals should be imported instead.\n *\n * @see https://linux.die.net/man/3/strlcpy\n */\n#include <string.h>\n#include <stddef.h>\n\n#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)\n#include \"../../../config.h\"\n#endif\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#if defined(__MACH__) && defined(__APPLE__)\n#ifndef HAVE_STRL\n#define HAVE_STRL\n#endif\n#endif\n\n#ifndef HAVE_STRL\n/* Avoid possible naming collisions during link since\n * we prefer to use the actual name. */\n#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)\n\n#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)\n\n/**\n * @brief Portable implementation of \\c strlcpy(3).\n * @see https://linux.die.net/man/3/strlcpy\n */\nsize_t strlcpy(char *s, const char *source, size_t len);\n\n/**\n * @brief Portable implementation of \\c strlcat(3).\n * @see https://linux.die.net/man/3/strlcpy\n */\nsize_t strlcat(char *s, const char *source, size_t len);\n\n#endif\n\n/**\n * A version of \\c strndup(3) that guarantees the result will be null-terminated.\n *\n * @param s The string to duplicate.\n * @param n The maximum number of characters to copy from \\c s.\n * The result will allocate one more byte than this value.\n * @return Pointer to the cloned string.\n * Must be freed with \\c free().\n */\nchar *strldup(const char *s, size_t n);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/compat/zlib/zconf.h",
    "content": "/* zconf.h -- configuration of the zlib compression library\n * Copyright (C) 1995-2013 Jean-loup Gailly.\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZCONF_H\n#define ZCONF_H\n\n/*\n * If you *really* need a unique prefix for all types and library functions,\n * compile with -DZ_PREFIX. The \"standard\" zlib should be compiled without it.\n * Even better than compiling with -DZ_PREFIX would be to use configure to set\n * this permanently in zconf.h using \"./configure --zprefix\".\n */\n#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */\n#  define Z_PREFIX_SET\n\n/* all linked symbols */\n#  define _dist_code            z__dist_code\n#  define _length_code          z__length_code\n#  define _tr_align             z__tr_align\n#  define _tr_flush_bits        z__tr_flush_bits\n#  define _tr_flush_block       z__tr_flush_block\n#  define _tr_init              z__tr_init\n#  define _tr_stored_block      z__tr_stored_block\n#  define _tr_tally             z__tr_tally\n#  define adler32               z_adler32\n#  define adler32_combine       z_adler32_combine\n#  define adler32_combine64     z_adler32_combine64\n#  ifndef Z_SOLO\n#    define compress              z_compress\n#    define compress2             z_compress2\n#    define compressBound         z_compressBound\n#  endif\n#  define crc32                 z_crc32\n#  define crc32_combine         z_crc32_combine\n#  define crc32_combine64       z_crc32_combine64\n#  define deflate               z_deflate\n#  define deflateBound          z_deflateBound\n#  define deflateCopy           z_deflateCopy\n#  define deflateEnd            z_deflateEnd\n#  define deflateInit2_         z_deflateInit2_\n#  define deflateInit_          z_deflateInit_\n#  define deflateParams         z_deflateParams\n#  define deflatePending        z_deflatePending\n#  define deflatePrime          z_deflatePrime\n#  define deflateReset          z_deflateReset\n#  define deflateResetKeep      z_deflateResetKeep\n#  define deflateSetDictionary  z_deflateSetDictionary\n#  define deflateSetHeader      z_deflateSetHeader\n#  define deflateTune           z_deflateTune\n#  define deflate_copyright     z_deflate_copyright\n#  define get_crc_table         z_get_crc_table\n#  ifndef Z_SOLO\n#    define gz_error              z_gz_error\n#    define gz_intmax             z_gz_intmax\n#    define gz_strwinerror        z_gz_strwinerror\n#    define gzbuffer              z_gzbuffer\n#    define gzclearerr            z_gzclearerr\n#    define gzclose               z_gzclose\n#    define gzclose_r             z_gzclose_r\n#    define gzclose_w             z_gzclose_w\n#    define gzdirect              z_gzdirect\n#    define gzdopen               z_gzdopen\n#    define gzeof                 z_gzeof\n#    define gzerror               z_gzerror\n#    define gzflush               z_gzflush\n#    define gzgetc                z_gzgetc\n#    define gzgetc_               z_gzgetc_\n#    define gzgets                z_gzgets\n#    define gzoffset              z_gzoffset\n#    define gzoffset64            z_gzoffset64\n#    define gzopen                z_gzopen\n#    define gzopen64              z_gzopen64\n#    ifdef _WIN32\n#      define gzopen_w              z_gzopen_w\n#    endif\n#    define gzprintf              z_gzprintf\n#    define gzvprintf             z_gzvprintf\n#    define gzputc                z_gzputc\n#    define gzputs                z_gzputs\n#    define gzread                z_gzread\n#    define gzrewind              z_gzrewind\n#    define gzseek                z_gzseek\n#    define gzseek64              z_gzseek64\n#    define gzsetparams           z_gzsetparams\n#    define gztell                z_gztell\n#    define gztell64              z_gztell64\n#    define gzungetc              z_gzungetc\n#    define gzwrite               z_gzwrite\n#  endif\n#  define inflate               z_inflate\n#  define inflateBack           z_inflateBack\n#  define inflateBackEnd        z_inflateBackEnd\n#  define inflateBackInit_      z_inflateBackInit_\n#  define inflateCopy           z_inflateCopy\n#  define inflateEnd            z_inflateEnd\n#  define inflateGetHeader      z_inflateGetHeader\n#  define inflateInit2_         z_inflateInit2_\n#  define inflateInit_          z_inflateInit_\n#  define inflateMark           z_inflateMark\n#  define inflatePrime          z_inflatePrime\n#  define inflateReset          z_inflateReset\n#  define inflateReset2         z_inflateReset2\n#  define inflateSetDictionary  z_inflateSetDictionary\n#  define inflateGetDictionary  z_inflateGetDictionary\n#  define inflateSync           z_inflateSync\n#  define inflateSyncPoint      z_inflateSyncPoint\n#  define inflateUndermine      z_inflateUndermine\n#  define inflateResetKeep      z_inflateResetKeep\n#  define inflate_copyright     z_inflate_copyright\n#  define inflate_fast          z_inflate_fast\n#  define inflate_table         z_inflate_table\n#  ifndef Z_SOLO\n#    define uncompress            z_uncompress\n#  endif\n#  define zError                z_zError\n#  ifndef Z_SOLO\n#    define zcalloc               z_zcalloc\n#    define zcfree                z_zcfree\n#  endif\n#  define zlibCompileFlags      z_zlibCompileFlags\n#  define zlibVersion           z_zlibVersion\n\n/* all zlib typedefs in zlib.h and zconf.h */\n#  define Byte                  z_Byte\n#  define Bytef                 z_Bytef\n#  define alloc_func            z_alloc_func\n#  define charf                 z_charf\n#  define free_func             z_free_func\n#  ifndef Z_SOLO\n#    define gzFile                z_gzFile\n#  endif\n#  define gz_header             z_gz_header\n#  define gz_headerp            z_gz_headerp\n#  define in_func               z_in_func\n#  define intf                  z_intf\n#  define out_func              z_out_func\n#  define uInt                  z_uInt\n#  define uIntf                 z_uIntf\n#  define uLong                 z_uLong\n#  define uLongf                z_uLongf\n#  define voidp                 z_voidp\n#  define voidpc                z_voidpc\n#  define voidpf                z_voidpf\n\n/* all zlib structs in zlib.h and zconf.h */\n#  define gz_header_s           z_gz_header_s\n#  define internal_state        z_internal_state\n\n#endif\n\n#if defined(__MSDOS__) && !defined(MSDOS)\n#  define MSDOS\n#endif\n#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)\n#  define OS2\n#endif\n#if defined(_WINDOWS) && !defined(WINDOWS)\n#  define WINDOWS\n#endif\n#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)\n#  ifndef WIN32\n#    define WIN32\n#  endif\n#endif\n#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)\n#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)\n#    ifndef SYS16BIT\n#      define SYS16BIT\n#    endif\n#  endif\n#endif\n\n/*\n * Compile with -DMAXSEG_64K if the alloc function cannot allocate more\n * than 64k bytes at a time (needed on systems with 16-bit int).\n */\n#ifdef SYS16BIT\n#  define MAXSEG_64K\n#endif\n#ifdef MSDOS\n#  define UNALIGNED_OK\n#endif\n\n#ifdef __STDC_VERSION__\n#  ifndef STDC\n#    define STDC\n#  endif\n#  if __STDC_VERSION__ >= 199901L\n#    ifndef STDC99\n#      define STDC99\n#    endif\n#  endif\n#endif\n#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))\n#  define STDC\n#endif\n\n#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */\n#  define STDC\n#endif\n\n#ifndef STDC\n#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */\n#    define const       /* note: need a more gentle solution here */\n#  endif\n#endif\n\n#if defined(ZLIB_CONST) && !defined(z_const)\n#  define z_const const\n#else\n#  define z_const\n#endif\n\n/* Some Mac compilers merge all .h files incorrectly: */\n#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)\n#  define NO_DUMMY_DECL\n#endif\n\n/* Maximum value for memLevel in deflateInit2 */\n#ifndef MAX_MEM_LEVEL\n#  ifdef MAXSEG_64K\n#    define MAX_MEM_LEVEL 8\n#  else\n#    define MAX_MEM_LEVEL 9\n#  endif\n#endif\n\n/* Maximum value for windowBits in deflateInit2 and inflateInit2.\n * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files\n * created by gzip. (Files created by minigzip can still be extracted by\n * gzip.)\n */\n#ifndef MAX_WBITS\n#  define MAX_WBITS   15 /* 32K LZ77 window */\n#endif\n\n/* The memory requirements for deflate are (in bytes):\n            (1 << (windowBits+2)) +  (1 << (memLevel+9))\n that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)\n plus a few kilobytes for small objects. For example, if you want to reduce\n the default memory requirements from 256K to 128K, compile with\n     make CFLAGS=\"-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7\"\n Of course this will generally degrade compression (there's no free lunch).\n\n   The memory requirements for inflate are (in bytes) 1 << windowBits\n that is, 32K for windowBits=15 (default value) plus a few kilobytes\n for small objects.\n*/\n\n                        /* Type declarations */\n\n#ifndef OF /* function prototypes */\n#  ifdef STDC\n#    define OF(args)  args\n#  else\n#    define OF(args)  ()\n#  endif\n#endif\n\n#ifndef Z_ARG /* function prototypes for stdarg */\n#  if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#    define Z_ARG(args)  args\n#  else\n#    define Z_ARG(args)  ()\n#  endif\n#endif\n\n/* The following definitions for FAR are needed only for MSDOS mixed\n * model programming (small or medium model with some far allocations).\n * This was tested only with MSC; for other MSDOS compilers you may have\n * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,\n * just define FAR to be empty.\n */\n#ifdef SYS16BIT\n#  if defined(M_I86SM) || defined(M_I86MM)\n     /* MSC small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef _MSC_VER\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#  if (defined(__SMALL__) || defined(__MEDIUM__))\n     /* Turbo C small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef __BORLANDC__\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#endif\n\n#if defined(WINDOWS) || defined(WIN32)\n   /* If building or using zlib as a DLL, define ZLIB_DLL.\n    * This is not mandatory, but it offers a little performance increase.\n    */\n#  ifdef ZLIB_DLL\n#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))\n#      ifdef ZLIB_INTERNAL\n#        define ZEXTERN extern __declspec(dllexport)\n#      else\n#        define ZEXTERN extern __declspec(dllimport)\n#      endif\n#    endif\n#  endif  /* ZLIB_DLL */\n   /* If building or using zlib with the WINAPI/WINAPIV calling convention,\n    * define ZLIB_WINAPI.\n    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.\n    */\n#  ifdef ZLIB_WINAPI\n#    ifdef FAR\n#      undef FAR\n#    endif\n#    include <windows.h>\n     /* No need for _export, use ZLIB.DEF instead. */\n     /* For complete Windows compatibility, use WINAPI, not __stdcall. */\n#  endif\n#endif\n\n#ifndef FAR\n#  define FAR\n#endif\n\n#if !defined(__MACTYPES__)\ntypedef unsigned char  Byte;  /* 8 bits */\n#endif\ntypedef unsigned int   uInt;  /* 16 bits or more */\ntypedef unsigned long  uLong; /* 32 bits or more */\n\n#ifdef SMALL_MEDIUM\n   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */\n#  define Bytef Byte FAR\n#else\n   typedef Byte  FAR Bytef;\n#endif\ntypedef char  FAR charf;\ntypedef int   FAR intf;\ntypedef uInt  FAR uIntf;\ntypedef uLong FAR uLongf;\n\n#ifdef STDC\n   typedef void const *voidpc;\n   typedef void FAR   *voidpf;\n   typedef void       *voidp;\n#else\n   typedef Byte const *voidpc;\n   typedef Byte FAR   *voidpf;\n   typedef Byte       *voidp;\n#endif\n\n#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)\n#  include <limits.h>\n#  if (UINT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned\n#  elif (ULONG_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned long\n#  elif (USHRT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned short\n#  endif\n#endif\n\n#ifdef Z_U4\n   typedef Z_U4 z_crc_t;\n#else\n   typedef unsigned long z_crc_t;\n#endif\n\n#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_UNISTD_H\n#endif\n\n#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_STDARG_H\n#endif\n\n#ifdef STDC\n#  ifndef Z_SOLO\n#    include <sys/types.h>      /* for off_t */\n#  endif\n#endif\n\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\n#    include <stdarg.h>         /* for va_list */\n#  endif\n#endif\n\n#ifdef _WIN32\n#  ifndef Z_SOLO\n#    include <stddef.h>         /* for wchar_t */\n#  endif\n#endif\n\n/* a little trick to accommodate both \"#define _LARGEFILE64_SOURCE\" and\n * \"#define _LARGEFILE64_SOURCE 1\" as requesting 64-bit operations, (even\n * though the former does not conform to the LFS document), but considering\n * both \"#undef _LARGEFILE64_SOURCE\" and \"#define _LARGEFILE64_SOURCE 0\" as\n * equivalently requesting no 64-bit operations\n */\n#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1\n#  undef _LARGEFILE64_SOURCE\n#endif\n\n#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)\n#  define Z_HAVE_UNISTD_H\n#endif\n#ifndef Z_SOLO\n#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)\n#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */\n#    ifdef VMS\n#      include <unixio.h>       /* for off_t */\n#    endif\n#    ifndef z_off_t\n#      define z_off_t off_t\n#    endif\n#  endif\n#endif\n\n#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0\n#  define Z_LFS64\n#endif\n\n#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)\n#  define Z_LARGE64\n#endif\n\n#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)\n#  define Z_WANT64\n#endif\n\n#if !defined(SEEK_SET) && !defined(Z_SOLO)\n#  define SEEK_SET        0       /* Seek from beginning of file.  */\n#  define SEEK_CUR        1       /* Seek from current position.  */\n#  define SEEK_END        2       /* Set file pointer to EOF plus \"offset\" */\n#endif\n\n#ifndef z_off_t\n#  define z_off_t long\n#endif\n\n#if !defined(_WIN32) && defined(Z_LARGE64)\n#  define z_off64_t off64_t\n#else\n#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)\n#    define z_off64_t __int64\n#  else\n#    define z_off64_t z_off_t\n#  endif\n#endif\n\n/* MVS linker does not support external names larger than 8 bytes */\n#if defined(__MVS__)\n  #pragma map(deflateInit_,\"DEIN\")\n  #pragma map(deflateInit2_,\"DEIN2\")\n  #pragma map(deflateEnd,\"DEEND\")\n  #pragma map(deflateBound,\"DEBND\")\n  #pragma map(inflateInit_,\"ININ\")\n  #pragma map(inflateInit2_,\"ININ2\")\n  #pragma map(inflateEnd,\"INEND\")\n  #pragma map(inflateSync,\"INSY\")\n  #pragma map(inflateSetDictionary,\"INSEDI\")\n  #pragma map(compressBound,\"CMBND\")\n  #pragma map(inflate_table,\"INTABL\")\n  #pragma map(inflate_fast,\"INFA\")\n  #pragma map(inflate_copyright,\"INCOPY\")\n#endif\n\n#endif /* ZCONF_H */\n"
  },
  {
    "path": "include/compat/zlib/zlib.h",
    "content": "#ifndef _COMPAT_ZLIB_H\n#define _COMPAT_ZLIB_H\n\n/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.2.8, April 28th, 2013\n\n  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n\n#ifndef ZLIB_H\n#define ZLIB_H\n\n#include <stdint.h>\n#include \"zconf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZLIB_VERSION \"1.2.8\"\n#define ZLIB_VERNUM 0x1280\n#define ZLIB_VER_MAJOR 1\n#define ZLIB_VER_MINOR 2\n#define ZLIB_VER_REVISION 8\n#define ZLIB_VER_SUBREVISION 0\n\n/*\n    The 'zlib' compression library provides in-memory compression and\n  decompression functions, including integrity checks of the uncompressed data.\n  This version of the library supports only one compression method (deflation)\n  but other algorithms will be added later and will have the same stream\n  interface.\n\n    Compression can be done in a single step if the buffers are large enough,\n  or can be done by repeated calls of the compression function.  In the latter\n  case, the application must provide more input and/or consume the output\n  (providing more output space) before each call.\n\n    The compressed data format used by default by the in-memory functions is\n  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped\n  around a deflate stream, which is itself documented in RFC 1951.\n\n    The library also supports reading and writing files in gzip (.gz) format\n  with an interface similar to that of stdio using the functions that start\n  with \"gz\".  The gzip format is different from the zlib format.  gzip is a\n  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.\n\n    This library can optionally read and write gzip streams in memory as well.\n\n    The zlib format was designed to be compact and fast for use in memory\n  and on communications channels.  The gzip format was designed for single-\n  file compression on file systems, has a larger header than zlib to maintain\n  directory information, and uses a different, slower check method than zlib.\n\n    The library does not install any signal handler.  The decoder checks\n  the consistency of the compressed data, so the library should never crash\n  even in case of corrupted input.\n*/\n\ntypedef voidpf (*alloc_func) (voidpf opaque, uInt items, uInt size);\ntypedef void   (*free_func)  (voidpf opaque, voidpf address);\n\nstruct internal_state;\n\ntypedef struct z_stream_s {\n    z_const Bytef *next_in;     /* next input byte */\n    uInt     avail_in;  /* number of bytes available at next_in */\n    uLong    total_in;  /* total number of input bytes read so far */\n\n    Bytef    *next_out; /* next output byte should be put there */\n    uInt     avail_out; /* remaining free space at next_out */\n    uLong    total_out; /* total number of bytes output so far */\n\n    z_const char *msg;  /* last error message, NULL if no error */\n    void *state; /* not visible by applications */\n\n    alloc_func zalloc;  /* used to allocate the internal state */\n    free_func  zfree;   /* used to free the internal state */\n    voidpf     opaque;  /* private data object passed to zalloc and zfree */\n\n    int     data_type;  /* best guess about the data type: binary or text */\n    uLong   adler;      /* adler32 value of the uncompressed data */\n    uLong   reserved;   /* reserved for future use */\n} z_stream;\n\ntypedef z_stream FAR *z_streamp;\n\n/*\n     gzip header information passed to and from zlib routines.  See RFC 1952\n  for more details on the meanings of these fields.\n*/\ntypedef struct gz_header_s {\n    int     text;       /* true if compressed data believed to be text */\n    uLong   time;       /* modification time */\n    int     xflags;     /* extra flags (not used when writing a gzip file) */\n    int     os;         /* operating system */\n    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */\n    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */\n    uInt    extra_max;  /* space at extra (only when reading header) */\n    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */\n    uInt    name_max;   /* space at name (only when reading header) */\n    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */\n    uInt    comm_max;   /* space at comment (only when reading header) */\n    int     hcrc;       /* true if there was or will be a header crc */\n    int     done;       /* true when done reading gzip header (not used\n                           when writing a gzip file) */\n} gz_header;\n\ntypedef gz_header FAR *gz_headerp;\n\n/*\n     The application must update next_in and avail_in when avail_in has dropped\n   to zero.  It must update next_out and avail_out when avail_out has dropped\n   to zero.  The application must initialize zalloc, zfree and opaque before\n   calling the init function.  All other fields are set by the compression\n   library and must not be updated by the application.\n\n     The opaque value provided by the application will be passed as the first\n   parameter for calls of zalloc and zfree.  This can be useful for custom\n   memory management.  The compression library attaches no meaning to the\n   opaque value.\n\n     zalloc must return Z_NULL if there is not enough memory for the object.\n   If zlib is used in a multi-threaded application, zalloc and zfree must be\n   thread safe.\n\n     On 16-bit systems, the functions zalloc and zfree must be able to allocate\n   exactly 65536 bytes, but will not be required to allocate more than this if\n   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers\n   returned by zalloc for objects of exactly 65536 bytes *must* have their\n   offset normalized to zero.  The default allocation function provided by this\n   library ensures this (see zutil.c).  To reduce memory requirements and avoid\n   any allocation of 64K objects, at the expense of compression ratio, compile\n   the library with -DMAX_WBITS=14 (see zconf.h).\n\n     The fields total_in and total_out can be used for statistics or progress\n   reports.  After compression, total_in holds the total size of the\n   uncompressed data and may be saved for use in the decompressor (particularly\n   if the decompressor wants to decompress everything in a single step).\n*/\n\n                        /* constants */\n\n#define Z_NO_FLUSH      0\n#define Z_PARTIAL_FLUSH 1\n#define Z_SYNC_FLUSH    2\n#define Z_FULL_FLUSH    3\n#define Z_FINISH        4\n#define Z_BLOCK         5\n#define Z_TREES         6\n/* Allowed flush values; see deflate() and inflate() below for details */\n\n#define Z_OK            0\n#define Z_STREAM_END    1\n#define Z_NEED_DICT     2\n#define Z_ERRNO        (-1)\n#define Z_STREAM_ERROR (-2)\n#define Z_DATA_ERROR   (-3)\n#define Z_MEM_ERROR    (-4)\n#define Z_BUF_ERROR    (-5)\n#define Z_VERSION_ERROR (-6)\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\n\n#define Z_NO_COMPRESSION         0\n#define Z_BEST_SPEED             1\n#define Z_BEST_COMPRESSION       9\n#define Z_DEFAULT_COMPRESSION  (-1)\n/* compression levels */\n\n#define Z_FILTERED            1\n#define Z_HUFFMAN_ONLY        2\n#define Z_RLE                 3\n#define Z_FIXED               4\n#define Z_DEFAULT_STRATEGY    0\n/* compression strategy; see deflateInit2() below for details */\n\n#define Z_BINARY   0\n#define Z_TEXT     1\n#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */\n#define Z_UNKNOWN  2\n/* Possible values of the data_type field (though see inflate()) */\n\n#define Z_DEFLATED   8\n/* The deflate compression method (the only one supported in this version) */\n\n#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */\n\n#define zlib_version zlibVersion()\n/* for compatibility with versions < 1.0.2 */\n\n                        /* basic functions */\n\n const char * zlibVersion (void);\n/* The application can compare zlibVersion and ZLIB_VERSION for consistency.\n   If the first character differs, the library code actually used is not\n   compatible with the zlib.h header file used by the application.  This check\n   is automatically made by deflateInit and inflateInit.\n */\n\n/*\n int deflateInit (z_streamp strm, int level);\n\n     Initializes the internal stream state for compression.  The fields\n   zalloc, zfree and opaque must be initialized before by the caller.  If\n   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default\n   allocation functions.\n\n     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:\n   1 gives best speed, 9 gives best compression, 0 gives no compression at all\n   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION\n   requests a default compromise between speed and compression (currently\n   equivalent to level 6).\n\n     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if level is not a valid compression level, or\n   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible\n   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null\n   if there is no error message.  deflateInit does not perform any compression:\n   this will be done by deflate().\n*/\n\n int deflate (z_streamp strm, int flush);\n/*\n    deflate compresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n    The detailed semantics are as follows.  deflate performs one or both of the\n  following actions:\n\n  - Compress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), next_in and avail_in are updated and\n    processing will resume at this point for the next call of deflate().\n\n  - Provide more output starting at next_out and update next_out and avail_out\n    accordingly.  This action is forced if the parameter flush is non zero.\n    Forcing flush frequently degrades the compression ratio, so this parameter\n    should be set only when necessary (in interactive applications).  Some\n    output may be provided even if flush is not set.\n\n    Before the call of deflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating avail_in or avail_out accordingly; avail_out should\n  never be zero before the call.  The application can consume the compressed\n  output when it wants, for example when the output buffer is full (avail_out\n  == 0), or after each call of deflate().  If deflate returns Z_OK and with\n  zero avail_out, it must be called again after making room in the output\n  buffer because there might be more output pending.\n\n    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to\n  decide how much data to accumulate before producing output, in order to\n  maximize compression.\n\n    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is\n  flushed to the output buffer and the output is aligned on a byte boundary, so\n  that the decompressor can get all input data available so far.  (In\n  particular avail_in is zero after the call if enough output space has been\n  provided before the call.) Flushing may degrade compression for some\n  compression algorithms and so it should be used only when necessary.  This\n  completes the current deflate block and follows it with an empty stored block\n  that is three bits plus filler bits to the next byte, followed by four bytes\n  (00 00 ff ff).\n\n    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the\n  output buffer, but the output is not aligned to a byte boundary.  All of the\n  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.\n  This completes the current deflate block and follows it with an empty fixed\n  codes block that is 10 bits long.  This assures that enough bytes are output\n  in order for the decompressor to finish the block before the empty fixed code\n  block.\n\n    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as\n  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to\n  seven bits of the current block are held to be written as the next byte after\n  the next deflate block is completed.  In this case, the decompressor may not\n  be provided enough bits at this point in order to complete decompression of\n  the data provided so far to the compressor.  It may need to wait for the next\n  block to be emitted.  This is for advanced applications that need to control\n  the emission of deflate blocks.\n\n    If flush is set to Z_FULL_FLUSH, all output is flushed as with\n  Z_SYNC_FLUSH, and the compression state is reset so that decompression can\n  restart from this point if previous compressed data has been damaged or if\n  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade\n  compression.\n\n    If deflate returns with avail_out == 0, this function must be called again\n  with the same value of the flush parameter and more output space (updated\n  avail_out), until the flush is complete (deflate returns with non-zero\n  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that\n  avail_out is greater than six to avoid repeated flush markers due to\n  avail_out == 0 on return.\n\n    If the parameter flush is set to Z_FINISH, pending input is processed,\n  pending output is flushed and deflate returns with Z_STREAM_END if there was\n  enough output space; if deflate returns with Z_OK, this function must be\n  called again with Z_FINISH and more output space (updated avail_out) but no\n  more input data, until it returns with Z_STREAM_END or an error.  After\n  deflate has returned Z_STREAM_END, the only possible operations on the stream\n  are deflateReset or deflateEnd.\n\n    Z_FINISH can be used immediately after deflateInit if all the compression\n  is to be done in a single step.  In this case, avail_out must be at least the\n  value returned by deflateBound (see below).  Then deflate is guaranteed to\n  return Z_STREAM_END.  If not enough output space is provided, deflate will\n  not return Z_STREAM_END, and it must be called again as described above.\n\n    deflate() sets strm->adler to the adler32 checksum of all input read\n  so far (that is, total_in bytes).\n\n    deflate() may update strm->data_type if it can make a good guess about\n  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered\n  binary.  This field is only for information purposes and does not affect the\n  compression algorithm in any manner.\n\n    deflate() returns Z_OK if some progress has been made (more input\n  processed or more output produced), Z_STREAM_END if all input has been\n  consumed and all output has been produced (only when flush is set to\n  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example\n  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible\n  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not\n  fatal, and deflate() can be called again with more input and more output\n  space to continue compressing.\n*/\n\n int deflateEnd (z_streamp strm);\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the\n   stream state was inconsistent, Z_DATA_ERROR if the stream was freed\n   prematurely (some input or output was discarded).  In the error case, msg\n   may be set but then points to a static string (which must not be\n   deallocated).\n*/\n\n/*\n int inflateInit (z_streamp strm);\n\n     Initializes the internal stream state for decompression.  The fields\n   next_in, avail_in, zalloc, zfree and opaque must be initialized before by\n   the caller.  If next_in is not Z_NULL and avail_in is large enough (the\n   exact value depends on the compression method), inflateInit determines the\n   compression method from the zlib header and allocates all data structures\n   accordingly; otherwise the allocation will be deferred to the first call of\n   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to\n   use default allocation functions.\n\n     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit does not perform any decompression\n   apart from possibly reading the zlib header if present: actual decompression\n   will be done by inflate().  (So next_in and avail_in may be modified, but\n   next_out and avail_out are unused and unchanged.) The current implementation\n   of inflateInit() does not process any header information -- that is deferred\n   until inflate() is called.\n*/\n\n int inflate (z_streamp strm, int flush);\n/*\n    inflate decompresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n  The detailed semantics are as follows.  inflate performs one or both of the\n  following actions:\n\n  - Decompress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), next_in is updated and processing will\n    resume at this point for the next call of inflate().\n\n  - Provide more output starting at next_out and update next_out and avail_out\n    accordingly.  inflate() provides as much output as possible, until there is\n    no more input data or no more space in the output buffer (see below about\n    the flush parameter).\n\n    Before the call of inflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating the next_* and avail_* values accordingly.  The\n  application can consume the uncompressed output when it wants, for example\n  when the output buffer is full (avail_out == 0), or after each call of\n  inflate().  If inflate returns Z_OK and with zero avail_out, it must be\n  called again after making room in the output buffer because there might be\n  more output pending.\n\n    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,\n  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much\n  output as possible to the output buffer.  Z_BLOCK requests that inflate()\n  stop if and when it gets to the next deflate block boundary.  When decoding\n  the zlib or gzip format, this will cause inflate() to return immediately\n  after the header and before the first block.  When doing a raw inflate,\n  inflate() will go ahead and process the first block, and will return when it\n  gets to the end of that block, or when it runs out of data.\n\n    The Z_BLOCK option assists in appending to or combining deflate streams.\n  Also to assist in this, on return inflate() will set strm->data_type to the\n  number of unused bits in the last byte taken from strm->next_in, plus 64 if\n  inflate() is currently decoding the last block in the deflate stream, plus\n  128 if inflate() returned immediately after decoding an end-of-block code or\n  decoding the complete header up to just before the first byte of the deflate\n  stream.  The end-of-block will not be indicated until all of the uncompressed\n  data from that block has been written to strm->next_out.  The number of\n  unused bits may in general be greater than seven, except when bit 7 of\n  data_type is set, in which case the number of unused bits will be less than\n  eight.  data_type is set as noted here every time inflate() returns for all\n  flush options, and so can be used to determine the amount of currently\n  consumed input in bits.\n\n    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the\n  end of each deflate block header is reached, before any actual data in that\n  block is decoded.  This allows the caller to determine the length of the\n  deflate block header for later use in random access within a deflate block.\n  256 is added to the value of strm->data_type when inflate() returns\n  immediately after reaching the end of the deflate block header.\n\n    inflate() should normally be called until it returns Z_STREAM_END or an\n  error.  However if all decompression is to be performed in a single step (a\n  single call of inflate), the parameter flush should be set to Z_FINISH.  In\n  this case all pending input is processed and all pending output is flushed;\n  avail_out must be large enough to hold all of the uncompressed data for the\n  operation to complete.  (The size of the uncompressed data may have been\n  saved by the compressor for this purpose.) The use of Z_FINISH is not\n  required to perform an inflation in one step.  However it may be used to\n  inform inflate that a faster approach can be used for the single inflate()\n  call.  Z_FINISH also informs inflate to not maintain a sliding window if the\n  stream completes, which reduces inflate's memory footprint.  If the stream\n  does not complete, either because not all of the stream is provided or not\n  enough output space is provided, then a sliding window will be allocated and\n  inflate() can be called again to continue the operation as if Z_NO_FLUSH had\n  been used.\n\n     In this implementation, inflate() always flushes as much output as\n  possible to the output buffer, and always uses the faster approach on the\n  first call.  So the effects of the flush parameter in this implementation are\n  on the return value of inflate() as noted below, when inflate() returns early\n  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of\n  memory for a sliding window when Z_FINISH is used.\n\n     If a preset dictionary is needed after this call (see inflateSetDictionary\n  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary\n  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets\n  strm->adler to the Adler-32 checksum of all output produced so far (that is,\n  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described\n  below.  At the end of the stream, inflate() checks that its computed adler32\n  checksum is equal to that saved by the compressor and returns Z_STREAM_END\n  only if the checksum is correct.\n\n    inflate() can decompress and check either zlib-wrapped or gzip-wrapped\n  deflate data.  The header type is detected automatically, if requested when\n  initializing with inflateInit2().  Any information contained in the gzip\n  header is not retained, so applications that need that information should\n  instead use raw inflate, see inflateInit2() below, or inflateBack() and\n  perform their own processing of the gzip header and trailer.  When processing\n  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output\n  produced so far.  The CRC-32 is checked against the gzip trailer.\n\n    inflate() returns Z_OK if some progress has been made (more input processed\n  or more output produced), Z_STREAM_END if the end of the compressed data has\n  been reached and all uncompressed output has been produced, Z_NEED_DICT if a\n  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was\n  corrupted (input stream not conforming to the zlib format or incorrect check\n  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example\n  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,\n  Z_BUF_ERROR if no progress is possible or if there was not enough room in the\n  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and\n  inflate() can be called again with more input and more output space to\n  continue decompressing.  If Z_DATA_ERROR is returned, the application may\n  then call inflateSync() to look for a good compression block if a partial\n  recovery of the data is desired.\n*/\n\n int inflateEnd (z_streamp strm);\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state\n   was inconsistent.  In the error case, msg may be set but then points to a\n   static string (which must not be deallocated).\n*/\n\n                        /* Advanced functions */\n\n/*\n    The following functions are needed only in some special applications.\n*/\n\n/*\n int deflateInit2 (z_streamp strm,\n                                     int  level,\n                                     int  method,\n                                     int  windowBits,\n                                     int  memLevel,\n                                     int  strategy);\n\n     This is another version of deflateInit with more compression options.  The\n   fields next_in, zalloc, zfree and opaque must be initialized before by the\n   caller.\n\n     The method parameter is the compression method.  It must be Z_DEFLATED in\n   this version of the library.\n\n     The windowBits parameter is the base two logarithm of the window size\n   (the size of the history buffer).  It should be in the range 8..15 for this\n   version of the library.  Larger values of this parameter result in better\n   compression at the expense of memory usage.  The default value is 15 if\n   deflateInit is used instead.\n\n     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits\n   determines the window size.  deflate() will then generate raw deflate data\n   with no zlib header or trailer, and will not compute an adler32 check value.\n\n     windowBits can also be greater than 15 for optional gzip encoding.  Add\n   16 to windowBits to write a simple gzip header and trailer around the\n   compressed data instead of a zlib wrapper.  The gzip header will have no\n   file name, no extra data, no comment, no modification time (set to zero), no\n   header crc, and the operating system will be set to 255 (unknown).  If a\n   gzip stream is being written, strm->adler is a crc32 instead of an adler32.\n\n     The memLevel parameter specifies how much memory should be allocated\n   for the internal compression state.  memLevel=1 uses minimum memory but is\n   slow and reduces compression ratio; memLevel=9 uses maximum memory for\n   optimal speed.  The default value is 8.  See zconf.h for total memory usage\n   as a function of windowBits and memLevel.\n\n     The strategy parameter is used to tune the compression algorithm.  Use the\n   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a\n   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no\n   string match), or Z_RLE to limit match distances to one (run-length\n   encoding).  Filtered data consists mostly of small values with a somewhat\n   random distribution.  In this case, the compression algorithm is tuned to\n   compress them better.  The effect of Z_FILTERED is to force more Huffman\n   coding and less string matching; it is somewhat intermediate between\n   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as\n   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The\n   strategy parameter only affects the compression ratio but not the\n   correctness of the compressed output even if it is not set appropriately.\n   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler\n   decoder for special applications.\n\n     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid\n   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is\n   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is\n   set to null if there is no error message.  deflateInit2 does not perform any\n   compression: this will be done by deflate().\n*/\n\n int deflateSetDictionary (z_streamp strm,\n                                             const Bytef *dictionary,\n                                             uInt  dictLength);\n/*\n     Initializes the compression dictionary from the given byte sequence\n   without producing any compressed output.  When using the zlib format, this\n   function must be called immediately after deflateInit, deflateInit2 or\n   deflateReset, and before any call of deflate.  When doing raw deflate, this\n   function must be called either before any call of deflate, or immediately\n   after the completion of a deflate block, i.e. after all input has been\n   consumed and all output has been delivered when using any of the flush\n   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The\n   compressor and decompressor must use exactly the same dictionary (see\n   inflateSetDictionary).\n\n     The dictionary should consist of strings (byte sequences) that are likely\n   to be encountered later in the data to be compressed, with the most commonly\n   used strings preferably put towards the end of the dictionary.  Using a\n   dictionary is most useful when the data to be compressed is short and can be\n   predicted with good accuracy; the data can then be compressed better than\n   with the default empty dictionary.\n\n     Depending on the size of the compression data structures selected by\n   deflateInit or deflateInit2, a part of the dictionary may in effect be\n   discarded, for example if the dictionary is larger than the window size\n   provided in deflateInit or deflateInit2.  Thus the strings most likely to be\n   useful should be put at the end of the dictionary, not at the front.  In\n   addition, the current implementation of deflate will use at most the window\n   size minus 262 bytes of the provided dictionary.\n\n     Upon return of this function, strm->adler is set to the adler32 value\n   of the dictionary; the decompressor may later use this value to determine\n   which dictionary has been used by the compressor.  (The adler32 value\n   applies to the whole dictionary even if only a subset of the dictionary is\n   actually used by the compressor.) If a raw deflate was requested, then the\n   adler32 value is not computed and strm->adler is not set.\n\n     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent (for example if deflate has already been called for this stream\n   or if not at a block boundary for raw deflate).  deflateSetDictionary does\n   not perform any compression: this will be done by deflate().\n*/\n\n int deflateCopy (z_streamp dest,\n                                    z_streamp source);\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when several compression strategies will be\n   tried, for example when there are several ways of pre-processing the input\n   data with a filter.  The streams that will be discarded should then be freed\n   by calling deflateEnd.  Note that deflateCopy duplicates the internal\n   compression state which can be quite large, so this strategy is slow and can\n   consume lots of memory.\n\n     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\n int deflateReset (z_streamp strm);\n/*\n     This function is equivalent to deflateEnd followed by deflateInit,\n   but does not free and reallocate all the internal compression state.  The\n   stream will keep the same compression level and any other attributes that\n   may have been set by deflateInit2.\n\n     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\n int deflateParams (z_streamp strm,\n                                      int level,\n                                      int strategy);\n/*\n     Dynamically update the compression level and compression strategy.  The\n   interpretation of level and strategy is as in deflateInit2.  This can be\n   used to switch between compression and straight copy of the input data, or\n   to switch to a different kind of input data requiring a different strategy.\n   If the compression level is changed, the input available so far is\n   compressed with the old level (and may be flushed); the new level will take\n   effect only at the next call of deflate().\n\n     Before the call of deflateParams, the stream state must be set as for\n   a call of deflate(), since the currently available input may have to be\n   compressed and flushed.  In particular, strm->avail_out must be non-zero.\n\n     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source\n   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if\n   strm->avail_out was zero.\n*/\n\n int deflateTune (z_streamp strm,\n                                    int good_length,\n                                    int max_lazy,\n                                    int nice_length,\n                                    int max_chain);\n/*\n     Fine tune deflate's internal compression parameters.  This should only be\n   used by someone who understands the algorithm used by zlib's deflate for\n   searching for the best matching string, and even then only by the most\n   fanatic optimizer trying to squeeze out the last compressed bit for their\n   specific input data.  Read the deflate.c source code for the meaning of the\n   max_lazy, good_length, nice_length, and max_chain parameters.\n\n     deflateTune() can be called after deflateInit() or deflateInit2(), and\n   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.\n */\n\n uLong deflateBound (z_streamp strm,\n                                       uLong sourceLen);\n/*\n     deflateBound() returns an upper bound on the compressed size after\n   deflation of sourceLen bytes.  It must be called after deflateInit() or\n   deflateInit2(), and after deflateSetHeader(), if used.  This would be used\n   to allocate an output buffer for deflation in a single pass, and so would be\n   called before deflate().  If that first deflate() call is provided the\n   sourceLen input bytes, an output buffer allocated to the size returned by\n   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed\n   to return Z_STREAM_END.  Note that it is possible for the compressed size to\n   be larger than the value returned by deflateBound() if flush options other\n   than Z_FINISH or Z_NO_FLUSH are used.\n*/\n\n int deflatePending (z_streamp strm,\n                                       unsigned *pending,\n                                       int *bits);\n/*\n     deflatePending() returns the number of bytes and bits of output that have\n   been generated, but not yet provided in the available output.  The bytes not\n   provided would be due to the available output space having being consumed.\n   The number of bits of output not provided are between 0 and 7, where they\n   await more bits to join them in order to fill out a full byte.  If pending\n   or bits are Z_NULL, then those values are not set.\n\n     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n */\n\n int deflatePrime (z_streamp strm,\n                                     int bits,\n                                     int value);\n/*\n     deflatePrime() inserts bits in the deflate output stream.  The intent\n   is that this function is used to start off the deflate output with the bits\n   leftover from a previous deflate stream when appending to it.  As such, this\n   function can only be used for raw deflate, and must be used before the first\n   deflate() call after a deflateInit2() or deflateReset().  bits must be less\n   than or equal to 16, and that many of the least significant bits of value\n   will be inserted in the output.\n\n     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough\n   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the\n   source stream state was inconsistent.\n*/\n\n int deflateSetHeader (z_streamp strm,\n                                         gz_headerp head);\n/*\n     deflateSetHeader() provides gzip header information for when a gzip\n   stream is requested by deflateInit2().  deflateSetHeader() may be called\n   after deflateInit2() or deflateReset() and before the first call of\n   deflate().  The text, time, os, extra field, name, and comment information\n   in the provided gz_header structure are written to the gzip header (xflag is\n   ignored -- the extra flags are set according to the compression level).  The\n   caller must assure that, if not Z_NULL, name and comment are terminated with\n   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are\n   available there.  If hcrc is true, a gzip header crc is included.  Note that\n   the current versions of the command-line version of gzip (up through version\n   1.3.x) do not support header crc's, and will report that it is a \"multi-part\n   gzip file\" and give up.\n\n     If deflateSetHeader is not used, the default gzip header has text false,\n   the time set to zero, and os set to 255, with no extra, name, or comment\n   fields.  The gzip header is returned to the default state by deflateReset().\n\n     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\n int inflateInit2 (z_streamp strm,\n                                     int  windowBits);\n\n     This is another version of inflateInit with an extra parameter.  The\n   fields next_in, avail_in, zalloc, zfree and opaque must be initialized\n   before by the caller.\n\n     The windowBits parameter is the base two logarithm of the maximum window\n   size (the size of the history buffer).  It should be in the range 8..15 for\n   this version of the library.  The default value is 15 if inflateInit is used\n   instead.  windowBits must be greater than or equal to the windowBits value\n   provided to deflateInit2() while compressing, or it must be equal to 15 if\n   deflateInit2() was not used.  If a compressed stream with a larger window\n   size is given as input, inflate() will return with the error code\n   Z_DATA_ERROR instead of trying to allocate a larger window.\n\n     windowBits can also be zero to request that inflate use the window size in\n   the zlib header of the compressed stream.\n\n     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits\n   determines the window size.  inflate() will then process raw deflate data,\n   not looking for a zlib or gzip header, not generating a check value, and not\n   looking for any check values for comparison at the end of the stream.  This\n   is for use with other formats that use the deflate compressed data format\n   such as zip.  Those formats provide their own check values.  If a custom\n   format is developed using the raw deflate format for compressed data, it is\n   recommended that a check value such as an adler32 or a crc32 be applied to\n   the uncompressed data as is done in the zlib, gzip, and zip formats.  For\n   most applications, the zlib format should be used as is.  Note that comments\n   above on the use in deflateInit2() applies to the magnitude of windowBits.\n\n     windowBits can also be greater than 15 for optional gzip decoding.  Add\n   32 to windowBits to enable zlib and gzip decoding with automatic header\n   detection, or add 16 to decode only the gzip format (the zlib format will\n   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a\n   crc32 instead of an adler32.\n\n     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit2 does not perform any decompression\n   apart from possibly reading the zlib header if present: actual decompression\n   will be done by inflate().  (So next_in and avail_in may be modified, but\n   next_out and avail_out are unused and unchanged.) The current implementation\n   of inflateInit2() does not process any header information -- that is\n   deferred until inflate() is called.\n*/\n\n int inflateSetDictionary (z_streamp strm,\n                                             const Bytef *dictionary,\n                                             uInt  dictLength);\n/*\n     Initializes the decompression dictionary from the given uncompressed byte\n   sequence.  This function must be called immediately after a call of inflate,\n   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor\n   can be determined from the adler32 value returned by that call of inflate.\n   The compressor and decompressor must use exactly the same dictionary (see\n   deflateSetDictionary).  For raw inflate, this function can be called at any\n   time to set the dictionary.  If the provided dictionary is smaller than the\n   window and there is already data in the window, then the provided dictionary\n   will amend what's there.  The application must insure that the dictionary\n   that was used for compression is provided.\n\n     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the\n   expected one (incorrect adler32 value).  inflateSetDictionary does not\n   perform any decompression: this will be done by subsequent calls of\n   inflate().\n*/\n\n int inflateGetDictionary (z_streamp strm,\n                                             Bytef *dictionary,\n                                             uInt  *dictLength);\n/*\n     Returns the sliding dictionary being maintained by inflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If inflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similarly, if dictLength is Z_NULL, then it is not set.\n\n     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\n int inflateSync (z_streamp strm);\n/*\n     Skips invalid compressed data until a possible full flush point (see above\n   for the description of deflate with Z_FULL_FLUSH) can be found, or until all\n   available input is skipped.  No output is provided.\n\n     inflateSync searches for a 00 00 FF FF pattern in the compressed data.\n   All full flush points have this pattern, but not all occurrences of this\n   pattern are full flush points.\n\n     inflateSync returns Z_OK if a possible full flush point has been found,\n   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point\n   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.\n   In the success case, the application may save the current current value of\n   total_in which indicates where valid compressed data was found.  In the\n   error case, the application may repeatedly call inflateSync, providing more\n   input each time, until success or end of the input data.\n*/\n\n int inflateCopy (z_streamp dest,\n                                    z_streamp source);\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when randomly accessing a large stream.  The\n   first pass through the stream can periodically record the inflate state,\n   allowing restarting inflate at those points when randomly accessing the\n   stream.\n\n     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\n int inflateReset (z_streamp strm);\n/*\n     This function is equivalent to inflateEnd followed by inflateInit,\n   but does not free and reallocate all the internal decompression state.  The\n   stream will keep attributes that may have been set by inflateInit2.\n\n     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\n int inflateReset2 (z_streamp strm,\n                                      int windowBits);\n/*\n     This function is the same as inflateReset, but it also permits changing\n   the wrap and window size requests.  The windowBits parameter is interpreted\n   the same as it is for inflateInit2.\n\n     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL), or if\n   the windowBits parameter is invalid.\n*/\n\n int inflatePrime (z_streamp strm,\n                                     int bits,\n                                     int value);\n/*\n     This function inserts bits in the inflate input stream.  The intent is\n   that this function is used to start inflating at a bit position in the\n   middle of a byte.  The provided bits will be used before any bytes are used\n   from next_in.  This function should only be used with raw inflate, and\n   should be used before the first inflate() call after inflateInit2() or\n   inflateReset().  bits must be less than or equal to 16, and that many of the\n   least significant bits of value will be inserted in the input.\n\n     If bits is negative, then the input stream bit buffer is emptied.  Then\n   inflatePrime() can be called again to put bits in the buffer.  This is used\n   to clear out bits leftover after feeding inflate a block description prior\n   to feeding inflate codes.\n\n     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n long  inflateMark (z_streamp strm);\n/*\n     This function returns two values, one in the lower 16 bits of the return\n   value, and the other in the remaining upper bits, obtained by shifting the\n   return value down 16 bits.  If the upper value is -1 and the lower value is\n   zero, then inflate() is currently decoding information outside of a block.\n   If the upper value is -1 and the lower value is non-zero, then inflate is in\n   the middle of a stored block, with the lower value equaling the number of\n   bytes from the input remaining to copy.  If the upper value is not -1, then\n   it is the number of bits back from the current bit position in the input of\n   the code (literal or length/distance pair) currently being processed.  In\n   that case the lower value is the number of bytes already emitted for that\n   code.\n\n     A code is being processed if inflate is waiting for more input to complete\n   decoding of the code, or if it has completed decoding but is waiting for\n   more output space to write the literal or match data.\n\n     inflateMark() is used to mark locations in the input data for random\n   access, which may be at bit positions, and to note those cases where the\n   output of a code may span boundaries of random access blocks.  The current\n   location in the input stream can be determined from avail_in and data_type\n   as noted in the description for the Z_BLOCK flush parameter for inflate.\n\n     inflateMark returns the value noted above or -1 << 16 if the provided\n   source stream state was inconsistent.\n*/\n\n int  inflateGetHeader (z_streamp strm,\n                                         gz_headerp head);\n/*\n     inflateGetHeader() requests that gzip header information be stored in the\n   provided gz_header structure.  inflateGetHeader() may be called after\n   inflateInit2() or inflateReset(), and before the first call of inflate().\n   As inflate() processes the gzip stream, head->done is zero until the header\n   is completed, at which time head->done is set to one.  If a zlib stream is\n   being decoded, then head->done is set to -1 to indicate that there will be\n   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be\n   used to force inflate() to return immediately after header processing is\n   complete and before any actual data is decompressed.\n\n     The text, time, xflags, and os fields are filled in with the gzip header\n   contents.  hcrc is set to true if there is a header CRC.  (The header CRC\n   was valid if done is set to one.) If extra is not Z_NULL, then extra_max\n   contains the maximum number of bytes to write to extra.  Once done is true,\n   extra_len contains the actual extra field length, and extra contains the\n   extra field, or that field truncated if extra_max is less than extra_len.\n   If name is not Z_NULL, then up to name_max characters are written there,\n   terminated with a zero unless the length is greater than name_max.  If\n   comment is not Z_NULL, then up to comm_max characters are written there,\n   terminated with a zero unless the length is greater than comm_max.  When any\n   of extra, name, or comment are not Z_NULL and the respective field is not\n   present in the header, then that field is set to Z_NULL to signal its\n   absence.  This allows the use of deflateSetHeader() with the returned\n   structure to duplicate the header.  However if those fields are set to\n   allocated memory, then the application will need to save those pointers\n   elsewhere so that they can be eventually freed.\n\n     If inflateGetHeader is not used, then the header information is simply\n   discarded.  The header is always checked for validity, including the header\n   CRC if present.  inflateReset() will reset the process to discard the header\n   information.  The application would need to call inflateGetHeader() again to\n   retrieve the header from the next gzip stream.\n\n     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\n int  inflateBackInit (z_streamp strm, int windowBits,\n                                        unsigned char FAR *window);\n\n     Initialize the internal stream state for decompression using inflateBack()\n   calls.  The fields zalloc, zfree and opaque in strm must be initialized\n   before the call.  If zalloc and zfree are Z_NULL, then the default library-\n   derived memory allocation routines are used.  windowBits is the base two\n   logarithm of the window size, in the range 8..15.  window is a caller\n   supplied buffer of that size.  Except for special applications where it is\n   assured that deflate was used with small window sizes, windowBits must be 15\n   and a 32K byte window must be supplied to be able to decompress general\n   deflate streams.\n\n     See inflateBack() for the usage of these routines.\n\n     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of\n   the parameters are invalid, Z_MEM_ERROR if the internal state could not be\n   allocated, or Z_VERSION_ERROR if the version of the library does not match\n   the version of the header file.\n*/\n\ntypedef unsigned (*in_func) (void FAR *,\n                                z_const unsigned char FAR * FAR *);\ntypedef int (*out_func) (void FAR *, unsigned char FAR *, unsigned);\n\n int  inflateBack (z_streamp strm,\n                                    in_func in, void FAR *in_desc,\n                                    out_func out, void FAR *out_desc);\n/*\n     inflateBack() does a raw inflate with a single call using a call-back\n   interface for input and output.  This is potentially more efficient than\n   inflate() for file i/o applications, in that it avoids copying between the\n   output and the sliding window by simply making the window itself the output\n   buffer.  inflate() can be faster on modern CPUs when used with large\n   buffers.  inflateBack() trusts the application to not change the output\n   buffer passed by the output function, at least until inflateBack() returns.\n\n     inflateBackInit() must be called first to allocate the internal state\n   and to initialize the state with the user-provided window buffer.\n   inflateBack() may then be used multiple times to inflate a complete, raw\n   deflate stream with each call.  inflateBackEnd() is then called to free the\n   allocated state.\n\n     A raw deflate stream is one with no zlib or gzip header or trailer.\n   This routine would normally be used in a utility that reads zip or gzip\n   files and writes out uncompressed files.  The utility would decode the\n   header and process the trailer on its own, hence this routine expects only\n   the raw deflate stream to decompress.  This is different from the normal\n   behavior of inflate(), which expects either a zlib or gzip header and\n   trailer around the deflate stream.\n\n     inflateBack() uses two subroutines supplied by the caller that are then\n   called by inflateBack() for input and output.  inflateBack() calls those\n   routines until it reads a complete deflate stream and writes out all of the\n   uncompressed data, or until it encounters an error.  The function's\n   parameters and return types are defined above in the in_func and out_func\n   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the\n   number of bytes of provided input, and a pointer to that input in buf.  If\n   there is no input available, in() must return zero--buf is ignored in that\n   case--and inflateBack() will return a buffer error.  inflateBack() will call\n   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()\n   should return zero on success, or non-zero on failure.  If out() returns\n   non-zero, inflateBack() will return with an error.  Neither in() nor out()\n   are permitted to change the contents of the window provided to\n   inflateBackInit(), which is also the buffer that out() uses to write from.\n   The length written by out() will be at most the window size.  Any non-zero\n   amount of input may be provided by in().\n\n     For convenience, inflateBack() can be provided input on the first call by\n   setting strm->next_in and strm->avail_in.  If that input is exhausted, then\n   in() will be called.  Therefore strm->next_in must be initialized before\n   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called\n   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in\n   must also be initialized, and then if strm->avail_in is not zero, input will\n   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].\n\n     The in_desc and out_desc parameters of inflateBack() is passed as the\n   first parameter of in() and out() respectively when they are called.  These\n   descriptors can be optionally used to pass any information that the caller-\n   supplied in() and out() functions need to do their job.\n\n     On return, inflateBack() will set strm->next_in and strm->avail_in to\n   pass back any unused input that was provided by the last in() call.  The\n   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR\n   if in() or out() returned an error, Z_DATA_ERROR if there was a format error\n   in the deflate stream (in which case strm->msg is set to indicate the nature\n   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.\n   In the case of Z_BUF_ERROR, an input or output error can be distinguished\n   using strm->next_in which will be Z_NULL only if in() returned an error.  If\n   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning\n   non-zero.  (in() will always be called before out(), so strm->next_in is\n   assured to be defined if out() returns non-zero.) Note that inflateBack()\n   cannot return Z_OK.\n*/\n\n int  inflateBackEnd (z_streamp strm);\n/*\n     All memory allocated by inflateBackInit() is freed.\n\n     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream\n   state was inconsistent.\n*/\n\n uLong  zlibCompileFlags (void);\n/* Return flags indicating compile-time options.\n\n    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:\n     1.0: size of uInt\n     3.2: size of uLong\n     5.4: size of voidpf (pointer)\n     7.6: size of z_off_t\n\n    Compiler, assembler, and debug options:\n     8: DEBUG\n     9: ASMV or ASMINF -- use ASM code\n     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention\n     11: 0 (reserved)\n\n    One-time table building (smaller code, but not thread-safe if true):\n     12: BUILDFIXED -- build static block decoding tables when needed\n     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed\n     14,15: 0 (reserved)\n\n    Library content (indicates missing functionality):\n     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking\n                          deflate code when not needed)\n     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect\n                    and decode gzip streams (to avoid linking crc code)\n     18-19: 0 (reserved)\n\n    Operation variations (changes in library functionality):\n     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate\n     21: FASTEST -- deflate algorithm with only one, lowest compression level\n     22,23: 0 (reserved)\n\n    The sprintf variant used by gzprintf (zero is best):\n     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format\n     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!\n     26: 0 = returns value, 1 = void -- 1 means inferred string length returned\n\n    Remainder:\n     27-31: 0 (reserved)\n */\n\n#ifndef Z_SOLO\n\n                        /* utility functions */\n\n/*\n     The following utility functions are implemented on top of the basic\n   stream-oriented functions.  To simplify the interface, some default options\n   are assumed (compression level and memory usage, standard memory allocation\n   functions).  The source code of these utility functions can be modified if\n   you need special options.\n*/\n\n int  compress (Bytef *dest,   uLongf *destLen,\n                                 const Bytef *source, uLong sourceLen);\n/*\n     Compresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed buffer.\n\n     compress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer.\n*/\n\n int  compress2 (Bytef *dest,   uLongf *destLen,\n                                  const Bytef *source, uLong sourceLen,\n                                  int level);\n/*\n     Compresses the source buffer into the destination buffer.  The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer.  Upon entry, destLen is the total size of the\n   destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed buffer.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\n\n uLong  compressBound (uLong sourceLen);\n/*\n     compressBound() returns an upper bound on the compressed size after\n   compress() or compress2() on sourceLen bytes.  It would be used before a\n   compress() or compress2() call to allocate the destination buffer.\n*/\n\n int  uncompress (unsigned char *dest,   uLongf *destLen,\n       const unsigned char *source, uint32_t sourceLen);\n/*\n     Decompresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be large enough to hold the entire\n   uncompressed data.  (The size of the uncompressed data must have been saved\n   previously by the compressor and transmitted to the decompressor by some\n   mechanism outside the scope of this compression library.) Upon exit, destLen\n   is the actual size of the uncompressed buffer.\n\n     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In\n   the case where there is not enough room, uncompress() will fill the output\n   buffer with the uncompressed data up to that point.\n*/\n\n                        /* gzip file access functions */\n\n/*\n     This library supports reading and writing files in gzip (.gz) format with\n   an interface similar to that of stdio, using the functions that start with\n   \"gz\".  The gzip format is different from the zlib format.  gzip is a gzip\n   wrapper, documented in RFC 1952, wrapped around a deflate stream.\n*/\n\ntypedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */\n\n/*\n gzFile  gzopen (const char *path, const char *mode);\n\n     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as\n   in fopen (\"rb\" or \"wb\") but can also include a compression level (\"wb9\") or\n   a strategy: 'f' for filtered data as in \"wb6f\", 'h' for Huffman-only\n   compression as in \"wb1h\", 'R' for run-length encoding as in \"wb1R\", or 'F'\n   for fixed code compression as in \"wb9F\".  (See the description of\n   deflateInit2 for more information about the strategy parameter.)  'T' will\n   request transparent writing or appending with no compression and not using\n   the gzip format.\n\n     \"a\" can be used instead of \"w\" to request that the gzip stream that will\n   be written be appended to the file.  \"+\" will result in an error, since\n   reading and writing to the same gzip file is not supported.  The addition of\n   \"x\" when writing will create the file exclusively, which fails if the file\n   already exists.  On systems that support it, the addition of \"e\" when\n   reading or writing will set the flag to close the file on an execve() call.\n\n     These functions, as well as gzip, will read and decode a sequence of gzip\n   streams in a file.  The append function of gzopen() can be used to create\n   such a file.  (Also see gzflush() for another way to do this.)  When\n   appending, gzopen does not test whether the file begins with a gzip stream,\n   nor does it look for the end of the gzip streams to begin appending.  gzopen\n   will simply append a gzip stream to the existing file.\n\n     gzopen can be used to read a file which is not in gzip format; in this\n   case gzread will directly read from the file without decompression.  When\n   reading, this will be detected automatically by looking for the magic two-\n   byte gzip header.\n\n     gzopen returns NULL if the file could not be opened, if there was\n   insufficient memory to allocate the gzFile state, or if an invalid mode was\n   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).\n   errno can be checked to determine if the reason gzopen failed was that the\n   file could not be opened.\n*/\n\n gzFile  gzdopen (int fd, const char *mode);\n/*\n     gzdopen associates a gzFile with the file descriptor fd.  File descriptors\n   are obtained from calls like open, dup, creat, pipe or fileno (if the file\n   has been previously opened with fopen).  The mode parameter is as in gzopen.\n\n     The next call of gzclose on the returned gzFile will also close the file\n   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor\n   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,\n   mode);.  The duplicated descriptor should be saved to avoid a leak, since\n   gzdopen does not close fd if it fails.  If you are using fileno() to get the\n   file descriptor from a FILE *, then you will have to use dup() to avoid\n   double-close()ing the file descriptor.  Both gzclose() and fclose() will\n   close the associated file descriptor, so they need to have different file\n   descriptors.\n\n     gzdopen returns NULL if there was insufficient memory to allocate the\n   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not\n   provided, or '+' was provided), or if fd is -1.  The file descriptor is not\n   used until the next gz* read, write, seek, or close operation, so gzdopen\n   will not detect if fd is invalid (unless fd is -1).\n*/\n\n int  gzbuffer (gzFile file, unsigned size);\n/*\n     Set the internal buffer size used by this library's functions.  The\n   default buffer size is 8192 bytes.  This function must be called after\n   gzopen() or gzdopen(), and before any other calls that read or write the\n   file.  The buffer memory allocation is always deferred to the first read or\n   write.  Two buffers are allocated, either both of the specified size when\n   writing, or one of the specified size and the other twice that size when\n   reading.  A larger buffer size of, for example, 64K or 128K bytes will\n   noticeably increase the speed of decompression (reading).\n\n     The new buffer size also affects the maximum length for gzprintf().\n\n     gzbuffer() returns 0 on success, or -1 on failure, such as being called\n   too late.\n*/\n\n int  gzsetparams (gzFile file, int level, int strategy);\n/*\n     Dynamically update the compression level or strategy.  See the description\n   of deflateInit2 for the meaning of these parameters.\n\n     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not\n   opened for writing.\n*/\n\n int  gzread (gzFile file, voidp buf, unsigned len);\n/*\n     Reads the given number of uncompressed bytes from the compressed file.  If\n   the input file is not in gzip format, gzread copies the given number of\n   bytes into the buffer directly from the file.\n\n     After reaching the end of a gzip stream in the input, gzread will continue\n   to read, looking for another gzip stream.  Any number of gzip streams may be\n   concatenated in the input file, and will all be decompressed by gzread().\n   If something other than a gzip stream is encountered after a gzip stream,\n   that remaining trailing garbage is ignored (and no error is returned).\n\n     gzread can be used to read a gzip file that is being concurrently written.\n   Upon reaching the end of the input, gzread will return with the available\n   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then\n   gzclearerr can be used to clear the end of file indicator in order to permit\n   gzread to be tried again.  Z_OK indicates that a gzip stream was completed\n   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the\n   middle of a gzip stream.  Note that gzread does not return -1 in the event\n   of an incomplete gzip stream.  This error is deferred until gzclose(), which\n   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip\n   stream.  Alternatively, gzerror can be used before gzclose to detect this\n   case.\n\n     gzread returns the number of uncompressed bytes actually read, less than\n   len for end of file, or -1 for error.\n*/\n\n int  gzwrite (gzFile file,\n                                voidpc buf, unsigned len);\n/*\n     Writes the given number of uncompressed bytes into the compressed file.\n   gzwrite returns the number of uncompressed bytes written or 0 in case of\n   error.\n*/\n\n int gzprintf Z_ARG((gzFile file, const char *format, ...));\n/*\n     Converts, formats, and writes the arguments to the compressed file under\n   control of the format string, as in fprintf.  gzprintf returns the number of\n   uncompressed bytes actually written, or 0 in case of error.  The number of\n   uncompressed bytes written is limited to 8191, or one less than the buffer\n   size given to gzbuffer().  The caller should assure that this limit is not\n   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with\n   nothing written.  In this case, there may also be a buffer overflow with\n   unpredictable consequences, which is possible only if zlib was compiled with\n   the insecure functions sprintf() or vsprintf() because the secure snprintf()\n   or vsnprintf() functions were not available.  This can be determined using\n   zlibCompileFlags().\n*/\n\n int  gzputs (gzFile file, const char *s);\n/*\n     Writes the given null-terminated string to the compressed file, excluding\n   the terminating null character.\n\n     gzputs returns the number of characters written, or -1 in case of error.\n*/\n\n char *  gzgets (gzFile file, char *buf, int len);\n/*\n     Reads bytes from the compressed file until len-1 characters are read, or a\n   newline character is read and transferred to buf, or an end-of-file\n   condition is encountered.  If any characters are read or if len == 1, the\n   string is terminated with a null character.  If no characters are read due\n   to an end-of-file or len < 1, then the buffer is left untouched.\n\n     gzgets returns buf which is a null-terminated string, or it returns NULL\n   for end-of-file or in case of error.  If there was an error, the contents at\n   buf are indeterminate.\n*/\n\n int  gzputc (gzFile file, int c);\n/*\n     Writes c, converted to an unsigned char, into the compressed file.  gzputc\n   returns the value that was written, or -1 in case of error.\n*/\n\n int  gzgetc (gzFile file);\n/*\n     Reads one byte from the compressed file.  gzgetc returns this byte or -1\n   in case of end of file or error.  This is implemented as a macro for speed.\n   As such, it does not do all of the checking the other functions do.  I.e.\n   it does not check to see if file is NULL, nor whether the structure file\n   points to has been clobbered or not.\n*/\n\n int  gzungetc (int c, gzFile file);\n/*\n     Push one character back onto the stream to be read as the first character\n   on the next read.  At least one character of push-back is allowed.\n   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will\n   fail if c is -1, and may fail if a character has been pushed but not read\n   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the\n   output buffer size of pushed characters is allowed.  (See gzbuffer above.)\n   The pushed character will be discarded if the stream is repositioned with\n   gzseek() or gzrewind().\n*/\n\n int  gzflush (gzFile file, int flush);\n/*\n     Flushes all pending output into the compressed file.  The parameter flush\n   is as in the deflate() function.  The return value is the zlib error number\n   (see function gzerror below).  gzflush is only permitted when writing.\n\n     If the flush parameter is Z_FINISH, the remaining data is written and the\n   gzip stream is completed in the output.  If gzwrite() is called again, a new\n   gzip stream will be started in the output.  gzread() is able to read such\n   concatenated gzip streams.\n\n     gzflush should be called only when strictly necessary because it will\n   degrade compression if called too often.\n*/\n\n/*\n z_off_t  gzseek (gzFile file,\n                                   z_off_t offset, int whence);\n\n     Sets the starting position for the next gzread or gzwrite on the given\n   compressed file.  The offset represents a number of bytes in the\n   uncompressed data stream.  The whence parameter is defined as in lseek(2);\n   the value SEEK_END is not supported.\n\n     If the file is opened for reading, this function is emulated but can be\n   extremely slow.  If the file is opened for writing, only forward seeks are\n   supported; gzseek then compresses a sequence of zeroes up to the new\n   starting position.\n\n     gzseek returns the resulting offset location as measured in bytes from\n   the beginning of the uncompressed stream, or -1 in case of error, in\n   particular if the file is opened for writing and the new starting position\n   would be before the current position.\n*/\n\n int     gzrewind (gzFile file);\n/*\n     Rewinds the given file. This function is supported only for reading.\n\n     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)\n*/\n\n/*\n z_off_t     gztell (gzFile file);\n\n     Returns the starting position for the next gzread or gzwrite on the given\n   compressed file.  This position represents a number of bytes in the\n   uncompressed data stream, and is zero when starting, even if appending or\n   reading a gzip stream from the middle of a file using gzdopen().\n\n     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)\n*/\n\n/*\n z_off_t  gzoffset (gzFile file);\n\n     Returns the current offset in the file being read or written.  This offset\n   includes the count of bytes that precede the gzip stream, for example when\n   appending or when using gzdopen() for reading.  When reading, the offset\n   does not include as yet unused buffered input.  This information can be used\n   for a progress indicator.  On error, gzoffset() returns -1.\n*/\n\n int  gzeof (gzFile file);\n/*\n     Returns true (1) if the end-of-file indicator has been set while reading,\n   false (0) otherwise.  Note that the end-of-file indicator is set only if the\n   read tried to go past the end of the input, but came up short.  Therefore,\n   just like feof(), gzeof() may return false even if there is no more data to\n   read, in the event that the last read request was for the exact number of\n   bytes remaining in the input file.  This will happen if the input file size\n   is an exact multiple of the buffer size.\n\n     If gzeof() returns true, then the read functions will return no more data,\n   unless the end-of-file indicator is reset by gzclearerr() and the input file\n   has grown since the previous end of file was detected.\n*/\n\n int  gzdirect (gzFile file);\n/*\n     Returns true (1) if file is being copied directly while reading, or false\n   (0) if file is a gzip stream being decompressed.\n\n     If the input file is empty, gzdirect() will return true, since the input\n   does not contain a gzip stream.\n\n     If gzdirect() is used immediately after gzopen() or gzdopen() it will\n   cause buffers to be allocated to allow reading the file to determine if it\n   is a gzip file.  Therefore if gzbuffer() is used, it should be called before\n   gzdirect().\n\n     When writing, gzdirect() returns true (1) if transparent writing was\n   requested (\"wT\" for the gzopen() mode), or false (0) otherwise.  (Note:\n   gzdirect() is not needed when writing.  Transparent writing must be\n   explicitly requested, so the application already knows the answer.  When\n   linking statically, using gzdirect() will include all of the zlib code for\n   gzip file reading and decompression, which may not be desired.)\n*/\n\n int     gzclose (gzFile file);\n/*\n     Flushes all pending output if necessary, closes the compressed file and\n   deallocates the (de)compression state.  Note that once file is closed, you\n   cannot call gzerror with file, since its structures have been deallocated.\n   gzclose must not be called more than once on the same file, just as free\n   must not be called more than once on the same allocation.\n\n     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a\n   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the\n   last read ended in the middle of a gzip stream, or Z_OK on success.\n*/\n\n int  gzclose_r (gzFile file);\n int  gzclose_w (gzFile file);\n/*\n     Same as gzclose(), but gzclose_r() is only for use when reading, and\n   gzclose_w() is only for use when writing or appending.  The advantage to\n   using these instead of gzclose() is that they avoid linking in zlib\n   compression or decompression code that is not used when only reading or only\n   writing respectively.  If gzclose() is used, then both compression and\n   decompression code will be included the application when linking to a static\n   zlib library.\n*/\n\n const char *  gzerror (gzFile file, int *errnum);\n/*\n     Returns the error message for the last error which occurred on the given\n   compressed file.  errnum is set to zlib error number.  If an error occurred\n   in the file system and not in the compression library, errnum is set to\n   Z_ERRNO and the application may consult errno to get the exact error code.\n\n     The application must not modify the returned string.  Future calls to\n   this function may invalidate the previously returned string.  If file is\n   closed, then the string previously returned by gzerror will no longer be\n   available.\n\n     gzerror() should be used to distinguish errors from end-of-file for those\n   functions above that do not distinguish those cases in their return values.\n*/\n\n void  gzclearerr (gzFile file);\n/*\n     Clears the error and end-of-file flags for file.  This is analogous to the\n   clearerr() function in stdio.  This is useful for continuing to read a gzip\n   file that is being written concurrently.\n*/\n\n#endif /* !Z_SOLO */\n\n                        /* checksum functions */\n\n/*\n     These functions are not related to compression but are exported\n   anyway because they might be useful in applications using the compression\n   library.\n*/\n\nuint32_t adler32 (uint32_t adler, const uint8_t *buf, size_t len);\n/*\n     Update a running Adler-32 checksum with the bytes buf[0..len-1] and\n   return the updated checksum.  If buf is Z_NULL, this function returns the\n   required initial value for the checksum.\n\n     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed\n   much faster.\n\n   Usage example:\n\n     uLong adler = adler32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       adler = adler32(adler, buffer, length);\n     }\n     if (adler != original_adler) error();\n*/\n\n/*\n uLong  adler32_combine (uLong adler1, uLong adler2,\n                                          z_off_t len2);\n\n     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1\n   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for\n   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of\n   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note\n   that the z_off_t type (like off_t) is a signed integer.  If len2 is\n   negative, the result has no meaning or utility.\n*/\n\n uLong  crc32   (uLong crc, const Bytef *buf, uInt len);\n/*\n     Update a running CRC-32 with the bytes buf[0..len-1] and return the\n   updated CRC-32.  If buf is Z_NULL, this function returns the required\n   initial value for the crc.  Pre- and post-conditioning (one's complement) is\n   performed within this function so it shouldn't be done by the application.\n\n   Usage example:\n\n     uLong crc = crc32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       crc = crc32(crc, buffer, length);\n     }\n     if (crc != original_crc) error();\n*/\n\n/*\n uLong  crc32_combine (uLong crc1, uLong crc2, z_off_t len2);\n\n     Combine two CRC-32 check values into one.  For two sequences of bytes,\n   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were\n   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32\n   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and\n   len2.\n*/\n\n                        /* various hacks, don't look :) */\n\n/* deflateInit and inflateInit are macros to allow checking the zlib version\n * and the compiler's view of z_stream:\n */\n int  deflateInit_ (z_streamp strm, int level,\n                                     const char *version, int stream_size);\n int  inflateInit_ (z_streamp strm,\n                                     const char *version, int stream_size);\n int  deflateInit2_ (z_streamp strm, int  level, int  method,\n                                      int windowBits, int memLevel,\n                                      int strategy, const char *version,\n                                      int stream_size);\n int  inflateInit2_ (z_streamp strm, int  windowBits,\n                                      const char *version, int stream_size);\n int  inflateBackInit_ (z_streamp strm, int windowBits,\n                                         unsigned char FAR *window,\n                                         const char *version,\n                                         int stream_size);\n#define deflateInit(strm, level) \\\n        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#define inflateInit(strm) \\\n        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#define inflateInit2(strm, windowBits) \\\n        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                      (int)sizeof(z_stream))\n#define inflateBackInit(strm, windowBits, window) \\\n        inflateBackInit_((strm), (windowBits), (window), \\\n                      ZLIB_VERSION, (int)sizeof(z_stream))\n\n#ifndef Z_SOLO\n\n/* gzgetc() macro and its supporting function and exposed data structure.  Note\n * that the real internal state is much larger than the exposed structure.\n * This abbreviated structure exposes just enough for the gzgetc() macro.  The\n * user should not mess with these exposed elements, since their names or\n * behavior could change in the future, perhaps even capriciously.  They can\n * only be used by the gzgetc() macro.  You have been warned.\n */\n int  gzgetc_ (gzFile file);  /* backward compatibility */\n#ifdef Z_PREFIX_SET\n#  undef z_gzgetc\n#  define z_gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))\n#else\n#  define gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))\n#endif\n\n/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or\n * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if\n * both are true, the application gets the *64 functions, and the regular\n * functions are changed to 64 bits) -- in case these are set on systems\n * without large file support, _LFS64_LARGEFILE must also be true\n */\n#ifdef Z_LARGE64\n    gzFile  gzopen64 (const char *, const char *);\n    z_off64_t  gzseek64 (gzFile, z_off64_t, int);\n    z_off64_t  gztell64 (gzFile);\n    z_off64_t  gzoffset64 (gzFile);\n    uLong  adler32_combine64 (uLong, uLong, z_off64_t);\n    uLong  crc32_combine64 (uLong, uLong, z_off64_t);\n#endif\n\n#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)\n#  ifdef Z_PREFIX_SET\n#    define z_gzopen z_gzopen64\n#    define z_gzseek z_gzseek64\n#    define z_gztell z_gztell64\n#    define z_gzoffset z_gzoffset64\n#    define z_adler32_combine z_adler32_combine64\n#    define z_crc32_combine z_crc32_combine64\n#  else\n#    define gzopen gzopen64\n#    define gzseek gzseek64\n#    define gztell gztell64\n#    define gzoffset gzoffset64\n#    define adler32_combine adler32_combine64\n#    define crc32_combine crc32_combine64\n#  endif\n#  ifndef Z_LARGE64\n      gzFile  gzopen64 (const char *, const char *);\n      z_off_t  gzseek64 (gzFile, z_off_t, int);\n      z_off_t  gztell64 (gzFile);\n      z_off_t  gzoffset64 (gzFile);\n      uLong  adler32_combine64 (uLong, uLong, z_off_t);\n      uLong  crc32_combine64 (uLong, uLong, z_off_t);\n#  endif\n#else\n    gzFile  gzopen (const char *, const char *);\n    z_off_t  gzseek (gzFile, z_off_t, int);\n    z_off_t  gztell (gzFile);\n    z_off_t  gzoffset (gzFile);\n    uLong  adler32_combine (uLong, uLong, z_off_t);\n    uLong  crc32_combine (uLong, uLong, z_off_t);\n#endif\n\n#else /* Z_SOLO */\n\n    uLong  adler32_combine (uLong, uLong, z_off_t);\n    uLong  crc32_combine (uLong, uLong, z_off_t);\n\n#endif /* !Z_SOLO */\n\n/* hack for buggy compilers */\n#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)\n    struct internal_state {int dummy;};\n#endif\n\n/* undocumented functions */\n const char   *  zError           (int);\n int             inflateSyncPoint (z_streamp);\n\nconst uint32_t * get_crc_table(void);\n int             inflateUndermine (z_streamp, int);\n int             inflateResetKeep (z_streamp);\n int             deflateResetKeep (z_streamp);\n#if defined(_WIN32) && !defined(Z_SOLO)\n gzFile          gzopen_w (const wchar_t *path,\n                                            const char *mode);\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\n int            gzvprintf Z_ARG((gzFile file,\n                                                  const char *format,\n                                                  va_list va));\n#  endif\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZLIB_H */\n\n#endif\n"
  },
  {
    "path": "include/defines/cocoa_defines.h",
    "content": "/* Copyright (C) 2010-2021 The RetroArch team\r\n *\r\n * ---------------------------------------------------------------------------------------\r\n * The following license statement only applies to this file (cocoa_defines.h).\r\n * ---------------------------------------------------------------------------------------\r\n *\r\n * Permission is hereby granted, free of charge,\r\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\r\n * to deal in the Software without restriction, including without limitation the rights to\r\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\r\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\r\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef __COCOA_COMMON_DEFINES_H\r\n#define __COCOA_COMMON_DEFINES_H\r\n\r\n#include <AvailabilityMacros.h>\r\n\r\n#ifndef MAC_OS_X_VERSION_10_12\r\n#define MAC_OS_X_VERSION_10_12 101200\r\n#endif\r\n\r\n#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12\r\n#define HAS_MACOSX_10_12 0\r\n#define NSEventModifierFlagCommand NSCommandKeyMask\r\n#define NSEventModifierFlagControl NSControlKeyMask\r\n#define NSEventModifierFlagHelp NSHelpKeyMask\r\n#define NSEventModifierFlagNumericPad NSNumericPadKeyMask\r\n#define NSEventModifierFlagOption NSAlternateKeyMask\r\n#define NSEventModifierFlagShift NSShiftKeyMask\r\n#define NSCompositingOperationSourceOver NSCompositeSourceOver\r\n#define NSEventMaskApplicationDefined NSApplicationDefinedMask\r\n#define NSEventTypeApplicationDefined NSApplicationDefined\r\n#define NSEventTypeCursorUpdate NSCursorUpdate\r\n#define NSEventTypeMouseMoved NSMouseMoved\r\n#define NSEventTypeMouseEntered NSMouseEntered\r\n#define NSEventTypeMouseExited NSMouseExited\r\n#define NSEventTypeLeftMouseDown NSLeftMouseDown\r\n#define NSEventTypeRightMouseDown NSRightMouseDown\r\n#define NSEventTypeOtherMouseDown NSOtherMouseDown\r\n#define NSEventTypeLeftMouseUp NSLeftMouseUp\r\n#define NSEventTypeRightMouseUp NSRightMouseUp\r\n#define NSEventTypeOtherMouseUp NSOtherMouseUp\r\n#define NSEventTypeLeftMouseDragged NSLeftMouseDragged\r\n#define NSEventTypeRightMouseDragged NSRightMouseDragged\r\n#define NSEventTypeOtherMouseDragged NSOtherMouseDragged\r\n#define NSEventTypeScrollWheel NSScrollWheel\r\n#define NSEventTypeKeyDown NSKeyDown\r\n#define NSEventTypeKeyUp NSKeyUp\r\n#define NSEventTypeFlagsChanged NSFlagsChanged\r\n#define NSEventMaskAny NSAnyEventMask\r\n#define NSWindowStyleMaskBorderless NSBorderlessWindowMask\r\n#define NSWindowStyleMaskClosable NSClosableWindowMask\r\n#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask\r\n#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask\r\n#define NSWindowStyleMaskResizable NSResizableWindowMask\r\n#define NSWindowStyleMaskTitled NSTitledWindowMask\r\n#define NSAlertStyleCritical NSCriticalAlertStyle\r\n#define NSAlertStyleInformational NSInformationalAlertStyle\r\n#define NSAlertStyleWarning  NSWarningAlertStyle\r\n#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask\r\n#define NSControlSizeRegular NSRegularControlSize\r\n#else\r\n#define HAS_MACOSX_10_12 1\r\n#endif\r\n\r\n/* ARC vs MRR macros.  Under ARC, release/autorelease are forbidden\r\n * (compile error); under MRR (Manual Retain-Release / MRC) they are\r\n * required.  These macros expand to the right thing for the current\r\n * translation unit regardless of which mode it is compiled under.\r\n *\r\n * Previous convention used `#ifndef HAVE_COCOA_METAL` as a proxy\r\n * for 'are we under ARC?' because HAVE_COCOA_METAL builds happened\r\n * to enable ARC via CLANG_ENABLE_OBJC_ARC=YES in BaseConfig.xcconfig.\r\n * That's brittle - RetroArch_PPC.xcodeproj turns ARC off explicitly\r\n * even on the Metal branch, and the qb/make build is always MRR\r\n * regardless.  __has_feature(objc_arc) is the canonical discriminator.\r\n *\r\n * GCC 4.0 (Xcode 3.1) doesn't support __has_feature; polyfill to 0\r\n * so the MRR branch is selected (which is correct for GCC 4.0 - it\r\n * predates ARC entirely). */\r\n#ifndef __has_feature\r\n#define __has_feature(x) 0\r\n#endif\r\n\r\n#if __has_feature(objc_arc)\r\n#define RARCH_RETAIN(x)         (x)\r\n#define RARCH_RELEASE(x)        ((void)0)\r\n#define RARCH_AUTORELEASE(x)    ((void)0)\r\n#define RARCH_SUPER_DEALLOC()   ((void)0)\r\n#define RARCH_DISPATCH_RELEASE(x) ((void)0)\r\n#else\r\n#define RARCH_RETAIN(x)         [(x) retain]\r\n#define RARCH_RELEASE(x)        [(x) release]\r\n#define RARCH_AUTORELEASE(x)    [(x) autorelease]\r\n#define RARCH_SUPER_DEALLOC()   [super dealloc]\r\n/* GCD object release for MRR.  Use dispatch_release() rather than\r\n * [x release] because the latter is a compile error on pre-10.8 SDKs\r\n * where OS_OBJECT_USE_OBJC is 0 and dispatch_queue_t is a plain C\r\n * handle rather than an Objective-C object.  dispatch_release works\r\n * uniformly across all MRR-capable SDKs.  NULL-guarded because\r\n * dispatch_release(NULL) is explicitly undefined, unlike\r\n * [nil release] which is a defined no-op. */\r\n#define RARCH_DISPATCH_RELEASE(x) do { if (x) dispatch_release(x); } while (0)\r\n#endif\r\n\r\n#endif\r\n"
  },
  {
    "path": "include/defines/d3d_defines.h",
    "content": "/* Copyright (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (d3d_defines.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef D3DVIDEO_DEFINES_H\n#define D3DVIDEO_DEFINES_H\n\n#if defined(DEBUG) || defined(_DEBUG)\n#define D3D_DEBUG_INFO\n#endif\n\n#if defined(HAVE_D3D9)\n/* Direct3D 9 */\n\n#ifndef D3DCREATE_SOFTWARE_VERTEXPROCESSING\n#define D3DCREATE_SOFTWARE_VERTEXPROCESSING 0\n#endif\n\n#elif defined(HAVE_D3D8)\n\n/* Direct3D 8 */\n\n#if !defined(D3DLOCK_NOSYSLOCK) && defined(_XBOX)\n#define D3DLOCK_NOSYSLOCK (0)\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/defines/gx_defines.h",
    "content": "/* Copyright (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (gx_defines.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _GX_DEFINES_H\n#define _GX_DEFINES_H\n\n#ifdef GEKKO\n\n#define SYSMEM1_SIZE 0x01800000\n\n#ifndef _SHIFTL\n#define _SHIFTL(v, s, w)\t((uint32_t) (((uint32_t)(v) & ((0x01 << (w)) - 1)) << (s)))\n#define _SHIFTR(v, s, w)\t((uint32_t)(((uint32_t)(v) >> (s)) & ((0x01 << (w)) - 1)))\n#endif\n\n#define OSThread lwp_t\n#define OSCond lwpq_t\n#define OSThreadQueue lwpq_t\n\n#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)\n#define OSLockMutex(mutex) LWP_MutexLock(mutex)\n#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)\n#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)\n\n#define OSInitCond(cond) LWP_CondInit(cond)\n#define OSSignalCond(cond) LWP_ThreadSignal(cond)\n#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)\n\n#define OSInitThreadQueue(queue) LWP_InitQueue(queue)\n#define OSCloseThreadQueue(queue) LWP_CloseQueue(queue)\n#define OSSleepThread(queue) LWP_ThreadSleep(queue)\n#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)\n\n#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)\n\n#define BLIT_LINE_16(off) \\\n{ \\\n   const uint32_t *tmp_src = src; \\\n   uint32_t       *tmp_dst = dst; \\\n   for (unsigned x = 0; x < width2 >> 1; x++, tmp_src += 2, tmp_dst += 8) \\\n   { \\\n      tmp_dst[ 0 + off] = BLIT_LINE_16_CONV(tmp_src[0]); \\\n      tmp_dst[ 1 + off] = BLIT_LINE_16_CONV(tmp_src[1]); \\\n   } \\\n   src += tmp_pitch; \\\n}\n\n#define BLIT_LINE_32(off) \\\n{ \\\n   const uint16_t *tmp_src = src; \\\n   uint16_t       *tmp_dst = dst; \\\n   for (unsigned x = 0; x < width2 >> 3; x++, tmp_src += 8, tmp_dst += 32) \\\n   { \\\n      tmp_dst[  0 + off] = tmp_src[0] | 0xFF00; \\\n      tmp_dst[ 16 + off] = tmp_src[1]; \\\n      tmp_dst[  1 + off] = tmp_src[2] | 0xFF00; \\\n      tmp_dst[ 17 + off] = tmp_src[3]; \\\n      tmp_dst[  2 + off] = tmp_src[4] | 0xFF00; \\\n      tmp_dst[ 18 + off] = tmp_src[5]; \\\n      tmp_dst[  3 + off] = tmp_src[6] | 0xFF00; \\\n      tmp_dst[ 19 + off] = tmp_src[7]; \\\n   } \\\n   src += tmp_pitch; \\\n}\n\n#define AIInit AUDIO_Init\n#define AIInitDMA AUDIO_InitDMA\n#define AIStartDMA AUDIO_StartDMA\n#define AIStopDMA AUDIO_StopDMA\n#define AIRegisterDMACallback AUDIO_RegisterDMACallback\n#define AISetDSPSampleRate AUDIO_SetDSPSampleRate\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/defines/ps3_defines.h",
    "content": "/* Copyright (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (ps3_defines.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _PS3_DEFINES_H\n#define _PS3_DEFINES_H\n\n/*============================================================\n\tAUDIO PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <audio/audio.h>\n#include <sys/thread.h>\n\n#include <sys/event_queue.h>\n#include <lv2/mutex.h>\n#include <lv2/cond.h>\n\n/*forward decl. for audioAddData */\nextern int audioAddData(uint32_t portNum, float *data,\n      uint32_t frames, float volume);\n\n#define PS3_SYS_NO_TIMEOUT 0\n#define param_attrib attrib\n\n#else\n#include <sdk_version.h>\n#include <cell/audio.h>\n#include <sys/event.h>\n#include <sys/synchronization.h>\n\n#define numChannels nChannel\n#define numBlocks nBlock\n#define param_attrib attr\n\n#define audioQuit cellAudioQuit \n#define audioInit cellAudioInit\n#define audioPortStart cellAudioPortStart\n#define audioPortOpen cellAudioPortOpen\n#define audioPortClose cellAudioPortClose\n#define audioPortStop cellAudioPortStop\n#define audioPortParam CellAudioPortParam\n#define audioPortOpen cellAudioPortOpen\n#define audioAddData cellAudioAddData\n\n/* event queue functions */\n#define sysEventQueueReceive sys_event_queue_receive\n#define audioSetNotifyEventQueue cellAudioSetNotifyEventQueue\n#define audioRemoveNotifyEventQueue cellAudioRemoveNotifyEventQueue\n#define audioCreateNotifyEventQueue cellAudioCreateNotifyEventQueue\n\n#define sysLwCondCreate sys_lwcond_create\n#define sysLwCondDestroy sys_lwcond_destroy\n#define sysLwCondWait sys_lwcond_wait\n#define sysLwCondSignal sys_lwcond_signal\n\n#define sysLwMutexDestroy sys_lwmutex_destroy\n#define sysLwMutexLock sys_lwmutex_lock\n#define sysLwMutexUnlock sys_lwmutex_unlock\n#define sysLwMutexCreate sys_lwmutex_create\n\n#define AUDIO_BLOCK_SAMPLES CELL_AUDIO_BLOCK_SAMPLES\n#define SYSMODULE_NET CELL_SYSMODULE_NET\n#define PS3_SYS_NO_TIMEOUT SYS_NO_TIMEOUT\n\n#define sys_lwmutex_attr_t sys_lwmutex_attribute_t \n#define sys_lwcond_attr_t sys_lwcond_attribute_t \n#define sys_sem_t sys_semaphore_t\n\n#define sysGetSystemTime sys_time_get_system_time\n#define sysModuleLoad cellSysmoduleLoadModule\n#define sysModuleUnload cellSysmoduleUnloadModule\n\n#define netInitialize sys_net_initialize_network\n\n#endif\n\n/*============================================================\n\tINPUT PAD PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <io/pad.h>\n#define CELL_PAD_CAPABILITY_SENSOR_MODE      4\n#define CELL_PAD_SETTING_SENSOR_ON           4\n#define CELL_PAD_STATUS_ASSIGN_CHANGES       2\n#define CELL_PAD_BTN_OFFSET_DIGITAL1         2\n#define CELL_PAD_BTN_OFFSET_DIGITAL2         3\n#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X   4\n#define CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y   5\n#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X    6\n#define CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y    7\n#define CELL_PAD_BTN_OFFSET_PRESS_RIGHT      8\n#define CELL_PAD_BTN_OFFSET_PRESS_LEFT       9\n#define CELL_PAD_BTN_OFFSET_PRESS_UP         10\n#define CELL_PAD_BTN_OFFSET_PRESS_DOWN       11\n#define CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE   12\n#define CELL_PAD_BTN_OFFSET_PRESS_CIRCLE     13\n#define CELL_PAD_BTN_OFFSET_PRESS_CROSS      14\n#define CELL_PAD_BTN_OFFSET_PRESS_SQUARE     15\n#define CELL_PAD_BTN_OFFSET_PRESS_L1         16\n#define CELL_PAD_BTN_OFFSET_PRESS_R1         17\n#define CELL_PAD_BTN_OFFSET_PRESS_L2         18\n#define CELL_PAD_BTN_OFFSET_PRESS_R2         19\n#define CELL_PAD_BTN_OFFSET_SENSOR_X         20\n#define CELL_PAD_BTN_OFFSET_SENSOR_Y         21\n#define CELL_PAD_BTN_OFFSET_SENSOR_Z         22\n#define CELL_PAD_BTN_OFFSET_SENSOR_G         23\n#define CELL_PAD_CTRL_LEFT          (128)\n#define CELL_PAD_CTRL_DOWN          (64)\n#define CELL_PAD_CTRL_RIGHT         (32)\n#define CELL_PAD_CTRL_UP            (16)\n#define CELL_PAD_CTRL_START         (8)\n#define CELL_PAD_CTRL_R3            (4)\n#define CELL_PAD_CTRL_L3            (2)\n#define CELL_PAD_CTRL_SELECT        (1)\n#define CELL_PAD_CTRL_SQUARE        (128)\n#define CELL_PAD_CTRL_CROSS         (64)\n#define CELL_PAD_CTRL_CIRCLE        (32)\n#define CELL_PAD_CTRL_TRIANGLE      (16)\n#define CELL_PAD_CTRL_R1            (8)\n#define CELL_PAD_CTRL_L1            (4)\n#define CELL_PAD_CTRL_R2            (2)\n#define CELL_PAD_CTRL_L2            (1)\n#define CELL_PAD_CTRL_LDD_PS        (1)\n#define CELL_PAD_STATUS_CONNECTED   (1)\n#define CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN\n#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CROSS  (1)\n#define CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CIRCLE (0)\n#define now_connect connected\n#define CellPadActParam padActParam\n#define cellPadSetPortSetting ioPadSetPortSetting\n#define cellSysutilGetSystemParamInt sysUtilGetSystemParamInt\n#define cellPadSetActDirect ioPadSetActDirect\n#define CellPadInfo2 padInfo2\n#define cellPadGetInfo2 ioPadGetInfo2\n#define CellPadData padData\n#define cellPadGetData ioPadGetData\n#define cellPadInit ioPadInit \n#define cellPadEnd ioPadEnd\n#else\n#include <cell/pad.h>\n#define padInfo2 CellPadInfo2\n#define padData CellPadData\n#define ioPadGetInfo2 cellPadGetInfo2 \n#define ioPadGetData cellPadGetData\n#define ioPadInit cellPadInit\n#define ioPadEnd cellPadEnd\n#define ioPadSetPortSetting cellPadSetPortSetting \n#endif\n\n/*============================================================\n\tINPUT MOUSE PROTOTYPES\n============================================================ */\n\n#ifdef HAVE_MOUSE\n\n#ifdef __PSL1GHT__\n#include <io/mouse.h>\n\n/* define ps3 mouse structs */\n#define CellMouseInfo mouseInfo\n#define CellMouseData mouseData\n\n/* define all the ps3 mouse functions */\n#define cellMouseInit ioMouseInit\n#define cellMouseGetData ioMouseGetData\n#define cellMouseEnd ioMouseEnd\n#define cellMouseGetInfo ioMouseGetInfo\n\n/* PSL1GHT does not define these in its header */\n#define CELL_MOUSE_BUTTON_1 (UINT64_C(1) << 0) /* Button 1 */\n#define CELL_MOUSE_BUTTON_2 (UINT64_C(1) << 1) /* Button 2 */\n#define CELL_MOUSE_BUTTON_3 (UINT64_C(1) << 2) /* Button 3 */\n#define CELL_MOUSE_BUTTON_4 (UINT64_C(1) << 3) /* Button 4 */\n#define CELL_MOUSE_BUTTON_5 (UINT64_C(1) << 4) /* Button 5 */\n#define CELL_MOUSE_BUTTON_6 (UINT64_C(1) << 5) /* Button 6 */\n#define CELL_MOUSE_BUTTON_7 (UINT64_C(1) << 6) /* Button 7 */\n#define CELL_MOUSE_BUTTON_8 (UINT64_C(1) << 7) /* Button 8 */\n\n#else\n#include <cell/mouse.h>\n#define mouseInfo CellMouseInfo\n#define mouseData CellMouseData\n\n#define ioMouseInit cellMouseInit\n#define ioMouseGetData cellMouseGetData\n#define ioMouseEnd cellMouseEnd\n#define ioMouseGetInfo cellMouseGetInfo\n#endif\n\n#endif\n\n/*============================================================\n\tINPUT KEYBOARD PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <io/kb.h>\n\n#define CELL_KB_RMODE_INPUTCHAR KB_RMODE_INPUTCHAR\n#define CELL_KB_CODETYPE_RAW    KB_CODETYPE_RAW\n\n#define cellKbData KbData\n#define cellKbInfo KbInfo\n\n#define cellKbSetCodeType ioKbSetCodeType\n#define cellKbSetReadMode ioKbSetReadMode\n#define cellKbInit ioKbInit\n#define cellKbGetInfo ioKbGetInfo\n#define cellKbRead ioKbRead\n#else\n#include <cell/keyboard.h>\n\n#define KB_RMODE_INPUTCHAR CELL_KB_RMODE_INPUTCHAR\n#define KB_CODETYPE_RAW    CELL_KB_CODETYPE_RAW\n\n#define KbInfo cellKbInfo\n\n#define ioKbSetCodeType cellKbSetCodeType\n#define ioKbSetReadMode cellKbSetReadMode\n#define ioKbInit cellKbInit\n#define ioKbGetInfo cellKbGetInfo\n#define ioKbRead cellKbRead\n\n/* Keyboard RAWDAT Key code (can't be converted to ASCII codes) */\n#define KB_RAWKEY_NO_EVENT\t\t\t0x00\n#define KB_RAWKEY_E_ROLLOVER\t\t\t0x01\n#define KB_RAWKEY_E_POSTFAIL\t\t\t0x02\n#define KB_RAWKEY_E_UNDEF\t\t\t0x03\n#define KB_RAWKEY_ESCAPE\t\t\t0x29\n#define KB_RAWKEY_106_KANJI\t\t\t0x35\t/* The half-width/full width Kanji key code */\n#define KB_RAWKEY_CAPS_LOCK\t\t\t0x39\n#define KB_RAWKEY_F1\t\t\t\t0x3a\n#define KB_RAWKEY_F2\t\t\t\t0x3b\n#define KB_RAWKEY_F3\t\t\t\t0x3c\n#define KB_RAWKEY_F4\t\t\t\t0x3d\n#define KB_RAWKEY_F5\t\t\t\t0x3e\n#define KB_RAWKEY_F6\t\t\t\t0x3f\n#define KB_RAWKEY_F7\t\t\t\t0x40\n#define KB_RAWKEY_F8\t\t\t\t0x41\n#define KB_RAWKEY_F9\t\t\t\t0x42\n#define KB_RAWKEY_F10\t\t\t\t0x43\n#define KB_RAWKEY_F11\t\t\t\t0x44\n#define KB_RAWKEY_F12\t\t\t\t0x45\n#define KB_RAWKEY_PRINTSCREEN\t\t\t0x46\n#define KB_RAWKEY_SCROLL_LOCK\t\t\t0x47\n#define KB_RAWKEY_PAUSE\t\t\t\t0x48\n#define KB_RAWKEY_INSERT\t\t\t0x49\n#define KB_RAWKEY_HOME\t\t\t\t0x4a\n#define KB_RAWKEY_PAGE_UP\t\t\t0x4b\n#define KB_RAWKEY_DELETE\t\t\t0x4c\n#define KB_RAWKEY_END\t\t\t\t0x4d\n#define KB_RAWKEY_PAGE_DOWN\t\t\t0x4e\n#define KB_RAWKEY_RIGHT_ARROW\t\t\t0x4f\n#define KB_RAWKEY_LEFT_ARROW\t\t\t0x50\n#define KB_RAWKEY_DOWN_ARROW\t\t\t0x51\n#define KB_RAWKEY_UP_ARROW\t\t\t0x52\n#define KB_RAWKEY_NUM_LOCK\t\t\t0x53\n#define KB_RAWKEY_APPLICATION\t\t\t0x65\t/* Application key code */\n#define KB_RAWKEY_KANA\t\t\t\t0x88\t/* Katakana/Hiragana/Romaji key code */\n#define KB_RAWKEY_HENKAN\t\t\t0x8a\t/* Conversion key code */\n#define KB_RAWKEY_MUHENKAN\t\t\t0x8b\t/* No Conversion key code */\n\n/* Keyboard RAW Key Code definition */\n#define KB_RAWKEY_A\t\t\t\t0x04\n#define KB_RAWKEY_B\t\t\t\t0x05\n#define KB_RAWKEY_C\t\t\t\t0x06\n#define KB_RAWKEY_D\t\t\t\t0x07\n#define KB_RAWKEY_E\t\t\t\t0x08\n#define KB_RAWKEY_F\t\t\t\t0x09\n#define KB_RAWKEY_G\t\t\t\t0x0A\n#define KB_RAWKEY_H\t\t\t\t0x0B\n#define KB_RAWKEY_I\t\t\t\t0x0C\n#define KB_RAWKEY_J\t\t\t\t0x0D\n#define KB_RAWKEY_K\t\t\t\t0x0E\n#define KB_RAWKEY_L\t\t\t\t0x0F\n#define KB_RAWKEY_M\t\t\t\t0x10\n#define KB_RAWKEY_N\t\t\t\t0x11\n#define KB_RAWKEY_O\t\t\t\t0x12\n#define KB_RAWKEY_P\t\t\t\t0x13\n#define KB_RAWKEY_Q\t\t\t\t0x14\n#define KB_RAWKEY_R\t\t\t\t0x15\n#define KB_RAWKEY_S\t\t\t\t0x16\n#define KB_RAWKEY_T\t\t\t\t0x17\n#define KB_RAWKEY_U\t\t\t\t0x18\n#define KB_RAWKEY_V\t\t\t\t0x19\n#define KB_RAWKEY_W\t\t\t\t0x1A\n#define KB_RAWKEY_X\t\t\t\t0x1B\n#define KB_RAWKEY_Y\t\t\t\t0x1C\n#define KB_RAWKEY_Z\t\t\t\t0x1D\n#define KB_RAWKEY_1\t\t\t\t0x1E\n#define KB_RAWKEY_2\t\t\t\t0x1F\n#define KB_RAWKEY_3\t\t\t\t0x20\n#define KB_RAWKEY_4\t\t\t\t0x21\n#define KB_RAWKEY_5\t\t\t\t0x22\n#define KB_RAWKEY_6\t\t\t\t0x23\n#define KB_RAWKEY_7\t\t\t\t0x24\n#define KB_RAWKEY_8\t\t\t\t0x25\n#define KB_RAWKEY_9\t\t\t\t0x26\n#define KB_RAWKEY_0\t\t\t\t0x27\n#define KB_RAWKEY_ENTER\t\t\t\t0x28\n#define KB_RAWKEY_ESC\t\t\t\t0x29\n#define KB_RAWKEY_BS\t\t\t\t0x2A\n#define KB_RAWKEY_TAB\t\t\t\t0x2B\n#define KB_RAWKEY_SPACE\t\t\t\t0x2C\n#define KB_RAWKEY_MINUS\t\t\t\t0x2D\n#define KB_RAWKEY_EQUAL_101\t\t\t0x2E\t/* = and + */\n#define KB_RAWKEY_ACCENT_CIRCONFLEX_106 \t0x2E\t/* ^ and ~ */\n#define KB_RAWKEY_LEFT_BRACKET_101\t\t0x2F\t/* [ */\n#define KB_RAWKEY_ATMARK_106\t\t\t0x2F\t/* @ */\n#define KB_RAWKEY_RIGHT_BRACKET_101\t\t0x30\t/* ] */\n#define KB_RAWKEY_LEFT_BRACKET_106\t\t0x30\t/* [ */\n#define KB_RAWKEY_BACKSLASH_101\t\t\t0x31\t/* \\ and | */\n#define KB_RAWKEY_RIGHT_BRACKET_106\t\t0x32\t/* ] */\n#define KB_RAWKEY_SEMICOLON\t\t\t0x33\t/* ; */\n#define KB_RAWKEY_QUOTATION_101\t\t\t0x34\t/* ' and \" */\n#define KB_RAWKEY_COLON_106\t\t\t0x34\t/* : and * */\n#define KB_RAWKEY_COMMA\t\t    \t\t0x36\n#define KB_RAWKEY_PERIOD\t\t\t0x37\n#define KB_RAWKEY_SLASH\t\t    \t\t0x38\n#define KB_RAWKEY_CAPS_LOCK\t\t\t0x39\n#define KB_RAWKEY_KPAD_NUMLOCK\t\t\t0x53\n#define KB_RAWKEY_KPAD_SLASH\t\t\t0x54\n#define KB_RAWKEY_KPAD_ASTERISK\t\t\t0x55\n#define KB_RAWKEY_KPAD_MINUS\t\t\t0x56\n#define KB_RAWKEY_KPAD_PLUS\t\t\t0x57\n#define KB_RAWKEY_KPAD_ENTER\t\t\t0x58\n#define KB_RAWKEY_KPAD_1\t\t\t0x59\n#define KB_RAWKEY_KPAD_2\t\t\t0x5A\n#define KB_RAWKEY_KPAD_3\t\t\t0x5B\n#define KB_RAWKEY_KPAD_4\t\t\t0x5C\n#define KB_RAWKEY_KPAD_5\t\t\t0x5D\n#define KB_RAWKEY_KPAD_6\t\t\t0x5E\n#define KB_RAWKEY_KPAD_7\t\t\t0x5F\n#define KB_RAWKEY_KPAD_8\t\t\t0x60\n#define KB_RAWKEY_KPAD_9\t\t\t0x61\n#define KB_RAWKEY_KPAD_0\t\t\t0x62\n#define KB_RAWKEY_KPAD_PERIOD\t\t\t0x63\n#define KB_RAWKEY_BACKSLASH_106\t\t\t0x87\n#define KB_RAWKEY_YEN_106\t\t\t0x89\n\n#define KB_CODETYPE_RAW CELL_KB_CODETYPE_RAW\n\n/*! \\brief Keyboard Led State. */\ntypedef struct KbLed\n{\n\tunion\n   {\n      uint32_t leds;\n      struct\n      {\n         uint32_t reserved\t   : 27;\t/*!< \\brief Reserved MSB */\n         uint32_t kana\t\t   : 1;\t/*!< \\brief LED Kana 0:OFF 1:ON Bit4 */\n         uint32_t compose\t\t: 1;\t/*!< \\brief LED Compose 0:OFF 1:ON Bit3 */\n         uint32_t scroll_lock\t: 1;\t/*!< \\brief LED Scroll Lock 0:OFF 1:ON Bit2 */\n         uint32_t caps_lock\t: 1;\t/*!< \\brief LED Caps Lock 0:OFF 1:ON Bit1 */\n         uint32_t num_lock\t   : 1;\t/*!< \\brief LED Num Lock 0:OFF 1:ON Bit0 LSB */\n      }_KbLedS;\n   }_KbLedU;\n} KbLed;\n\n\n/*! \\brief Keyboard Modifier Key State. */\ntypedef struct KbMkey\n{\n   union\n   {\n      uint32_t mkeys;\n      struct\n      {\n         uint32_t reserved\t   : 24;\t/*!< \\brief Reserved MSB */\n         uint32_t r_win\t\t   : 1;\t/*!< \\brief Modifier Key Right WIN 0:OFF 1:ON Bit7 */\n         uint32_t r_alt\t\t   : 1;\t/*!< \\brief Modifier Key Right ALT 0:OFF 1:ON Bit6 */\n         uint32_t r_shift\t\t: 1;\t/*!< \\brief Modifier Key Right SHIFT 0:OFF 1:ON Bit5 */\t\t\n         uint32_t r_ctrl\t\t: 1;\t/*!< \\brief Modifier Key Right CTRL 0:OFF 1:ON Bit4 */\n         uint32_t l_win\t\t   : 1;\t/*!< \\brief Modifier Key Left WIN 0:OFF 1:ON Bit3 */\n         uint32_t l_alt\t\t   : 1;\t/*!< \\brief Modifier Key Left ALT 0:OFF 1:ON Bit2 */\n         uint32_t l_shift\t\t: 1;\t/*!< \\brief Modifier Key Left SHIFT 0:OFF 1:ON Bit1 */\n         uint32_t l_ctrl\t\t: 1;\t/*!< \\brief Modifier Key Left CTRL 0:OFF 1:ON Bit0 LSB */\n         /* For Macintosh Keyboard ALT & WIN correspond respectively to OPTION & APPLE keys */\n      }_KbMkeyS;\n   }_KbMkeyU;\n} KbMkey;\n\n/*! \\brief Keyboard input data data structure. */\ntypedef struct KbData\n{\n\tKbLed led;\t\t\t\t\t/*!< \\brief Keyboard Led State */\n\tKbMkey mkey;\t\t\t\t/*!< \\brief Keyboard Modifier Key State */\n\tint32_t  nb_keycode;\t\t\t\t/*!< \\brief Number of key codes (0 equal no data) */\n\tuint16_t keycode[MAX_KEYCODES];\t/*!< \\brief Keycode values */\n} KbData;\n#endif\n\n/*============================================================\n\tOSK PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <sysutil/osk.h>\n/* define all the OSK functions */\n#define pOskLoadAsync oskLoadAsync\n#define pOskSetLayoutMode oskSetLayoutMode\n#define pOskSetKeyLayoutOption oskSetKeyLayoutOption\n#define pOskGetSize oskGetSize\n#define pOskDisableDimmer oskDisableDimmer\n#define pOskAbort oskAbort\n#define pOskUnloadAsync oskUnloadAsync\n\n/* define OSK structs / types */\n#define sys_memory_container_t sys_mem_container_t\n#define CellOskDialogPoint oskPoint\n#define CellOskDialogInputFieldInfo oskInputFieldInfo\n#define CellOskDialogCallbackReturnParam oskCallbackReturnParam\n#define CellOskDialogParam oskParam\n\n#define osk_allowed_panels allowedPanels\n#define osk_prohibit_flags prohibitFlags\n\n#define osk_inputfield_message message\n#define osk_inputfield_starttext startText\n#define osk_inputfield_max_length maxLength\n#define osk_callback_return_param res\n#define osk_callback_num_chars len\n#define osk_callback_return_string str\n\n/* define the OSK defines */\n#define CELL_OSKDIALOG_10KEY_PANEL OSK_10KEY_PANEL\n#define CELL_OSKDIALOG_FULLKEY_PANEL OSK_FULLKEY_PANEL\n#define CELL_OSKDIALOG_LAYOUTMODE_X_ALIGN_CENTER OSK_LAYOUTMODE_HORIZONTAL_ALIGN_CENTER\n#define CELL_OSKDIALOG_LAYOUTMODE_Y_ALIGN_TOP OSK_LAYOUTMODE_VERTICAL_ALIGN_TOP\n#define CELL_OSKDIALOG_PANELMODE_NUMERAL OSK_PANEL_TYPE_NUMERAL\n#define CELL_OSKDIALOG_PANELMODE_NUMERAL_FULL_WIDTH OSK_PANEL_TYPE_NUMERAL_FULL_WIDTH\n#define CELL_OSKDIALOG_PANELMODE_ALPHABET OSK_PANEL_TYPE_ALPHABET\n#define CELL_OSKDIALOG_PANELMODE_ENGLISH OSK_PANEL_TYPE_ENGLISH\n#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK (0)\n#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED (1)\n#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT (2)\n#define CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT (3)\n#define CELL_OSKDIALOG_STRING_SIZE (512)\n#else\n#include <sysutil/sysutil_oskdialog.h>\n/* define all the OSK functions */\n#define pOskLoadAsync cellOskDialogLoadAsync\n#define pOskSetLayoutMode cellOskDialogSetLayoutMode\n#define pOskSetKeyLayoutOption cellOskDialogSetKeyLayoutOption\n#define pOskGetSize cellOskDialogGetSize\n#define pOskDisableDimmer cellOskDialogDisableDimmer\n#define pOskAbort cellOskDialogAbort\n#define pOskUnloadAsync cellOskDialogUnloadAsync\n\n/* define OSK structs / types */\n#define osk_allowed_panels allowOskPanelFlg\n#define osk_prohibit_flags prohibitFlgs\n#define osk_inputfield_message message\n#define osk_inputfield_starttext init_text\n#define osk_inputfield_max_length limit_length\n#define osk_callback_return_param result\n#define osk_callback_num_chars numCharsResultString\n#define osk_callback_return_string pResultString\n#endif\n\n/*============================================================\n\tJPEG/PNG DECODING/ENCODING PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n\n#define spu_enable enable\n#define stream_select stream\n#define color_alpha alpha\n#define color_space space\n#define output_mode mode\n#define output_bytes_per_line bytes_per_line\n#define output_width width\n#define output_height height\n\n#define CELL_OK 0\n#define PTR_NULL 0\n\n#else\n/* define the JPEG/PNG struct member names */\n#define spu_enable spuThreadEnable\n#define ppu_prio ppuThreadPriority\n#define spu_prio spuThreadPriority\n#define malloc_func cbCtrlMallocFunc\n#define malloc_arg cbCtrlMallocArg\n#define free_func cbCtrlFreeFunc\n#define free_arg cbCtrlFreeArg\n#define stream_select srcSelect\n#define file_name fileName\n#define file_offset fileOffset\n#define file_size fileSize\n#define stream_ptr streamPtr\n#define stream_size streamSize\n#define down_scale downScale\n#define color_alpha outputColorAlpha\n#define color_space outputColorSpace\n#define cmd_ptr commandPtr\n#define quality method\n#define output_mode outputMode\n#define output_bytes_per_line outputBytesPerLine\n#define output_width outputWidth\n#define output_height outputHeight\n#define bit_depth outputBitDepth\n#define pack_flag outputPackFlag\n#define alpha_select outputAlphaSelect\n\n#define PTR_NULL NULL\n\n#endif\n\n/*============================================================\n\tTIMER PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#define sys_timer_usleep usleep\n#endif\n\n/*============================================================\n\tTHREADING PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <sys/thread.h>\n\n/* FIXME - not sure if this is correct -> FIXED! 1 and not 0 */\n#define SYS_THREAD_CREATE_JOINABLE THREAD_JOINABLE\n\n#else\n#include <sys/ppu_thread.h>\n\n#define SYS_PROCESS_SPAWN_STACK_SIZE_1M SYS_PROCESS_PRIMARY_STACK_SIZE_1M \n#define SYS_THREAD_CREATE_JOINABLE SYS_PPU_THREAD_CREATE_JOINABLE\n\n#define sysThreadCreate sys_ppu_thread_create \n#define sysThreadJoin sys_ppu_thread_join \n#define sysThreadExit sys_ppu_thread_exit \n\n#define sysProcessExit sys_process_exit \n#define sysProcessExitSpawn2 sys_game_process_exitspawn \n\n#endif\n\n/*============================================================\n\tMEMORY PROTOTYPES\n============================================================ */\n\n#ifndef __PSL1GHT__\n#define sysMemContainerCreate sys_memory_container_create \n#define sysMemContainerDestroy sys_memory_container_destroy \n#endif\n\n/*============================================================\n\tRSX PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <sysutil/video.h>\n#define CELL_GCM_FALSE GCM_FALSE\n#define CELL_GCM_TRUE GCM_TRUE\n\n#define CELL_GCM_ONE GCM_ONE\n#define CELL_GCM_ZERO GCM_ZERO\n#define CELL_GCM_ALWAYS GCM_ALWAYS\n\n#define CELL_GCM_LOCATION_LOCAL GCM_LOCATION_RSX\n#define CELL_GCM_LOCATION_MAIN GCM_LOCATION_CELL\n\n#define CELL_GCM_MAX_RT_DIMENSION (4096)\n\n#define CELL_GCM_TEXTURE_LINEAR_NEAREST GCM_TEXTURE_LINEAR_MIPMAP_NEAREST\n#define CELL_GCM_TEXTURE_LINEAR_LINEAR GCM_TEXTURE_LINEAR_MIPMAP_LINEAR\n#define CELL_GCM_TEXTURE_NEAREST_LINEAR GCM_TEXTURE_NEAREST_MIPMAP_LINEAR\n#define CELL_GCM_TEXTURE_NEAREST_NEAREST GCM_TEXTURE_NEAREST_MIPMAP_NEAREST\n#define CELL_GCM_TEXTURE_NEAREST GCM_TEXTURE_NEAREST\n#define CELL_GCM_TEXTURE_LINEAR GCM_TEXTURE_LINEAR\n\n#define CELL_GCM_TEXTURE_A8R8G8B8 GCM_TEXTURE_FORMAT_A8R8G8B8\n#define CELL_GCM_TEXTURE_R5G6B5 GCM_TEXTURE_FORMAT_R5G6B5\n#define CELL_GCM_TEXTURE_A1R5G5B5 GCM_TEXTURE_FORMAT_A1R5G5B5\n\n#define CELL_GCM_TEXTURE_CLAMP_TO_EDGE GCM_TEXTURE_CLAMP_TO_EDGE\n\n#define CELL_GCM_TEXTURE_MAX_ANISO_1 GCM_TEXTURE_MAX_ANISO_1\n#define CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX GCM_TEXTURE_CONVOLUTION_QUINCUNX\n#define CELL_GCM_TEXTURE_ZFUNC_NEVER GCM_TEXTURE_ZFUNC_NEVER\n\n#define CELL_GCM_DISPLAY_HSYNC GCM_FLIP_HSYNC\n#define CELL_GCM_DISPLAY_VSYNC GCM_FLIP_VSYNC\n\n#define CELL_GCM_CLEAR_R GCM_CLEAR_R\n#define CELL_GCM_CLEAR_G GCM_CLEAR_G\n#define CELL_GCM_CLEAR_B GCM_CLEAR_B\n#define CELL_GCM_CLEAR_A GCM_CLEAR_A\n\n#define CELL_GCM_FUNC_ADD GCM_FUNC_ADD\n\n#define CELL_GCM_SMOOTH\t(0x1D01)\n#define CELL_GCM_DEBUG_LEVEL2 2\n\n#define CELL_GCM_COMPMODE_DISABLED 0\n\n#define CELL_GCM_TRANSFER_LOCAL_TO_LOCAL 0\n\n#define CELL_GCM_TEXTURE_REMAP_ORDER_XYXY (0)\n#define CELL_GCM_TEXTURE_REMAP_ORDER_XXXY (1)\n\n#define CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL (0)\n\n#define CELL_GCM_TEXTURE_REMAP_FROM_A (0)\n#define CELL_GCM_TEXTURE_REMAP_FROM_R (1)\n#define CELL_GCM_TEXTURE_REMAP_FROM_G (2)\n#define CELL_GCM_TEXTURE_REMAP_FROM_B (3)\n\n#define CELL_GCM_TEXTURE_REMAP_ZERO (0)\n#define CELL_GCM_TEXTURE_REMAP_ONE (1)\n#define CELL_GCM_TEXTURE_REMAP_REMAP (2)\n\n#define CELL_GCM_MAX_TEXIMAGE_COUNT (16)\n\n#define CELL_GCM_TEXTURE_WRAP (1)\n\n#define CELL_GCM_TEXTURE_NR (0x00)\n#define CELL_GCM_TEXTURE_LN (0x20)\n\n#define CELL_GCM_TEXTURE_B8 (0x81)\n\n#define CELL_RESC_720x480 RESC_720x480\n#define CELL_RESC_720x576 RESC_720x576\n#define CELL_RESC_1280x720 RESC_1280x720\n#define CELL_RESC_1920x1080 RESC_1920x1080\n\n#define CELL_RESC_FULLSCREEN RESC_FULLSCREEN\n#define CELL_RESC_PANSCAN RESC_PANSCAN\n#define CELL_RESC_LETTERBOX RESC_LETTERBOX\n#define CELL_RESC_CONSTANT_VRAM RESC_CONSTANT_VRAM\n#define CELL_RESC_MINIMUM_GPU_LOAD RESC_MINIMUM_GPU_LOAD\n\n#define CELL_RESC_PAL_50 RESC_PAL_50\n#define CELL_RESC_PAL_60_DROP RESC_PAL_60_DROP\n#define CELL_RESC_PAL_60_INTERPOLATE RESC_PAL_60_INTERPOLATE\n#define CELL_RESC_PAL_60_INTERPOLATE_30_DROP RESC_PAL_60_INTERPOLATE_30_DROP\n#define CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE\n\n#define CELL_RESC_INTERLACE_FILTER RESC_INTERLACE_FILTER\n#define CELL_RESC_NORMAL_BILINEAR RESC_NORMAL_BILINEAR\n\n#define CELL_RESC_ELEMENT_HALF RESC_ELEMENT_HALF\n\n#define CELL_VIDEO_OUT_ASPECT_AUTO VIDEO_ASPECT_AUTO\n#define CELL_VIDEO_OUT_ASPECT_4_3 VIDEO_ASPECT_4_3\n#define CELL_VIDEO_OUT_ASPECT_16_9 VIDEO_ASPECT_16_9\n\n#define CELL_VIDEO_OUT_RESOLUTION_480 VIDEO_RESOLUTION_480\n#define CELL_VIDEO_OUT_RESOLUTION_576 VIDEO_RESOLUTION_576\n#define CELL_VIDEO_OUT_RESOLUTION_720 VIDEO_RESOLUTION_720\n#define CELL_VIDEO_OUT_RESOLUTION_1080 VIDEO_RESOLUTION_1080\n#define CELL_VIDEO_OUT_RESOLUTION_960x1080 VIDEO_RESOLUTION_960x1080\n#define CELL_VIDEO_OUT_RESOLUTION_1280x1080 VIDEO_RESOLUTION_1280x1080\n#define CELL_VIDEO_OUT_RESOLUTION_1440x1080 VIDEO_RESOLUTION_1440x1080\n#define CELL_VIDEO_OUT_RESOLUTION_1600x1080 VIDEO_RESOLUTION_1600x1080\n\n#define CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE VIDEO_SCANMODE_PROGRESSIVE\n\n#define CELL_VIDEO_OUT_PRIMARY VIDEO_PRIMARY\n\n#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 VIDEO_BUFFER_FORMAT_XRGB\n#define CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT VIDEO_BUFFER_FORMAT_FLOAT\n\n#define CellGcmSurface gcmSurface\n#define CellGcmTexture gcmTexture\n#define CellGcmContextData _gcmCtxData\n#define CellGcmConfig gcmConfiguration\n#define CellVideoOutConfiguration videoConfiguration\n#define CellVideoOutResolution videoResolution\n#define CellVideoOutState videoState\n\n#define CellRescInitConfig rescInitConfig\n#define CellRescSrc rescSrc\n#define CellRescBufferMode rescBufferMode\n\n#define resolutionId resolution\n#define memoryFrequency memoryFreq\n#define coreFrequency coreFreq\n\n#define cellGcmFinish rsxFinish\n\n#define cellGcmGetFlipStatus gcmGetFlipStatus\n#define cellGcmResetFlipStatus gcmResetFlipStatus\n#define cellGcmSetWaitFlip gcmSetWaitFlip\n#define cellGcmSetDebugOutputLevel gcmSetDebugOutputLevel\n#define cellGcmSetDisplayBuffer gcmSetDisplayBuffer\n#define cellGcmSetGraphicsHandler gcmSetGraphicsHandler\n#define cellGcmSetFlipHandler gcmSetFlipHandler\n#define cellGcmSetVBlankHandler gcmSetVBlankHandler\n#define cellGcmGetConfiguration gcmGetConfiguration\n#define cellGcmSetJumpCommand rsxSetJumpCommand\n#define cellGcmFlush rsxFlushBuffer\n#define cellGcmSetFlipMode gcmSetFlipMode\n#define cellGcmSetFlip gcmSetFlip\n#define cellGcmGetLabelAddress gcmGetLabelAddress\n#define cellGcmUnbindTile gcmUnbindTile\n#define cellGcmBindTile gcmBindTile\n#define cellGcmSetTileInfo gcmSetTileInfo\n#define cellGcmAddressToOffset gcmAddressToOffset\n\n#define cellRescCreateInterlaceTable rescCreateInterlaceTable\n#define cellRescSetDisplayMode rescSetDisplayMode\n#define cellRescGetNumColorBuffers rescGetNumColorBuffers\n#define cellRescGetBufferSize rescGetBufferSize\n#define cellRescSetBufferAddress rescSetBufferAddress\n#define cellRescGetFlipStatus rescGetFlipStatus\n#define cellRescResetFlipStatus rescResetFlipStatus\n#define cellRescSetConvertAndFlip rescSetConvertAndFlip\n#define cellRescSetVBlankHandler rescSetVBlankHandler\n#define cellRescSetFlipHandler rescSetFlipHandler\n#define cellRescAdjustAspectRatio rescAdjustAspectRatio\n#define cellRescSetWaitFlip rescSetWaitFlip\n#define cellRescSetSrc rescSetSrc\n#define cellRescInit rescInit\n#define cellRescExit rescExit\n\n#define cellVideoOutConfigure videoConfigure\n#define cellVideoOutGetState videoGetState\n#define cellVideoOutGetResolution videoGetResolution\n#define cellVideoOutGetResolutionAvailability videoGetResolutionAvailability\n\n#define cellGcmSetViewportInline rsxSetViewport\n#define cellGcmSetReferenceCommandInline rsxSetReferenceCommand\n#define cellGcmSetBlendEquationInline rsxSetBlendEquation\n#define cellGcmSetWriteBackEndLabelInline rsxSetWriteBackendLabel\n#define cellGcmSetWaitLabelInline rsxSetWaitLabel\n#define cellGcmSetDepthTestEnableInline rsxSetDepthTestEnable\n#define cellGcmSetScissorInline rsxSetScissor\n#define cellGcmSetBlendEnableInline rsxSetBlendEnable\n#define cellGcmSetClearColorInline rsxSetClearColor\n#define cellGcmSetBlendFuncInline rsxSetBlendFunc\n#define cellGcmSetBlendColorInline rsxSetBlendColor\n#define cellGcmSetTextureFilterInline rsxTextureFilter\n#define cellGcmSetTextureControlInline rsxTextureControl\n#define cellGcmSetCullFaceEnableInline rsxSetCullFaceEnable\n#define cellGcmSetShadeModeInline rsxSetShadeModel\n#define cellGcmSetTransferImage rsxSetTransferImage\n#define cellGcmSetBlendColor rsxSetBlendColor\n#define cellGcmSetBlendEquation rsxSetBlendEquation\n#define cellGcmSetBlendFunc rsxSetBlendFunc\n#define cellGcmSetClearColor rsxSetClearColor\n#define cellGcmSetScissor rsxSetScissor\n#define celGcmSetInvalidateVertexCache(fifo) rsxInvalidateTextureCache(fifo, GCM_INVALIDATE_VERTEX_TEXTURE)\n#else\n#define cellGcmSetTransferImage cellGcmSetTransferImageInline\n#define celGcmSetInvalidateVertexCache cellGcmSetInvalidateVertexCacheInline\n#define rsxInit cellGcmInit\n#define rsxInvalidateTextureCache(a, b) cellGcmSetInvalidateVertexCache(a)\n#define rsxTextureControl cellGcmSetTextureControlInline\n#define rsxSetBlendEnable cellGcmSetBlendEnableInline \n#endif\n\n/*============================================================\n\tNETWORK PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <net/netctl.h>\n\n#define cellNetCtlInit netCtlInit\n#define cellNetCtlGetState netCtlGetState\n#define cellNetCtlTerm netCtlTerm\n\n#define CELL_NET_CTL_STATE_IPObtained NET_CTL_STATE_IPObtained\n#else\n#define netCtlInit cellNetCtlInit\n#define netCtlGetState cellNetCtlGetState\n#define netCtlTerm cellNetCtlTerm\n#define NET_CTL_STATE_IPObtained CELL_NET_CTL_STATE_IPObtained\n#endif\n\n/*============================================================\n\tNET PROTOTYPES\n============================================================ */\n\n#if defined(HAVE_NETWORKING)\n#ifdef __PSL1GHT__\n#include <net/net.h>\n\n#define socketselect select\n#define socketclose close\n\n#define sys_net_initialize_network netInitialize\n#define sys_net_finalize_network netFinalizeNetwork\n#else\n#include <netex/net.h>\n#include <np.h>\n#include <np/drm.h>\n\n#define netInitialize sys_net_initialize_network\n#define netFinalizeNetwork sys_net_finalize_network\n#endif\n#endif\n\n/*============================================================\n\tSYSUTIL PROTOTYPES\n============================================================ */\n\n#ifdef __PSL1GHT__\n#include <sysutil/game.h>\n#define CellGameContentSize sysGameContentSize\n#define cellGameContentPermit sysGameContentPermit\n#define cellGameBootCheck sysGameBootCheck\n\n#define CELL_GAME_ATTRIBUTE_APP_HOME   (UINT64_C(1) <<1) /* boot from / app_home/PS3_GAME */\n#define CELL_GAME_DIRNAME_SIZE\t\t\t32\n\n#define CELL_GAME_GAMETYPE_SYS\t\t0\n#define CELL_GAME_GAMETYPE_DISC\t\t1\n#define CELL_GAME_GAMETYPE_HDD\t\t2\n#define CELL_GAME_GAMETYPE_GAMEDATA\t3\n#define CELL_GAME_GAMETYPE_HOME\t\t4\n\n#endif\n\n#if defined(HAVE_SYSUTILS)\n#ifdef __PSL1GHT__\n#include <sysutil/sysutil.h>\n\n#define CELL_SYSUTIL_REQUEST_EXITGAME SYSUTIL_EXIT_GAME\n\n#define cellSysutilRegisterCallback sysUtilRegisterCallback\n#define cellSysutilCheckCallback sysUtilCheckCallback\n#else\n#include <sysutil/sysutil_screenshot.h>\n#include <sysutil/sysutil_common.h>\n#include <sysutil/sysutil_gamecontent.h>\n#endif\n#endif\n\n#if(CELL_SDK_VERSION > 0x340000)\n#include <sysutil/sysutil_bgmplayback.h>\n#endif\n\n/*============================================================\n\tSYSMODULE PROTOTYPES\n============================================================ */\n\n#if defined(HAVE_SYSMODULES)\n#ifdef __PSL1GHT__\n#include <sysmodule/sysmodule.h>\n\n#define CELL_SYSMODULE_IO SYSMODULE_IO\n#define CELL_SYSMODULE_FS SYSMODULE_FS\n#define CELL_SYSMODULE_NET SYSMODULE_NET\n#define CELL_SYSMODULE_SYSUTIL_NP SYSMODULE_SYSUTIL_NP\n#define CELL_SYSMODULE_JPGDEC SYSMODULE_JPGDEC\n#define CELL_SYSMODULE_PNGDEC SYSMODULE_PNGDEC\n#define CELL_SYSMODULE_FONT SYSMODULE_FONT\n#define CELL_SYSMODULE_FREETYPE SYSMODULE_FREETYPE\n#define CELL_SYSMODULE_FONTFT SYSMODULE_FONTFT\n\n#define cellSysmoduleLoadModule sysModuleLoad\n#define cellSysmoduleUnloadModule sysModuleUnload\n\n#else\n#include <cell/sysmodule.h>\n\n#define sysModuleLoad cellSysmoduleLoadModule\n#define sysModuleUnload cellSysmoduleUnloadModule\n#define SYSMODULE_NET CELL_SYSMODULE_NET\n#endif\n#endif\n\n/*============================================================\n\tFS PROTOTYPES\n============================================================ */\n#define FS_SUCCEEDED 0\n#define FS_TYPE_DIR 1\n#ifdef __PSL1GHT__\n#include <lv2/sysfs.h>\n#ifndef O_RDONLY\n#define O_RDONLY SYS_O_RDONLY\n#endif\n#ifndef O_WRONLY\n#define O_WRONLY SYS_O_WRONLY\n#endif\n#ifndef O_CREAT\n#define O_CREAT SYS_O_CREAT\n#endif\n#ifndef O_TRUNC\n#define O_TRUNC SYS_O_TRUNC\n#endif\n#ifndef O_RDWR\n#define O_RDWR SYS_O_RDWR\n#endif\n#else\n#include <cell/cell_fs.h>\n#ifndef O_RDONLY\n#define O_RDONLY CELL_FS_O_RDONLY\n#endif\n#ifndef O_WRONLY\n#define O_WRONLY CELL_FS_O_WRONLY\n#endif\n#ifndef O_CREAT\n#define O_CREAT CELL_FS_O_CREAT\n#endif\n#ifndef O_TRUNC\n#define O_TRUNC CELL_FS_O_TRUNC\n#endif\n#ifndef O_RDWR\n#define O_RDWR CELL_FS_O_RDWR\n#endif\n#ifndef sysFsStat\n#define sysFsStat cellFsStat\n#endif\n#ifndef sysFSDirent\n#define sysFSDirent CellFsDirent\n#endif\n#ifndef sysFsOpendir\n#define sysFsOpendir cellFsOpendir\n#endif\n#ifndef sysFsReaddir\n#define sysFsReaddir cellFsReaddir\n#endif\n#ifndef sysFSDirent\n#define sysFSDirent CellFsDirent\n#endif\n#ifndef sysFsClosedir\n#define sysFsClosedir cellFsClosedir\n#endif\n#endif\n\n#endif\n"
  },
  {
    "path": "include/defines/ps4_defines.h",
    "content": "#ifndef _PS4_DEFINES_H\n#define _PS4_DEFINES_H\n\n#define PS4_MAX_ORBISPADS 16\n#define PS4_MAX_PAD_PORT_TYPES 3\n\n#define\tORBISPAD_L3\t\t        0x00000002\n#define\tORBISPAD_R3\t\t        0x00000004\n#define\tORBISPAD_OPTIONS\t    0x00000008\n#define\tORBISPAD_UP\t\t        0x00000010\n#define\tORBISPAD_RIGHT\t\t    0x00000020\n#define\tORBISPAD_DOWN\t\t      0x00000040\n#define\tORBISPAD_LEFT\t\t      0x00000080\n#define\tORBISPAD_L2\t\t        0x00000100\n#define\tORBISPAD_R2\t\t        0x00000200\n#define\tORBISPAD_L1\t\t        0x00000400\n#define\tORBISPAD_R1\t\t        0x00000800\n#define\tORBISPAD_TRIANGLE\t    0x00001000\n#define\tORBISPAD_CIRCLE\t\t    0x00002000\n#define\tORBISPAD_CROSS\t\t    0x00004000\n#define\tORBISPAD_SQUARE\t\t    0x00008000\n#define\tORBISPAD_TOUCH_PAD\t  0x00100000\n#define\tORBISPAD_INTERCEPTED\t0x80000000\n\n#define SceUID uint32_t\n#define SceKernelStat OrbisKernelStat\n#define SCE_KERNEL_PRIO_FIFO_DEFAULT 700\n#define SCE_AUDIO_OUT_PORT_TYPE_MAIN   0\n#define SCE_AUDIO_OUT_MODE_STEREO      1\n#define SCE_MOUSE_BUTTON_PRIMARY 0x00000001\n#define SCE_MOUSE_BUTTON_SECONDARY 0x00000002\n#define SCE_MOUSE_BUTTON_OPTIONAL 0x00000004\n#define SCE_MOUSE_BUTTON_INTERCEPTED 0x80000000\n#define SCE_MOUSE_OPEN_PARAM_MERGED\t0x01\n#define SCE_MOUSE_PORT_TYPE_STANDARD 0\n#define SCE_DBG_KEYBOARD_PORT_TYPE_STANDARD\t0\n#define SCE_USER_SERVICE_MAX_LOGIN_USERS 16\n#define SCE_USER_SERVICE_USER_ID_INVALID 0xFFFFFFFF\n#define SCE_ORBISPAD_ERROR_ALREADY_OPENED 0x80920004\n#define SCE_PAD_PORT_TYPE_STANDARD 0\n#define SCE_PAD_PORT_TYPE_SPECIAL\t2\n#define SCE_PAD_PORT_TYPE_REMOTE_CONTROL 16\n#define SCE_KERNEL_PROT_CPU_RW 0x02\n#define SCE_KERNEL_MAP_FIXED 0x10\n\n#endif\n"
  },
  {
    "path": "include/defines/psp_defines.h",
    "content": "/* Copyright (C) 2010-2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (psp_defines.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _PSP_DEFINES_H\n#define _PSP_DEFINES_H\n\n/*============================================================\n\tERROR PROTOTYPES\n============================================================ */\n\n#ifndef SCE_OK\n#define SCE_OK 0\n#endif\n\n/*============================================================\n\tDISPLAY PROTOTYPES\n============================================================ */\n\n#if defined(SN_TARGET_PSP2) || defined(VITA)\n\n#ifdef VITA\nint sceClibPrintf ( const char * format, ... );\n#define printf sceClibPrintf\n#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)\n#else\n#define PSP_DISPLAY_PIXEL_FORMAT_8888 (SCE_DISPLAY_PIXELFORMAT_A8B8G8R8)\n#endif\n\n#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, sync)\n\n#define PSP_FB_WIDTH        960\n#define PSP_FB_HEIGHT       544\n#define PSP_PITCH_PIXELS 1024\n\n/* Memory left to the system for threads and other internal stuffs */\n#ifdef SCE_LIBC_SIZE\n#define RAM_THRESHOLD 0x2000000 + SCE_LIBC_SIZE\n#else\n#define RAM_THRESHOLD 0x2000000\n#endif\n\n#elif defined(PSP)\n#define DisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync) sceDisplaySetFrameBuf(topaddr, bufferwidth, pixelformat, sync)\n\n#define SCE_DISPLAY_UPDATETIMING_NEXTVSYNC 1\n\n#define PSP_FB_WIDTH        512\n#define PSP_FB_HEIGHT       512\n#define PSP_PITCH_PIXELS 512\n\n#endif\n\n/*============================================================\n\tINPUT PROTOTYPES\n============================================================ */\n\n#if defined(SN_TARGET_PSP2) || defined(VITA)\n\n#define STATE_BUTTON(state) ((state).buttons)\n#define STATE_ANALOGLX(state) ((state).lx)\n#define STATE_ANALOGLY(state) ((state).ly)\n#define STATE_ANALOGRX(state) ((state).rx)\n#define STATE_ANALOGRY(state) ((state).ry)\n\n#if defined(VITA)\n#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_ANALOG)\n\n#define PSP_CTRL_LEFT SCE_CTRL_LEFT\n#define PSP_CTRL_DOWN SCE_CTRL_DOWN\n#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT\n#define PSP_CTRL_UP SCE_CTRL_UP\n#define PSP_CTRL_START SCE_CTRL_START\n#define PSP_CTRL_SELECT SCE_CTRL_SELECT\n#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE\n#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE\n#define PSP_CTRL_CROSS SCE_CTRL_CROSS\n#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE\n#define PSP_CTRL_L SCE_CTRL_L1\n#define PSP_CTRL_R SCE_CTRL_R1\n#define PSP_CTRL_L2 SCE_CTRL_LTRIGGER\n#define PSP_CTRL_R2 SCE_CTRL_RTRIGGER\n#define PSP_CTRL_L3 SCE_CTRL_L3\n#define PSP_CTRL_R3 SCE_CTRL_R3\n#define STATE_ANALOGL2(state) ((state).lt)\n#define STATE_ANALOGR2(state) ((state).rt)\n#else\n#define DEFAULT_SAMPLING_MODE (SCE_CTRL_MODE_DIGITALANALOG)\n\n#define PSP_CTRL_LEFT SCE_CTRL_LEFT\n#define PSP_CTRL_DOWN SCE_CTRL_DOWN\n#define PSP_CTRL_RIGHT SCE_CTRL_RIGHT\n#define PSP_CTRL_UP SCE_CTRL_UP\n#define PSP_CTRL_START SCE_CTRL_START\n#define PSP_CTRL_SELECT SCE_CTRL_SELECT\n#define PSP_CTRL_TRIANGLE SCE_CTRL_TRIANGLE\n#define PSP_CTRL_SQUARE SCE_CTRL_SQUARE\n#define PSP_CTRL_CROSS SCE_CTRL_CROSS\n#define PSP_CTRL_CIRCLE SCE_CTRL_CIRCLE\n#define PSP_CTRL_L SCE_CTRL_L\n#define PSP_CTRL_R SCE_CTRL_R\n#endif\n\n#if defined(VITA)\n#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingModeExt(mode)\n#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositiveExt2(port, pad_data, bufs)\n#else\n#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)\n#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(port, pad_data, bufs)\n#endif\n\n#elif defined(PSP)\n\n#define PSP_CTRL_L PSP_CTRL_LTRIGGER\n#define PSP_CTRL_R PSP_CTRL_RTRIGGER\n\n#define STATE_BUTTON(state) ((state).Buttons)\n#define STATE_ANALOGLX(state) ((state).Lx)\n#define STATE_ANALOGLY(state) ((state).Ly)\n#define STATE_ANALOGRX(state) ((state).Rx)\n#define STATE_ANALOGRY(state) ((state).Ry)\n\n#define DEFAULT_SAMPLING_MODE (PSP_CTRL_MODE_ANALOG)\n\n#define CtrlSetSamplingMode(mode) sceCtrlSetSamplingMode(mode)\n#define CtrlPeekBufferPositive(port, pad_data, bufs) sceCtrlPeekBufferPositive(pad_data, bufs)\n#endif\n\n#endif\n"
  },
  {
    "path": "include/dynamic/dylib.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (dylib.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __DYLIB_H\n#define __DYLIB_H\n\n#include <boolean.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <retro_common_api.h>\n\n#if defined(HAVE_DYNAMIC) || defined(HAVE_DYLIB)\n#define NEED_DYNAMIC\n#else\n#undef NEED_DYNAMIC\n#endif\n\nRETRO_BEGIN_DECLS\n\n/**\n * Opaque handle to a dynamic library.\n * @see dylib_load\n */\ntypedef void *dylib_t;\n\n/**\n * Opaque handle to a function exposed by a dynamic library.\n *\n * Should be cast to a known function pointer type before being used.\n * @see dylib_proc\n */\ntypedef void (*function_t)(void);\n\n#ifdef NEED_DYNAMIC\n/**\n * Loads a dynamic library in a platform-independent manner.\n *\n * @param path Path to the library to load.\n * May be either a complete path or a filename without an extension.\n * If not a complete path, the operating system will search for a library by this name;\n * details will depend on the platform.\n * @note The returned library must be freed with \\c dylib_close\n * before the core or frontend exits.\n *\n * @return Handle to the loaded library, or \\c NULL on failure.\n * Upon failure, \\c dylib_error may be used\n * to retrieve a string describing the error.\n * @see dylib_close\n * @see dylib_error\n * @see dylib_proc\n **/\ndylib_t dylib_load(const char *path);\n\n/**\n * Frees the resources associated with a dynamic library.\n *\n * Any function pointers obtained from the library may become invalid,\n * depending on whether the operating system manages reference counts to dynamic libraries.\n *\n * If there was an error closing the library,\n * it will be reported by \\c dylib_error.\n *\n * @param lib Handle to the library to close.\n * Behavior is undefined if \\c NULL.\n **/\nvoid dylib_close(dylib_t lib);\n\n/**\n * Returns a string describing the most recent error that occurred\n * within the other \\c dylib functions.\n *\n * @return Pointer to the most recent error string,\n * \\c or NULL if there was no error.\n * @warning The returned string is only valid\n * until the next call to a \\c dylib function.\n * Additionally, the string is managed by the library\n * and should not be modified or freed by the caller.\n */\nchar *dylib_error(void);\n\n/**\n * Returns a pointer to a function exposed by a dynamic library.\n *\n * @param lib The library to get a function pointer from.\n * @param proc The name of the function to get a pointer to.\n * @return Pointer to the requested function,\n * or \\c NULL if there was an error.\n * This must be cast to the correct function pointer type before being used.\n * @warning The returned pointer is only valid for the lifetime of \\c lib.\n * Once \\c lib is closed, all function pointers returned from it will be invalidated;\n * using them is undefined behavior.\n */\nfunction_t dylib_proc(dylib_t lib, const char *proc);\n#endif\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/encodings/base64.h",
    "content": "#ifndef _LIBRETRO_ENCODINGS_BASE64_H\n#define _LIBRETRO_ENCODINGS_BASE64_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Encodes binary data into a \\c NULL-terminated base64 string.\n *\n * @param binaryData The data to encode.\n * Behavior is undefined if \\c NULL.\n * @param len The length of the data to encode.\n * @param flen Pointer to the length of the returned string.\n * @return Pointer to the base64-encoded string, or \\c NULL on failure.\n * The returned string is owned by the caller and must be released with \\c free().\n * @see unbase64\n */\nchar* base64(const void* binaryData, int len, int *flen);\n\n/**\n * Decodes a base64-encoded string into binary data.\n *\n * @param ascii The base64 string to decode, in ASCII format.\n * @param len Length of the string to decode.\n * @param flen Pointer to the length of the returned data.\n * @return The decoded binary data, or \\c NULL on failure.\n * The returned buffer is owned by the caller and must be released with \\c free().\n * @see base64\n */\nunsigned char* unbase64(const char* ascii, int len, int *flen);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/encodings/crc32.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (crc32.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_ENCODINGS_CRC32_H\n#define _LIBRETRO_ENCODINGS_CRC32_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Computes a buffer's CRC32 checksum.\n *\n * @param crc The initial CRC32 value.\n * @param buf The buffer to calculate the CRC32 checksum of.\n * @param len The length of the data in \\c buf.\n * @return The CRC32 checksum of the given buffer.\n */\nuint32_t encoding_crc32(uint32_t crc, const uint8_t *buf, size_t len);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/encodings/utf.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (utf.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_ENCODINGS_UTF_H\n#define _LIBRETRO_ENCODINGS_UTF_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <boolean.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nenum CodePage\n{\n   CODEPAGE_LOCAL = 0, /* CP_ACP */\n   CODEPAGE_UTF8  = 65001 /* CP_UTF8 */\n};\n\n/**\n * utf8_conv_utf32:\n *\n * Simple implementation. Assumes the sequence is\n * properly synchronized and terminated.\n **/\nsize_t utf8_conv_utf32(uint32_t *out, size_t out_chars,\n      const char *in, size_t in_size);\n\n/**\n * utf16_conv_utf8:\n *\n * Leaf function.\n **/\nbool utf16_conv_utf8(uint8_t *out, size_t *out_chars,\n      const uint16_t *in, size_t in_size);\n\n/**\n * utf8len:\n *\n * Leaf function.\n **/\nsize_t utf8len(const char *string);\n\n/**\n * utf8cpy:\n *\n * Acts mostly like strlcpy.\n *\n * Copies the given number of UTF-8 characters,\n * but at most @d_len bytes.\n *\n * Always NULL terminates. Does not copy half a character.\n * @s is assumed valid UTF-8.\n * Use only if @chars is considerably less than @d_len. \n *\n * Hidden non-leaf function cost:\n * - Calls memcpy\n *\n * @return Number of bytes. \n **/\nsize_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);\n\n/**\n * utf8skip:\n *\n * Leaf function\n **/\nconst char *utf8skip(const char *str, size_t chars);\n\n/** \n * utf8_walk:\n *\n * Does not validate the input.\n *\n * Leaf function.\n *\n * @return Returns garbage if it's not UTF-8.\n **/\nuint32_t utf8_walk(const char **string);\n\n/**\n * utf16_to_char_string:\n **/\nbool utf16_to_char_string(const uint16_t *in, char *s, size_t len);\n\n/**\n * utf8_to_local_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nchar *utf8_to_local_string_alloc(const char *str);\n\n/**\n * local_to_utf8_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nchar *local_to_utf8_string_alloc(const char *str);\n\n/**\n * utf8_to_utf16_string_alloc:\n * \n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nwchar_t *utf8_to_utf16_string_alloc(const char *str);\n\n/**\n * utf16_to_utf8_string_alloc:\n *\n * @return Returned pointer MUST be freed by the caller if non-NULL.\n **/\nchar *utf16_to_utf8_string_alloc(const wchar_t *str);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/encodings/win32.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (utf.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_ENCODINGS_WIN32_H\n#define _LIBRETRO_ENCODINGS_WIN32_H\n\n#ifndef _XBOX\n#ifdef _WIN32\n/*#define UNICODE\n#include <tchar.h>\n#include <wchar.h>*/\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <encodings/utf.h>\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n#endif\n\n#ifdef UNICODE\n#define CHAR_TO_WCHAR_ALLOC(s, ws) \\\n   size_t ws##_size = (NULL != s && s[0] ? strlen(s) : 0) + 1; \\\n   wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \\\n   if (NULL != s && s[0]) \\\n      MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t));\n\n#define WCHAR_TO_CHAR_ALLOC(ws, s) \\\n   size_t s##_size = ((NULL != ws && ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \\\n   char *s = (char*)calloc(s##_size, 1); \\\n   if (NULL != ws && ws[0]) \\\n      utf16_to_char_string((const uint16_t*)ws, s, s##_size);\n\n#else\n#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s && s[0] ? strdup(s) : NULL);\n#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws && ws[0] ? strdup(ws) : NULL);\n#endif\n\n#endif\n"
  },
  {
    "path": "include/fastcpy.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fastcpy.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* in the future ASM and new c++ features can be added to speed up copying */\n#include <stdint.h>\n#include <string.h>\n#include <retro_inline.h>\n\nstatic INLINE void* memcpy16(void* dst, void* src, size_t len)\n{\n   return memcpy(dst, src, len * 2);\n}\n\nstatic INLINE void* memcpy32(void* dst, void* src, size_t len)\n{\n   return memcpy(dst, src, len * 4);\n}\n\nstatic INLINE void* memcpy64(void* dst, void* src, size_t len)\n{\n   return memcpy(dst, src, len * 8);\n}\n\n#ifdef USECPPSTDFILL\n#include <algorithm>\n\nstatic INLINE void* memset16(void* dst,uint16_t val, size_t len)\n{\n   uint16_t *typedptr = (uint16_t*)dst;\n   std::fill(typedptr, typedptr + len, val);\n   return dst;\n}\n\nstatic INLINE void* memset32(void* dst, uint32_t val, size_t len)\n{\n   uint32_t *typedptr = (uint32_t*)dst;\n   std::fill(typedptr, typedptr + len, val);\n   return dst;\n}\n\nstatic INLINE void* memset64(void* dst, uint64_t val, size_t len)\n{\n   uint64_t *typedptr = (uint64_t*)dst;\n   std::fill(typedptr, typedptr + len, val);\n   return dst;\n}\n#else\nstatic INLINE void *memset16(void* dst, uint16_t val, size_t len)\n{\n   size_t i;\n   uint16_t *typedptr = (uint16_t*)dst;\n   for (i = 0; i < len; i++)\n      typedptr[i] = val;\n   return dst;\n}\n\nstatic INLINE void *memset32(void* dst, uint32_t val, size_t len)\n{\n   size_t i;\n   uint32_t *typedptr = (uint32_t*)dst;\n   for (i = 0; i < len; i++)\n      typedptr[i] = val;\n   return dst;\n}\n\nstatic INLINE void *memset64(void* dst, uint64_t val, size_t len)\n{\n   size_t i;\n   uint64_t *typedptr = (uint64_t*)dst;\n   for (i = 0; i < len;i++)\n      typedptr[i] = val;\n   return dst;\n}\n#endif\n"
  },
  {
    "path": "include/features/features_cpu.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (features_cpu.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_CPU_INFO_H\n#define _LIBRETRO_SDK_CPU_INFO_H\n\n#include <retro_common_api.h>\n\n#include <stdint.h>\n\n#include <libretro.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Gets the time in ticks since some unspecified epoch.\n * The notion of a \"tick\" varies per platform.\n *\n * The epoch may change between devices or across reboots.\n *\n * Suitable for use as a default implementation of \\c retro_perf_callback::get_perf_counter,\n * (or as a fallback by the core),\n * although a frontend may provide its own implementation.\n *\n * @return The current time, in ticks.\n * @see retro_perf_callback::get_perf_counter\n */\nretro_perf_tick_t cpu_features_get_perf_counter(void);\n\n/**\n * Gets the time in microseconds since some unspecified epoch.\n *\n * The epoch may change between devices or across reboots.\n *\n * Suitable for use as a default implementation of \\c retro_perf_callback::get_time_usec,\n * (or as a fallback by the core),\n * although a frontend may provide its own implementation.\n *\n * @return The current time, in microseconds.\n * @see retro_perf_callback::get_time_usec\n */\nretro_time_t cpu_features_get_time_usec(void);\n\n/**\n * Returns the available features (mostly SIMD extensions)\n * supported by this CPU.\n *\n * Suitable for use as a default implementation of \\c retro_perf_callback::get_time_usec,\n * (or as a fallback by the core),\n * although a frontend may provide its own implementation.\n *\n * @return Bitmask of all CPU features available.\n * @see RETRO_SIMD\n * @see retro_perf_callback::get_cpu_features\n */\nuint64_t cpu_features_get(void);\n\n/**\n * @return The number of CPU cores available,\n * or 1 if the number of cores could not be determined.\n */\nunsigned cpu_features_get_core_amount(void);\n\n/**\n * Returns the name of the CPU model.\n *\n * @param[out] name Pointer to a buffer to store the name.\n * Will be \\c NULL-terminated.\n * If \\c NULL, this value will not be modified.\n * @param len The amount of space available in \\c name.\n */\nvoid cpu_features_get_model_name(char *name, int len);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/file/archive_file.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_file.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_SDK_ARCHIVE_FILE_H__\n#define LIBRETRO_SDK_ARCHIVE_FILE_H__\n\n#include <stdint.h>\n#include <stddef.h>\n#include <boolean.h>\n\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\n#include <retro_miscellaneous.h>\n\n#include <retro_common_api.h>\n\n#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)\n#include \"../../../config.h\" /* for HAVE_MMAP */\n#endif\n\nRETRO_BEGIN_DECLS\n\nenum file_archive_transfer_type\n{\n   ARCHIVE_TRANSFER_NONE = 0,\n   ARCHIVE_TRANSFER_INIT,\n   ARCHIVE_TRANSFER_ITERATE,\n   ARCHIVE_TRANSFER_DEINIT,\n   ARCHIVE_TRANSFER_DEINIT_ERROR\n};\n\ntypedef struct file_archive_handle\n{\n   uint8_t  *data;\n   uint32_t real_checksum;\n} file_archive_file_handle_t;\n\ntypedef struct file_archive_transfer\n{\n   int64_t archive_size;\n   void *context;\n   struct RFILE *archive_file;\n   const struct file_archive_file_backend *backend;\n#ifdef HAVE_MMAP\n   uint8_t *archive_mmap_data;\n   int archive_mmap_fd;\n#endif\n   unsigned step_total;\n   unsigned step_current;\n   enum file_archive_transfer_type type;\n} file_archive_transfer_t;\n\ntypedef struct\n{\n   file_archive_transfer_t archive;             /* int64_t alignment */\n   char *source_file;\n   char *subdir;\n   char *target_dir;\n   char *target_file;\n   char *valid_ext;\n   char *callback_error;\n   struct archive_extract_userdata *userdata;\n} decompress_state_t;\n\nstruct archive_extract_userdata\n{\n   /* These are set or read by the archive processing */\n   char *first_extracted_file_path;\n   const char *extraction_directory;\n   struct string_list *ext;\n   struct string_list *list;\n   file_archive_transfer_t *transfer;\n   /* Not used by the processing, free to use outside or in iterate callback */\n   decompress_state_t *dec;\n   void* cb_data;\n   uint32_t crc;\n   uint64_t size;\n   char archive_path[PATH_MAX_LENGTH];\n   char current_file_path[PATH_MAX_LENGTH];\n   bool found_file;\n   bool list_only;\n};\n\n/* Returns true when parsing should continue. False to stop. */\ntypedef int (*file_archive_file_cb)(const char *name, const char *valid_exts,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,\n      uint32_t crc32, struct archive_extract_userdata *userdata);\n\nstruct file_archive_file_backend\n{\n   int (*archive_parse_file_init)(\n      file_archive_transfer_t *state,\n      const char *file);\n   int (*archive_parse_file_iterate_step)(\n      void *context,\n      const char *valid_exts,\n      struct archive_extract_userdata *userdata,\n      file_archive_file_cb file_cb);\n   void (*archive_parse_file_free)(\n      void *context);\n\n   bool     (*stream_decompress_data_to_file_init)(\n      void *context, file_archive_file_handle_t *handle,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size);\n   int      (*stream_decompress_data_to_file_iterate)(\n      void *context,\n      file_archive_file_handle_t *handle);\n\n   uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t);\n   int64_t (*compressed_file_read)(const char *path, const char *needle, void **buf,\n         const char *optional_outfile);\n   const char *ident;\n};\n\nint file_archive_parse_file_iterate(\n      file_archive_transfer_t *state,\n      bool *returnerr,\n      const char *file,\n      const char *valid_exts,\n      file_archive_file_cb file_cb,\n      struct archive_extract_userdata *userdata);\n\nvoid file_archive_parse_file_iterate_stop(file_archive_transfer_t *state);\n\nint file_archive_parse_file_progress(file_archive_transfer_t *state);\n\n/**\n * file_archive_extract_file:\n * @archive_path                : filename path to ZIP archive.\n * @valid_exts                  : valid extensions for a file.\n * @extraction_directory        : the directory to extract the temporary\n *                                file to.\n *\n * Extract file from archive. If no file inside the archive is\n * specified, the first file found will be used.\n *\n * Returns : true (1) on success, otherwise false (0).\n **/\nbool file_archive_extract_file(const char *archive_path,\n      const char *valid_exts, const char *extraction_dir,\n      char *out_path, size_t len);\n\n/* Warning: 'list' must zero initialised before\n * calling this function, otherwise memory leaks/\n * undefined behaviour will occur */\nbool file_archive_get_file_list_noalloc(struct string_list *list,\n      const char *path,\n      const char *valid_exts);\n\n/**\n * file_archive_get_file_list:\n * @path                        : filename path of archive\n * @valid_exts                  : Valid extensions of archive to be parsed.\n *                                If NULL, allow all.\n *\n * Returns: string listing of files from archive on success, otherwise NULL.\n **/\nstruct string_list* file_archive_get_file_list(const char *path, const char *valid_exts);\n\nbool file_archive_perform_mode(const char *name, const char *valid_exts,\n      const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,\n      uint32_t crc32, struct archive_extract_userdata *userdata);\n\nint file_archive_compressed_read(\n      const char* path, void **buf,\n      const char* optional_filename, int64_t *length);\n\nconst struct file_archive_file_backend* file_archive_get_zlib_file_backend(void);\nconst struct file_archive_file_backend* file_archive_get_7z_file_backend(void);\nconst struct file_archive_file_backend* file_archive_get_zstd_file_backend(void);\n\nconst struct file_archive_file_backend* file_archive_get_file_backend(const char *path);\n\n/**\n * file_archive_get_file_crc32:\n * @path                         : filename path of archive\n *\n * Returns: CRC32 of the specified file in the archive, otherwise 0.\n * If no path within the archive is specified, the first\n * file found inside is used.\n **/\nuint32_t file_archive_get_file_crc32(const char *path);\n\n/**\n * file_archive_get_file_crc32_and_size:\n * @path                         : filename path of archive\n * @size                         : size of the file inside the archive\n *\n * Returns: CRC32 of the specified file in the archive, otherwise 0.\n * If no path within the archive is specified, the first\n * file found inside is used.\n **/\nuint32_t file_archive_get_file_crc32_and_size(const char *path, uint64_t *size);\n\nextern const struct file_archive_file_backend zlib_backend;\nextern const struct file_archive_file_backend sevenzip_backend;\nextern const struct file_archive_file_backend zstd_backend;\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/file/config_file.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (config_file.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_CONFIG_FILE_H\n#define __LIBRETRO_SDK_CONFIG_FILE_H\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stddef.h>\n\n#include <boolean.h>\n\n#define CONFIG_GET_BOOL_BASE(conf, base, var, key) do { \\\n   bool tmp = false; \\\n   if (config_get_bool(conf, key, &tmp)) \\\n      base->var = tmp; \\\n} while(0)\n\n#define CONFIG_GET_INT_BASE(conf, base, var, key) do { \\\n   int tmp = 0; \\\n   if (config_get_int(conf, key, &tmp)) \\\n      base->var = tmp; \\\n} while(0)\n\n#define CONFIG_GET_FLOAT_BASE(conf, base, var, key) do { \\\n   float tmp = 0.0f; \\\n   if (config_get_float(conf, key, &tmp)) \\\n      base->var = tmp; \\\n} while(0)\n\nenum config_file_flags\n{\n   CONF_FILE_FLG_MODIFIED                 = (1 << 0),\n   CONF_FILE_FLG_GUARANTEED_NO_DUPLICATES = (1 << 1)\n};\n\nstruct config_file\n{\n   char *path;\n   struct config_entry_list **entries_map;\n   struct config_entry_list *entries;\n   struct config_entry_list *tail;\n   struct config_entry_list *last;\n   struct config_include_list *includes;\n   struct path_linked_list *references;\n   unsigned include_depth;\n   uint8_t flags;\n};\n\ntypedef struct config_file config_file_t;\n\nstruct config_file_cb\n{\n   void (*config_file_new_entry_cb)(char*, char*);\n};\n\ntypedef struct config_file_cb config_file_cb_t ;\n\n/* Config file format\n * - # are treated as comments. Rest of the line is ignored.\n * - Format is: key = value. There can be as many spaces as you like in-between.\n * - Value can be wrapped inside \"\" for multiword strings. (foo = \"hai u\")\n * - #include includes a config file in-place.\n *\n * Path is relative to where config file was loaded unless an absolute path is chosen.\n * Key/value pairs from an #include are read-only, and cannot be modified.\n */\n\n/**\n * config_file_new:\n *\n * Loads a config file.\n * If @path is NULL, will create an empty config file.\n *\n * @return Returns NULL if file doesn't exist.\n **/\nconfig_file_t *config_file_new(const char *path);\n\nconfig_file_t *config_file_new_alloc(void);\n\n/**\n * config_file_initialize:\n *\n * Leaf function.\n **/\nvoid config_file_initialize(struct config_file *conf);\n\n/**\n * config_file_new_with_callback:\n *\n * Loads a config file.\n * If @path is NULL, will create an empty config file.\n * Includes cb callbacks  to run custom code during config file processing.\n *\n * @return Returns NULL if file doesn't exist.\n **/\nconfig_file_t *config_file_new_with_callback(\n      const char *path, config_file_cb_t *cb);\n\n/**\n * config_file_new_from_string:\n *\n * Load a config file from a string.\n *\n * NOTE: This will modify @from_string.\n * Pass a copy of source string if original\n * contents must be preserved\n **/\nconfig_file_t *config_file_new_from_string(char *from_string,\n      const char *path);\n\nconfig_file_t *config_file_new_from_path_to_string(const char *path);\n\n/**\n * config_file_free:\n *\n * Frees config file.\n **/\nvoid config_file_free(config_file_t *conf);\n\nsize_t config_file_add_reference(config_file_t *conf, char *path);\n\nbool config_file_deinitialize(config_file_t *conf);\n\n/**\n * config_append_file:\n *\n * Loads a new config, and appends its data to @conf.\n * The key-value pairs of the new config file takes priority over the old.\n **/\nbool config_append_file(config_file_t *conf, const char *path);\n\n/* All extract functions return true when value is valid and exists.\n * Returns false otherwise. */\n\nstruct config_entry_list\n{\n   char *key;\n   char *value;\n   struct config_entry_list *next;\n   /* If we got this from an #include,\n    * do not allow overwrite. */\n   bool readonly;\n};\n\nstruct config_file_entry\n{\n   const char *key;\n   const char *value;\n   /* Used intentionally. Opaque here. */\n   const struct config_entry_list *next;\n};\n\nstruct config_entry_list *config_get_entry(\n      const config_file_t *conf, const char *key);\n\n/**\n * config_get_entry_list_head:\n *\n * Leaf function.\n **/\nbool config_get_entry_list_head(config_file_t *conf,\n      struct config_file_entry *entry);\n\n/**\n * config_get_entry_list_next:\n *\n * Leaf function.\n **/\nbool config_get_entry_list_next(struct config_file_entry *entry);\n\n/**\n * config_get_double:\n *\n * Extracts a double from config file.\n *\n * Hidden non-leaf function cost:\n * - Calls config_get_entry()\n * - Calls strtod\n *\n * @return True if double found, otherwise false.\n **/\nbool config_get_double(config_file_t *conf, const char *entry, double *in);\n\n/**\n * config_get_float:\n *\n * Extracts a float from config file.\n *\n * Hidden non-leaf function cost:\n * - Calls config_get_entry()\n * - Calls strtod\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_float(config_file_t *conf, const char *entry, float *in);\n\n/* Extracts an int from config file. */\nbool config_get_int(config_file_t *conf, const char *entry, int *in);\n\n/* Extracts an uint from config file. */\nbool config_get_uint(config_file_t *conf, const char *entry, unsigned *in);\n\n/* Extracts an size_t from config file. */\nbool config_get_size_t(config_file_t *conf, const char *key, size_t *in);\n\n#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L\n/* Extracts an uint64 from config file. */\nbool config_get_uint64(config_file_t *conf, const char *entry, uint64_t *in);\n#endif\n\n/* Extracts an unsigned int from config file treating input as hex. */\nbool config_get_hex(config_file_t *conf, const char *entry, unsigned *in);\n\n/**\n * config_get_char:\n *\n * Extracts a single char from config file.\n * If value consists of several chars, this is an error.\n *\n * Hidden non-leaf function cost:\n * - Calls config_get_entry()\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_char(config_file_t *conf, const char *entry, char *in);\n\n/**\n * config_get_string:\n *\n * Extracts an allocated string in *in. This must be free()-d if\n * this function succeeds.\n *\n * Hidden non-leaf function cost:\n * - Calls config_get_entry()\n * - Calls strdup\n *\n * @return true if found, otherwise false.\n **/\nbool config_get_string(config_file_t *conf, const char *entry, char **in);\n\n/* Extracts a string to a preallocated buffer. Avoid memory allocation. */\nbool config_get_array(config_file_t *conf, const char *entry, char *s, size_t len);\n\n/**\n  * config_get_config_path:\n  *\n  * Extracts a string to a preallocated buffer.\n  * Avoid memory allocation.\n  *\n  * Hidden non-leaf function cost:\n  * - Calls strlcpy\n  **/\nsize_t config_get_config_path(config_file_t *conf, char *s, size_t len);\n\n/* Extracts a string to a preallocated buffer. Avoid memory allocation.\n * Recognized magic like ~/. Similar to config_get_array() otherwise. */\nbool config_get_path(config_file_t *conf, const char *entry, char *s, size_t len);\n\n/**\n * config_get_bool:\n *\n * Extracts a boolean from config.\n * Valid boolean true are \"true\" and \"1\". Valid false are \"false\" and \"0\".\n * Other values will be treated as an error.\n *\n * Hidden non-leaf function cost:\n * - Calls string_is_equal() x times\n *\n * @return true if preconditions are true, otherwise false.\n **/\nbool config_get_bool(config_file_t *conf, const char *entry, bool *in);\n\n/* Setters. Similar to the getters.\n * Will not write to entry if the entry was obtained from an #include. */\nsize_t config_set_double(config_file_t *conf, const char *entry, double value);\nsize_t config_set_float(config_file_t *conf, const char *entry, float value);\nsize_t config_set_int(config_file_t *conf, const char *entry, int val);\nsize_t config_set_hex(config_file_t *conf, const char *entry, unsigned val);\nsize_t config_set_uint64(config_file_t *conf, const char *entry, uint64_t val);\nsize_t config_set_char(config_file_t *conf, const char *entry, char val);\nsize_t config_set_uint(config_file_t *conf, const char *key, unsigned int val);\n\nvoid config_set_path(config_file_t *conf, const char *entry, const char *val);\nvoid config_set_string(config_file_t *conf, const char *entry, const char *val);\nvoid config_unset(config_file_t *conf, const char *key);\n\n/**\n * config_file_write:\n *\n * Write the current config to a file.\n **/\nbool config_file_write(config_file_t *conf, const char *path, bool val);\n\n/**\n * config_file_dump:\n *\n * Dump the current config to an already opened file.\n * Does not close the file.\n **/\nvoid config_file_dump(config_file_t *conf, FILE *file, bool val);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/file/config_file_userdata.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (config_file_userdata.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H\n#define _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H\n\n#include <string.h>\n\n#include <file/config_file.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nstruct config_file_userdata\n{\n   config_file_t *conf;\n   const char *prefix[2];\n};\n\nint config_userdata_get_float(void *userdata, const char *key_str,\n      float *value, float default_value);\n\nint config_userdata_get_int(void *userdata, const char *key_str,\n      int *value, int default_value);\n\nint config_userdata_get_hex(void *userdata, const char *key_str,\n      unsigned *value, unsigned default_value);\n\nint config_userdata_get_float_array(void *userdata, const char *key_str,\n      float **values, unsigned *out_num_values,\n      const float *default_values, unsigned num_default_values);\n\nint config_userdata_get_int_array(void *userdata, const char *key_str,\n      int **values, unsigned *out_num_values,\n      const int *default_values, unsigned num_default_values);\n\nint config_userdata_get_string(void *userdata, const char *key_str,\n      char **output, const char *default_output);\n\nvoid config_userdata_free(void *ptr);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/file/file_path.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_path.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FILE_PATH_H\n#define __LIBRETRO_SDK_FILE_PATH_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <sys/types.h>\n\n#include <libretro.h>\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\n#define PATH_REQUIRED_VFS_VERSION 3\n#define STAT64_REQUIRED_VFS_VERSION 4\n\nvoid path_vfs_init(const struct retro_vfs_interface_info* vfs_info);\n\n/* Order in this enum is equivalent to negative sort order in filelist\n *  (i.e. DIRECTORY is on top of PLAIN_FILE) */\nenum\n{\n   RARCH_FILETYPE_UNSET,\n   RARCH_PLAIN_FILE,\n   RARCH_COMPRESSED_FILE_IN_ARCHIVE,\n   RARCH_COMPRESSED_ARCHIVE,\n   RARCH_DIRECTORY,\n   RARCH_FILE_UNSUPPORTED\n};\n\nstruct path_linked_list\n{\n   char *path;\n   struct path_linked_list *next;\n};\n\n/**\n * Create a new linked list with one item in it\n * The path on this item will be set to NULL\n**/\nstruct path_linked_list* path_linked_list_new(void);\n\n/* Free the entire linked list */\nvoid path_linked_list_free(struct path_linked_list *in_path_linked_list);\n\n/**\n * Add a node to the linked list with this path\n * If the first node's path if it's not yet set,\n * set this instead\n**/\nvoid path_linked_list_add_path(struct path_linked_list *in_path_linked_list, char *path);\n\n/**\n * path_is_compressed_file:\n * @path               : path\n *\n * Checks if path is a compressed file.\n *\n * Returns: true (1) if path is a compressed file, otherwise false (0).\n **/\nbool path_is_compressed_file(const char *path);\n\n/**\n * path_contains_compressed_file:\n * @path               : path\n *\n * Checks if path contains a compressed file.\n *\n * Currently we only check for hash symbol (#) inside the pathname.\n * If path is ever expanded to a general URI, we should check for that here.\n *\n * Example:  Somewhere in the path there might be a compressed file\n * E.g.: /path/to/file.7z#mygame.img\n *\n * Returns: true (1) if path contains compressed file, otherwise false (0).\n **/\n#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)\n\n/**\n * path_get_archive_delim:\n * @path               : path\n *\n * Find delimiter of an archive file. Only the first '#'\n * after a compression extension is considered.\n *\n * @return pointer to the delimiter in the path if it contains\n * a path inside a compressed file, otherwise NULL.\n **/\nconst char *path_get_archive_delim(const char *path);\n\n/**\n * path_get_extension:\n * @path               : path\n *\n * Gets extension of file. Only '.'s\n * after the last slash are considered.\n *\n * Hidden non-leaf function cost:\n * - calls strrchr\n *\n * @return extension part from the path.\n **/\nconst char *path_get_extension(const char *path);\n\n/**\n * path_get_extension_mutable:\n * @path               : path\n *\n * Specialized version of path_get_extension(). Return\n * value is mutable.\n *\n * Gets extension of file. Only '.'s\n * after the last slash are considered.\n *\n * @return extension part from the path.\n **/\nchar *path_get_extension_mutable(const char *path);\n\n/**\n * path_remove_extension:\n * @path               : path\n *\n * Mutates path by removing its extension. Removes all\n * text after and including the last '.'.\n * Only '.'s after the last slash are considered.\n *\n * Hidden non-leaf function cost:\n * - calls strrchr\n *\n * @return\n * 1) If path has an extension, returns path with the\n *    extension removed.\n * 2) If there is no extension, returns NULL.\n * 3) If path is empty or NULL, returns NULL\n */\nchar *path_remove_extension(char *path);\n\n/**\n * path_basename:\n * @path               : path\n *\n * Get basename from @path.\n *\n * Hidden non-leaf function cost:\n * - Calls path_get_archive_delim()\n *\n * @return basename from path.\n **/\nconst char *path_basename(const char *path);\n\n/**\n * path_basename_nocompression:\n * @path               : path\n *\n * Specialized version of path_basename().\n * Get basename from @path.\n *\n * @return basename from path.\n **/\nconst char *path_basename_nocompression(const char *path);\n\n/**\n * path_basedir:\n * @path               : path\n *\n * Extracts base directory by mutating path.\n * Keeps trailing '/'.\n **/\nsize_t path_basedir(char *path);\n\n/**\n * path_parent_dir:\n * @s                  : path\n * @len                : size of buffer\n *\n * Extracts parent directory by mutating path.\n * Assumes that path is a directory. Keeps trailing '/'.\n * If the path was already at the root directory, returns empty string\n **/\nsize_t path_parent_dir(char *s, size_t len);\n\n/**\n * path_resolve_realpath:\n * @s                  : input and output buffer for path\n * @size               : size of buffer\n * @resolve_symlinks   : whether to resolve symlinks or not\n *\n * Resolves use of \".\", \"..\", multiple slashes etc in absolute paths.\n *\n * Relative paths are rebased on the current working dir.\n *\n * @return @s if successful, NULL otherwise.\n * Note: Not implemented on consoles\n * Note: Symlinks are only resolved on Unix-likes\n * Note: The current working dir might not be what you expect,\n *       e.g. on Android it is \"/\"\n *       Use of fill_pathname_resolve_relative() should be preferred\n **/\nchar *path_resolve_realpath(char *s, size_t len, bool resolve_symlinks);\n\n/**\n * path_relative_to:\n * @s                  : buffer to write the relative path to\n * @path               : path to be expressed relatively\n * @base               : relative to this\n * @len                : size of output buffer\n *\n * Turns @path into a path relative to @base and writes it to @s.\n *\n * @base is assumed to be a base directory, i.e. a path ending with '/' or '\\'.\n * Both @path and @base are assumed to be absolute paths without \".\" or \"..\".\n *\n * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp\n *\n * @return Length of the string copied into @s\n **/\nsize_t path_relative_to(char *s, const char *path, const char *base,\n      size_t len);\n\n/**\n * path_is_absolute:\n * @path               : path\n *\n * Checks if @path is an absolute path or a relative path.\n *\n * @return true if path is absolute, false if path is relative.\n **/\nbool path_is_absolute(const char *path);\n\n/**\n * fill_pathname:\n * @s                  : output path\n * @in_path            : input  path\n * @replace            : what to replace\n * @len                : buffer size of output path\n *\n * FIXME: Verify\n *\n * Replaces filename extension with 'replace' and outputs result to s.\n * The extension here is considered to be the string from the last '.'\n * to the end.\n *\n * Only '.'s after the last slash are considered as extensions.\n * If no '.' is present, in_path and replace will simply be concatenated.\n * 'len' is buffer size of 's'.\n * E.g.: in_path = \"/foo/bar/baz/boo.c\", replace = \".asm\" =>\n * s = \"/foo/bar/baz/boo.asm\"\n * E.g.: in_path = \"/foo/bar/baz/boo.c\", replace = \"\"     =>\n * s = \"/foo/bar/baz/boo\"\n *\n * Hidden non-leaf function cost:\n * - calls strlcpy 2x\n * - calls strrchr\n * - calls strlcat\n *\n * @return Length of the string copied into @s\n */\nsize_t fill_pathname(char *s, const char *in_path,\n      const char *replace, size_t len);\n\n/**\n * fill_dated_filename:\n * @s                  : output filename\n * @ext                : extension of output filename\n * @len                : buffer size of output filename\n *\n * Creates a 'dated' filename prefixed by 'RetroArch', and\n * concatenates extension (@ext) to it.\n *\n * E.g.:\n * s = \"RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}\"\n *\n * Hidden non-leaf function cost:\n * - Calls rtime_localtime()\n * - Calls strftime\n * - Calls strlcpy\n *\n **/\nsize_t fill_dated_filename(char *s, const char *ext, size_t len);\n\n/**\n * fill_str_dated_filename:\n * @s                  : output filename\n * @in_str             : input string\n * @ext                : extension of output filename\n * @len                : buffer size of output filename\n *\n * Creates a 'dated' filename prefixed by the string @in_str, and\n * concatenates extension (@ext) to it.\n *\n * E.g.:\n * s = \"RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}\"\n *\n * Hidden non-leaf function cost:\n * - Calls time\n * - Calls rtime_localtime()\n * - Calls strlcpy (at least once)\n * - Calls strftime\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_str_dated_filename(char *s, const char *in_str, const char *ext, size_t len);\n\n/**\n * find_last_slash:\n * @str                : path\n *\n * Find last slash in path. Tries to find\n * a backslash on Windows too which takes precedence\n * over regular slash.\n *\n * Leaf function.\n *\n * @return pointer to last slash/backslash found in @str.\n **/\nchar *find_last_slash(const char *str);\n\n/**\n * fill_pathname_dir:\n * @s                  : input directory path\n * @in_basename        : input basename to be appended to @s\n * @replace            : replacement to be appended to @in_basename\n * @len                : size of buffer\n *\n * Appends basename of 'in_basename', to 's', along with 'replace'.\n * Basename of in_basename is the string after the last '/' or '\\\\',\n * i.e the filename without directories.\n *\n * If in_basename has no '/' or '\\\\', the whole 'in_basename' will be used.\n * 'len' is buffer size of 's'.\n *\n * E.g..: s = \"/tmp/some_dir\", in_basename = \"/some_content/foo.c\",\n * replace = \".asm\" => s = \"/tmp/some_dir/foo.c.asm\"\n *\n * Hidden non-leaf function cost:\n * - Calls fill_pathname_slash()\n * - Calls path_basename()\n * - Calls strlcpy 2x\n **/\nsize_t fill_pathname_dir(char *s, const char *in_basename,\n      const char *replace, size_t len);\n\n/**\n * fill_pathname_base:\n * @s                  : output path\n * @in_path            : input path\n * @len                : size of output path\n *\n * Copies basename of @in_path into @s.\n *\n * Hidden non-leaf function cost:\n * - Calls path_basename()\n * - Calls strlcpy\n *\n * @return length of the string copied into @s\n **/\nsize_t fill_pathname_base(char *s, const char *in_path, size_t len);\n\n/**\n * fill_pathname_basedir:\n * @s                  : output directory\n * @in_path            : input path\n * @len                : size of output directory\n *\n * Copies base directory of @in_path into @s.\n * If in_path is a path without any slashes (relative current directory),\n * @s will get path \"./\".\n *\n * Hidden non-leaf function cost:\n * - Calls strlcpy\n * - Calls path_basedir()\n **/\nsize_t fill_pathname_basedir(char *s, const char *in_path, size_t len);\n\n/**\n * fill_pathname_parent_dir_name:\n * @s                  : output string\n * @in_dir             : input directory\n * @len                : size of @s\n *\n * Copies only the parent directory name of @in_dir into @s.\n * The two buffers must not overlap. Removes trailing '/'.\n *\n * Hidden non-leaf function cost:\n * - Can call strlcpy\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_parent_dir_name(char *s,\n      const char *in_dir, size_t len);\n\n/**\n * fill_pathname_parent_dir:\n * @s                  : output directory\n * @in_dir             : input directory\n * @len                : size of output directory\n *\n * Copies parent directory of @in_dir into @s.\n * Assumes @in_dir is a directory. Keeps trailing '/'.\n * If the path was already at the root directory, @s will be an empty string.\n *\n * Hidden non-leaf function cost:\n * - Can call strlcpy if (@s!= @in_dir)\n * - Calls strlen if (@s == @in_dir)\n * - Calls path_parent_dir()\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_parent_dir(char *s,\n      const char *in_dir, size_t len);\n\n/**\n * fill_pathname_resolve_relative:\n * @s                  : output path\n * @in_refpath         : input reference path\n * @in_path            : input path\n * @len                : size of @s\n *\n * Joins basedir of @in_refpath together with @in_path.\n * If @in_path is an absolute path, s = in_path.\n * E.g.: in_refpath = \"/foo/bar/baz.a\", in_path = \"foobar.cg\",\n * s = \"/foo/bar/foobar.cg\".\n **/\nvoid fill_pathname_resolve_relative(char *s, const char *in_refpath,\n      const char *in_path, size_t len);\n\n/**\n * fill_pathname_join:\n * @s                  : output path\n * @dir                : directory\n * @path               : path\n * @len                : size of output path\n *\n * Joins a directory (@dir) and path (@path) together.\n * Makes sure not to get two consecutive slashes\n * between directory and path.\n *\n * Hidden non-leaf function cost:\n * - calls strlcpy at least once\n * - calls fill_pathname_slash()\n *\n * Deprecated. Use fill_pathname_join_special() instead\n * if you can ensure @dir != @s\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_join(char *s, const char *dir,\n      const char *path, size_t len);\n\n/**\n * fill_pathname_join_special:\n * @s                  : output path\n * @dir                : directory. Cannot be identical to @s\n * @path               : path\n * @len                : size of output path\n *\n *\n * Specialized version of fill_pathname_join.\n * Unlike fill_pathname_join(),\n * @dir and @s CANNOT be identical.\n *\n * Joins a directory (@dir) and path (@path) together.\n * Makes sure not to get two consecutive slashes\n * between directory and path.\n *\n * Hidden non-leaf function cost:\n * - calls strlcpy 2x\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_join_special(char *s,\n      const char *dir, const char *path, size_t len);\n\nsize_t fill_pathname_join_special_ext(char *s,\n      const char *dir,  const char *path,\n      const char *last, const char *ext,\n      size_t len);\n\n/**\n * fill_pathname_join_delim:\n * @s                  : output path\n * @dir                : directory\n * @path               : path\n * @delim              : delimiter\n * @len                : size of output path\n *\n * Joins a directory (@dir) and path (@path) together\n * using the given delimiter (@delim).\n *\n * Hidden non-leaf function cost:\n * - can call strlen\n * - can call strlcpy\n * - can call strlcat\n **/\nsize_t fill_pathname_join_delim(char *s, const char *dir,\n      const char *path, const char delim, size_t len);\n\nsize_t fill_pathname_expand_special(char *s,\n      const char *in_path, size_t len);\n\nsize_t fill_pathname_abbreviate_special(char *s,\n      const char *in_path, size_t len);\n\n/**\n * fill_pathname_abbreviated_or_relative:\n *\n * Fills the supplied path with either the abbreviated path or\n * the relative path, which ever one has less depth / number of slashes\n *\n * If lengths of abbreviated and relative paths are the same,\n * the relative path will be used\n * @in_path can be an absolute, relative or abbreviated path\n *\n * @return Length of the string copied into @s\n **/\nsize_t fill_pathname_abbreviated_or_relative(char *s,\n\t\tconst char *in_refpath, const char *in_path, size_t len);\n\n/**\n * sanitize_path_part:\n *\n * @path_part          : directory or filename\n * @len                : length of path_part\n *\n * Takes single part of a path eg. single filename\n * or directory, and removes any special chars that are\n * unavailable.\n *\n * @returns newly allocated string that has been sanitized.\n * Caller is responsible for freeing the returned string.\n **/\nchar *sanitize_path_part(const char *path_part, size_t len);\n\n/**\n * pathname_conform_slashes_to_os:\n *\n * @path               : path\n *\n * Leaf function.\n *\n * Changes the slashes to the correct kind for the os\n * So forward slash on linux and backslash on Windows\n **/\nvoid pathname_conform_slashes_to_os(char *s);\n\n/**\n * pathname_make_slashes_portable:\n * @path               : path\n *\n * Leaf function.\n *\n * Change all slashes to forward so they are more\n * portable between Windows and Linux\n **/\nvoid pathname_make_slashes_portable(char *s);\n\n/**\n * path_basedir:\n * @path               : path\n *\n * Extracts base directory by mutating path.\n * Keeps trailing '/'.\n **/\nvoid path_basedir_wrapper(char *s);\n\n/**\n * path_char_is_slash:\n * @c                  : character\n *\n * Checks if character (@c) is a slash.\n *\n * @return true if character is a slash, otherwise false.\n **/\n#ifdef _WIN32\n#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\\\'))\n#else\n#define PATH_CHAR_IS_SLASH(c) ((c) == '/')\n#endif\n\n/**\n * path_default_slash and path_default_slash_c:\n *\n * Gets the default slash separator.\n *\n * @return default slash separator.\n **/\n#ifdef _WIN32\n#define PATH_DEFAULT_SLASH() \"\\\\\"\n#define PATH_DEFAULT_SLASH_C() '\\\\'\n#else\n#define PATH_DEFAULT_SLASH() \"/\"\n#define PATH_DEFAULT_SLASH_C() '/'\n#endif\n\n/**\n * fill_pathname_slash:\n * @s                  : path\n * @len                : size of path\n *\n * Assumes path is a directory. Appends a slash\n * if not already there.\n\n * Hidden non-leaf function cost:\n * - can call strlcat once if it returns false\n * - calls strlen\n **/\nsize_t fill_pathname_slash(char *s, size_t len);\n\n#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)\nsize_t fill_pathname_application_path(char *s, size_t len);\nsize_t fill_pathname_application_dir(char *s, size_t len);\nsize_t fill_pathname_home_dir(char *s, size_t len);\n#endif\n\n/**\n * path_mkdir:\n * @dir                : directory\n *\n * Create directory on filesystem.\n *\n * Recursive function.\n *\n * Hidden non-leaf function cost:\n * - Calls strdup\n * - Calls path_parent_dir()\n * - Calls strcmp\n * - Calls path_is_directory()\n * - Calls path_mkdir()\n *\n * @return true if directory could be created, otherwise false.\n **/\nbool path_mkdir(const char *dir);\n\n/**\n * path_is_directory:\n * @path               : path\n *\n * Checks if path is a directory.\n *\n * @return true if path is a directory, otherwise false.\n */\nbool path_is_directory(const char *path);\n\n/* Time format strings with AM-PM designation require special\n * handling due to platform dependence\n * @return Length of the string written to @s\n */\nsize_t strftime_am_pm(char *s, size_t len, const char* format,\n      const void* timeptr);\n\nbool path_is_character_special(const char *path);\n\nint path_stat(const char *path);\n\nbool path_is_valid(const char *path);\n\nint64_t path_get_size(const char *path);\n\nbool is_path_accessible_using_standard_io(const char *path);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/file/nbio.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nbio.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_NBIO_H\n#define __LIBRETRO_SDK_NBIO_H\n\n#include <stddef.h>\n#include <boolean.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#ifndef NBIO_READ\n#define NBIO_READ   0\n#endif\n\n#ifndef NBIO_WRITE\n#define NBIO_WRITE  1\n#endif\n\n#ifndef NBIO_UPDATE\n#define NBIO_UPDATE 2\n#endif\n\n/* these two are blocking; nbio_iterate always returns true, but that operation (or something earlier) may take arbitrarily long */\n#ifndef BIO_READ\n#define BIO_READ    3\n#endif\n\n#ifndef BIO_WRITE\n#define BIO_WRITE   4\n#endif\n\ntypedef struct nbio_intf\n{\n   void *(*open)(const char * filename, unsigned mode);\n\n   void (*begin_read)(void *data);\n\n   void (*begin_write)(void *data);\n\n   bool (*iterate)(void *data);\n\n   void (*resize)(void *data, size_t len);\n\n   void *(*get_ptr)(void *data, size_t* len);\n\n   void (*cancel)(void *data);\n\n   void (*free)(void *data);\n\n   /* Set the per-iteration chunk size in bytes.\n    * Only meaningful for backends that read/write in chunks (e.g. stdio).\n    * Backends that ignore this (mmap, linux AIO) may set this to NULL. */\n   void (*set_chunk_size)(void *data, size_t chunk_size);\n\n   /* Return the underlying OS file descriptor, or -1 if unavailable.\n    * Enables callers to use platform-specific optimizations\n    * (posix_fadvise, sendfile, copy_file_range, etc.). */\n   int (*get_fd)(void *data);\n\n   /* Report byte-level I/O progress.\n    * Sets *completed and *total; returns true if operation in progress.\n    * Backends that do not track progress may set this to NULL. */\n   bool (*get_progress)(void *data, size_t *completed, size_t *total);\n\n   /* Fast path: load an entire file in one blocking call.\n    * Collapses begin_read + iterate-loop + get_ptr into a single\n    * operation. For mmap backends this is a no-op (data already mapped).\n    * For AIO it does a blocking wait. For stdio it does a single fread.\n    * Returns a pointer to the data and sets *len, or NULL on failure.\n    * The handle must have been opened in a read mode.\n    * Backends that do not implement this may set it to NULL;\n    * the dispatch layer falls back to begin_read + iterate + get_ptr. */\n   void *(*load_entire)(void *data, size_t *len);\n\n   /* Human readable string. */\n   const char *ident;\n} nbio_intf_t;\n\n/*\n * Creates an nbio structure for performing the\n * given operation on the given file.\n */\nvoid *nbio_open(const char * filename, unsigned mode);\n\n/*\n * Starts reading the given file. When done, it will be available in nbio_get_ptr.\n * Can not be done if the structure was created with {N,}BIO_WRITE.\n */\nvoid nbio_begin_read(void *data);\n\n/*\n * Starts writing to the given file. Before this, you should've copied the data to nbio_get_ptr.\n * Can not be done if the structure was created with {N,}BIO_READ.\n */\nvoid nbio_begin_write(void *data);\n\n/*\n * Performs part of the requested operation, or checks how it's going.\n * When it returns true, it's done.\n */\nbool nbio_iterate(void *data);\n\n/*\n * Resizes the file up to the given size; cannot shrink.\n * Can not be done if the structure was created with {N,}BIO_READ.\n */\nvoid nbio_resize(void *data, size_t len);\n\n/*\n * Returns a pointer to the file data. Writable only if structure was not created with {N,}BIO_READ.\n * If any operation is in progress, the pointer will be NULL, but len will still be correct.\n */\nvoid* nbio_get_ptr(void *data, size_t* len);\n\n/*\n * Stops any pending operation, allowing the object to be freed.\n */\nvoid nbio_cancel(void *data);\n\n/*\n * Deletes the nbio structure and its associated pointer.\n */\nvoid nbio_free(void *data);\n\n/*\n * Sets the chunk size (in bytes) for each iteration of I/O.\n * Larger values reduce per-iteration overhead at the cost of\n * longer blocking per call to nbio_iterate.\n * A value of 0 resets to the backend default.\n * Backends that do not chunk (mmap, linux AIO) ignore this.\n */\nvoid nbio_set_chunk_size(void *data, size_t chunk_size);\n\n/*\n * Returns the underlying OS file descriptor for the nbio handle,\n * or -1 if the backend does not expose one.\n * Useful for platform-specific I/O optimizations (fadvise, sendfile, etc.).\n */\nint nbio_get_fd(void *data);\n\n/*\n * Reports the current I/O progress.\n * Sets *completed to the number of bytes transferred so far,\n * and *total to the total file size.\n * Returns true if the operation is still in progress, false if idle/done.\n */\nbool nbio_get_progress(void *data, size_t *completed, size_t *total);\n\n/*\n * Fast path: load the entire file into memory in one blocking call.\n * Equivalent to begin_read + while(!iterate) + get_ptr, but backends\n * can implement this far more efficiently:\n *   - mmap: returns the mapped pointer directly (zero-copy, instant)\n *   - linux AIO: blocking io_getevents wait (one syscall)\n *   - stdio: single fread of the whole file\n * Returns a pointer to the file data and sets *len, or NULL on error.\n * The handle remains valid; call nbio_free() when done.\n */\nvoid *nbio_load_entire(void *data, size_t *len);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/filters.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (filters.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_FILTERS_H\n#define _LIBRETRO_SDK_FILTERS_H\n\n/* for MSVC; should be benign under any circumstances */\n#define _USE_MATH_DEFINES\n\n#include <stdlib.h>\n#include <math.h>\n#include <retro_inline.h>\n#include <retro_math.h>\n\n/**\n * sinc:\n *\n * Pure function.\n **/\nstatic INLINE double sinc(double val)\n{\n   if (fabs(val) < 0.00001)\n      return 1.0;\n   return sin(val) / val;\n}\n\n/**\n * paeth:\n *\n * Pure function.\n * Paeth prediction filter.\n **/\nstatic INLINE int paeth(int a, int b, int c)\n{\n   int p  = a + b - c;\n   int pa = abs(p - a);\n   int pb = abs(p - b);\n   int pc = abs(p - c);\n\n   if (pa <= pb && pa <= pc)\n      return a;\n   else if (pb <= pc)\n      return b;\n   return c;\n}\n\n/**\n * besseli0:\n *\n * Pure function.\n *\n * Modified Bessel function of first order.\n * Check Wiki for mathematical definition ...\n **/\nstatic INLINE double besseli0(double x)\n{\n   int i;\n   double sum            = 0.0;\n   double factorial      = 1.0;\n   double factorial_mult = 0.0;\n   double x_pow          = 1.0;\n   double two_div_pow    = 1.0;\n   double x_sqr          = x * x;\n\n   /* Approximate. This is an infinite sum.\n    * Luckily, it converges rather fast. */\n   for (i = 0; i < 18; i++)\n   {\n      sum            += x_pow * two_div_pow / (factorial * factorial);\n      factorial_mult += 1.0;\n      x_pow          *= x_sqr;\n      two_div_pow    *= 0.25;\n      factorial      *= factorial_mult;\n   }\n\n   return sum;\n}\n\nstatic INLINE double kaiser_window_function(double index, double beta)\n{\n   return besseli0(beta * sqrtf(1 - index * index));\n}\n\n#endif\n"
  },
  {
    "path": "include/formats/cdfs.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (cdfs.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __RARCH_CDFS_H\n#define __RARCH_CDFS_H\n\n#include <streams/interface_stream.h>\n\nRETRO_BEGIN_DECLS\n\n/* these functions provide an interface for locating and reading files within a data track\n * of a CD (following the ISO-9660 directory structure definition)\n */\n\ntypedef struct cdfs_track_t\n{\n   intfstream_t* stream;\n   unsigned int stream_sector_size;\n   unsigned int stream_sector_header_size;\n   unsigned int first_sector_offset;\n   unsigned int first_sector_index;\n} cdfs_track_t;\n\ntypedef struct cdfs_file_t\n{\n   struct cdfs_track_t* track;\n   int first_sector;\n   int current_sector;\n   int sector_buffer_valid;\n   unsigned int current_sector_offset;\n   unsigned int size;\n   unsigned int pos;\n   uint8_t sector_buffer[2048];\n} cdfs_file_t;\n\n/* opens the specified file within the CD or virtual CD.\n * if path is NULL, will open the raw CD (useful for \n * reading CD without having to worry about sector sizes,\n * headers, or checksum data)\n */\nint cdfs_open_file(cdfs_file_t* file, cdfs_track_t* stream, const char* path);\n\nvoid cdfs_close_file(cdfs_file_t* file);\n\nint64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len);\n\nint64_t cdfs_get_size(cdfs_file_t* file);\n\nint64_t cdfs_tell(cdfs_file_t* file);\n\nint64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence);\n\nvoid cdfs_seek_sector(cdfs_file_t* file, unsigned int sector);\n\nuint32_t cdfs_get_num_sectors(cdfs_file_t* file);\n\nuint32_t cdfs_get_first_sector(cdfs_file_t* file);\n\n/* opens the specified track in a CD or virtual CD file - the resulting stream should be passed to\n * cdfs_open_file to get access to a file within the CD.\n *\n * supported files:\n *   real CD - path will be in the form \"cdrom://drive1.cue\" or \"cdrom://d:/drive.cue\"\n *   bin/cue - path will point to the cue file\n *   chd     - path will point to the chd file\n *\n * for bin/cue files, the following storage modes are supported:\n *   MODE2/2352\n *   MODE1/2352\n *   MODE1/2048 - untested\n *   MODE2/2336 - untested\n */\ncdfs_track_t* cdfs_open_track(const char* path, unsigned int track_index);\n\n/* opens the first data track in a CD or virtual CD file. see cdfs_open_track for supported file formats\n */\ncdfs_track_t* cdfs_open_data_track(const char* path);\n\n/* opens a raw track file for a CD or virtual CD.\n *\n * supported files:\n *   real CD - path will be in the form \"cdrom://drive1-track01.bin\" or \"cdrom://d:/drive-track01.bin\"\n *             NOTE: cue file for CD must be opened first to populate vfs_cdrom_toc.\n *   bin     - path will point to the bin file\n *   iso     - path will point to the iso file\n */\ncdfs_track_t* cdfs_open_raw_track(const char* path);\n\n/* closes the CD or virtual CD track and frees the associated memory */\nvoid cdfs_close_track(cdfs_track_t* track);\n\nRETRO_END_DECLS\n\n#endif /* __RARCH_CDFS_H */\n"
  },
  {
    "path": "include/formats/image.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (image.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __RARCH_IMAGE_CONTEXT_H\n#define __RARCH_IMAGE_CONTEXT_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\nenum image_process_code\n{\n   IMAGE_PROCESS_ERROR     = -2,\n   IMAGE_PROCESS_ERROR_END = -1,\n   IMAGE_PROCESS_NEXT      =  0,\n   IMAGE_PROCESS_END       =  1\n};\n\nstruct texture_image\n{\n   uint32_t *pixels;\n   unsigned width;\n   unsigned height;\n   bool supports_rgba;\n};\n\nenum image_type_enum\n{\n   IMAGE_TYPE_NONE = 0,\n   IMAGE_TYPE_PNG,\n   IMAGE_TYPE_JPEG,\n   IMAGE_TYPE_BMP,\n   IMAGE_TYPE_TGA,\n   IMAGE_TYPE_WEBP\n};\n\nenum image_type_enum image_texture_get_type(const char *path);\n\nbool image_texture_load_buffer(struct texture_image *img,\n   enum image_type_enum type, void *s, size_t len);\n\nbool image_texture_load(struct texture_image *img, const char *path);\nvoid image_texture_free(struct texture_image *img);\n\n/* Image transfer */\n\nvoid image_transfer_free(void *data, enum image_type_enum type);\n\nvoid *image_transfer_new(enum image_type_enum type);\n\nbool image_transfer_start(void *data, enum image_type_enum type);\n\nvoid image_transfer_set_buffer_ptr(\n      void *data,\n      enum image_type_enum type,\n      void *ptr,\n      size_t len);\n\nint image_transfer_process(\n      void *data,\n      enum image_type_enum type,\n      uint32_t **buf,\n      size_t len,\n      unsigned *width,\n      unsigned *height,\n      bool supports_rgba);\n\nbool image_transfer_iterate(void *data, enum image_type_enum type);\n\nbool image_transfer_is_valid(void *data, enum image_type_enum type);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/logiqx_dat.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (logiqx_dat.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__\n#define __LIBRETRO_SDK_FORMAT_LOGIQX_DAT_H__\n\n#include <retro_common_api.h>\n#include <retro_miscellaneous.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\n/* Trivial handler for DAT files in Logiqx XML format\n * (http://www.logiqx.com/). Provides bare minimum\n * functionality - predominantly concerned with obtaining\n * description text for specific arcade ROM images.\n *\n * Note: Also supports the following alternative DAT\n * formats, since they are functionally identical to\n * Logiqx XML (but with different element names):\n * > MAME List XML\n * > MAME 'Software List' */\n\n/* Prevent direct access to logiqx_dat_t members */\ntypedef struct logiqx_dat logiqx_dat_t;\n\n/* Holds all metadata for a single game entry\n * in the DAT file (minimal at present - may be\n * expanded with individual internal ROM data\n * if required) */\ntypedef struct\n{\n   char name[NAME_MAX_LENGTH];\n   char description[NAME_MAX_LENGTH];\n   char year[8];\n   char manufacturer[128];\n   bool is_bios;\n   bool is_runnable;\n} logiqx_dat_game_info_t;\n\n/* Validation */\n\n/* Performs rudimentary validation of the specified\n * Logiqx XML DAT file path (not rigorous - just\n * enough to prevent obvious errors).\n * Also provides access to file size (DAT files can\n * be very large, so it is useful to have this information\n * on hand - i.e. so we can check that the system has\n * enough free memory to load the file). */\nbool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size);\n\n/* File initialisation/de-initialisation */\n\n/* Loads specified Logiqx XML DAT file from disk.\n * Returned logiqx_dat_t object must be free'd using\n * logiqx_dat_free().\n * Returns NULL if file is invalid or a read error\n * occurs. */\nlogiqx_dat_t *logiqx_dat_init(const char *path);\n\n/* Frees specified DAT file */\nvoid logiqx_dat_free(logiqx_dat_t *dat_file);\n\n/* Game information access */\n\n/* Sets/resets internal node pointer to the first\n * entry in the DAT file */\nvoid logiqx_dat_set_first(logiqx_dat_t *dat_file);\n\n/* Fetches game information for the current entry\n * in the DAT file and increments the internal node\n * pointer.\n * Returns false if the end of the DAT file has been\n * reached (in which case 'game_info' will be invalid) */\nbool logiqx_dat_get_next(\n      logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info);\n\n/* Fetches information for the specified game.\n * Returns false if game does not exist, or arguments\n * are invalid. */\nbool logiqx_dat_search(\n      logiqx_dat_t *dat_file, const char *game_name,\n      logiqx_dat_game_info_t *game_info);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/m3u_file.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (m3u_file.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_M3U_FILE_H__\n#define __LIBRETRO_SDK_FORMAT_M3U_FILE_H__\n\n#include <retro_common_api.h>\n\n#include <stdint.h>\n#include <stddef.h>\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\n/* Trivial handler for M3U playlist files */\n\n/* M3U file extension */\n#define M3U_FILE_EXT \"m3u\"\n\n/* Prevent direct access to m3u_file_t members */\ntypedef struct content_m3u_file m3u_file_t;\n\n/* Holds all metadata for a single M3U file entry */\ntypedef struct\n{\n   char *path;\n   char *full_path;\n   char *label;\n} m3u_file_entry_t;\n\n/* Defines entry label formatting when\n * writing M3U files to disk */\nenum m3u_file_label_type\n{\n   M3U_FILE_LABEL_NONE = 0,\n   M3U_FILE_LABEL_NONSTD,\n   M3U_FILE_LABEL_EXTSTD,\n   M3U_FILE_LABEL_RETRO\n};\n\n/* File Initialisation / De-Initialisation */\n\n/* Creates and initialises an M3U file\n * - If 'path' refers to an existing file,\n *   contents is parsed\n * - If path does not exist, an empty M3U file\n *   is created\n * - Returned m3u_file_t object must be free'd using\n *   m3u_file_free()\n * - Returns NULL in the event of an error */\nm3u_file_t *m3u_file_init(const char *path);\n\n/* Frees specified M3U file */\nvoid m3u_file_free(m3u_file_t *m3u_file);\n\n/* Getters */\n\n/* Returns M3U file path */\nchar *m3u_file_get_path(m3u_file_t *m3u_file);\n\n/* Returns number of entries in M3U file */\nsize_t m3u_file_get_size(m3u_file_t *m3u_file);\n\n/* Fetches specified M3U file entry\n * - Returns false if 'idx' is invalid, or internal\n *   entry is NULL */\nbool m3u_file_get_entry(\n      m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry);\n\n/* Setters */\n\n/* Adds specified entry to the M3U file\n * - Returns false if path is invalid, or\n *   memory could not be allocated for the\n *   entry */\nbool m3u_file_add_entry(\n      m3u_file_t *m3u_file, const char *path, const char *label);\n\n/* Removes all entries in M3U file */\nvoid m3u_file_clear(m3u_file_t *m3u_file);\n\n/* Saving */\n\n/* Saves M3U file to disk\n * - Setting 'label_type' to M3U_FILE_LABEL_NONE\n *   just outputs entry paths - this the most\n *   common format supported by most cores\n * - Returns false in the event of an error */\nbool m3u_file_save(\n      m3u_file_t *m3u_file, enum m3u_file_label_type label_type);\n\n/* Utilities */\n\n/* Sorts M3U file entries in alphabetical order */\nvoid m3u_file_qsort(m3u_file_t *m3u_file);\n\n/* Returns true if specified path corresponds\n * to an M3U file (simple convenience function) */\nbool m3u_file_is_m3u(const char *path);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rbmp.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rbmp.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RBMP_H__\n#define __LIBRETRO_SDK_FORMAT_RBMP_H__\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\nenum rbmp_source_type\n{\n   RBMP_SOURCE_TYPE_DONT_CARE,\n   RBMP_SOURCE_TYPE_BGR24,\n   RBMP_SOURCE_TYPE_XRGB888,\n   RBMP_SOURCE_TYPE_RGB565,\n   RBMP_SOURCE_TYPE_ARGB8888\n};\n\ntypedef struct rbmp rbmp_t;\n\nbool rbmp_save_image(\n      const char *filename,\n      const void *frame,\n      unsigned width,\n      unsigned height,\n      unsigned pitch,\n      enum rbmp_source_type type);\n\nint rbmp_process_image(rbmp_t *rbmp, void **buf,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba);\n\nvoid form_bmp_header(uint8_t *header,\n      unsigned width, unsigned height,\n      bool is32bpp);\n\nbool rbmp_set_buf_ptr(rbmp_t *rbmp, void *data);\n\nvoid rbmp_free(rbmp_t *rbmp);\n\nrbmp_t *rbmp_alloc(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rjpeg.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rjpeg.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RJPEG_H__\n#define __LIBRETRO_SDK_FORMAT_RJPEG_H__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct rjpeg rjpeg_t;\n\nbool rjpeg_start(rjpeg_t *rjpeg);\n\nbool rjpeg_iterate_image(rjpeg_t *rjpeg);\n\nbool rjpeg_is_valid(rjpeg_t *rjpeg);\n\nint rjpeg_process_image(rjpeg_t *rjpeg, void **buf,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba);\n\nbool rjpeg_set_buf_ptr(rjpeg_t *rjpeg, void *data, size_t len);\n\nvoid rjpeg_free(rjpeg_t *rjpeg);\n\nrjpeg_t *rjpeg_alloc(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rjson.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rjson.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RJSON_H__\n#define __LIBRETRO_SDK_FORMAT_RJSON_H__\n\n#include <retro_common_api.h>\n#include <boolean.h> /* bool */\n#include <stddef.h> /* size_t */\n\nRETRO_BEGIN_DECLS\n\n/* List of possible element types returned by rjson_next */\nenum rjson_type\n{\n   RJSON_DONE,\n   RJSON_OBJECT, RJSON_ARRAY, RJSON_OBJECT_END, RJSON_ARRAY_END,\n   RJSON_STRING, RJSON_NUMBER, RJSON_TRUE, RJSON_FALSE, RJSON_NULL,\n   RJSON_ERROR\n};\n\n/* Options that can be passed to rjson_set_options */\nenum rjson_option\n{\n   /* Allow UTF-8 byte order marks */\n   RJSON_OPTION_ALLOW_UTF8BOM                      = (1<<0),\n   /* Allow JavaScript style comments in the stream */\n   RJSON_OPTION_ALLOW_COMMENTS                     = (1<<1),\n   /* Allow unescaped control characters in strings (bytes 0x00 - 0x1F) */\n   RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS = (1<<2),\n   /* Ignore invalid Unicode escapes and don't validate UTF-8 codes */\n   RJSON_OPTION_IGNORE_INVALID_ENCODING            = (1<<3),\n   /* Replace invalid Unicode escapes and UTF-8 codes with a '?' character */\n   RJSON_OPTION_REPLACE_INVALID_ENCODING           = (1<<4),\n   /* Ignore carriage return (\\r escape sequence) in strings */\n   RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN      = (1<<5),\n   /* Allow data after the end of the top JSON object/array/value */\n   RJSON_OPTION_ALLOW_TRAILING_DATA                = (1<<6)\n};\n\n/* Custom data input callback\n * Should return > 0 and <= len on success, 0 on file end and < 0 on error. */\ntypedef int (*rjson_io_t)(void* buf, int len, void *user_data);\ntypedef struct rjson rjson_t;\nstruct intfstream_internal;\nstruct RFILE;\n\n/* Create a new parser instance from various sources */\nrjson_t *rjson_open_stream(struct intfstream_internal *stream);\nrjson_t *rjson_open_rfile(struct RFILE *rfile);\nrjson_t *rjson_open_buffer(const void *buffer, size_t len);\nrjson_t *rjson_open_string(const char *string, size_t len);\nrjson_t *rjson_open_user(rjson_io_t io, void *user_data, int io_block_size);\n\n/* Free the parser instance created with rjson_open_* */\nvoid rjson_free(rjson_t *json);\n\n/* Set one or more enum rjson_option, will override previously set options.\n * Use bitwise OR to concatenate multiple options.\n * By default none of the options are set. */\nvoid rjson_set_options(rjson_t *json, char rjson_option_flags);\n\n/* Sets the maximum context depth, recursion inside arrays and objects.\n * By default this is set to 50. */\nvoid rjson_set_max_depth(rjson_t *json, unsigned int max_depth);\n\n/* Parse to the next JSON element and return the type of it.\n * Will return RJSON_DONE when successfully reaching the end or\n * RJSON_ERROR when an error was encountered. */\nenum rjson_type rjson_next(rjson_t *json);\n\n/* Get the current string, null-terminated unescaped UTF-8 encoded.\n * Can only be used when the current element is RJSON_STRING or RJSON_NUMBER.\n * The returned pointer is only valid until the parsing continues. */\nconst char *rjson_get_string(rjson_t *json, size_t *length);\n\n/* Returns the current number (or string) converted to double or int */\ndouble rjson_get_double(rjson_t *json);\nint    rjson_get_int(rjson_t *json);\n\n/* Returns a string describing the error once rjson_next/rjson_parse\n * has returned an unrecoverable RJSON_ERROR (otherwise returns \"\"). */\nconst char *rjson_get_error(rjson_t *json);\n\n/* Can be used to set a custom error description on an invalid JSON structure.\n * Maximum length of 79 characters and once set the parsing can't continue. */\nvoid rjson_set_error(rjson_t *json, const char* error);\n\n/* Functions to get the current position in the source stream as well as */\n/* a bit of source json around the current position for additional detail\n * when parsing has failed with RJSON_ERROR.\n * Intended to be used with printf style formatting like:\n * printf(\"Invalid JSON at line %d, column %d - %s - Source: ...%.*s...\\n\",\n *       (int)rjson_get_source_line(json), (int)rjson_get_source_column(json),\n *       rjson_get_error(json), rjson_get_source_context_len(json),\n *       rjson_get_source_context_buf(json)); */\nsize_t      rjson_get_source_line(rjson_t *json);\nsize_t      rjson_get_source_column(rjson_t *json);\nint         rjson_get_source_context_len(rjson_t *json);\nconst char* rjson_get_source_context_buf(rjson_t *json);\n\n/* Confirm the parsing context stack, for example calling\n   rjson_check_context(json, 2, RJSON_OBJECT, RJSON_ARRAY)\n   returns true when inside \"{ [ ...\" but not for \"[ ..\" or \"{ [ { ...\" */\nbool rjson_check_context(rjson_t *json, unsigned int depth, ...);\n\n/* Returns the current level of nested objects/arrays */\nunsigned int rjson_get_context_depth(rjson_t *json);\n\n/* Return the current parsing context, that is, RJSON_OBJECT if we are inside\n * an object, RJSON_ARRAY if we are inside an array, and RJSON_DONE or\n * RJSON_ERROR if we are not yet/anymore in either. */\nenum rjson_type rjson_get_context_type(rjson_t *json);\n\n/* While inside an object or an array, this return the number of parsing\n * events that have already been observed at this level with rjson_next.\n * In particular, inside an object, an odd number would indicate that the just\n * observed RJSON_STRING event is a member name. */\nsize_t rjson_get_context_count(rjson_t *json);\n\n/* Parse an entire JSON stream with a list of element specific handlers.\n * Each of the handlers can be passed a function or NULL to ignore it.\n * If a handler returns false, the parsing will abort and the returned\n * rjson_type will indicate on which element type parsing was aborted.\n * Otherwise the return value will be RJSON_DONE or RJSON_ERROR. */\nenum rjson_type rjson_parse(rjson_t *json, void* context,\n      bool (*object_member_handler)(void *context, const char *str, size_t len),\n      bool (*string_handler       )(void *context, const char *str, size_t len),\n      bool (*number_handler       )(void *context, const char *str, size_t len),\n      bool (*start_object_handler )(void *context),\n      bool (*end_object_handler   )(void *context),\n      bool (*start_array_handler  )(void *context),\n      bool (*end_array_handler    )(void *context),\n      bool (*boolean_handler      )(void *context, bool value),\n      bool (*null_handler         )(void *context));\n\n/* A simpler interface to parse a JSON in memory. This will avoid any memory\n * allocations unless the document contains strings longer than 512 characters.\n * In the error handler, error will be \"\" if any of the other handlers aborted. */\nbool rjson_parse_quick(const char *string, size_t len, void* context, char option_flags,\n      bool (*object_member_handler)(void *context, const char *str, size_t len),\n      bool (*string_handler       )(void *context, const char *str, size_t len),\n      bool (*number_handler       )(void *context, const char *str, size_t len),\n      bool (*start_object_handler )(void *context),\n      bool (*end_object_handler   )(void *context),\n      bool (*start_array_handler  )(void *context),\n      bool (*end_array_handler    )(void *context),\n      bool (*boolean_handler      )(void *context, bool value),\n      bool (*null_handler         )(void *context),\n      void (*error_handler        )(void *context, int line, int col, const char* error));\n\n/* ------------------------------------------------------------------------- */\n\n/* Options that can be passed to rjsonwriter_set_options */\nenum rjsonwriter_option\n{\n   /* Don't write spaces, tabs or newlines to the output (except in strings) */\n   RJSONWRITER_OPTION_SKIP_WHITESPACE = (1<<0)\n};\n\n/* Custom data output callback\n * Should return len on success and < len on a write error. */\ntypedef int (*rjsonwriter_io_t)(const void* buf, int len, void *user_data);\ntypedef struct rjsonwriter rjsonwriter_t;\n\n/* Create a new writer instance to various targets */\nrjsonwriter_t *rjsonwriter_open_stream(struct intfstream_internal *stream);\nrjsonwriter_t *rjsonwriter_open_rfile(struct RFILE *rfile);\nrjsonwriter_t *rjsonwriter_open_memory(void);\nrjsonwriter_t *rjsonwriter_open_user(rjsonwriter_io_t io, void *user_data);\n\n/* When opened with rjsonwriter_open_memory, will return the generated JSON.\n * Result is always null-terminated. Passed len can be NULL if not needed,\n * otherwise returned len will be string length without null-terminator.\n * Returns NULL if writing ran out of memory or not opened from memory.\n * Returned buffer is only valid until writer is modified or freed. */\nchar* rjsonwriter_get_memory_buffer(rjsonwriter_t *writer, int* len);\n\n/* When opened with rjsonwriter_open_memory, will return current length */\nint rjsonwriter_count_memory_buffer(rjsonwriter_t *writer);\n\n/* When opened with rjsonwriter_open_memory, will clear the buffer.\n   The buffer will be partially erased if keep_len is > 0.\n   No memory is freed or re-allocated with this function. */\nvoid rjsonwriter_erase_memory_buffer(rjsonwriter_t *writer, int keep_len);\n\n/* Free rjsonwriter handle and return result of final rjsonwriter_flush call */\nbool rjsonwriter_free(rjsonwriter_t *writer);\n\n/* Set one or more enum rjsonwriter_option, will override previously set options.\n * Use bitwise OR to concatenate multiple options.\n * By default none of the options are set. */\nvoid rjsonwriter_set_options(rjsonwriter_t *writer, int rjsonwriter_option_flags);\n\n/* Flush any buffered output data to the output stream.\n * Returns true if the data was successfully written. Once writing fails once,\n * no more data will be written and flush will always returns false */\nbool rjsonwriter_flush(rjsonwriter_t *writer);\n\n/* Returns a string describing an error or \"\" if there was none.\n * The only error possible is \"output error\" after the io function failed.\n * If rjsonwriter_rawf were used manually, \"out of memory\" is also possible. */\nconst char *rjsonwriter_get_error(rjsonwriter_t *writer);\n\n/* Used by the inline functions below to append raw data */\nvoid rjsonwriter_raw(rjsonwriter_t *writer, const char *buf, int len);\nvoid rjsonwriter_rawf(rjsonwriter_t *writer, const char *fmt, ...);\n\n/* Add a UTF-8 encoded string\n * Special and control characters are automatically escaped.\n * If NULL is passed an empty string will be written (not JSON null). */\nvoid rjsonwriter_add_string(rjsonwriter_t *writer, const char *value);\nvoid rjsonwriter_add_string_len(rjsonwriter_t *writer, const char *value, int len);\n\nvoid rjsonwriter_add_double(rjsonwriter_t *writer, double value);\n\nvoid rjsonwriter_add_spaces(rjsonwriter_t *writer, int count);\n\nvoid rjsonwriter_add_tabs(rjsonwriter_t *writer, int count);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rjson_helpers.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rjson.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__\n#define __LIBRETRO_SDK_FORMAT_RJSON_HELPERS_H__\n\n#include <retro_common_api.h>\n#include <retro_inline.h> /* INLINE */\n#include <boolean.h> /* bool */\n#include <stddef.h> /* size_t */\n\nRETRO_BEGIN_DECLS\n\n/* Functions to add JSON token characters */\nstatic INLINE void rjsonwriter_add_start_object(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"{\", 1); }\n\nstatic INLINE void rjsonwriter_add_end_object(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"}\", 1); }\n\nstatic INLINE void rjsonwriter_add_start_array(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"[\", 1); }\n\nstatic INLINE void rjsonwriter_add_end_array(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"]\", 1); }\n\nstatic INLINE void rjsonwriter_add_colon(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \":\", 1); }\n\nstatic INLINE void rjsonwriter_add_comma(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \",\", 1); }\n\n/* Functions to add whitespace characters */\n/* These do nothing with the option RJSONWRITER_OPTION_SKIP_WHITESPACE */\nstatic INLINE void rjsonwriter_add_newline(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"\\n\", 1); }\n\nstatic INLINE void rjsonwriter_add_space(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \" \", 1); }\n\nstatic INLINE void rjsonwriter_add_tab(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"\\t\", 1); }\n\nstatic INLINE void rjsonwriter_add_unsigned(rjsonwriter_t *writer, unsigned value)\n      { rjsonwriter_rawf(writer, \"%u\", value); }\n\n/* Add a signed or unsigned integer or a double number */\nstatic INLINE void rjsonwriter_add_int(rjsonwriter_t *writer, int value)\n      { rjsonwriter_rawf(writer, \"%d\", value); }\n\nstatic INLINE void rjsonwriter_add_bool(rjsonwriter_t *writer, bool value)\n      { rjsonwriter_raw(writer, (value ? \"true\" : \"false\"), (value ? 4 : 5)); }\n\nstatic INLINE void rjsonwriter_add_null(rjsonwriter_t *writer)\n      { rjsonwriter_raw(writer, \"null\", 4); }\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rpng.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rpng.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RPNG_H__\n#define __LIBRETRO_SDK_FORMAT_RPNG_H__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct rpng rpng_t;\n\nrpng_t *rpng_alloc(void);\n\nbool rpng_is_valid(rpng_t *rpng);\n\nbool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len);\n\nrpng_t *rpng_alloc(void);\n\nvoid rpng_free(rpng_t *rpng);\n\nbool rpng_iterate_image(rpng_t *rpng);\n\nint rpng_process_image(rpng_t *rpng,\n      void **data, size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba);\n\nbool rpng_start(rpng_t *rpng);\n\nbool rpng_save_image_argb(const char *path, const uint32_t *data,\n      unsigned width, unsigned height, unsigned pitch);\nbool rpng_save_image_bgr24(const char *path, const uint8_t *data,\n      unsigned width, unsigned height, unsigned pitch);\n\nuint8_t* rpng_save_image_bgr24_string(const uint8_t *data,\n      unsigned width, unsigned height, signed pitch, uint64_t *bytes);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rtga.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rtga.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RTGA_H__\n#define __LIBRETRO_SDK_FORMAT_RTGA_H__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct rtga rtga_t;\n\nint rtga_process_image(rtga_t *rtga, void **buf,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba);\n\nbool rtga_set_buf_ptr(rtga_t *rtga, void *data);\n\nvoid rtga_free(rtga_t *rtga);\n\nrtga_t *rtga_alloc(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rwav.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rwav.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RWAV_H__\n#define __LIBRETRO_SDK_FORMAT_RWAV_H__\n\n#include <retro_common_api.h>\n#include <stdint.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct\n{\n   /* bits per sample */\n   unsigned int bitspersample;\n\n   /* number of channels */\n   unsigned int numchannels;\n\n   /* sample rate */\n   unsigned int samplerate;\n\n   /* number of *samples* */\n   size_t numsamples;\n\n   /* number of *bytes* in the pointer below, i.e. numsamples * numchannels * bitspersample/8 */\n   size_t subchunk2size;\n\n   /* PCM data */\n   const void* samples;\n} rwav_t;\n\nenum rwav_state\n{\n   RWAV_ITERATE_ERROR    = -1,\n   RWAV_ITERATE_MORE     = 0,\n   RWAV_ITERATE_DONE     = 1,\n   RWAV_ITERATE_BUF_SIZE = 4096\n};\n\ntypedef struct rwav_iterator rwav_iterator_t;\n\n/**\n * Initializes the iterator to fill the out structure with data parsed from buf.\n */\nvoid rwav_init(rwav_iterator_t *iter, rwav_t *out, const void* buf, size_t len);\n\n/**\n * Parses a piece of the data. Continue calling as long as it returns RWAV_ITERATE_MORE.\n * Stop calling otherwise, and check for errors. If RWAV_ITERATE_DONE is returned,\n * the rwav_t structure passed to rwav_init is ready to be used. The iterator does not\n * have to be freed.\n */\nenum rwav_state rwav_iterate(rwav_iterator_t *iter);\n\n/**\n * Loads the entire data in one go.\n */\nenum rwav_state rwav_load(rwav_t *out, const void *buf, size_t len);\n\n/**\n * Frees parsed wave data.\n */\nvoid rwav_free(rwav_t *rwav);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rwebp.h",
    "content": "/* Copyright  (C) 2010-2024 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rwebp.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FORMAT_RWEBP_H__\n#define __LIBRETRO_SDK_FORMAT_RWEBP_H__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct rwebp rwebp_t;\n\nint rwebp_process_image(rwebp_t *rwebp, void **buf,\n      size_t size, unsigned *width, unsigned *height,\n      bool supports_rgba);\n\nbool rwebp_set_buf_ptr(rwebp_t *rwebp, void *data, size_t len);\n\nvoid rwebp_free(rwebp_t *rwebp);\n\nrwebp_t *rwebp_alloc(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/formats/rxml.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rxml.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#ifndef __LIBRETRO_SDK_FORMAT_RXML_H__\n#define __LIBRETRO_SDK_FORMAT_RXML_H__\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/* Total NIH. Very trivial \"XML\" implementation for use in RetroArch.\n * Error checking is minimal. Invalid documents may lead to very\n * buggy behavior, but memory corruption should never happen.\n *\n * Only parts of standard that RetroArch cares about is supported.\n * Nothing more, nothing less. \"Clever\" XML documents will\n * probably break the implementation.\n *\n * Do *NOT* try to use this for anything else. You have been warned.\n */\n\ntypedef struct rxml_document rxml_document_t;\n\nstruct rxml_attrib_node\n{\n   char *attrib;\n   char *value;\n   struct rxml_attrib_node *next;\n};\n\ntypedef struct rxml_node\n{\n   char *name;\n   char *data;\n   struct rxml_attrib_node *attrib;\n\n   struct rxml_node *children;\n   struct rxml_node *next;\n} rxml_node_t;\n\nrxml_document_t *rxml_load_document(const char *path);\nrxml_document_t *rxml_load_document_string(const char *str);\nvoid rxml_free_document(rxml_document_t *doc);\n\nstruct rxml_node *rxml_root_node(rxml_document_t *doc);\n\nconst char *rxml_node_attrib(struct rxml_node *node, const char *attrib);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/gl_capabilities.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (gl_capabilities.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _GL_CAPABILITIES_H\n#define _GL_CAPABILITIES_H\n\n#include <boolean.h>\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nenum gl_capability_enum\n{\n   GL_CAPS_NONE = 0,\n   GL_CAPS_EGLIMAGE,\n   GL_CAPS_SYNC,\n   GL_CAPS_MIPMAP,\n   GL_CAPS_VAO,\n   GL_CAPS_FBO,\n   GL_CAPS_ARGB8,\n   GL_CAPS_DEBUG,\n   GL_CAPS_PACKED_DEPTH_STENCIL,\n   GL_CAPS_ES2_COMPAT,\n   GL_CAPS_UNPACK_ROW_LENGTH,\n   GL_CAPS_FULL_NPOT_SUPPORT,\n   GL_CAPS_SRGB_FBO,\n   GL_CAPS_SRGB_FBO_ES3,\n   GL_CAPS_FP_FBO,\n   GL_CAPS_BGRA8888,\n   GL_CAPS_GLES3_SUPPORTED,\n   GL_CAPS_TEX_STORAGE,\n   GL_CAPS_TEX_STORAGE_EXT\n};\n\nbool gl_query_core_context_in_use(void);\n\nvoid gl_query_core_context_set(bool set);\n\nvoid gl_query_core_context_unset(void);\n\nbool gl_query_extension(const char *ext);\n\nbool gl_check_error(char **error_string);\n\nbool gl_check_capability(enum gl_capability_enum enum_idx);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/math/matrix_3x3.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (matrix_3x3.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__\n#define __LIBRETRO_SDK_GFX_MATH_MATRIX_3X3_H__\n\n#include <boolean.h>\n#include <math.h>\n#include <string.h>\n\n#include <retro_common_api.h>\n#include <retro_inline.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct math_matrix_3x3\n{\n   float data[9];\n} math_matrix_3x3;\n\n#define MAT_ELEM_3X3(mat, r, c) ((mat).data[3 * (r) + (c)])\n\n#define matrix_3x3_init(mat, n11, n12, n13, n21, n22, n23, n31, n32, n33) \\\n   MAT_ELEM_3X3(mat, 0, 0) = n11; \\\n   MAT_ELEM_3X3(mat, 0, 1) = n12; \\\n   MAT_ELEM_3X3(mat, 0, 2) = n13; \\\n   MAT_ELEM_3X3(mat, 1, 0) = n21; \\\n   MAT_ELEM_3X3(mat, 1, 1) = n22; \\\n   MAT_ELEM_3X3(mat, 1, 2) = n23; \\\n   MAT_ELEM_3X3(mat, 2, 0) = n31; \\\n   MAT_ELEM_3X3(mat, 2, 1) = n32; \\\n   MAT_ELEM_3X3(mat, 2, 2) = n33\n\n#define matrix_3x3_identity(mat) \\\n   MAT_ELEM_3X3(mat, 0, 0) = 1.0f; \\\n   MAT_ELEM_3X3(mat, 0, 1) = 0; \\\n   MAT_ELEM_3X3(mat, 0, 2) = 0; \\\n   MAT_ELEM_3X3(mat, 1, 0) = 0; \\\n   MAT_ELEM_3X3(mat, 1, 1) = 1.0f; \\\n   MAT_ELEM_3X3(mat, 1, 2) = 0; \\\n   MAT_ELEM_3X3(mat, 2, 0) = 0; \\\n   MAT_ELEM_3X3(mat, 2, 1) = 0; \\\n   MAT_ELEM_3X3(mat, 2, 2) = 1.0f\n\n#define matrix_3x3_divide_scalar(mat, s) \\\n   MAT_ELEM_3X3(mat, 0, 0) /= s; \\\n   MAT_ELEM_3X3(mat, 0, 1) /= s; \\\n   MAT_ELEM_3X3(mat, 0, 2) /= s; \\\n   MAT_ELEM_3X3(mat, 1, 0) /= s; \\\n   MAT_ELEM_3X3(mat, 1, 1) /= s; \\\n   MAT_ELEM_3X3(mat, 1, 2) /= s; \\\n   MAT_ELEM_3X3(mat, 2, 0) /= s; \\\n   MAT_ELEM_3X3(mat, 2, 1) /= s; \\\n   MAT_ELEM_3X3(mat, 2, 2) /= s\n\n#define matrix_3x3_transpose(mat, in) \\\n   MAT_ELEM_3X3(mat, 0, 0) = MAT_ELEM_3X3(in, 0, 0); \\\n   MAT_ELEM_3X3(mat, 1, 0) = MAT_ELEM_3X3(in, 0, 1); \\\n   MAT_ELEM_3X3(mat, 2, 0) = MAT_ELEM_3X3(in, 0, 2); \\\n   MAT_ELEM_3X3(mat, 0, 1) = MAT_ELEM_3X3(in, 1, 0); \\\n   MAT_ELEM_3X3(mat, 1, 1) = MAT_ELEM_3X3(in, 1, 1); \\\n   MAT_ELEM_3X3(mat, 2, 1) = MAT_ELEM_3X3(in, 1, 2); \\\n   MAT_ELEM_3X3(mat, 0, 2) = MAT_ELEM_3X3(in, 2, 0); \\\n   MAT_ELEM_3X3(mat, 1, 2) = MAT_ELEM_3X3(in, 2, 1); \\\n   MAT_ELEM_3X3(mat, 2, 2) = MAT_ELEM_3X3(in, 2, 2)\n\n#define matrix_3x3_multiply(out, a, b) \\\n   MAT_ELEM_3X3(out, 0, 0) =  \\\n      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 0) + \\\n      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 0) + \\\n      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 0); \\\n   MAT_ELEM_3X3(out, 0, 1) = \\\n      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 1) + \\\n      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 1) + \\\n      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 1); \\\n   MAT_ELEM_3X3(out, 0, 2) = \\\n      MAT_ELEM_3X3(a, 0, 0) * MAT_ELEM_3X3(b, 0, 2) + \\\n      MAT_ELEM_3X3(a, 0, 1) * MAT_ELEM_3X3(b, 1, 2) + \\\n      MAT_ELEM_3X3(a, 0, 2) * MAT_ELEM_3X3(b, 2, 2); \\\n   MAT_ELEM_3X3(out, 1, 0) = \\\n      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 0) + \\\n      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 0) + \\\n      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 0); \\\n   MAT_ELEM_3X3(out, 1, 1) =  \\\n      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 1) + \\\n      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 1) + \\\n      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 1); \\\n   MAT_ELEM_3X3(out, 1, 2) = \\\n      MAT_ELEM_3X3(a, 1, 0) * MAT_ELEM_3X3(b, 0, 2) + \\\n      MAT_ELEM_3X3(a, 1, 1) * MAT_ELEM_3X3(b, 1, 2) + \\\n      MAT_ELEM_3X3(a, 1, 2) * MAT_ELEM_3X3(b, 2, 2); \\\n   MAT_ELEM_3X3(out, 2, 0) =  \\\n      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 0) + \\\n      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 0) + \\\n      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 0); \\\n   MAT_ELEM_3X3(out, 2, 1) = \\\n      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 1) + \\\n      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 1) + \\\n      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 1); \\\n   MAT_ELEM_3X3(out, 2, 2) =  \\\n      MAT_ELEM_3X3(a, 2, 0) * MAT_ELEM_3X3(b, 0, 2) + \\\n      MAT_ELEM_3X3(a, 2, 1) * MAT_ELEM_3X3(b, 1, 2) + \\\n      MAT_ELEM_3X3(a, 2, 2) * MAT_ELEM_3X3(b, 2, 2)\n\n#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)))\n\n#define matrix_3x3_adjoint(mat) \\\n   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)); \\\n   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)); \\\n   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)); \\\n   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)); \\\n   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)); \\\n   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)); \\\n   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)); \\\n   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)); \\\n   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))\n\n#define FLOATS_ARE_EQUAL(x, y)  (fabs(x - y) <= 0.00001f * ((x) > (y) ? (y) : (x)))\n#define FLOAT_IS_ZERO(x)        (FLOATS_ARE_EQUAL((x) + 1, 1))\n\nstatic INLINE bool matrix_3x3_invert(math_matrix_3x3 *mat)\n{\n   float det = matrix_3x3_determinant(*mat);\n\n   if (FLOAT_IS_ZERO(det))\n      return false;\n\n   matrix_3x3_adjoint(*mat);\n   matrix_3x3_divide_scalar(*mat, det);\n\n   return true;\n}\n\nstatic INLINE bool matrix_3x3_square_to_quad(\n      const float dx0, const float dy0,\n      const float dx1, const float dy1,\n      const float dx3, const float dy3,\n      const float dx2, const float dy2,\n      math_matrix_3x3 *mat)\n{\n   float a, b, d, e;\n   float ax  = dx0 - dx1 + dx2 - dx3;\n   float ay  = dy0 - dy1 + dy2 - dy3;\n   float c   = dx0;\n   float f   = dy0;\n   float g   = 0;\n   float h   = 0;\n\n   if (FLOAT_IS_ZERO(ax) && FLOAT_IS_ZERO(ay))\n   {\n      /* affine case */\n      a = dx1 - dx0;\n      b = dx2 - dx1;\n      d = dy1 - dy0;\n      e = dy2 - dy1;\n   }\n   else\n   {\n      float ax1 = dx1 - dx2;\n      float ax2 = dx3 - dx2;\n      float ay1 = dy1 - dy2;\n      float ay2 = dy3 - dy2;\n\n      /* determinants */\n      float gtop    =  ax  * ay2 - ax2 * ay;\n      float htop    =  ax1 * ay  - ax  * ay1;\n      float bottom  =  ax1 * ay2 - ax2 * ay1;\n\n      if (!bottom)\n         return false;\n\n      g = gtop / bottom;\n      h = htop / bottom;\n\n      a = dx1 - dx0 + g * dx1;\n      b = dx3 - dx0 + h * dx3;\n      d = dy1 - dy0 + g * dy1;\n      e = dy3 - dy0 + h * dy3;\n   }\n\n   matrix_3x3_init(*mat,\n         a, d, g,\n         b, e, h,\n         c, f, 1.f);\n\n   return true;\n}\n\nstatic INLINE bool matrix_3x3_quad_to_square(\n      const float sx0, const float sy0,\n      const float sx1, const float sy1,\n      const float sx2, const float sy2,\n      const float sx3, const float sy3,\n      math_matrix_3x3 *mat)\n{\n   return matrix_3x3_square_to_quad(sx0, sy0, sx1, sy1,\n         sx2, sy2, sx3, sy3,\n         mat) ? matrix_3x3_invert(mat) : false;\n}\n\nstatic INLINE bool matrix_3x3_quad_to_quad(\n      const float dx0, const float dy0,\n      const float dx1, const float dy1,\n      const float dx2, const float dy2,\n      const float dx3, const float dy3,\n      const float sx0, const float sy0,\n      const float sx1, const float sy1,\n      const float sx2, const float sy2,\n      const float sx3, const float sy3,\n      math_matrix_3x3 *mat)\n{\n   math_matrix_3x3 square_to_quad;\n\n   if (matrix_3x3_square_to_quad(dx0, dy0, dx1, dy1,\n            dx2, dy2, dx3, dy3,\n            &square_to_quad))\n   {\n      math_matrix_3x3 quad_to_square;\n      if (matrix_3x3_quad_to_square(sx0, sy0, sx1, sy1,\n               sx2, sy2, sx3, sy3,\n               &quad_to_square))\n      {\n         matrix_3x3_multiply(*mat, quad_to_square, square_to_quad);\n\n         return true;\n      }\n   }\n\n   return false;\n}\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/math/matrix_4x4.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (matrix_4x4.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__\n#define __LIBRETRO_SDK_GFX_MATH_MATRIX_4X4_H__\n\n#include <retro_common_api.h>\n\n#include <math.h>\n#include <gfx/math/vector_3.h>\n\n/* Column-major matrix (OpenGL-style).\n * Reimplements functionality from FF OpenGL pipeline to be able\n * to work on GLES 2.0 and modern GL variants.\n */\n\n#define MAT_ELEM_4X4(mat, row, column) ((mat).data[4 * (column) + (row)])\n\nRETRO_BEGIN_DECLS\n\ntypedef struct math_matrix_4x4\n{\n   float data[16];\n} math_matrix_4x4;\n\n#define matrix_4x4_copy(dst, src) \\\n   MAT_ELEM_4X4(dst, 0, 0) = MAT_ELEM_4X4(src, 0, 0); \\\n   MAT_ELEM_4X4(dst, 0, 1) = MAT_ELEM_4X4(src, 0, 1); \\\n   MAT_ELEM_4X4(dst, 0, 2) = MAT_ELEM_4X4(src, 0, 2); \\\n   MAT_ELEM_4X4(dst, 0, 3) = MAT_ELEM_4X4(src, 0, 3); \\\n   MAT_ELEM_4X4(dst, 1, 0) = MAT_ELEM_4X4(src, 1, 0); \\\n   MAT_ELEM_4X4(dst, 1, 1) = MAT_ELEM_4X4(src, 1, 1); \\\n   MAT_ELEM_4X4(dst, 1, 2) = MAT_ELEM_4X4(src, 1, 2); \\\n   MAT_ELEM_4X4(dst, 1, 3) = MAT_ELEM_4X4(src, 1, 3); \\\n   MAT_ELEM_4X4(dst, 2, 0) = MAT_ELEM_4X4(src, 2, 0); \\\n   MAT_ELEM_4X4(dst, 2, 1) = MAT_ELEM_4X4(src, 2, 1); \\\n   MAT_ELEM_4X4(dst, 2, 2) = MAT_ELEM_4X4(src, 2, 2); \\\n   MAT_ELEM_4X4(dst, 2, 3) = MAT_ELEM_4X4(src, 2, 3); \\\n   MAT_ELEM_4X4(dst, 3, 0) = MAT_ELEM_4X4(src, 3, 0); \\\n   MAT_ELEM_4X4(dst, 3, 1) = MAT_ELEM_4X4(src, 3, 1); \\\n   MAT_ELEM_4X4(dst, 3, 2) = MAT_ELEM_4X4(src, 3, 2); \\\n   MAT_ELEM_4X4(dst, 3, 3) = MAT_ELEM_4X4(src, 3, 3)\n\n/*\n * Sets mat to an identity matrix\n */\n#define matrix_4x4_identity(mat) \\\n   MAT_ELEM_4X4(mat, 0, 0)    = 1.0f; \\\n   MAT_ELEM_4X4(mat, 0, 1)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 0)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1)    = 1.0f; \\\n   MAT_ELEM_4X4(mat, 1, 2)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 0)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2)    = 1.0f; \\\n   MAT_ELEM_4X4(mat, 2, 3)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 0)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2)    = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3)    = 1.0f\n\n/*\n * Sets out to the transposed matrix of in\n */\n\n#define matrix_4x4_transpose(out, in) \\\n   MAT_ELEM_4X4(out, 0, 0) = MAT_ELEM_4X4(in, 0, 0); \\\n   MAT_ELEM_4X4(out, 1, 0) = MAT_ELEM_4X4(in, 0, 1); \\\n   MAT_ELEM_4X4(out, 2, 0) = MAT_ELEM_4X4(in, 0, 2); \\\n   MAT_ELEM_4X4(out, 3, 0) = MAT_ELEM_4X4(in, 0, 3); \\\n   MAT_ELEM_4X4(out, 0, 1) = MAT_ELEM_4X4(in, 1, 0); \\\n   MAT_ELEM_4X4(out, 1, 1) = MAT_ELEM_4X4(in, 1, 1); \\\n   MAT_ELEM_4X4(out, 2, 1) = MAT_ELEM_4X4(in, 1, 2); \\\n   MAT_ELEM_4X4(out, 3, 1) = MAT_ELEM_4X4(in, 1, 3); \\\n   MAT_ELEM_4X4(out, 0, 2) = MAT_ELEM_4X4(in, 2, 0); \\\n   MAT_ELEM_4X4(out, 1, 2) = MAT_ELEM_4X4(in, 2, 1); \\\n   MAT_ELEM_4X4(out, 2, 2) = MAT_ELEM_4X4(in, 2, 2); \\\n   MAT_ELEM_4X4(out, 3, 2) = MAT_ELEM_4X4(in, 2, 3); \\\n   MAT_ELEM_4X4(out, 0, 3) = MAT_ELEM_4X4(in, 3, 0); \\\n   MAT_ELEM_4X4(out, 1, 3) = MAT_ELEM_4X4(in, 3, 1); \\\n   MAT_ELEM_4X4(out, 2, 3) = MAT_ELEM_4X4(in, 3, 2); \\\n   MAT_ELEM_4X4(out, 3, 3) = MAT_ELEM_4X4(in, 3, 3)\n\n/*\n * Builds an X-axis rotation matrix\n */\n#define matrix_4x4_rotate_x(mat, radians) \\\n{ \\\n   float cosine            = cosf(radians); \\\n   float sine              = sinf(radians); \\\n   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1) = cosine; \\\n   MAT_ELEM_4X4(mat, 1, 2) = -sine; \\\n   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1) = sine; \\\n   MAT_ELEM_4X4(mat, 2, 2) = cosine; \\\n   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \\\n}\n\n/*\n * Builds a rotation matrix using the\n * rotation around the Y-axis.\n */\n\n#define matrix_4x4_rotate_y(mat, radians) \\\n{ \\\n   float cosine            = cosf(radians); \\\n   float sine              = sinf(radians); \\\n   MAT_ELEM_4X4(mat, 0, 0) = cosine; \\\n   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2) = -sine; \\\n   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 0) = sine; \\\n   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2) = cosine; \\\n   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \\\n}\n\n/*\n * Builds a rotation matrix using the\n * rotation around the Z-axis.\n */\n#define matrix_4x4_rotate_z(mat, radians) \\\n{ \\\n   float cosine            = cosf(radians); \\\n   float sine              = sinf(radians); \\\n   MAT_ELEM_4X4(mat, 0, 0) = cosine; \\\n   MAT_ELEM_4X4(mat, 0, 1) = -sine; \\\n   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 0) = sine; \\\n   MAT_ELEM_4X4(mat, 1, 1) = cosine; \\\n   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3) = 1.0f; \\\n}\n\n/*\n * Creates an orthographic projection matrix.\n */\n#define matrix_4x4_ortho(mat, left, right, bottom, top, znear, zfar) \\\n{ \\\n   float rl                = (right) - (left); \\\n   float tb                = (top)   - (bottom); \\\n   float fn                = (zfar)  - (znear); \\\n   MAT_ELEM_4X4(mat, 0, 0) =  2.0f / rl; \\\n   MAT_ELEM_4X4(mat, 0, 1) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3) = -((left) + (right))  / rl; \\\n   MAT_ELEM_4X4(mat, 1, 0) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1) =  2.0f / tb; \\\n   MAT_ELEM_4X4(mat, 1, 2) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3) = -((top)  + (bottom)) / tb; \\\n   MAT_ELEM_4X4(mat, 2, 0) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2) = -2.0f / fn; \\\n   MAT_ELEM_4X4(mat, 2, 3) = -((zfar) + (znear))  / fn; \\\n   MAT_ELEM_4X4(mat, 3, 0) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) =  0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3) =  1.0f; \\\n}\n\n#define matrix_4x4_lookat(out, eye, center, up) \\\n{ \\\n   vec3_t zaxis;   /* the \"forward\" vector */ \\\n   vec3_t xaxis;   /* the \"right\"   vector */ \\\n   vec3_t yaxis;   /* the \"up\"      vector */ \\\n   vec3_copy(zaxis, center); \\\n   vec3_subtract(zaxis, eye); \\\n   vec3_normalize(zaxis); \\\n   vec3_cross(xaxis, zaxis, up); \\\n   vec3_normalize(xaxis); \\\n   vec3_cross(yaxis, xaxis, zaxis); \\\n   MAT_ELEM_4X4(out, 0, 0) = xaxis[0]; \\\n   MAT_ELEM_4X4(out, 0, 1) = yaxis[0]; \\\n   MAT_ELEM_4X4(out, 0, 2) = -zaxis[0]; \\\n   MAT_ELEM_4X4(out, 0, 3) = 0.0; \\\n   MAT_ELEM_4X4(out, 1, 0) = xaxis[1]; \\\n   MAT_ELEM_4X4(out, 1, 1) = yaxis[1]; \\\n   MAT_ELEM_4X4(out, 1, 2) = -zaxis[1]; \\\n   MAT_ELEM_4X4(out, 1, 3) = 0.0f; \\\n   MAT_ELEM_4X4(out, 2, 0) = xaxis[2]; \\\n   MAT_ELEM_4X4(out, 2, 1) = yaxis[2]; \\\n   MAT_ELEM_4X4(out, 2, 2) = -zaxis[2]; \\\n   MAT_ELEM_4X4(out, 2, 3) = 0.0f; \\\n   MAT_ELEM_4X4(out, 3, 0) = -(xaxis[0] * eye[0] + xaxis[1] * eye[1] + xaxis[2] * eye[2]); \\\n   MAT_ELEM_4X4(out, 3, 1) = -(yaxis[0] * eye[0] + yaxis[1] * eye[1] + yaxis[2] * eye[2]); \\\n   MAT_ELEM_4X4(out, 3, 2) = (zaxis[0] * eye[0] + zaxis[1] * eye[1] + zaxis[2] * eye[2]); \\\n   MAT_ELEM_4X4(out, 3, 3) = 1.f; \\\n}\n\n/*\n * Multiplies a with b, stores the result in out\n */\n\n#define matrix_4x4_multiply(out, a, b) \\\n   MAT_ELEM_4X4(out, 0, 0) =  \\\n      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 0) + \\\n      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 0) + \\\n      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 0) + \\\n      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 0); \\\n   MAT_ELEM_4X4(out, 0, 1) =  \\\n      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 1) + \\\n      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 1) + \\\n      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 1) + \\\n      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 1); \\\n   MAT_ELEM_4X4(out, 0, 2) =  \\\n      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 2) + \\\n      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 2) + \\\n      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 2) + \\\n      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 2); \\\n   MAT_ELEM_4X4(out, 0, 3) =  \\\n      MAT_ELEM_4X4(a, 0, 0) * MAT_ELEM_4X4(b, 0, 3) + \\\n      MAT_ELEM_4X4(a, 0, 1) * MAT_ELEM_4X4(b, 1, 3) + \\\n      MAT_ELEM_4X4(a, 0, 2) * MAT_ELEM_4X4(b, 2, 3) + \\\n      MAT_ELEM_4X4(a, 0, 3) * MAT_ELEM_4X4(b, 3, 3); \\\n   MAT_ELEM_4X4(out, 1, 0) =  \\\n      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 0) + \\\n      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 0) + \\\n      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 0) + \\\n      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 0); \\\n   MAT_ELEM_4X4(out, 1, 1) =  \\\n      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 1) + \\\n      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 1) + \\\n      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 1) + \\\n      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 1); \\\n   MAT_ELEM_4X4(out, 1, 2) =  \\\n      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 2) + \\\n      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 2) + \\\n      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 2) + \\\n      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 2); \\\n   MAT_ELEM_4X4(out, 1, 3) =  \\\n      MAT_ELEM_4X4(a, 1, 0) * MAT_ELEM_4X4(b, 0, 3) + \\\n      MAT_ELEM_4X4(a, 1, 1) * MAT_ELEM_4X4(b, 1, 3) + \\\n      MAT_ELEM_4X4(a, 1, 2) * MAT_ELEM_4X4(b, 2, 3) + \\\n      MAT_ELEM_4X4(a, 1, 3) * MAT_ELEM_4X4(b, 3, 3); \\\n   MAT_ELEM_4X4(out, 2, 0) =  \\\n      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 0) + \\\n      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 0) + \\\n      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 0) + \\\n      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 0); \\\n   MAT_ELEM_4X4(out, 2, 1) =  \\\n      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 1) + \\\n      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 1) + \\\n      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 1) + \\\n      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 1); \\\n   MAT_ELEM_4X4(out, 2, 2) =  \\\n      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 2) + \\\n      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 2) + \\\n      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 2) + \\\n      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 2); \\\n   MAT_ELEM_4X4(out, 2, 3) =  \\\n      MAT_ELEM_4X4(a, 2, 0) * MAT_ELEM_4X4(b, 0, 3) + \\\n      MAT_ELEM_4X4(a, 2, 1) * MAT_ELEM_4X4(b, 1, 3) + \\\n      MAT_ELEM_4X4(a, 2, 2) * MAT_ELEM_4X4(b, 2, 3) + \\\n      MAT_ELEM_4X4(a, 2, 3) * MAT_ELEM_4X4(b, 3, 3); \\\n   MAT_ELEM_4X4(out, 3, 0) =  \\\n      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 0) + \\\n      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 0) + \\\n      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 0) + \\\n      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 0); \\\n   MAT_ELEM_4X4(out, 3, 1) =  \\\n      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 1) + \\\n      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 1) + \\\n      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 1) + \\\n      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 1); \\\n   MAT_ELEM_4X4(out, 3, 2) = \\\n      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 2) + \\\n      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 2) + \\\n      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 2) + \\\n      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 2); \\\n   MAT_ELEM_4X4(out, 3, 3) =  \\\n      MAT_ELEM_4X4(a, 3, 0) * MAT_ELEM_4X4(b, 0, 3) + \\\n      MAT_ELEM_4X4(a, 3, 1) * MAT_ELEM_4X4(b, 1, 3) + \\\n      MAT_ELEM_4X4(a, 3, 2) * MAT_ELEM_4X4(b, 2, 3) + \\\n      MAT_ELEM_4X4(a, 3, 3) * MAT_ELEM_4X4(b, 3, 3)\n\n#define matrix_4x4_scale(mat, x, y, z) \\\n   MAT_ELEM_4X4(mat, 0, 0) = x; \\\n   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1) = y; \\\n   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2) = z; \\\n   MAT_ELEM_4X4(mat, 2, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3) = 1.0f\n\n/*\n * Builds a translation matrix. All other elements in\n * the matrix will be set to zero except for the\n * diagonal which is set to 1.0\n */\n\n#define matrix_4x4_translate(mat, x, y, z) \\\n   MAT_ELEM_4X4(mat, 0, 0) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3) = x; \\\n   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 1, 2) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3) = y; \\\n   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2) = 1.0f; \\\n   MAT_ELEM_4X4(mat, 2, 3) = z; \\\n   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 3) = 1.0f\n\n/*\n * Creates a perspective projection matrix.\n */\n\n#define  matrix_4x4_projection(mat, y_fov, aspect, znear, zfar) \\\n{ \\\n   float const a           = 1.f / tan((y_fov) / 2.f); \\\n   float delta_z           = (zfar) - (znear); \\\n   MAT_ELEM_4X4(mat, 0, 0) = a / (aspect); \\\n   MAT_ELEM_4X4(mat, 0, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 0, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 1) = a; \\\n   MAT_ELEM_4X4(mat, 1, 2) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 1, 3) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 2, 2) = -(((zfar) + (znear)) / delta_z); \\\n   MAT_ELEM_4X4(mat, 2, 3) = -1.f; \\\n   MAT_ELEM_4X4(mat, 3, 0) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 1) = 0.0f; \\\n   MAT_ELEM_4X4(mat, 3, 2) = -((2.f * (zfar) * (znear)) / delta_z); \\\n   MAT_ELEM_4X4(mat, 3, 3) = 0.0f; \\\n}\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/math/vector_2.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (vector_2.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__\n#define __LIBRETRO_SDK_GFX_MATH_VECTOR_2_H__\n\n#include <stdint.h>\n#include <math.h>\n\n#include <retro_common_api.h>\n#include <retro_inline.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef float vec2_t[2];\n\n#define vec2_dot(a, b)   ((a[0] * b[0]) + (a[1] * b[1]))\n\n#define vec2_cross(a, b) ((a[0]*b[1]) - (a[1]*b[0]))\n\n#define vec2_add(dst, src) \\\n   dst[0] += src[0]; \\\n   dst[1] += src[1]\n\n#define vec2_subtract(dst, src) \\\n   dst[0] -= src[0]; \\\n   dst[1] -= src[1]\n\n#define vec2_copy(dst, src) \\\n   dst[0] = src[0]; \\\n   dst[1] = src[1]\n\nstatic INLINE float overflow(void)\n{\n   unsigned i;\n   volatile float f = 1e10;\n\n   for (i = 0; i < 10; ++i)\n      f *= f;\n   return f;\n}\n\nstatic INLINE int16_t tofloat16(float f)\n{\n\tunion uif32\n   {\n      float f;\n      uint32_t i;\n   };\n\n   int i, s, e, m;\n   union uif32 Entry;\n   Entry.f = f;\n   i       = (int)Entry.i;\n   s       =  (i >> 16) & 0x00008000;\n   e       = ((i >> 23) & 0x000000ff) - (127 - 15);\n   m       =   i        & 0x007fffff;\n\n   if (e <= 0)\n   {\n      if (e < -10)\n         return (int16_t)(s);\n\n      m = (m | 0x00800000) >> (1 - e);\n\n      if (m & 0x00001000)\n         m += 0x00002000;\n\n      return (int16_t)(s | (m >> 13));\n   }\n\n   if (e == 0xff - (127 - 15))\n   {\n      if (m == 0)\n         return (int16_t)(s | 0x7c00);\n\n      m >>= 13;\n\n      return (int16_t)(s | 0x7c00 | m | (m == 0));\n   }\n\n   if (m &  0x00001000)\n   {\n      m += 0x00002000;\n\n      if (m & 0x00800000)\n      {\n         m =  0;\n         e += 1;\n      }\n   }\n\n   if (e > 30)\n   {\n      overflow();\n\n      return (int16_t)(s | 0x7c00);\n   }\n\n   return (int16_t)(s | (e << 10) | (m >> 13));\n}\n\nstatic INLINE unsigned int vec2_packHalf2x16(float vec0, float vec1)\n{\n   union\n   {\n      int16_t in[2];\n      unsigned int out;\n   } u;\n\n   u.in[0] = tofloat16(vec0);\n   u.in[1] = tofloat16(vec1);\n\n   return u.out;\n}\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/math/vector_3.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (vector_3.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__\n#define __LIBRETRO_SDK_GFX_MATH_VECTOR_3_H__\n\n#include <stdint.h>\n#include <math.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef float vec3_t[3];\n\n#define vec3_dot(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])\n\n#define vec3_cross(dst, a, b)  \\\n   dst[0] = a[1]*b[2] - a[2]*b[1]; \\\n   dst[1] = a[2]*b[0] - a[0]*b[2]; \\\n   dst[2] = a[0]*b[1] - a[1]*b[0]\n\n#define vec3_length(a) sqrtf(vec3_dot(a,a))\n\n#define vec3_add(dst, src) \\\n   dst[0] += src[0]; \\\n   dst[1] += src[1]; \\\n   dst[2] += src[2]\n\n#define vec3_subtract(dst, src) \\\n   dst[0] -= src[0]; \\\n   dst[1] -= src[1]; \\\n   dst[2] -= src[2]\n\n#define vec3_scale(dst, scale) \\\n   dst[0] *= scale; \\\n   dst[1] *= scale; \\\n   dst[2] *= scale\n\n#define vec3_copy(dst, src) \\\n   dst[0] = src[0]; \\\n   dst[1] = src[1]; \\\n   dst[2] = src[2]\n\n#define vec3_normalize(dst) vec3_scale(dst,1.0f / vec3_length(dst))\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/math/vector_4.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (vector_4.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__\n#define __LIBRETRO_SDK_GFX_MATH_VECTOR_4_H__\n\n#include <stdint.h>\n#include <math.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef float vec4_t[4];\n\n#define vec4_add(dst, src) \\\n   dst[0] += src[0]; \\\n   dst[1] += src[1]; \\\n   dst[2] += src[2]; \\\n   dst[3] += src[3]\n\n#define vec4_subtract(dst, src) \\\n   dst[0] -= src[0]; \\\n   dst[1] -= src[1]; \\\n   dst[2] -= src[2]; \\\n   dst[3] -= src[3]\n\n#define vec4_scale(dst, scale) \\\n   dst[0] *= scale; \\\n   dst[1] *= scale; \\\n   dst[2] *= scale; \\\n   dst[3] *= scale\n\n#define vec4_copy(dst, src) \\\n   dst[0] = src[0]; \\\n   dst[1] = src[1]; \\\n   dst[2] = src[2]; \\\n   dst[3] = src[3]\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/scaler/filter.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (filter.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_SCALER_FILTER_H__\n#define __LIBRETRO_SDK_SCALER_FILTER_H__\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#include <boolean.h>\n#include <gfx/scaler/scaler.h>\n\nbool scaler_gen_filter(struct scaler_ctx *ctx);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/scaler/pixconv.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (pixconv.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_SCALER_PIXCONV_H__\n#define __LIBRETRO_SDK_SCALER_PIXCONV_H__\n\n#include <clamping.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nvoid conv_0rgb1555_argb8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_0rgb1555_rgb565(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_rgb565_0rgb1555(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_rgb565_abgr8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_rgb565_argb8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_rgba4444_argb8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_rgba4444_rgb565(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_bgr24_argb8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_bgr24_rgb565(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_argb8888_0rgb1555(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_argb8888_rgba4444(void *output_, const void *input_,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_argb8888_rgb565(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_argb8888_bgr24(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_abgr8888_bgr24(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_argb8888_abgr8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_0rgb1555_bgr24(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_rgb565_bgr24(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_yuyv_argb8888(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nvoid conv_copy(void *output, const void *input,\n      int width, int height,\n      int out_stride, int in_stride);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/scaler/scaler.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (scaler.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_SCALER_H__\n#define __LIBRETRO_SDK_SCALER_H__\n\n#include <stdint.h>\n#include <stddef.h>\n#include <boolean.h>\n#include <clamping.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nenum scaler_pix_fmt\n{\n   SCALER_FMT_ARGB8888 = 0,\n   SCALER_FMT_ABGR8888,\n   SCALER_FMT_0RGB1555,\n   SCALER_FMT_RGB565,\n   SCALER_FMT_BGR24,\n   SCALER_FMT_YUYV,\n   SCALER_FMT_RGBA4444\n};\n\nenum scaler_type\n{\n   SCALER_TYPE_UNKNOWN = 0,\n   SCALER_TYPE_POINT,\n   SCALER_TYPE_BILINEAR,\n   SCALER_TYPE_SINC\n};\n\nstruct scaler_filter\n{\n   int16_t *filter;\n   int     *filter_pos;\n   int      filter_len;\n   int      filter_stride;\n};\n\nstruct scaler_ctx\n{\n   void (*scaler_horiz)(const struct scaler_ctx*,\n         const void*, int);\n   void (*scaler_vert)(const struct scaler_ctx*,\n         void*, int);\n   void (*scaler_special)(const struct scaler_ctx*,\n         void*, const void*, int, int, int, int, int, int);\n\n   void (*in_pixconv)(void*, const void*, int, int, int, int);\n   void (*out_pixconv)(void*, const void*, int, int, int, int);\n   void (*direct_pixconv)(void*, const void*, int, int, int, int);\n   struct scaler_filter horiz, vert;   /* ptr alignment */\n\n   struct\n   {\n      uint32_t *frame;\n      int stride;\n   } input;\n\n   struct\n   {\n      uint64_t *frame;\n      int width;\n      int height;\n      int stride;\n   } scaled;\n\n   struct\n   {\n      uint32_t *frame;\n      int stride;\n   } output;\n\n   int in_width;\n   int in_height;\n   int in_stride;\n\n   int out_width;\n   int out_height;\n   int out_stride;\n\n   enum scaler_pix_fmt in_fmt;\n   enum scaler_pix_fmt out_fmt;\n   enum scaler_type scaler_type;\n\n   bool unscaled;\n};\n\nbool scaler_ctx_gen_filter(struct scaler_ctx *ctx);\n\nvoid scaler_ctx_gen_reset(struct scaler_ctx *ctx);\n\n/**\n * scaler_ctx_scale:\n * @ctx          : pointer to scaler context object.\n * @output       : pointer to output image.\n * @input        : pointer to input image.\n *\n * Scales an input image to an output image.\n **/\nvoid scaler_ctx_scale(struct scaler_ctx *ctx,\n      void *output, const void *input);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/scaler/scaler_int.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (scaler_int.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_SCALER_INT_H__\n#define __LIBRETRO_SDK_SCALER_INT_H__\n\n#include <gfx/scaler/scaler.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nvoid scaler_argb8888_vert(const struct scaler_ctx *ctx,\n      void *output, int stride);\n\nvoid scaler_argb8888_horiz(const struct scaler_ctx *ctx,\n      const void *input, int stride);\n\nvoid scaler_argb8888_point_special(const struct scaler_ctx *ctx,\n      void *output, const void *input,\n      int out_width, int out_height,\n      int in_width, int in_height,\n      int out_stride, int in_stride);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/gfx/video_frame.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (video_frame.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_VIDEO_FRAME_H\n#define _LIBRETRO_SDK_VIDEO_FRAME_H\n\n#include <stdint.h>\n#include <retro_common_api.h>\n#include <retro_inline.h>\n\n#include <gfx/scaler/scaler.h>\n\n#include <libretro.h>\n\nRETRO_BEGIN_DECLS\n\n#define scaler_ctx_scale_direct(ctx, output, input) \\\n{ \\\n   if (ctx && ctx->unscaled && ctx->direct_pixconv) \\\n      /* Just perform straight pixel conversion. */ \\\n      ctx->direct_pixconv(output, input, \\\n            ctx->out_width,  ctx->out_height, \\\n            ctx->out_stride, ctx->in_stride); \\\n   else \\\n      scaler_ctx_scale(ctx, output, input); \\\n}\n\nstatic INLINE void video_frame_convert_rgb16_to_rgb32(\n      struct scaler_ctx *scaler,\n      void *output,\n      const void *input,\n      int width, int height,\n      int in_pitch)\n{\n   if (width != scaler->in_width || height != scaler->in_height)\n   {\n      scaler->in_width    = width;\n      scaler->in_height   = height;\n      scaler->out_width   = width;\n      scaler->out_height  = height;\n      scaler->in_fmt      = SCALER_FMT_RGB565;\n      scaler->out_fmt     = SCALER_FMT_ARGB8888;\n      scaler->scaler_type = SCALER_TYPE_POINT;\n      scaler_ctx_gen_filter(scaler);\n   }\n\n   scaler->in_stride  = in_pitch;\n   scaler->out_stride = width * sizeof(uint32_t);\n\n   scaler_ctx_scale_direct(scaler, output, input);\n}\n\nstatic INLINE void video_frame_scale(\n      struct scaler_ctx *scaler,\n      void *output,\n      const void *input,\n      enum scaler_pix_fmt format,\n      unsigned scaler_width,\n      unsigned scaler_height,\n      unsigned scaler_pitch,\n      unsigned width,\n      unsigned height,\n      unsigned pitch)\n{\n   if (\n            width  != (unsigned)scaler->in_width\n         || height != (unsigned)scaler->in_height\n         || format != scaler->in_fmt\n         || pitch  != (unsigned)scaler->in_stride\n      )\n   {\n      scaler->in_fmt    = format;\n      scaler->in_width  = width;\n      scaler->in_height = height;\n      scaler->in_stride = pitch;\n\n      scaler->out_width  = scaler_width;\n      scaler->out_height = scaler_height;\n      scaler->out_stride = scaler_pitch;\n\n      scaler_ctx_gen_filter(scaler);\n   }\n\n   scaler_ctx_scale_direct(scaler, output, input);\n}\n\nstatic INLINE void video_frame_record_scale(\n      struct scaler_ctx *scaler,\n      void *output,\n      const void *input,\n      unsigned scaler_width,\n      unsigned scaler_height,\n      unsigned scaler_pitch,\n      unsigned width,\n      unsigned height,\n      unsigned pitch,\n      bool bilinear)\n{\n   if (\n            width  != (unsigned)scaler->in_width\n         || height != (unsigned)scaler->in_height\n      )\n   {\n      scaler->in_width    = width;\n      scaler->in_height   = height;\n      scaler->in_stride   = pitch;\n\n      scaler->scaler_type = bilinear ?\n         SCALER_TYPE_BILINEAR : SCALER_TYPE_POINT;\n\n      scaler->out_width  = scaler_width;\n      scaler->out_height = scaler_height;\n      scaler->out_stride = scaler_pitch;\n\n      scaler_ctx_gen_filter(scaler);\n   }\n\n   scaler_ctx_scale_direct(scaler, output, input);\n}\n\nstatic INLINE void video_frame_convert_argb8888_to_abgr8888(\n      struct scaler_ctx *scaler,\n      void *output, const void *input,\n      int width, int height, int in_pitch)\n{\n   if (width != scaler->in_width || height != scaler->in_height)\n   {\n      scaler->in_width    = width;\n      scaler->in_height   = height;\n      scaler->out_width   = width;\n      scaler->out_height  = height;\n      scaler->in_fmt      = SCALER_FMT_ARGB8888;\n      scaler->out_fmt     = SCALER_FMT_ABGR8888;\n      scaler->scaler_type = SCALER_TYPE_POINT;\n      scaler_ctx_gen_filter(scaler);\n   }\n\n   scaler->in_stride  = in_pitch;\n   scaler->out_stride = width * sizeof(uint32_t);\n\n   scaler_ctx_scale_direct(scaler, output, input);\n}\n\nstatic INLINE void video_frame_convert_to_bgr24(\n      struct scaler_ctx *scaler,\n      void *output, const void *input,\n      int in_width, int in_height, int in_pitch,\n      int out_width, int out_height, int out_pitch)\n{\n   scaler->in_width    = in_width;\n   scaler->in_height   = in_height;\n   scaler->out_width   = out_width;\n   scaler->out_height  = out_height;\n\n   scaler->out_fmt     = SCALER_FMT_BGR24;\n   scaler->scaler_type = SCALER_TYPE_POINT;\n\n   scaler_ctx_gen_filter(scaler);\n\n   scaler->in_stride   = in_pitch;\n   scaler->out_stride  = out_pitch;\n\n   scaler_ctx_scale_direct(scaler, output, input);\n}\n\nstatic INLINE void video_frame_convert_rgba_to_bgr(\n      const void *src_data,\n      void *dst_data,\n      unsigned src_pitch,\n      unsigned dst_pitch,\n      unsigned width,\n      unsigned height)\n{\n   unsigned x, y;\n   uint8_t       *dst = (uint8_t*)dst_data;\n   const uint8_t *src = (const uint8_t*)src_data;\n\n   for (y = 0; y < height; y++, dst += dst_pitch, src += src_pitch)\n   {\n      uint8_t       *d = dst;\n      const uint8_t *s = src;\n      for (x = 0; x < width; x++, d += 3, s += 4)\n      {\n         d[0] = s[2];\n         d[1] = s[1];\n         d[2] = s[0];\n      }\n   }\n}\n\nstatic INLINE void video_pixel_frame_scale(\n      struct scaler_ctx *scaler,\n      void *output, const void *data,\n      unsigned width, unsigned height,\n      size_t pitch)\n{\n   scaler->in_width      = width;\n   scaler->in_height     = height;\n   scaler->out_width     = width;\n   scaler->out_height    = height;\n   scaler->in_stride     = (int)pitch;\n   scaler->out_stride    = width * sizeof(uint16_t);\n   scaler_ctx_scale_direct(scaler, output, data);\n}\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/glsym/glsym.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (glsym).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GLSYM_H__\n#define __LIBRETRO_SDK_GLSYM_H__\n\n#include \"rglgen.h\"\n\n#ifndef HAVE_PSGL\n#if defined(HAVE_OPENGLES2)\n#include \"glsym_es2.h\"\n#elif defined(HAVE_OPENGLES3)\n#include \"glsym_es3.h\"\n#else\n#ifdef HAVE_LIBNX\n#include \"switch/nx_glsym.h\"\n#endif\n#include \"glsym_gl.h\"\n#endif\n#endif\n\n#ifdef HAVE_GLSYM_PRIVATE\n#include \"glsym_private.h\"\n#endif\n\n#endif\n"
  },
  {
    "path": "include/glsym/glsym_es2.h",
    "content": "#ifndef RGLGEN_DECL_H__\n#define RGLGEN_DECL_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#ifdef GL_APIENTRY\ntypedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\ntypedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n#else\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\ntypedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\ntypedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n#endif\n#ifndef GL_OES_EGL_image\ntypedef void *GLeglImageOES;\n#endif\n#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\ntypedef GLint GLfixed;\n#endif\n\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\ntypedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);\ntypedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\ntypedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);\ntypedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);\ntypedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);\ntypedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);\ntypedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);\ntypedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);\ntypedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\ntypedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);\ntypedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);\ntypedef 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);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);\ntypedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);\ntypedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);\ntypedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\ntypedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);\ntypedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);\ntypedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);\ntypedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);\ntypedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);\ntypedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);\ntypedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);\ntypedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);\ntypedef 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);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);\ntypedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);\ntypedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);\ntypedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);\ntypedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);\ntypedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);\ntypedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);\ntypedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);\ntypedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);\ntypedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);\ntypedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);\ntypedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);\ntypedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);\ntypedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\ntypedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);\ntypedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);\ntypedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);\ntypedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);\ntypedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);\ntypedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);\ntypedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);\ntypedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);\ntypedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\ntypedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);\n\n#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR\n#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR\n#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR\n#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR\n#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR\n#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR\n#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR\n#define glObjectLabelKHR __rglgen_glObjectLabelKHR\n#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR\n#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR\n#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR\n#define glGetPointervKHR __rglgen_glGetPointervKHR\n#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR\n#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR\n#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR\n#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR\n#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR\n#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES\n#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES\n#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES\n#define glEnableiOES __rglgen_glEnableiOES\n#define glDisableiOES __rglgen_glDisableiOES\n#define glBlendEquationiOES __rglgen_glBlendEquationiOES\n#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES\n#define glBlendFunciOES __rglgen_glBlendFunciOES\n#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES\n#define glColorMaskiOES __rglgen_glColorMaskiOES\n#define glIsEnablediOES __rglgen_glIsEnablediOES\n#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES\n#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES\n#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES\n#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES\n#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES\n#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES\n#define glProgramBinaryOES __rglgen_glProgramBinaryOES\n#define glMapBufferOES __rglgen_glMapBufferOES\n#define glUnmapBufferOES __rglgen_glUnmapBufferOES\n#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES\n#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES\n#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES\n#define glPatchParameteriOES __rglgen_glPatchParameteriOES\n#define glTexImage3DOES __rglgen_glTexImage3DOES\n#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES\n#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES\n#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES\n#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES\n#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES\n#define glTexParameterIivOES __rglgen_glTexParameterIivOES\n#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES\n#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES\n#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES\n#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES\n#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES\n#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES\n#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES\n#define glTexBufferOES __rglgen_glTexBufferOES\n#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES\n#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES\n#define glTextureViewOES __rglgen_glTextureViewOES\n#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES\n#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES\n#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES\n#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES\n#define glViewportArrayvOES __rglgen_glViewportArrayvOES\n#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES\n#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES\n#define glScissorArrayvOES __rglgen_glScissorArrayvOES\n#define glScissorIndexedOES __rglgen_glScissorIndexedOES\n#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES\n#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES\n#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES\n#define glGetFloati_vOES __rglgen_glGetFloati_vOES\n#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT\n#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT\n#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT\n#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT\n#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT\n#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT\n#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT\n#define glBufferStorageEXT __rglgen_glBufferStorageEXT\n#define glClearTexImageEXT __rglgen_glClearTexImageEXT\n#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT\n#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT\n#define glLabelObjectEXT __rglgen_glLabelObjectEXT\n#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT\n#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT\n#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT\n#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT\n#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT\n#define glGenQueriesEXT __rglgen_glGenQueriesEXT\n#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT\n#define glIsQueryEXT __rglgen_glIsQueryEXT\n#define glBeginQueryEXT __rglgen_glBeginQueryEXT\n#define glEndQueryEXT __rglgen_glEndQueryEXT\n#define glQueryCounterEXT __rglgen_glQueryCounterEXT\n#define glGetQueryivEXT __rglgen_glGetQueryivEXT\n#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT\n#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT\n#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT\n#define glEnableiEXT __rglgen_glEnableiEXT\n#define glDisableiEXT __rglgen_glDisableiEXT\n#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT\n#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT\n#define glBlendFunciEXT __rglgen_glBlendFunciEXT\n#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT\n#define glColorMaskiEXT __rglgen_glColorMaskiEXT\n#define glIsEnablediEXT __rglgen_glIsEnablediEXT\n#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT\n#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT\n#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT\n#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT\n#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT\n#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT\n#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT\n#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT\n#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT\n#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT\n#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT\n#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT\n#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT\n#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT\n#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT\n#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT\n#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT\n#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT\n#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT\n#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT\n#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT\n#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT\n#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT\n#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT\n#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT\n#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT\n#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT\n#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT\n#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT\n#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT\n#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT\n#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT\n#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT\n#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT\n#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT\n#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT\n#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT\n#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT\n#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT\n#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT\n#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT\n#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT\n#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT\n#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT\n#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT\n#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT\n#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT\n#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT\n#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT\n#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT\n#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT\n#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT\n#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT\n#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT\n#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT\n#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT\n#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT\n#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT\n#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT\n#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT\n#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT\n#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT\n#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT\n#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT\n#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT\n#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT\n#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT\n#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT\n#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT\n#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT\n#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT\n#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT\n#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT\n#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT\n#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT\n#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT\n#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT\n#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT\n#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT\n#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT\n#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT\n#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT\n#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT\n#define glTexBufferEXT __rglgen_glTexBufferEXT\n#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT\n#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT\n#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT\n#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT\n#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT\n#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT\n#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT\n#define glTextureViewEXT __rglgen_glTextureViewEXT\n#define glesEXT __rglgen_glesEXT\n#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR\n#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR\n\nextern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;\nextern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;\nextern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;\nextern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;\nextern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;\nextern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;\nextern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;\nextern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;\nextern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;\nextern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;\nextern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;\nextern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;\nextern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;\nextern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;\nextern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;\nextern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;\nextern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;\nextern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;\nextern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;\nextern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;\nextern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;\nextern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;\nextern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;\nextern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;\nextern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;\nextern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;\nextern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;\nextern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;\nextern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;\nextern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;\nextern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;\nextern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;\nextern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;\nextern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;\nextern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;\nextern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;\nextern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;\nextern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;\nextern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;\nextern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;\nextern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;\nextern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;\nextern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;\nextern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;\nextern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;\nextern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;\nextern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;\nextern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;\nextern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;\nextern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;\nextern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;\nextern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;\nextern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;\nextern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;\nextern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;\nextern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;\nextern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;\nextern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;\nextern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;\nextern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;\nextern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;\nextern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;\nextern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;\nextern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;\nextern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;\nextern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;\nextern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;\nextern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;\nextern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;\nextern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;\nextern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;\nextern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;\nextern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;\nextern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;\nextern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;\nextern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;\nextern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;\nextern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;\nextern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;\nextern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;\nextern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;\nextern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;\nextern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;\nextern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;\nextern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;\nextern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;\nextern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;\nextern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;\nextern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;\nextern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;\nextern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;\nextern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;\nextern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;\nextern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;\nextern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;\nextern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;\nextern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;\nextern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;\nextern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;\nextern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;\nextern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;\nextern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;\nextern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;\nextern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;\nextern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;\nextern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;\nextern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;\nextern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;\nextern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;\nextern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;\nextern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;\nextern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;\nextern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;\nextern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;\nextern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;\nextern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;\nextern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;\nextern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;\nextern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;\nextern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;\nextern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;\nextern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;\nextern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;\nextern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;\nextern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;\nextern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;\nextern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;\nextern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;\nextern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;\nextern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;\nextern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;\nextern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;\nextern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;\nextern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;\nextern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;\nextern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;\nextern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;\nextern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;\nextern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;\nextern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;\nextern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;\nextern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;\nextern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;\nextern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;\nextern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;\nextern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;\nextern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;\nextern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;\nextern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;\nextern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;\nextern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;\nextern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;\nextern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;\nextern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;\nextern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;\nextern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;\nextern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;\nextern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;\nextern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;\nextern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;\nextern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;\nextern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;\nextern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;\nextern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;\nextern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;\nextern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;\nextern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;\nextern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;\nextern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;\nextern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;\nextern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;\nextern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;\nextern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;\nextern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;\nextern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;\nextern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;\nextern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;\n\nstruct rglgen_sym_map { const char *sym; void *ptr; };\nextern const struct rglgen_sym_map rglgen_symbol_map[];\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "include/glsym/glsym_es3.h",
    "content": "#ifndef RGLGEN_DECL_H__\n#define RGLGEN_DECL_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#ifdef GL_APIENTRY\ntypedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\ntypedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n#else\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\ntypedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\ntypedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n#endif\n#ifndef GL_OES_EGL_image\ntypedef void *GLeglImageOES;\n#endif\n#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\ntypedef GLint GLfixed;\n#endif\n#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\ntypedef long long int GLint64;\ntypedef unsigned long long int GLuint64;\ntypedef unsigned long long int GLuint64EXT;\ntypedef struct __GLsync *GLsync;\n#endif\n#ifndef GL_APIENTRYP\n#define GL_APIENTRYP GL_APIENTRY*\n#endif\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDBARRIERKHRPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLKHRPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTKHRPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\ntypedef void (GL_APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC) (RGLGENGLDEBUGPROCKHR callback, const void *userParam);\ntypedef GLuint (GL_APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGKHRPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\ntypedef void (GL_APIENTRYP RGLSYMGLPUSHDEBUGGROUPKHRPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);\ntypedef void (GL_APIENTRYP RGLSYMGLPOPDEBUGGROUPKHRPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELKHRPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei length, const GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETOBJECTPTRLABELKHRPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPOINTERVKHRPROC) (GLenum pname, void **params);\ntypedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSKHRPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMUIVKHRPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);\ntypedef void (GL_APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLENABLEIOESPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDISABLEIOESPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIOESPROC) (GLuint buf, GLenum mode);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIOESPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIOESPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIOESPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIOESPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREOESPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length);\ntypedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFEROESPROC) (GLenum target, GLenum access);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLUNMAPBUFFEROESPROC) (GLenum target);\ntypedef void (GL_APIENTRYP RGLSYMGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void **params);\ntypedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\ntypedef void (GL_APIENTRYP RGLSYMGLMINSAMPLESHADINGOESPROC) (GLfloat value);\ntypedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIOESPROC) (GLenum pname, GLint value);\ntypedef 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);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVOESPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVOESPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, const GLuint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC) (GLuint sampler, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEROESPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEOESPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWOESPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDVERTEXARRAYOESPROC) (GLuint array);\ntypedef void (GL_APIENTRYP RGLSYMGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);\ntypedef void (GL_APIENTRYP RGLSYMGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISVERTEXARRAYOESPROC) (GLuint array);\ntypedef void (GL_APIENTRYP RGLSYMGLVIEWPORTARRAYVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFOESPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\ntypedef void (GL_APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVOESPROC) (GLuint index, const GLfloat *v);\ntypedef void (GL_APIENTRYP RGLSYMGLSCISSORARRAYVOESPROC) (GLuint first, GLsizei count, const GLint *v);\ntypedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDOESPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLSCISSORINDEXEDVOESPROC) (GLuint index, const GLint *v);\ntypedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEARRAYFVOESPROC) (GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (GL_APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDFOESPROC) (GLuint index, GLfloat n, GLfloat f);\ntypedef void (GL_APIENTRYP RGLSYMGLGETFLOATI_VOESPROC) (GLenum target, GLuint index, GLfloat *data);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);\ntypedef GLint (GL_APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef GLint (GL_APIENTRYP RGLSYMGLGETFRAGDATAINDEXEXTPROC) (GLuint program, const GLchar *name);\ntypedef void (GL_APIENTRYP RGLSYMGLBUFFERSTORAGEEXTPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);\ntypedef void (GL_APIENTRYP RGLSYMGLCLEARTEXIMAGEEXTPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);\ntypedef 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);\ntypedef 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);\ntypedef void (GL_APIENTRYP RGLSYMGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (GL_APIENTRYP RGLSYMGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);\ntypedef void (GL_APIENTRYP RGLSYMGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);\ntypedef void (GL_APIENTRYP RGLSYMGLPOPGROUPMARKEREXTPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);\ntypedef void (GL_APIENTRYP RGLSYMGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);\ntypedef void (GL_APIENTRYP RGLSYMGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISQUERYEXTPROC) (GLuint id);\ntypedef void (GL_APIENTRYP RGLSYMGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);\ntypedef void (GL_APIENTRYP RGLSYMGLENDQUERYEXTPROC) (GLenum target);\ntypedef void (GL_APIENTRYP RGLSYMGLQUERYCOUNTEREXTPROC) (GLuint id, GLenum target);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTIVEXTPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);\ntypedef void (GL_APIENTRYP RGLSYMGLENABLEIEXTPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDISABLEIEXTPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONIEXTPROC) (GLuint buf, GLenum mode);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCIEXTPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (GL_APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIEXTPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (GL_APIENTRYP RGLSYMGLCOLORMASKIEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISENABLEDIEXTPROC) (GLenum target, GLuint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (GL_APIENTRYP RGLSYMGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor);\ntypedef void *(GL_APIENTRYP RGLSYMGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef void (GL_APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (GL_APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (GL_APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);\ntypedef void (GL_APIENTRYP RGLSYMGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);\ntypedef void (GL_APIENTRYP RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);\ntypedef void (GL_APIENTRYP RGLSYMGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);\ntypedef void (GL_APIENTRYP RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);\ntypedef void (GL_APIENTRYP RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\ntypedef void (GL_APIENTRYP RGLSYMGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);\ntypedef GLenum (GL_APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC) (void);\ntypedef void (GL_APIENTRYP RGLSYMGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);\ntypedef void (GL_APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);\ntypedef GLuint (GL_APIENTRYP RGLSYMGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);\ntypedef void (GL_APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);\ntypedef void (GL_APIENTRYP RGLSYMGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (GL_APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);\ntypedef GLboolean (GL_APIENTRYP RGLSYMGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);\ntypedef void (GL_APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target, GLsizei size);\ntypedef GLsizei (GL_APIENTRYP RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC) (GLuint target);\ntypedef void (GL_APIENTRYP RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC) (GLsizei offset, GLsizei n, const GLuint *values);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPAGECOMMITMENTEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);\ntypedef void (GL_APIENTRYP RGLSYMGLPATCHPARAMETERIEXTPROC) (GLenum pname, GLint value);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, const GLuint *param);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC) (GLuint sampler, GLenum pname, GLuint *params);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXBUFFERRANGEEXTPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (GL_APIENTRYP RGLSYMGLTEXTUREVIEWEXTPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\ntypedef void (GL_APIENTRYP RGLSYMGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);\ntypedef void (GL_APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews);\n\n#define glBlendBarrierKHR __rglgen_glBlendBarrierKHR\n#define glDebugMessageControlKHR __rglgen_glDebugMessageControlKHR\n#define glDebugMessageInsertKHR __rglgen_glDebugMessageInsertKHR\n#define glDebugMessageCallbackKHR __rglgen_glDebugMessageCallbackKHR\n#define glGetDebugMessageLogKHR __rglgen_glGetDebugMessageLogKHR\n#define glPushDebugGroupKHR __rglgen_glPushDebugGroupKHR\n#define glPopDebugGroupKHR __rglgen_glPopDebugGroupKHR\n#define glObjectLabelKHR __rglgen_glObjectLabelKHR\n#define glGetObjectLabelKHR __rglgen_glGetObjectLabelKHR\n#define glObjectPtrLabelKHR __rglgen_glObjectPtrLabelKHR\n#define glGetObjectPtrLabelKHR __rglgen_glGetObjectPtrLabelKHR\n#define glGetPointervKHR __rglgen_glGetPointervKHR\n#define glGetGraphicsResetStatusKHR __rglgen_glGetGraphicsResetStatusKHR\n#define glReadnPixelsKHR __rglgen_glReadnPixelsKHR\n#define glGetnUniformfvKHR __rglgen_glGetnUniformfvKHR\n#define glGetnUniformivKHR __rglgen_glGetnUniformivKHR\n#define glGetnUniformuivKHR __rglgen_glGetnUniformuivKHR\n#define glEGLImageTargetTexture2DOES __rglgen_glEGLImageTargetTexture2DOES\n#define glEGLImageTargetRenderbufferStorageOES __rglgen_glEGLImageTargetRenderbufferStorageOES\n#define glCopyImageSubDataOES __rglgen_glCopyImageSubDataOES\n#define glEnableiOES __rglgen_glEnableiOES\n#define glDisableiOES __rglgen_glDisableiOES\n#define glBlendEquationiOES __rglgen_glBlendEquationiOES\n#define glBlendEquationSeparateiOES __rglgen_glBlendEquationSeparateiOES\n#define glBlendFunciOES __rglgen_glBlendFunciOES\n#define glBlendFuncSeparateiOES __rglgen_glBlendFuncSeparateiOES\n#define glColorMaskiOES __rglgen_glColorMaskiOES\n#define glIsEnablediOES __rglgen_glIsEnablediOES\n#define glDrawElementsBaseVertexOES __rglgen_glDrawElementsBaseVertexOES\n#define glDrawRangeElementsBaseVertexOES __rglgen_glDrawRangeElementsBaseVertexOES\n#define glDrawElementsInstancedBaseVertexOES __rglgen_glDrawElementsInstancedBaseVertexOES\n#define glMultiDrawElementsBaseVertexOES __rglgen_glMultiDrawElementsBaseVertexOES\n#define glFramebufferTextureOES __rglgen_glFramebufferTextureOES\n#define glGetProgramBinaryOES __rglgen_glGetProgramBinaryOES\n#define glProgramBinaryOES __rglgen_glProgramBinaryOES\n#define glMapBufferOES __rglgen_glMapBufferOES\n#define glUnmapBufferOES __rglgen_glUnmapBufferOES\n#define glGetBufferPointervOES __rglgen_glGetBufferPointervOES\n#define glPrimitiveBoundingBoxOES __rglgen_glPrimitiveBoundingBoxOES\n#define glMinSampleShadingOES __rglgen_glMinSampleShadingOES\n#define glPatchParameteriOES __rglgen_glPatchParameteriOES\n#define glTexImage3DOES __rglgen_glTexImage3DOES\n#define glTexSubImage3DOES __rglgen_glTexSubImage3DOES\n#define glCopyTexSubImage3DOES __rglgen_glCopyTexSubImage3DOES\n#define glCompressedTexImage3DOES __rglgen_glCompressedTexImage3DOES\n#define glCompressedTexSubImage3DOES __rglgen_glCompressedTexSubImage3DOES\n#define glFramebufferTexture3DOES __rglgen_glFramebufferTexture3DOES\n#define glTexParameterIivOES __rglgen_glTexParameterIivOES\n#define glTexParameterIuivOES __rglgen_glTexParameterIuivOES\n#define glGetTexParameterIivOES __rglgen_glGetTexParameterIivOES\n#define glGetTexParameterIuivOES __rglgen_glGetTexParameterIuivOES\n#define glSamplerParameterIivOES __rglgen_glSamplerParameterIivOES\n#define glSamplerParameterIuivOES __rglgen_glSamplerParameterIuivOES\n#define glGetSamplerParameterIivOES __rglgen_glGetSamplerParameterIivOES\n#define glGetSamplerParameterIuivOES __rglgen_glGetSamplerParameterIuivOES\n#define glTexBufferOES __rglgen_glTexBufferOES\n#define glTexBufferRangeOES __rglgen_glTexBufferRangeOES\n#define glTexStorage3DMultisampleOES __rglgen_glTexStorage3DMultisampleOES\n#define glTextureViewOES __rglgen_glTextureViewOES\n#define glBindVertexArrayOES __rglgen_glBindVertexArrayOES\n#define glDeleteVertexArraysOES __rglgen_glDeleteVertexArraysOES\n#define glGenVertexArraysOES __rglgen_glGenVertexArraysOES\n#define glIsVertexArrayOES __rglgen_glIsVertexArrayOES\n#define glViewportArrayvOES __rglgen_glViewportArrayvOES\n#define glViewportIndexedfOES __rglgen_glViewportIndexedfOES\n#define glViewportIndexedfvOES __rglgen_glViewportIndexedfvOES\n#define glScissorArrayvOES __rglgen_glScissorArrayvOES\n#define glScissorIndexedOES __rglgen_glScissorIndexedOES\n#define glScissorIndexedvOES __rglgen_glScissorIndexedvOES\n#define glDepthRangeArrayfvOES __rglgen_glDepthRangeArrayfvOES\n#define glDepthRangeIndexedfOES __rglgen_glDepthRangeIndexedfOES\n#define glGetFloati_vOES __rglgen_glGetFloati_vOES\n#define glDrawArraysInstancedBaseInstanceEXT __rglgen_glDrawArraysInstancedBaseInstanceEXT\n#define glDrawElementsInstancedBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseInstanceEXT\n#define glDrawElementsInstancedBaseVertexBaseInstanceEXT __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT\n#define glBindFragDataLocationIndexedEXT __rglgen_glBindFragDataLocationIndexedEXT\n#define glBindFragDataLocationEXT __rglgen_glBindFragDataLocationEXT\n#define glGetProgramResourceLocationIndexEXT __rglgen_glGetProgramResourceLocationIndexEXT\n#define glGetFragDataIndexEXT __rglgen_glGetFragDataIndexEXT\n#define glBufferStorageEXT __rglgen_glBufferStorageEXT\n#define glClearTexImageEXT __rglgen_glClearTexImageEXT\n#define glClearTexSubImageEXT __rglgen_glClearTexSubImageEXT\n#define glCopyImageSubDataEXT __rglgen_glCopyImageSubDataEXT\n#define glLabelObjectEXT __rglgen_glLabelObjectEXT\n#define glGetObjectLabelEXT __rglgen_glGetObjectLabelEXT\n#define glInsertEventMarkerEXT __rglgen_glInsertEventMarkerEXT\n#define glPushGroupMarkerEXT __rglgen_glPushGroupMarkerEXT\n#define glPopGroupMarkerEXT __rglgen_glPopGroupMarkerEXT\n#define glDiscardFramebufferEXT __rglgen_glDiscardFramebufferEXT\n#define glGenQueriesEXT __rglgen_glGenQueriesEXT\n#define glDeleteQueriesEXT __rglgen_glDeleteQueriesEXT\n#define glIsQueryEXT __rglgen_glIsQueryEXT\n#define glBeginQueryEXT __rglgen_glBeginQueryEXT\n#define glEndQueryEXT __rglgen_glEndQueryEXT\n#define glQueryCounterEXT __rglgen_glQueryCounterEXT\n#define glGetQueryivEXT __rglgen_glGetQueryivEXT\n#define glGetQueryObjectivEXT __rglgen_glGetQueryObjectivEXT\n#define glGetQueryObjectuivEXT __rglgen_glGetQueryObjectuivEXT\n#define glGetQueryObjecti64vEXT __rglgen_glGetQueryObjecti64vEXT\n#define glGetQueryObjectui64vEXT __rglgen_glGetQueryObjectui64vEXT\n#define glDrawBuffersEXT __rglgen_glDrawBuffersEXT\n#define glEnableiEXT __rglgen_glEnableiEXT\n#define glDisableiEXT __rglgen_glDisableiEXT\n#define glBlendEquationiEXT __rglgen_glBlendEquationiEXT\n#define glBlendEquationSeparateiEXT __rglgen_glBlendEquationSeparateiEXT\n#define glBlendFunciEXT __rglgen_glBlendFunciEXT\n#define glBlendFuncSeparateiEXT __rglgen_glBlendFuncSeparateiEXT\n#define glColorMaskiEXT __rglgen_glColorMaskiEXT\n#define glIsEnablediEXT __rglgen_glIsEnablediEXT\n#define glDrawElementsBaseVertexEXT __rglgen_glDrawElementsBaseVertexEXT\n#define glDrawRangeElementsBaseVertexEXT __rglgen_glDrawRangeElementsBaseVertexEXT\n#define glDrawElementsInstancedBaseVertexEXT __rglgen_glDrawElementsInstancedBaseVertexEXT\n#define glMultiDrawElementsBaseVertexEXT __rglgen_glMultiDrawElementsBaseVertexEXT\n#define glDrawArraysInstancedEXT __rglgen_glDrawArraysInstancedEXT\n#define glDrawElementsInstancedEXT __rglgen_glDrawElementsInstancedEXT\n#define glFramebufferTextureEXT __rglgen_glFramebufferTextureEXT\n#define glVertexAttribDivisorEXT __rglgen_glVertexAttribDivisorEXT\n#define glMapBufferRangeEXT __rglgen_glMapBufferRangeEXT\n#define glFlushMappedBufferRangeEXT __rglgen_glFlushMappedBufferRangeEXT\n#define glMultiDrawArraysEXT __rglgen_glMultiDrawArraysEXT\n#define glMultiDrawElementsEXT __rglgen_glMultiDrawElementsEXT\n#define glMultiDrawArraysIndirectEXT __rglgen_glMultiDrawArraysIndirectEXT\n#define glMultiDrawElementsIndirectEXT __rglgen_glMultiDrawElementsIndirectEXT\n#define glRenderbufferStorageMultisampleEXT __rglgen_glRenderbufferStorageMultisampleEXT\n#define glFramebufferTexture2DMultisampleEXT __rglgen_glFramebufferTexture2DMultisampleEXT\n#define glReadBufferIndexedEXT __rglgen_glReadBufferIndexedEXT\n#define glDrawBuffersIndexedEXT __rglgen_glDrawBuffersIndexedEXT\n#define glGetIntegeri_vEXT __rglgen_glGetIntegeri_vEXT\n#define glPolygonOffsetClampEXT __rglgen_glPolygonOffsetClampEXT\n#define glPrimitiveBoundingBoxEXT __rglgen_glPrimitiveBoundingBoxEXT\n#define glRasterSamplesEXT __rglgen_glRasterSamplesEXT\n#define glGetGraphicsResetStatusEXT __rglgen_glGetGraphicsResetStatusEXT\n#define glReadnPixelsEXT __rglgen_glReadnPixelsEXT\n#define glGetnUniformfvEXT __rglgen_glGetnUniformfvEXT\n#define glGetnUniformivEXT __rglgen_glGetnUniformivEXT\n#define glActiveShaderProgramEXT __rglgen_glActiveShaderProgramEXT\n#define glBindProgramPipelineEXT __rglgen_glBindProgramPipelineEXT\n#define glCreateShaderProgramvEXT __rglgen_glCreateShaderProgramvEXT\n#define glDeleteProgramPipelinesEXT __rglgen_glDeleteProgramPipelinesEXT\n#define glGenProgramPipelinesEXT __rglgen_glGenProgramPipelinesEXT\n#define glGetProgramPipelineInfoLogEXT __rglgen_glGetProgramPipelineInfoLogEXT\n#define glGetProgramPipelineivEXT __rglgen_glGetProgramPipelineivEXT\n#define glIsProgramPipelineEXT __rglgen_glIsProgramPipelineEXT\n#define glProgramParameteriEXT __rglgen_glProgramParameteriEXT\n#define glProgramUniform1fEXT __rglgen_glProgramUniform1fEXT\n#define glProgramUniform1fvEXT __rglgen_glProgramUniform1fvEXT\n#define glProgramUniform1iEXT __rglgen_glProgramUniform1iEXT\n#define glProgramUniform1ivEXT __rglgen_glProgramUniform1ivEXT\n#define glProgramUniform2fEXT __rglgen_glProgramUniform2fEXT\n#define glProgramUniform2fvEXT __rglgen_glProgramUniform2fvEXT\n#define glProgramUniform2iEXT __rglgen_glProgramUniform2iEXT\n#define glProgramUniform2ivEXT __rglgen_glProgramUniform2ivEXT\n#define glProgramUniform3fEXT __rglgen_glProgramUniform3fEXT\n#define glProgramUniform3fvEXT __rglgen_glProgramUniform3fvEXT\n#define glProgramUniform3iEXT __rglgen_glProgramUniform3iEXT\n#define glProgramUniform3ivEXT __rglgen_glProgramUniform3ivEXT\n#define glProgramUniform4fEXT __rglgen_glProgramUniform4fEXT\n#define glProgramUniform4fvEXT __rglgen_glProgramUniform4fvEXT\n#define glProgramUniform4iEXT __rglgen_glProgramUniform4iEXT\n#define glProgramUniform4ivEXT __rglgen_glProgramUniform4ivEXT\n#define glProgramUniformMatrix2fvEXT __rglgen_glProgramUniformMatrix2fvEXT\n#define glProgramUniformMatrix3fvEXT __rglgen_glProgramUniformMatrix3fvEXT\n#define glProgramUniformMatrix4fvEXT __rglgen_glProgramUniformMatrix4fvEXT\n#define glUseProgramStagesEXT __rglgen_glUseProgramStagesEXT\n#define glValidateProgramPipelineEXT __rglgen_glValidateProgramPipelineEXT\n#define glProgramUniform1uiEXT __rglgen_glProgramUniform1uiEXT\n#define glProgramUniform2uiEXT __rglgen_glProgramUniform2uiEXT\n#define glProgramUniform3uiEXT __rglgen_glProgramUniform3uiEXT\n#define glProgramUniform4uiEXT __rglgen_glProgramUniform4uiEXT\n#define glProgramUniform1uivEXT __rglgen_glProgramUniform1uivEXT\n#define glProgramUniform2uivEXT __rglgen_glProgramUniform2uivEXT\n#define glProgramUniform3uivEXT __rglgen_glProgramUniform3uivEXT\n#define glProgramUniform4uivEXT __rglgen_glProgramUniform4uivEXT\n#define glProgramUniformMatrix2x3fvEXT __rglgen_glProgramUniformMatrix2x3fvEXT\n#define glProgramUniformMatrix3x2fvEXT __rglgen_glProgramUniformMatrix3x2fvEXT\n#define glProgramUniformMatrix2x4fvEXT __rglgen_glProgramUniformMatrix2x4fvEXT\n#define glProgramUniformMatrix4x2fvEXT __rglgen_glProgramUniformMatrix4x2fvEXT\n#define glProgramUniformMatrix3x4fvEXT __rglgen_glProgramUniformMatrix3x4fvEXT\n#define glProgramUniformMatrix4x3fvEXT __rglgen_glProgramUniformMatrix4x3fvEXT\n#define glFramebufferPixelLocalStorageSizeEXT __rglgen_glFramebufferPixelLocalStorageSizeEXT\n#define glGetFramebufferPixelLocalStorageSizeEXT __rglgen_glGetFramebufferPixelLocalStorageSizeEXT\n#define glClearPixelLocalStorageuiEXT __rglgen_glClearPixelLocalStorageuiEXT\n#define glTexPageCommitmentEXT __rglgen_glTexPageCommitmentEXT\n#define glPatchParameteriEXT __rglgen_glPatchParameteriEXT\n#define glTexParameterIivEXT __rglgen_glTexParameterIivEXT\n#define glTexParameterIuivEXT __rglgen_glTexParameterIuivEXT\n#define glGetTexParameterIivEXT __rglgen_glGetTexParameterIivEXT\n#define glGetTexParameterIuivEXT __rglgen_glGetTexParameterIuivEXT\n#define glSamplerParameterIivEXT __rglgen_glSamplerParameterIivEXT\n#define glSamplerParameterIuivEXT __rglgen_glSamplerParameterIuivEXT\n#define glGetSamplerParameterIivEXT __rglgen_glGetSamplerParameterIivEXT\n#define glGetSamplerParameterIuivEXT __rglgen_glGetSamplerParameterIuivEXT\n#define glTexBufferEXT __rglgen_glTexBufferEXT\n#define glTexBufferRangeEXT __rglgen_glTexBufferRangeEXT\n#define glTexStorage1DEXT __rglgen_glTexStorage1DEXT\n#define glTexStorage2DEXT __rglgen_glTexStorage2DEXT\n#define glTexStorage3DEXT __rglgen_glTexStorage3DEXT\n#define glTextureStorage1DEXT __rglgen_glTextureStorage1DEXT\n#define glTextureStorage2DEXT __rglgen_glTextureStorage2DEXT\n#define glTextureStorage3DEXT __rglgen_glTextureStorage3DEXT\n#define glTextureViewEXT __rglgen_glTextureViewEXT\n#define glesEXT __rglgen_glesEXT\n#define glFramebufferTextureMultiviewOVR __rglgen_glFramebufferTextureMultiviewOVR\n#define glFramebufferTextureMultisampleMultiviewOVR __rglgen_glFramebufferTextureMultisampleMultiviewOVR\n\nextern RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;\nextern RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;\nextern RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;\nextern RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;\nextern RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;\nextern RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;\nextern RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;\nextern RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;\nextern RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;\nextern RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;\nextern RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;\nextern RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;\nextern RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;\nextern RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;\nextern RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;\nextern RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;\nextern RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;\nextern RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;\nextern RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;\nextern RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;\nextern RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;\nextern RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;\nextern RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;\nextern RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;\nextern RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;\nextern RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;\nextern RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;\nextern RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;\nextern RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;\nextern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;\nextern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;\nextern RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;\nextern RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;\nextern RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;\nextern RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;\nextern RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;\nextern RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;\nextern RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;\nextern RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;\nextern RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;\nextern RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;\nextern RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;\nextern RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;\nextern RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;\nextern RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;\nextern RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;\nextern RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;\nextern RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;\nextern RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;\nextern RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;\nextern RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;\nextern RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;\nextern RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;\nextern RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;\nextern RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;\nextern RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;\nextern RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;\nextern RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;\nextern RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;\nextern RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;\nextern RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;\nextern RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;\nextern RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;\nextern RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;\nextern RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;\nextern RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;\nextern RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;\nextern RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;\nextern RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;\nextern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;\nextern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;\nextern RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;\nextern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;\nextern RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;\nextern RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;\nextern RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;\nextern RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;\nextern RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;\nextern RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;\nextern RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;\nextern RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;\nextern RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;\nextern RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;\nextern RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;\nextern RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;\nextern RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;\nextern RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;\nextern RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;\nextern RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;\nextern RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;\nextern RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;\nextern RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;\nextern RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;\nextern RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;\nextern RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;\nextern RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;\nextern RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;\nextern RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;\nextern RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;\nextern RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;\nextern RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;\nextern RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;\nextern RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;\nextern RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;\nextern RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;\nextern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;\nextern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;\nextern RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;\nextern RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;\nextern RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;\nextern RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;\nextern RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;\nextern RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;\nextern RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;\nextern RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;\nextern RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;\nextern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;\nextern RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;\nextern RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;\nextern RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;\nextern RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;\nextern RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;\nextern RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;\nextern RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;\nextern RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;\nextern RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;\nextern RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;\nextern RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;\nextern RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;\nextern RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;\nextern RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;\nextern RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;\nextern RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;\nextern RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;\nextern RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;\nextern RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;\nextern RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;\nextern RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;\nextern RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;\nextern RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;\nextern RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;\nextern RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;\nextern RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;\nextern RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;\nextern RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;\nextern RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;\nextern RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;\nextern RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;\nextern RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;\nextern RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;\nextern RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;\nextern RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;\nextern RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;\nextern RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;\nextern RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;\nextern RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;\nextern RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;\nextern RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;\nextern RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;\nextern RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;\nextern RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;\nextern RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;\nextern RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;\nextern RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;\nextern RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;\nextern RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;\nextern RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;\nextern RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;\nextern RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;\nextern RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;\nextern RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;\nextern RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;\nextern RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;\nextern RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;\nextern RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;\nextern RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;\nextern RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;\nextern RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;\nextern RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;\nextern RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;\nextern RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;\n\nstruct rglgen_sym_map { const char *sym; void *ptr; };\nextern const struct rglgen_sym_map rglgen_symbol_map[];\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "include/glsym/glsym_gl.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (glsym).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef RGLGEN_DECL_H__\n#define RGLGEN_DECL_H__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#ifdef GL_APIENTRY\ntypedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\ntypedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n#else\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\ntypedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\ntypedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n#endif\n#ifndef GL_OES_EGL_image\ntypedef void *GLeglImageOES;\n#endif\n#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\ntypedef GLint GLfixed;\n#endif\n#if defined(__MACH__) && defined(__APPLE__) && !defined(OS_TARGET_IPHONE) && !defined(MAC_OS_X_VERSION_10_7)\ntypedef long long int GLint64;\ntypedef unsigned long long int GLuint64;\ntypedef unsigned long long int GLuint64EXT;\ntypedef struct __GLsync *GLsync;\n#endif\ntypedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);\ntypedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) (GLenum texture);\ntypedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);\ntypedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) (GLenum texture);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP RGLSYMGLFOGCOORDFPROC) (GLfloat coord);\ntypedef void (APIENTRYP RGLSYMGLFOGCOORDFVPROC) (const GLfloat *coord);\ntypedef void (APIENTRYP RGLSYMGLFOGCOORDDPROC) (GLdouble coord);\ntypedef void (APIENTRYP RGLSYMGLFOGCOORDDVPROC) (const GLdouble *coord);\ntypedef void (APIENTRYP RGLSYMGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLOR3USVPROC) (const GLushort *v);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2IPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVPROC) (const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2SPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) (GLenum mode);\ntypedef void (APIENTRYP RGLSYMGLGENQUERIESPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP RGLSYMGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP RGLSYMGLISQUERYPROC) (GLuint id);\ntypedef void (APIENTRYP RGLSYMGLBEGINQUERYPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP RGLSYMGLENDQUERYPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLBINDBUFFERPROC) (GLenum target, GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);\ntypedef void (APIENTRYP RGLSYMGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);\ntypedef GLboolean (APIENTRYP RGLSYMGLISBUFFERPROC) (GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);\ntypedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);\ntypedef void *(APIENTRYP RGLSYMGLMAPBUFFERPROC) (GLenum target, GLenum access);\ntypedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP RGLSYMGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);\ntypedef void (APIENTRYP RGLSYMGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\ntypedef void (APIENTRYP RGLSYMGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);\ntypedef void (APIENTRYP RGLSYMGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);\ntypedef void (APIENTRYP RGLSYMGLATTACHSHADERPROC) (GLuint program, GLuint shader);\ntypedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLCOMPILESHADERPROC) (GLuint shader);\ntypedef GLuint (APIENTRYP RGLSYMGLCREATEPROGRAMPROC) (void);\ntypedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROC) (GLenum type);\ntypedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP RGLSYMGLDELETESHADERPROC) (GLuint shader);\ntypedef void (APIENTRYP RGLSYMGLDETACHSHADERPROC) (GLuint program, GLuint shader);\ntypedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);\ntypedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);\ntypedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP RGLSYMGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);\ntypedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);\ntypedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPROC) (GLuint program);\ntypedef GLboolean (APIENTRYP RGLSYMGLISSHADERPROC) (GLuint shader);\ntypedef void (APIENTRYP RGLSYMGLLINKPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP RGLSYMGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);\ntypedef void (APIENTRYP RGLSYMGLUSEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1FPROC) (GLint location, GLfloat v0);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1IPROC) (GLint location, GLint v0);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef void (APIENTRYP RGLSYMGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);\ntypedef void (APIENTRYP RGLSYMGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);\ntypedef void (APIENTRYP RGLSYMGLENABLEIPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP RGLSYMGLDISABLEIPROC) (GLenum target, GLuint index);\ntypedef GLboolean (APIENTRYP RGLSYMGLISENABLEDIPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP RGLSYMGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);\ntypedef void (APIENTRYP RGLSYMGLENDTRANSFORMFEEDBACKPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP RGLSYMGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);\ntypedef void (APIENTRYP RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);\ntypedef void (APIENTRYP RGLSYMGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);\ntypedef void (APIENTRYP RGLSYMGLENDCONDITIONALRENDERPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);\ntypedef GLint (APIENTRYP RGLSYMGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1UIPROC) (GLint location, GLuint v0);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\ntypedef const GLubyte *(APIENTRYP RGLSYMGLGETSTRINGIPROC) (GLenum name, GLuint index);\ntypedef GLboolean (APIENTRYP RGLSYMGLISRENDERBUFFERPROC) (GLuint renderbuffer);\ntypedef void (APIENTRYP RGLSYMGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);\ntypedef void (APIENTRYP RGLSYMGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);\ntypedef void (APIENTRYP RGLSYMGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);\ntypedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef GLboolean (APIENTRYP RGLSYMGLISFRAMEBUFFERPROC) (GLuint framebuffer);\ntypedef void (APIENTRYP RGLSYMGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);\ntypedef void (APIENTRYP RGLSYMGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);\ntypedef void (APIENTRYP RGLSYMGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);\ntypedef GLenum (APIENTRYP RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGENERATEMIPMAPPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\ntypedef void (APIENTRYP RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void *(APIENTRYP RGLSYMGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef void (APIENTRYP RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);\ntypedef void (APIENTRYP RGLSYMGLBINDVERTEXARRAYPROC) (GLuint array);\ntypedef void (APIENTRYP RGLSYMGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);\ntypedef void (APIENTRYP RGLSYMGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);\ntypedef GLboolean (APIENTRYP RGLSYMGLISVERTEXARRAYPROC) (GLuint array);\ntypedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);\ntypedef void (APIENTRYP RGLSYMGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLPRIMITIVERESTARTINDEXPROC) (GLuint index);\ntypedef void (APIENTRYP RGLSYMGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);\ntypedef GLuint (APIENTRYP RGLSYMGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);\ntypedef void (APIENTRYP RGLSYMGLPROVOKINGVERTEXPROC) (GLenum mode);\ntypedef GLsync (APIENTRYP RGLSYMGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);\ntypedef GLboolean (APIENTRYP RGLSYMGLISSYNCPROC) (GLsync sync);\ntypedef void (APIENTRYP RGLSYMGLDELETESYNCPROC) (GLsync sync);\ntypedef GLenum (APIENTRYP RGLSYMGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);\ntypedef void (APIENTRYP RGLSYMGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);\ntypedef void (APIENTRYP RGLSYMGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);\ntypedef void (APIENTRYP RGLSYMGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);\ntypedef void (APIENTRYP RGLSYMGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP RGLSYMGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);\ntypedef void (APIENTRYP RGLSYMGLSAMPLEMASKIPROC) (GLuint index, GLbitfield mask);\ntypedef void (APIENTRYP RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);\ntypedef GLint (APIENTRYP RGLSYMGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);\ntypedef void (APIENTRYP RGLSYMGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);\ntypedef GLboolean (APIENTRYP RGLSYMGLISSAMPLERPROC) (GLuint sampler);\ntypedef void (APIENTRYP RGLSYMGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);\ntypedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);\ntypedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);\ntypedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (APIENTRYP RGLSYMGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);\ntypedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLQUERYCOUNTERPROC) (GLuint id, GLenum target);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXP2UIPROC) (GLenum type, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXP3UIPROC) (GLenum type, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXP4UIPROC) (GLenum type, GLuint value);\ntypedef void (APIENTRYP RGLSYMGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLNORMALP3UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP RGLSYMGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP RGLSYMGLCOLORP3UIPROC) (GLenum type, GLuint color);\ntypedef void (APIENTRYP RGLSYMGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);\ntypedef void (APIENTRYP RGLSYMGLCOLORP4UIPROC) (GLenum type, GLuint color);\ntypedef void (APIENTRYP RGLSYMGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);\ntypedef void (APIENTRYP RGLSYMGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);\ntypedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGPROC) (GLfloat value);\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP RGLSYMGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (APIENTRYP RGLSYMGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1DPROC) (GLint location, GLdouble x);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);\ntypedef GLint (APIENTRYP RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);\ntypedef GLuint (APIENTRYP RGLSYMGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);\ntypedef void (APIENTRYP RGLSYMGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);\ntypedef void (APIENTRYP RGLSYMGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);\ntypedef void (APIENTRYP RGLSYMGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP RGLSYMGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);\ntypedef void (APIENTRYP RGLSYMGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);\ntypedef GLboolean (APIENTRYP RGLSYMGLISTRANSFORMFEEDBACKPROC) (GLuint id);\ntypedef void (APIENTRYP RGLSYMGLPAUSETRANSFORMFEEDBACKPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLRESUMETRANSFORMFEEDBACKPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);\ntypedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);\ntypedef void (APIENTRYP RGLSYMGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);\ntypedef void (APIENTRYP RGLSYMGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLRELEASESHADERCOMPILERPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);\ntypedef void (APIENTRYP RGLSYMGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);\ntypedef void (APIENTRYP RGLSYMGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);\ntypedef void (APIENTRYP RGLSYMGLCLEARDEPTHFPROC) (GLfloat d);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);\ntypedef void (APIENTRYP RGLSYMGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);\ntypedef void (APIENTRYP RGLSYMGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);\ntypedef GLuint (APIENTRYP RGLSYMGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);\ntypedef void (APIENTRYP RGLSYMGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);\ntypedef void (APIENTRYP RGLSYMGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);\ntypedef void (APIENTRYP RGLSYMGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);\ntypedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMPIPELINEPROC) (GLuint pipeline);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\ntypedef void (APIENTRYP RGLSYMGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);\ntypedef void (APIENTRYP RGLSYMGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);\ntypedef void (APIENTRYP RGLSYMGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);\ntypedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);\ntypedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);\ntypedef void (APIENTRYP RGLSYMGLMEMORYBARRIERPROC) (GLbitfield barriers);\ntypedef void (APIENTRYP RGLSYMGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);\ntypedef void (APIENTRYP RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);\ntypedef void (APIENTRYP RGLSYMGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);\ntypedef void (APIENTRYP RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64 *params);\ntypedef void (APIENTRYP RGLSYMGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP RGLSYMGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);\ntypedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);\ntypedef void (APIENTRYP RGLSYMGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);\ntypedef void (APIENTRYP RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);\ntypedef GLuint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLint *params);\ntypedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef GLint (APIENTRYP RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);\ntypedef void (APIENTRYP RGLSYMGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP RGLSYMGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\ntypedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);\ntypedef void (APIENTRYP RGLSYMGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);\ntypedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\ntypedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKPROC) (RGLGENGLDEBUGPROC callback, const void *userParam);\ntypedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\ntypedef void (APIENTRYP RGLSYMGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);\ntypedef void (APIENTRYP RGLSYMGLPOPDEBUGGROUPPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);\ntypedef void (APIENTRYP RGLSYMGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (APIENTRYP RGLSYMGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);\ntypedef void (APIENTRYP RGLSYMGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (APIENTRYP RGLSYMGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);\ntypedef void (APIENTRYP RGLSYMGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);\ntypedef void (APIENTRYP RGLSYMGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);\ntypedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);\ntypedef void (APIENTRYP RGLSYMGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);\ntypedef void (APIENTRYP RGLSYMGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);\ntypedef void (APIENTRYP RGLSYMGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\ntypedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTUREHANDLEARBPROC) (GLuint texture);\ntypedef GLuint64 (APIENTRYP RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);\ntypedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);\ntypedef void (APIENTRYP RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);\ntypedef GLuint64 (APIENTRYP RGLSYMGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);\ntypedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);\ntypedef void (APIENTRYP RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);\ntypedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);\ntypedef GLboolean (APIENTRYP RGLSYMGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);\n#ifdef __APPLE__\n\tstruct _cl_context;\n\tstruct _cl_event;\n#endif\ntypedef GLsync (APIENTRYP RGLSYMGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);\ntypedef void (APIENTRYP RGLSYMGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (APIENTRYP RGLSYMGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\ntypedef void (APIENTRYP RGLSYMGLDEBUGMESSAGECALLBACKARBPROC) (RGLGENGLDEBUGPROCARB callback, const void *userParam);\ntypedef GLuint (APIENTRYP RGLSYMGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\ntypedef void (APIENTRYP RGLSYMGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP RGLSYMGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (APIENTRYP RGLSYMGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (APIENTRYP RGLSYMGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);\ntypedef void (APIENTRYP RGLSYMGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);\ntypedef void (APIENTRYP RGLSYMGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP RGLSYMGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);\ntypedef GLboolean (APIENTRYP RGLSYMGLISPROGRAMARBPROC) (GLuint program);\ntypedef void (APIENTRYP RGLSYMGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void (APIENTRYP RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);\ntypedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);\ntypedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);\ntypedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data);\ntypedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);\ntypedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\ntypedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP RGLSYMGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\ntypedef void (APIENTRYP RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);\ntypedef void (APIENTRYP RGLSYMGLCURRENTPALETTEMATRIXARBPROC) (GLint index);\ntypedef void (APIENTRYP RGLSYMGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);\ntypedef void (APIENTRYP RGLSYMGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);\ntypedef void (APIENTRYP RGLSYMGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);\ntypedef void (APIENTRYP RGLSYMGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);\ntypedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP RGLSYMGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP RGLSYMGLISQUERYARBPROC) (GLuint id);\ntypedef void (APIENTRYP RGLSYMGLBEGINQUERYARBPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP RGLSYMGLENDQUERYARBPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);\ntypedef GLenum (APIENTRYP RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);\ntypedef void (APIENTRYP RGLSYMGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (APIENTRYP RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);\ntypedef void (APIENTRYP RGLSYMGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\ntypedef void (APIENTRYP RGLSYMGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);\ntypedef void (APIENTRYP RGLSYMGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);\ntypedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);\ntypedef void (APIENTRYP RGLSYMGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);\ntypedef void (APIENTRYP RGLSYMGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);\ntypedef void (APIENTRYP RGLSYMGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);\ntypedef void (APIENTRYP RGLSYMGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);\ntypedef void (APIENTRYP RGLSYMGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);\ntypedef void (APIENTRYP RGLSYMGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\ntypedef void (APIENTRYP RGLSYMGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\ntypedef void (APIENTRYP RGLSYMGLMINSAMPLESHADINGARBPROC) (GLfloat value);\ntypedef void (APIENTRYP RGLSYMGLDELETEOBJECTARBPROC) (GLhandleARB obj);\ntypedef GLhandleARB (APIENTRYP RGLSYMGLGETHANDLEARBPROC) (GLenum pname);\ntypedef void (APIENTRYP RGLSYMGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);\ntypedef GLhandleARB (APIENTRYP RGLSYMGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);\ntypedef void (APIENTRYP RGLSYMGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);\ntypedef void (APIENTRYP RGLSYMGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);\ntypedef GLhandleARB (APIENTRYP RGLSYMGLCREATEPROGRAMOBJECTARBPROC) (void);\ntypedef void (APIENTRYP RGLSYMGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);\ntypedef void (APIENTRYP RGLSYMGLLINKPROGRAMARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP RGLSYMGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP RGLSYMGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1IARBPROC) (GLint location, GLint v0);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);\ntypedef void (APIENTRYP RGLSYMGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);\ntypedef GLint (APIENTRYP RGLSYMGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);\ntypedef void (APIENTRYP RGLSYMGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);\ntypedef void (APIENTRYP RGLSYMGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);\ntypedef GLboolean (APIENTRYP RGLSYMGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);\ntypedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);\ntypedef void (APIENTRYP RGLSYMGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean resident);\ntypedef void (APIENTRYP RGLSYMGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);\ntypedef void (APIENTRYP RGLSYMGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLVERTEXBLENDARBPROC) (GLint count);\ntypedef void (APIENTRYP RGLSYMGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);\ntypedef void (APIENTRYP RGLSYMGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);\ntypedef GLboolean (APIENTRYP RGLSYMGLISBUFFERARBPROC) (GLuint buffer);\ntypedef void (APIENTRYP RGLSYMGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);\ntypedef void (APIENTRYP RGLSYMGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);\ntypedef void *(APIENTRYP RGLSYMGLMAPBUFFERARBPROC) (GLenum target, GLenum access);\ntypedef GLboolean (APIENTRYP RGLSYMGLUNMAPBUFFERARBPROC) (GLenum target);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP RGLSYMGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);\ntypedef void (APIENTRYP RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);\ntypedef void (APIENTRYP RGLSYMGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);\ntypedef void (APIENTRYP RGLSYMGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\ntypedef GLint (APIENTRYP RGLSYMGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2DVARBPROC) (const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2FVARBPROC) (const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2IARBPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2IVARBPROC) (const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS2SVARBPROC) (const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3DVARBPROC) (const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3FVARBPROC) (const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3IVARBPROC) (const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP RGLSYMGLWINDOWPOS3SVARBPROC) (const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1BOESPROC) (GLbyte s);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLVERTEX2BOESPROC) (GLbyte x);\ntypedef void (APIENTRYP RGLSYMGLVERTEX2BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLVERTEX3BOESPROC) (GLbyte x, GLbyte y);\ntypedef void (APIENTRYP RGLSYMGLVERTEX3BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z);\ntypedef void (APIENTRYP RGLSYMGLVERTEX4BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP RGLSYMGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);\ntypedef void (APIENTRYP RGLSYMGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP RGLSYMGLCLEARDEPTHXOESPROC) (GLfixed depth);\ntypedef void (APIENTRYP RGLSYMGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);\ntypedef void (APIENTRYP RGLSYMGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP RGLSYMGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);\ntypedef void (APIENTRYP RGLSYMGLFOGXOESPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);\ntypedef void (APIENTRYP RGLSYMGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);\ntypedef void (APIENTRYP RGLSYMGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);\ntypedef void (APIENTRYP RGLSYMGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);\ntypedef void (APIENTRYP RGLSYMGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLLINEWIDTHXOESPROC) (GLfixed width);\ntypedef void (APIENTRYP RGLSYMGLLOADMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP RGLSYMGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);\ntypedef void (APIENTRYP RGLSYMGLMULTMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);\ntypedef void (APIENTRYP RGLSYMGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);\ntypedef void (APIENTRYP RGLSYMGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);\ntypedef void (APIENTRYP RGLSYMGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLPOINTSIZEXOESPROC) (GLfixed size);\ntypedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);\ntypedef void (APIENTRYP RGLSYMGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEOESPROC) (GLfixed value, GLboolean invert);\ntypedef void (APIENTRYP RGLSYMGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP RGLSYMGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP RGLSYMGLACCUMXOESPROC) (GLenum op, GLfixed value);\ntypedef void (APIENTRYP RGLSYMGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);\ntypedef void (APIENTRYP RGLSYMGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP RGLSYMGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP RGLSYMGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);\ntypedef void (APIENTRYP RGLSYMGLCOLOR3XVOESPROC) (const GLfixed *components);\ntypedef void (APIENTRYP RGLSYMGLCOLOR4XVOESPROC) (const GLfixed *components);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD1XOESPROC) (GLfixed u);\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD1XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);\ntypedef void (APIENTRYP RGLSYMGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);\ntypedef void (APIENTRYP RGLSYMGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLINDEXXOESPROC) (GLfixed component);\ntypedef void (APIENTRYP RGLSYMGLINDEXXVOESPROC) (const GLfixed *component);\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP RGLSYMGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);\ntypedef void (APIENTRYP RGLSYMGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);\ntypedef void (APIENTRYP RGLSYMGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);\ntypedef void (APIENTRYP RGLSYMGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLNORMAL3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLPASSTHROUGHXOESPROC) (GLfixed token);\ntypedef void (APIENTRYP RGLSYMGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);\ntypedef void (APIENTRYP RGLSYMGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);\ntypedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);\ntypedef void (APIENTRYP RGLSYMGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1XOESPROC) (GLfixed s);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP RGLSYMGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP RGLSYMGLVERTEX2XOESPROC) (GLfixed x);\ntypedef void (APIENTRYP RGLSYMGLVERTEX2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);\ntypedef void (APIENTRYP RGLSYMGLVERTEX3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP RGLSYMGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP RGLSYMGLVERTEX4XVOESPROC) (const GLfixed *coords);\ntypedef GLbitfield (APIENTRYP RGLSYMGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);\ntypedef void (APIENTRYP RGLSYMGLCLEARDEPTHFOESPROC) (GLclampf depth);\ntypedef void (APIENTRYP RGLSYMGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);\ntypedef void (APIENTRYP RGLSYMGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);\ntypedef void (APIENTRYP RGLSYMGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);\ntypedef void (APIENTRYP RGLSYMGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);\ntypedef void (APIENTRYP RGLSYMGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);\ntypedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);\n\n#define glDrawRangeElements __rglgen_glDrawRangeElements\n#define glTexImage3D __rglgen_glTexImage3D\n#define glTexSubImage3D __rglgen_glTexSubImage3D\n#define glCopyTexSubImage3D __rglgen_glCopyTexSubImage3D\n#define glActiveTexture __rglgen_glActiveTexture\n#define glSampleCoverage __rglgen_glSampleCoverage\n#define glCompressedTexImage3D __rglgen_glCompressedTexImage3D\n#define glCompressedTexImage2D __rglgen_glCompressedTexImage2D\n#define glCompressedTexImage1D __rglgen_glCompressedTexImage1D\n#define glCompressedTexSubImage3D __rglgen_glCompressedTexSubImage3D\n#define glCompressedTexSubImage2D __rglgen_glCompressedTexSubImage2D\n#define glCompressedTexSubImage1D __rglgen_glCompressedTexSubImage1D\n#define glGetCompressedTexImage __rglgen_glGetCompressedTexImage\n#define glClientActiveTexture __rglgen_glClientActiveTexture\n#define glMultiTexCoord1d __rglgen_glMultiTexCoord1d\n#define glMultiTexCoord1dv __rglgen_glMultiTexCoord1dv\n#define glMultiTexCoord1f __rglgen_glMultiTexCoord1f\n#define glMultiTexCoord1fv __rglgen_glMultiTexCoord1fv\n#define glMultiTexCoord1i __rglgen_glMultiTexCoord1i\n#define glMultiTexCoord1iv __rglgen_glMultiTexCoord1iv\n#define glMultiTexCoord1s __rglgen_glMultiTexCoord1s\n#define glMultiTexCoord1sv __rglgen_glMultiTexCoord1sv\n#define glMultiTexCoord2d __rglgen_glMultiTexCoord2d\n#define glMultiTexCoord2dv __rglgen_glMultiTexCoord2dv\n#define glMultiTexCoord2f __rglgen_glMultiTexCoord2f\n#define glMultiTexCoord2fv __rglgen_glMultiTexCoord2fv\n#define glMultiTexCoord2i __rglgen_glMultiTexCoord2i\n#define glMultiTexCoord2iv __rglgen_glMultiTexCoord2iv\n#define glMultiTexCoord2s __rglgen_glMultiTexCoord2s\n#define glMultiTexCoord2sv __rglgen_glMultiTexCoord2sv\n#define glMultiTexCoord3d __rglgen_glMultiTexCoord3d\n#define glMultiTexCoord3dv __rglgen_glMultiTexCoord3dv\n#define glMultiTexCoord3f __rglgen_glMultiTexCoord3f\n#define glMultiTexCoord3fv __rglgen_glMultiTexCoord3fv\n#define glMultiTexCoord3i __rglgen_glMultiTexCoord3i\n#define glMultiTexCoord3iv __rglgen_glMultiTexCoord3iv\n#define glMultiTexCoord3s __rglgen_glMultiTexCoord3s\n#define glMultiTexCoord3sv __rglgen_glMultiTexCoord3sv\n#define glMultiTexCoord4d __rglgen_glMultiTexCoord4d\n#define glMultiTexCoord4dv __rglgen_glMultiTexCoord4dv\n#define glMultiTexCoord4f __rglgen_glMultiTexCoord4f\n#define glMultiTexCoord4fv __rglgen_glMultiTexCoord4fv\n#define glMultiTexCoord4i __rglgen_glMultiTexCoord4i\n#define glMultiTexCoord4iv __rglgen_glMultiTexCoord4iv\n#define glMultiTexCoord4s __rglgen_glMultiTexCoord4s\n#define glMultiTexCoord4sv __rglgen_glMultiTexCoord4sv\n#define glLoadTransposeMatrixf __rglgen_glLoadTransposeMatrixf\n#define glLoadTransposeMatrixd __rglgen_glLoadTransposeMatrixd\n#define glMultTransposeMatrixf __rglgen_glMultTransposeMatrixf\n#define glMultTransposeMatrixd __rglgen_glMultTransposeMatrixd\n#define glBlendFuncSeparate __rglgen_glBlendFuncSeparate\n#define glMultiDrawArrays __rglgen_glMultiDrawArrays\n#define glMultiDrawElements __rglgen_glMultiDrawElements\n#define glPointParameterf __rglgen_glPointParameterf\n#define glPointParameterfv __rglgen_glPointParameterfv\n#define glPointParameteri __rglgen_glPointParameteri\n#define glPointParameteriv __rglgen_glPointParameteriv\n#define glFogCoordf __rglgen_glFogCoordf\n#define glFogCoordfv __rglgen_glFogCoordfv\n#define glFogCoordd __rglgen_glFogCoordd\n#define glFogCoorddv __rglgen_glFogCoorddv\n#define glFogCoordPointer __rglgen_glFogCoordPointer\n#define glSecondaryColor3b __rglgen_glSecondaryColor3b\n#define glSecondaryColor3bv __rglgen_glSecondaryColor3bv\n#define glSecondaryColor3d __rglgen_glSecondaryColor3d\n#define glSecondaryColor3dv __rglgen_glSecondaryColor3dv\n#define glSecondaryColor3f __rglgen_glSecondaryColor3f\n#define glSecondaryColor3fv __rglgen_glSecondaryColor3fv\n#define glSecondaryColor3i __rglgen_glSecondaryColor3i\n#define glSecondaryColor3iv __rglgen_glSecondaryColor3iv\n#define glSecondaryColor3s __rglgen_glSecondaryColor3s\n#define glSecondaryColor3sv __rglgen_glSecondaryColor3sv\n#define glSecondaryColor3ub __rglgen_glSecondaryColor3ub\n#define glSecondaryColor3ubv __rglgen_glSecondaryColor3ubv\n#define glSecondaryColor3ui __rglgen_glSecondaryColor3ui\n#define glSecondaryColor3uiv __rglgen_glSecondaryColor3uiv\n#define glSecondaryColor3us __rglgen_glSecondaryColor3us\n#define glSecondaryColor3usv __rglgen_glSecondaryColor3usv\n#define glSecondaryColorPointer __rglgen_glSecondaryColorPointer\n#define glWindowPos2d __rglgen_glWindowPos2d\n#define glWindowPos2dv __rglgen_glWindowPos2dv\n#define glWindowPos2f __rglgen_glWindowPos2f\n#define glWindowPos2fv __rglgen_glWindowPos2fv\n#define glWindowPos2i __rglgen_glWindowPos2i\n#define glWindowPos2iv __rglgen_glWindowPos2iv\n#define glWindowPos2s __rglgen_glWindowPos2s\n#define glWindowPos2sv __rglgen_glWindowPos2sv\n#define glWindowPos3d __rglgen_glWindowPos3d\n#define glWindowPos3dv __rglgen_glWindowPos3dv\n#define glWindowPos3f __rglgen_glWindowPos3f\n#define glWindowPos3fv __rglgen_glWindowPos3fv\n#define glWindowPos3i __rglgen_glWindowPos3i\n#define glWindowPos3iv __rglgen_glWindowPos3iv\n#define glWindowPos3s __rglgen_glWindowPos3s\n#define glWindowPos3sv __rglgen_glWindowPos3sv\n#define glBlendColor __rglgen_glBlendColor\n#define glBlendEquation __rglgen_glBlendEquation\n#define glGenQueries __rglgen_glGenQueries\n#define glDeleteQueries __rglgen_glDeleteQueries\n#define glIsQuery __rglgen_glIsQuery\n#define glBeginQuery __rglgen_glBeginQuery\n#define glEndQuery __rglgen_glEndQuery\n#define glGetQueryiv __rglgen_glGetQueryiv\n#define glGetQueryObjectiv __rglgen_glGetQueryObjectiv\n#define glGetQueryObjectuiv __rglgen_glGetQueryObjectuiv\n#define glBindBuffer __rglgen_glBindBuffer\n#define glDeleteBuffers __rglgen_glDeleteBuffers\n#define glGenBuffers __rglgen_glGenBuffers\n#define glIsBuffer __rglgen_glIsBuffer\n#define glBufferData __rglgen_glBufferData\n#define glBufferSubData __rglgen_glBufferSubData\n#define glGetBufferSubData __rglgen_glGetBufferSubData\n#define glMapBuffer __rglgen_glMapBuffer\n#define glUnmapBuffer __rglgen_glUnmapBuffer\n#define glGetBufferParameteriv __rglgen_glGetBufferParameteriv\n#define glGetBufferPointerv __rglgen_glGetBufferPointerv\n#define glBlendEquationSeparate __rglgen_glBlendEquationSeparate\n#define glDrawBuffers __rglgen_glDrawBuffers\n#define glStencilOpSeparate __rglgen_glStencilOpSeparate\n#define glStencilFuncSeparate __rglgen_glStencilFuncSeparate\n#define glStencilMaskSeparate __rglgen_glStencilMaskSeparate\n#define glAttachShader __rglgen_glAttachShader\n#define glBindAttribLocation __rglgen_glBindAttribLocation\n#define glCompileShader __rglgen_glCompileShader\n#define glCreateProgram __rglgen_glCreateProgram\n#define glCreateShader __rglgen_glCreateShader\n#define glDeleteProgram __rglgen_glDeleteProgram\n#define glDeleteShader __rglgen_glDeleteShader\n#define glDetachShader __rglgen_glDetachShader\n#define glDisableVertexAttribArray __rglgen_glDisableVertexAttribArray\n#define glEnableVertexAttribArray __rglgen_glEnableVertexAttribArray\n#define glGetActiveAttrib __rglgen_glGetActiveAttrib\n#define glGetActiveUniform __rglgen_glGetActiveUniform\n#define glGetAttachedShaders __rglgen_glGetAttachedShaders\n#define glGetAttribLocation __rglgen_glGetAttribLocation\n#define glGetProgramiv __rglgen_glGetProgramiv\n#define glGetProgramInfoLog __rglgen_glGetProgramInfoLog\n#define glGetShaderiv __rglgen_glGetShaderiv\n#define glGetShaderInfoLog __rglgen_glGetShaderInfoLog\n#define glGetShaderSource __rglgen_glGetShaderSource\n#define glGetUniformLocation __rglgen_glGetUniformLocation\n#define glGetUniformfv __rglgen_glGetUniformfv\n#define glGetUniformiv __rglgen_glGetUniformiv\n#define glGetVertexAttribdv __rglgen_glGetVertexAttribdv\n#define glGetVertexAttribfv __rglgen_glGetVertexAttribfv\n#define glGetVertexAttribiv __rglgen_glGetVertexAttribiv\n#define glGetVertexAttribPointerv __rglgen_glGetVertexAttribPointerv\n#define glIsProgram __rglgen_glIsProgram\n#define glIsShader __rglgen_glIsShader\n#define glLinkProgram __rglgen_glLinkProgram\n#define glShaderSource __rglgen_glShaderSource\n#define glUseProgram __rglgen_glUseProgram\n#define glUniform1f __rglgen_glUniform1f\n#define glUniform2f __rglgen_glUniform2f\n#define glUniform3f __rglgen_glUniform3f\n#define glUniform4f __rglgen_glUniform4f\n#define glUniform1i __rglgen_glUniform1i\n#define glUniform2i __rglgen_glUniform2i\n#define glUniform3i __rglgen_glUniform3i\n#define glUniform4i __rglgen_glUniform4i\n#define glUniform1fv __rglgen_glUniform1fv\n#define glUniform2fv __rglgen_glUniform2fv\n#define glUniform3fv __rglgen_glUniform3fv\n#define glUniform4fv __rglgen_glUniform4fv\n#define glUniform1iv __rglgen_glUniform1iv\n#define glUniform2iv __rglgen_glUniform2iv\n#define glUniform3iv __rglgen_glUniform3iv\n#define glUniform4iv __rglgen_glUniform4iv\n#define glUniformMatrix2fv __rglgen_glUniformMatrix2fv\n#define glUniformMatrix3fv __rglgen_glUniformMatrix3fv\n#define glUniformMatrix4fv __rglgen_glUniformMatrix4fv\n#define glValidateProgram __rglgen_glValidateProgram\n#define glVertexAttrib1d __rglgen_glVertexAttrib1d\n#define glVertexAttrib1dv __rglgen_glVertexAttrib1dv\n#define glVertexAttrib1f __rglgen_glVertexAttrib1f\n#define glVertexAttrib1fv __rglgen_glVertexAttrib1fv\n#define glVertexAttrib1s __rglgen_glVertexAttrib1s\n#define glVertexAttrib1sv __rglgen_glVertexAttrib1sv\n#define glVertexAttrib2d __rglgen_glVertexAttrib2d\n#define glVertexAttrib2dv __rglgen_glVertexAttrib2dv\n#define glVertexAttrib2f __rglgen_glVertexAttrib2f\n#define glVertexAttrib2fv __rglgen_glVertexAttrib2fv\n#define glVertexAttrib2s __rglgen_glVertexAttrib2s\n#define glVertexAttrib2sv __rglgen_glVertexAttrib2sv\n#define glVertexAttrib3d __rglgen_glVertexAttrib3d\n#define glVertexAttrib3dv __rglgen_glVertexAttrib3dv\n#define glVertexAttrib3f __rglgen_glVertexAttrib3f\n#define glVertexAttrib3fv __rglgen_glVertexAttrib3fv\n#define glVertexAttrib3s __rglgen_glVertexAttrib3s\n#define glVertexAttrib3sv __rglgen_glVertexAttrib3sv\n#define glVertexAttrib4Nbv __rglgen_glVertexAttrib4Nbv\n#define glVertexAttrib4Niv __rglgen_glVertexAttrib4Niv\n#define glVertexAttrib4Nsv __rglgen_glVertexAttrib4Nsv\n#define glVertexAttrib4Nub __rglgen_glVertexAttrib4Nub\n#define glVertexAttrib4Nubv __rglgen_glVertexAttrib4Nubv\n#define glVertexAttrib4Nuiv __rglgen_glVertexAttrib4Nuiv\n#define glVertexAttrib4Nusv __rglgen_glVertexAttrib4Nusv\n#define glVertexAttrib4bv __rglgen_glVertexAttrib4bv\n#define glVertexAttrib4d __rglgen_glVertexAttrib4d\n#define glVertexAttrib4dv __rglgen_glVertexAttrib4dv\n#define glVertexAttrib4f __rglgen_glVertexAttrib4f\n#define glVertexAttrib4fv __rglgen_glVertexAttrib4fv\n#define glVertexAttrib4iv __rglgen_glVertexAttrib4iv\n#define glVertexAttrib4s __rglgen_glVertexAttrib4s\n#define glVertexAttrib4sv __rglgen_glVertexAttrib4sv\n#define glVertexAttrib4ubv __rglgen_glVertexAttrib4ubv\n#define glVertexAttrib4uiv __rglgen_glVertexAttrib4uiv\n#define glVertexAttrib4usv __rglgen_glVertexAttrib4usv\n#define glVertexAttribPointer __rglgen_glVertexAttribPointer\n#define glUniformMatrix2x3fv __rglgen_glUniformMatrix2x3fv\n#define glUniformMatrix3x2fv __rglgen_glUniformMatrix3x2fv\n#define glUniformMatrix2x4fv __rglgen_glUniformMatrix2x4fv\n#define glUniformMatrix4x2fv __rglgen_glUniformMatrix4x2fv\n#define glUniformMatrix3x4fv __rglgen_glUniformMatrix3x4fv\n#define glUniformMatrix4x3fv __rglgen_glUniformMatrix4x3fv\n#define glColorMaski __rglgen_glColorMaski\n#define glGetBooleani_v __rglgen_glGetBooleani_v\n#define glGetIntegeri_v __rglgen_glGetIntegeri_v\n#define glEnablei __rglgen_glEnablei\n#define glDisablei __rglgen_glDisablei\n#define glIsEnabledi __rglgen_glIsEnabledi\n#define glBeginTransformFeedback __rglgen_glBeginTransformFeedback\n#define glEndTransformFeedback __rglgen_glEndTransformFeedback\n#define glBindBufferRange __rglgen_glBindBufferRange\n#define glBindBufferBase __rglgen_glBindBufferBase\n#define glTransformFeedbackVaryings __rglgen_glTransformFeedbackVaryings\n#define glGetTransformFeedbackVarying __rglgen_glGetTransformFeedbackVarying\n#define glClampColor __rglgen_glClampColor\n#define glBeginConditionalRender __rglgen_glBeginConditionalRender\n#define glEndConditionalRender __rglgen_glEndConditionalRender\n#define glVertexAttribIPointer __rglgen_glVertexAttribIPointer\n#define glGetVertexAttribIiv __rglgen_glGetVertexAttribIiv\n#define glGetVertexAttribIuiv __rglgen_glGetVertexAttribIuiv\n#define glVertexAttribI1i __rglgen_glVertexAttribI1i\n#define glVertexAttribI2i __rglgen_glVertexAttribI2i\n#define glVertexAttribI3i __rglgen_glVertexAttribI3i\n#define glVertexAttribI4i __rglgen_glVertexAttribI4i\n#define glVertexAttribI1ui __rglgen_glVertexAttribI1ui\n#define glVertexAttribI2ui __rglgen_glVertexAttribI2ui\n#define glVertexAttribI3ui __rglgen_glVertexAttribI3ui\n#define glVertexAttribI4ui __rglgen_glVertexAttribI4ui\n#define glVertexAttribI1iv __rglgen_glVertexAttribI1iv\n#define glVertexAttribI2iv __rglgen_glVertexAttribI2iv\n#define glVertexAttribI3iv __rglgen_glVertexAttribI3iv\n#define glVertexAttribI4iv __rglgen_glVertexAttribI4iv\n#define glVertexAttribI1uiv __rglgen_glVertexAttribI1uiv\n#define glVertexAttribI2uiv __rglgen_glVertexAttribI2uiv\n#define glVertexAttribI3uiv __rglgen_glVertexAttribI3uiv\n#define glVertexAttribI4uiv __rglgen_glVertexAttribI4uiv\n#define glVertexAttribI4bv __rglgen_glVertexAttribI4bv\n#define glVertexAttribI4sv __rglgen_glVertexAttribI4sv\n#define glVertexAttribI4ubv __rglgen_glVertexAttribI4ubv\n#define glVertexAttribI4usv __rglgen_glVertexAttribI4usv\n#define glGetUniformuiv __rglgen_glGetUniformuiv\n#define glBindFragDataLocation __rglgen_glBindFragDataLocation\n#define glGetFragDataLocation __rglgen_glGetFragDataLocation\n#define glUniform1ui __rglgen_glUniform1ui\n#define glUniform2ui __rglgen_glUniform2ui\n#define glUniform3ui __rglgen_glUniform3ui\n#define glUniform4ui __rglgen_glUniform4ui\n#define glUniform1uiv __rglgen_glUniform1uiv\n#define glUniform2uiv __rglgen_glUniform2uiv\n#define glUniform3uiv __rglgen_glUniform3uiv\n#define glUniform4uiv __rglgen_glUniform4uiv\n#define glTexParameterIiv __rglgen_glTexParameterIiv\n#define glTexParameterIuiv __rglgen_glTexParameterIuiv\n#define glGetTexParameterIiv __rglgen_glGetTexParameterIiv\n#define glGetTexParameterIuiv __rglgen_glGetTexParameterIuiv\n#define glClearBufferiv __rglgen_glClearBufferiv\n#define glClearBufferuiv __rglgen_glClearBufferuiv\n#define glClearBufferfv __rglgen_glClearBufferfv\n#define glClearBufferfi __rglgen_glClearBufferfi\n#define glGetStringi __rglgen_glGetStringi\n#define glIsRenderbuffer __rglgen_glIsRenderbuffer\n#define glBindRenderbuffer __rglgen_glBindRenderbuffer\n#define glDeleteRenderbuffers __rglgen_glDeleteRenderbuffers\n#define glGenRenderbuffers __rglgen_glGenRenderbuffers\n#define glRenderbufferStorage __rglgen_glRenderbufferStorage\n#define glGetRenderbufferParameteriv __rglgen_glGetRenderbufferParameteriv\n#define glIsFramebuffer __rglgen_glIsFramebuffer\n#define glBindFramebuffer __rglgen_glBindFramebuffer\n#define glDeleteFramebuffers __rglgen_glDeleteFramebuffers\n#define glGenFramebuffers __rglgen_glGenFramebuffers\n#define glCheckFramebufferStatus __rglgen_glCheckFramebufferStatus\n#define glFramebufferTexture1D __rglgen_glFramebufferTexture1D\n#define glFramebufferTexture2D __rglgen_glFramebufferTexture2D\n#define glFramebufferTexture3D __rglgen_glFramebufferTexture3D\n#define glFramebufferRenderbuffer __rglgen_glFramebufferRenderbuffer\n#define glGetFramebufferAttachmentParameteriv __rglgen_glGetFramebufferAttachmentParameteriv\n#define glGenerateMipmap __rglgen_glGenerateMipmap\n#define glBlitFramebuffer __rglgen_glBlitFramebuffer\n#define glRenderbufferStorageMultisample __rglgen_glRenderbufferStorageMultisample\n#define glFramebufferTextureLayer __rglgen_glFramebufferTextureLayer\n#define glMapBufferRange __rglgen_glMapBufferRange\n#define glFlushMappedBufferRange __rglgen_glFlushMappedBufferRange\n#define glBindVertexArray __rglgen_glBindVertexArray\n#define glDeleteVertexArrays __rglgen_glDeleteVertexArrays\n#define glGenVertexArrays __rglgen_glGenVertexArrays\n#define glIsVertexArray __rglgen_glIsVertexArray\n#define glDrawArraysInstanced __rglgen_glDrawArraysInstanced\n#define glDrawElementsInstanced __rglgen_glDrawElementsInstanced\n#define glTexBuffer __rglgen_glTexBuffer\n#define glPrimitiveRestartIndex __rglgen_glPrimitiveRestartIndex\n#define glCopyBufferSubData __rglgen_glCopyBufferSubData\n#define glGetUniformIndices __rglgen_glGetUniformIndices\n#define glGetActiveUniformsiv __rglgen_glGetActiveUniformsiv\n#define glGetActiveUniformName __rglgen_glGetActiveUniformName\n#define glGetUniformBlockIndex __rglgen_glGetUniformBlockIndex\n#define glGetActiveUniformBlockiv __rglgen_glGetActiveUniformBlockiv\n#define glGetActiveUniformBlockName __rglgen_glGetActiveUniformBlockName\n#define glUniformBlockBinding __rglgen_glUniformBlockBinding\n#define glDrawElementsBaseVertex __rglgen_glDrawElementsBaseVertex\n#define glDrawRangeElementsBaseVertex __rglgen_glDrawRangeElementsBaseVertex\n#define glDrawElementsInstancedBaseVertex __rglgen_glDrawElementsInstancedBaseVertex\n#define glMultiDrawElementsBaseVertex __rglgen_glMultiDrawElementsBaseVertex\n#define glProvokingVertex __rglgen_glProvokingVertex\n#define glFenceSync __rglgen_glFenceSync\n#define glIsSync __rglgen_glIsSync\n#define glDeleteSync __rglgen_glDeleteSync\n#define glClientWaitSync __rglgen_glClientWaitSync\n#define glWaitSync __rglgen_glWaitSync\n#define glGetInteger64v __rglgen_glGetInteger64v\n#define glGetSynciv __rglgen_glGetSynciv\n#define glGetInteger64i_v __rglgen_glGetInteger64i_v\n#define glGetBufferParameteri64v __rglgen_glGetBufferParameteri64v\n#define glFramebufferTexture __rglgen_glFramebufferTexture\n#define glTexImage2DMultisample __rglgen_glTexImage2DMultisample\n#define glTexImage3DMultisample __rglgen_glTexImage3DMultisample\n#define glGetMultisamplefv __rglgen_glGetMultisamplefv\n#define glSampleMaski __rglgen_glSampleMaski\n#define glBindFragDataLocationIndexed __rglgen_glBindFragDataLocationIndexed\n#define glGetFragDataIndex __rglgen_glGetFragDataIndex\n#define glGenSamplers __rglgen_glGenSamplers\n#define glDeleteSamplers __rglgen_glDeleteSamplers\n#define glIsSampler __rglgen_glIsSampler\n#define glBindSampler __rglgen_glBindSampler\n#define glSamplerParameteri __rglgen_glSamplerParameteri\n#define glSamplerParameteriv __rglgen_glSamplerParameteriv\n#define glSamplerParameterf __rglgen_glSamplerParameterf\n#define glSamplerParameterfv __rglgen_glSamplerParameterfv\n#define glSamplerParameterIiv __rglgen_glSamplerParameterIiv\n#define glSamplerParameterIuiv __rglgen_glSamplerParameterIuiv\n#define glGetSamplerParameteriv __rglgen_glGetSamplerParameteriv\n#define glGetSamplerParameterIiv __rglgen_glGetSamplerParameterIiv\n#define glGetSamplerParameterfv __rglgen_glGetSamplerParameterfv\n#define glGetSamplerParameterIuiv __rglgen_glGetSamplerParameterIuiv\n#define glQueryCounter __rglgen_glQueryCounter\n#define glGetQueryObjecti64v __rglgen_glGetQueryObjecti64v\n#define glGetQueryObjectui64v __rglgen_glGetQueryObjectui64v\n#define glVertexAttribDivisor __rglgen_glVertexAttribDivisor\n#define glVertexAttribP1ui __rglgen_glVertexAttribP1ui\n#define glVertexAttribP1uiv __rglgen_glVertexAttribP1uiv\n#define glVertexAttribP2ui __rglgen_glVertexAttribP2ui\n#define glVertexAttribP2uiv __rglgen_glVertexAttribP2uiv\n#define glVertexAttribP3ui __rglgen_glVertexAttribP3ui\n#define glVertexAttribP3uiv __rglgen_glVertexAttribP3uiv\n#define glVertexAttribP4ui __rglgen_glVertexAttribP4ui\n#define glVertexAttribP4uiv __rglgen_glVertexAttribP4uiv\n#define glVertexP2ui __rglgen_glVertexP2ui\n#define glVertexP2uiv __rglgen_glVertexP2uiv\n#define glVertexP3ui __rglgen_glVertexP3ui\n#define glVertexP3uiv __rglgen_glVertexP3uiv\n#define glVertexP4ui __rglgen_glVertexP4ui\n#define glVertexP4uiv __rglgen_glVertexP4uiv\n#define glTexCoordP1ui __rglgen_glTexCoordP1ui\n#define glTexCoordP1uiv __rglgen_glTexCoordP1uiv\n#define glTexCoordP2ui __rglgen_glTexCoordP2ui\n#define glTexCoordP2uiv __rglgen_glTexCoordP2uiv\n#define glTexCoordP3ui __rglgen_glTexCoordP3ui\n#define glTexCoordP3uiv __rglgen_glTexCoordP3uiv\n#define glTexCoordP4ui __rglgen_glTexCoordP4ui\n#define glTexCoordP4uiv __rglgen_glTexCoordP4uiv\n#define glMultiTexCoordP1ui __rglgen_glMultiTexCoordP1ui\n#define glMultiTexCoordP1uiv __rglgen_glMultiTexCoordP1uiv\n#define glMultiTexCoordP2ui __rglgen_glMultiTexCoordP2ui\n#define glMultiTexCoordP2uiv __rglgen_glMultiTexCoordP2uiv\n#define glMultiTexCoordP3ui __rglgen_glMultiTexCoordP3ui\n#define glMultiTexCoordP3uiv __rglgen_glMultiTexCoordP3uiv\n#define glMultiTexCoordP4ui __rglgen_glMultiTexCoordP4ui\n#define glMultiTexCoordP4uiv __rglgen_glMultiTexCoordP4uiv\n#define glNormalP3ui __rglgen_glNormalP3ui\n#define glNormalP3uiv __rglgen_glNormalP3uiv\n#define glColorP3ui __rglgen_glColorP3ui\n#define glColorP3uiv __rglgen_glColorP3uiv\n#define glColorP4ui __rglgen_glColorP4ui\n#define glColorP4uiv __rglgen_glColorP4uiv\n#define glSecondaryColorP3ui __rglgen_glSecondaryColorP3ui\n#define glSecondaryColorP3uiv __rglgen_glSecondaryColorP3uiv\n#define glMinSampleShading __rglgen_glMinSampleShading\n#define glBlendEquationi __rglgen_glBlendEquationi\n#define glBlendEquationSeparatei __rglgen_glBlendEquationSeparatei\n#define glBlendFunci __rglgen_glBlendFunci\n#define glBlendFuncSeparatei __rglgen_glBlendFuncSeparatei\n#define glDrawArraysIndirect __rglgen_glDrawArraysIndirect\n#define glDrawElementsIndirect __rglgen_glDrawElementsIndirect\n#define glUniform1d __rglgen_glUniform1d\n#define glUniform2d __rglgen_glUniform2d\n#define glUniform3d __rglgen_glUniform3d\n#define glUniform4d __rglgen_glUniform4d\n#define glUniform1dv __rglgen_glUniform1dv\n#define glUniform2dv __rglgen_glUniform2dv\n#define glUniform3dv __rglgen_glUniform3dv\n#define glUniform4dv __rglgen_glUniform4dv\n#define glUniformMatrix2dv __rglgen_glUniformMatrix2dv\n#define glUniformMatrix3dv __rglgen_glUniformMatrix3dv\n#define glUniformMatrix4dv __rglgen_glUniformMatrix4dv\n#define glUniformMatrix2x3dv __rglgen_glUniformMatrix2x3dv\n#define glUniformMatrix2x4dv __rglgen_glUniformMatrix2x4dv\n#define glUniformMatrix3x2dv __rglgen_glUniformMatrix3x2dv\n#define glUniformMatrix3x4dv __rglgen_glUniformMatrix3x4dv\n#define glUniformMatrix4x2dv __rglgen_glUniformMatrix4x2dv\n#define glUniformMatrix4x3dv __rglgen_glUniformMatrix4x3dv\n#define glGetUniformdv __rglgen_glGetUniformdv\n#define glGetSubroutineUniformLocation __rglgen_glGetSubroutineUniformLocation\n#define glGetSubroutineIndex __rglgen_glGetSubroutineIndex\n#define glGetActiveSubroutineUniformiv __rglgen_glGetActiveSubroutineUniformiv\n#define glGetActiveSubroutineUniformName __rglgen_glGetActiveSubroutineUniformName\n#define glGetActiveSubroutineName __rglgen_glGetActiveSubroutineName\n#define glUniformSubroutinesuiv __rglgen_glUniformSubroutinesuiv\n#define glGetUniformSubroutineuiv __rglgen_glGetUniformSubroutineuiv\n#define glGetProgramStageiv __rglgen_glGetProgramStageiv\n#define glPatchParameteri __rglgen_glPatchParameteri\n#define glPatchParameterfv __rglgen_glPatchParameterfv\n#define glBindTransformFeedback __rglgen_glBindTransformFeedback\n#define glDeleteTransformFeedbacks __rglgen_glDeleteTransformFeedbacks\n#define glGenTransformFeedbacks __rglgen_glGenTransformFeedbacks\n#define glIsTransformFeedback __rglgen_glIsTransformFeedback\n#define glPauseTransformFeedback __rglgen_glPauseTransformFeedback\n#define glResumeTransformFeedback __rglgen_glResumeTransformFeedback\n#define glDrawTransformFeedback __rglgen_glDrawTransformFeedback\n#define glDrawTransformFeedbackStream __rglgen_glDrawTransformFeedbackStream\n#define glBeginQueryIndexed __rglgen_glBeginQueryIndexed\n#define glEndQueryIndexed __rglgen_glEndQueryIndexed\n#define glGetQueryIndexediv __rglgen_glGetQueryIndexediv\n#define glReleaseShaderCompiler __rglgen_glReleaseShaderCompiler\n#define glShaderBinary __rglgen_glShaderBinary\n#define glGetShaderPrecisionFormat __rglgen_glGetShaderPrecisionFormat\n#define glDepthRangef __rglgen_glDepthRangef\n#define glClearDepthf __rglgen_glClearDepthf\n#define glGetProgramBinary __rglgen_glGetProgramBinary\n#define glProgramBinary __rglgen_glProgramBinary\n#define glProgramParameteri __rglgen_glProgramParameteri\n#define glUseProgramStages __rglgen_glUseProgramStages\n#define glActiveShaderProgram __rglgen_glActiveShaderProgram\n#define glCreateShaderProgramv __rglgen_glCreateShaderProgramv\n#define glBindProgramPipeline __rglgen_glBindProgramPipeline\n#define glDeleteProgramPipelines __rglgen_glDeleteProgramPipelines\n#define glGenProgramPipelines __rglgen_glGenProgramPipelines\n#define glIsProgramPipeline __rglgen_glIsProgramPipeline\n#define glGetProgramPipelineiv __rglgen_glGetProgramPipelineiv\n#define glProgramUniform1i __rglgen_glProgramUniform1i\n#define glProgramUniform1iv __rglgen_glProgramUniform1iv\n#define glProgramUniform1f __rglgen_glProgramUniform1f\n#define glProgramUniform1fv __rglgen_glProgramUniform1fv\n#define glProgramUniform1d __rglgen_glProgramUniform1d\n#define glProgramUniform1dv __rglgen_glProgramUniform1dv\n#define glProgramUniform1ui __rglgen_glProgramUniform1ui\n#define glProgramUniform1uiv __rglgen_glProgramUniform1uiv\n#define glProgramUniform2i __rglgen_glProgramUniform2i\n#define glProgramUniform2iv __rglgen_glProgramUniform2iv\n#define glProgramUniform2f __rglgen_glProgramUniform2f\n#define glProgramUniform2fv __rglgen_glProgramUniform2fv\n#define glProgramUniform2d __rglgen_glProgramUniform2d\n#define glProgramUniform2dv __rglgen_glProgramUniform2dv\n#define glProgramUniform2ui __rglgen_glProgramUniform2ui\n#define glProgramUniform2uiv __rglgen_glProgramUniform2uiv\n#define glProgramUniform3i __rglgen_glProgramUniform3i\n#define glProgramUniform3iv __rglgen_glProgramUniform3iv\n#define glProgramUniform3f __rglgen_glProgramUniform3f\n#define glProgramUniform3fv __rglgen_glProgramUniform3fv\n#define glProgramUniform3d __rglgen_glProgramUniform3d\n#define glProgramUniform3dv __rglgen_glProgramUniform3dv\n#define glProgramUniform3ui __rglgen_glProgramUniform3ui\n#define glProgramUniform3uiv __rglgen_glProgramUniform3uiv\n#define glProgramUniform4i __rglgen_glProgramUniform4i\n#define glProgramUniform4iv __rglgen_glProgramUniform4iv\n#define glProgramUniform4f __rglgen_glProgramUniform4f\n#define glProgramUniform4fv __rglgen_glProgramUniform4fv\n#define glProgramUniform4d __rglgen_glProgramUniform4d\n#define glProgramUniform4dv __rglgen_glProgramUniform4dv\n#define glProgramUniform4ui __rglgen_glProgramUniform4ui\n#define glProgramUniform4uiv __rglgen_glProgramUniform4uiv\n#define glProgramUniformMatrix2fv __rglgen_glProgramUniformMatrix2fv\n#define glProgramUniformMatrix3fv __rglgen_glProgramUniformMatrix3fv\n#define glProgramUniformMatrix4fv __rglgen_glProgramUniformMatrix4fv\n#define glProgramUniformMatrix2dv __rglgen_glProgramUniformMatrix2dv\n#define glProgramUniformMatrix3dv __rglgen_glProgramUniformMatrix3dv\n#define glProgramUniformMatrix4dv __rglgen_glProgramUniformMatrix4dv\n#define glProgramUniformMatrix2x3fv __rglgen_glProgramUniformMatrix2x3fv\n#define glProgramUniformMatrix3x2fv __rglgen_glProgramUniformMatrix3x2fv\n#define glProgramUniformMatrix2x4fv __rglgen_glProgramUniformMatrix2x4fv\n#define glProgramUniformMatrix4x2fv __rglgen_glProgramUniformMatrix4x2fv\n#define glProgramUniformMatrix3x4fv __rglgen_glProgramUniformMatrix3x4fv\n#define glProgramUniformMatrix4x3fv __rglgen_glProgramUniformMatrix4x3fv\n#define glProgramUniformMatrix2x3dv __rglgen_glProgramUniformMatrix2x3dv\n#define glProgramUniformMatrix3x2dv __rglgen_glProgramUniformMatrix3x2dv\n#define glProgramUniformMatrix2x4dv __rglgen_glProgramUniformMatrix2x4dv\n#define glProgramUniformMatrix4x2dv __rglgen_glProgramUniformMatrix4x2dv\n#define glProgramUniformMatrix3x4dv __rglgen_glProgramUniformMatrix3x4dv\n#define glProgramUniformMatrix4x3dv __rglgen_glProgramUniformMatrix4x3dv\n#define glValidateProgramPipeline __rglgen_glValidateProgramPipeline\n#define glGetProgramPipelineInfoLog __rglgen_glGetProgramPipelineInfoLog\n#define glVertexAttribL1d __rglgen_glVertexAttribL1d\n#define glVertexAttribL2d __rglgen_glVertexAttribL2d\n#define glVertexAttribL3d __rglgen_glVertexAttribL3d\n#define glVertexAttribL4d __rglgen_glVertexAttribL4d\n#define glVertexAttribL1dv __rglgen_glVertexAttribL1dv\n#define glVertexAttribL2dv __rglgen_glVertexAttribL2dv\n#define glVertexAttribL3dv __rglgen_glVertexAttribL3dv\n#define glVertexAttribL4dv __rglgen_glVertexAttribL4dv\n#define glVertexAttribLPointer __rglgen_glVertexAttribLPointer\n#define glGetVertexAttribLdv __rglgen_glGetVertexAttribLdv\n#define glViewportArrayv __rglgen_glViewportArrayv\n#define glViewportIndexedf __rglgen_glViewportIndexedf\n#define glViewportIndexedfv __rglgen_glViewportIndexedfv\n#define glScissorArrayv __rglgen_glScissorArrayv\n#define glScissorIndexed __rglgen_glScissorIndexed\n#define glScissorIndexedv __rglgen_glScissorIndexedv\n#define glDepthRangeArrayv __rglgen_glDepthRangeArrayv\n#define glDepthRangeIndexed __rglgen_glDepthRangeIndexed\n#define glGetFloati_v __rglgen_glGetFloati_v\n#define glGetDoublei_v __rglgen_glGetDoublei_v\n#define glDrawArraysInstancedBaseInstance __rglgen_glDrawArraysInstancedBaseInstance\n#define glDrawElementsInstancedBaseInstance __rglgen_glDrawElementsInstancedBaseInstance\n#define glDrawElementsInstancedBaseVertexBaseInstance __rglgen_glDrawElementsInstancedBaseVertexBaseInstance\n#define glGetInternalformativ __rglgen_glGetInternalformativ\n#define glGetActiveAtomicCounterBufferiv __rglgen_glGetActiveAtomicCounterBufferiv\n#define glBindImageTexture __rglgen_glBindImageTexture\n#define glMemoryBarrier __rglgen_glMemoryBarrier\n#define glTexStorage1D __rglgen_glTexStorage1D\n#define glTexStorage2D __rglgen_glTexStorage2D\n#define glTexStorage3D __rglgen_glTexStorage3D\n#define glDrawTransformFeedbackInstanced __rglgen_glDrawTransformFeedbackInstanced\n#define glDrawTransformFeedbackStreamInstanced __rglgen_glDrawTransformFeedbackStreamInstanced\n#define glClearBufferData __rglgen_glClearBufferData\n#define glClearBufferSubData __rglgen_glClearBufferSubData\n#define glDispatchCompute __rglgen_glDispatchCompute\n#define glDispatchComputeIndirect __rglgen_glDispatchComputeIndirect\n#define glCopyImageSubData __rglgen_glCopyImageSubData\n#define glFramebufferParameteri __rglgen_glFramebufferParameteri\n#define glGetFramebufferParameteriv __rglgen_glGetFramebufferParameteriv\n#define glGetInternalformati64v __rglgen_glGetInternalformati64v\n#define glInvalidateTexSubImage __rglgen_glInvalidateTexSubImage\n#define glInvalidateTexImage __rglgen_glInvalidateTexImage\n#define glInvalidateBufferSubData __rglgen_glInvalidateBufferSubData\n#define glInvalidateBufferData __rglgen_glInvalidateBufferData\n#define glInvalidateFramebuffer __rglgen_glInvalidateFramebuffer\n#define glInvalidateSubFramebuffer __rglgen_glInvalidateSubFramebuffer\n#define glMultiDrawArraysIndirect __rglgen_glMultiDrawArraysIndirect\n#define glMultiDrawElementsIndirect __rglgen_glMultiDrawElementsIndirect\n#define glGetProgramInterfaceiv __rglgen_glGetProgramInterfaceiv\n#define glGetProgramResourceIndex __rglgen_glGetProgramResourceIndex\n#define glGetProgramResourceName __rglgen_glGetProgramResourceName\n#define glGetProgramResourceiv __rglgen_glGetProgramResourceiv\n#define glGetProgramResourceLocation __rglgen_glGetProgramResourceLocation\n#define glGetProgramResourceLocationIndex __rglgen_glGetProgramResourceLocationIndex\n#define glShaderStorageBlockBinding __rglgen_glShaderStorageBlockBinding\n#define glTexBufferRange __rglgen_glTexBufferRange\n#define glTexStorage2DMultisample __rglgen_glTexStorage2DMultisample\n#define glTexStorage3DMultisample __rglgen_glTexStorage3DMultisample\n#define glTextureView __rglgen_glTextureView\n#define glBindVertexBuffer __rglgen_glBindVertexBuffer\n#define glVertexAttribFormat __rglgen_glVertexAttribFormat\n#define glVertexAttribIFormat __rglgen_glVertexAttribIFormat\n#define glVertexAttribLFormat __rglgen_glVertexAttribLFormat\n#define glVertexAttribBinding __rglgen_glVertexAttribBinding\n#define glVertexBindingDivisor __rglgen_glVertexBindingDivisor\n#define glDebugMessageControl __rglgen_glDebugMessageControl\n#define glDebugMessageInsert __rglgen_glDebugMessageInsert\n#define glDebugMessageCallback __rglgen_glDebugMessageCallback\n#define glGetDebugMessageLog __rglgen_glGetDebugMessageLog\n#define glPushDebugGroup __rglgen_glPushDebugGroup\n#define glPopDebugGroup __rglgen_glPopDebugGroup\n#define glObjectLabel __rglgen_glObjectLabel\n#define glGetObjectLabel __rglgen_glGetObjectLabel\n#define glObjectPtrLabel __rglgen_glObjectPtrLabel\n#define glGetObjectPtrLabel __rglgen_glGetObjectPtrLabel\n#define glBufferStorage __rglgen_glBufferStorage\n#define glClearTexImage __rglgen_glClearTexImage\n#define glClearTexSubImage __rglgen_glClearTexSubImage\n#define glBindBuffersBase __rglgen_glBindBuffersBase\n#define glBindBuffersRange __rglgen_glBindBuffersRange\n#define glBindTextures __rglgen_glBindTextures\n#define glBindSamplers __rglgen_glBindSamplers\n#define glBindImageTextures __rglgen_glBindImageTextures\n#define glBindVertexBuffers __rglgen_glBindVertexBuffers\n#define glGetTextureHandleARB __rglgen_glGetTextureHandleARB\n#define glGetTextureSamplerHandleARB __rglgen_glGetTextureSamplerHandleARB\n#define glMakeTextureHandleResidentARB __rglgen_glMakeTextureHandleResidentARB\n#define glMakeTextureHandleNonResidentARB __rglgen_glMakeTextureHandleNonResidentARB\n#define glGetImageHandleARB __rglgen_glGetImageHandleARB\n#define glMakeImageHandleResidentARB __rglgen_glMakeImageHandleResidentARB\n#define glMakeImageHandleNonResidentARB __rglgen_glMakeImageHandleNonResidentARB\n#define glUniformHandleui64ARB __rglgen_glUniformHandleui64ARB\n#define glUniformHandleui64vARB __rglgen_glUniformHandleui64vARB\n#define glProgramUniformHandleui64ARB __rglgen_glProgramUniformHandleui64ARB\n#define glProgramUniformHandleui64vARB __rglgen_glProgramUniformHandleui64vARB\n#define glIsTextureHandleResidentARB __rglgen_glIsTextureHandleResidentARB\n#define glIsImageHandleResidentARB __rglgen_glIsImageHandleResidentARB\n#define glVertexAttribL1ui64ARB __rglgen_glVertexAttribL1ui64ARB\n#define glVertexAttribL1ui64vARB __rglgen_glVertexAttribL1ui64vARB\n#define glGetVertexAttribLui64vARB __rglgen_glGetVertexAttribLui64vARB\n#define glCreateSyncFromCLeventARB __rglgen_glCreateSyncFromCLeventARB\n#define glClampColorARB __rglgen_glClampColorARB\n#define glDispatchComputeGroupSizeARB __rglgen_glDispatchComputeGroupSizeARB\n#define glDebugMessageControlARB __rglgen_glDebugMessageControlARB\n#define glDebugMessageInsertARB __rglgen_glDebugMessageInsertARB\n#define glDebugMessageCallbackARB __rglgen_glDebugMessageCallbackARB\n#define glGetDebugMessageLogARB __rglgen_glGetDebugMessageLogARB\n#define glDrawBuffersARB __rglgen_glDrawBuffersARB\n#define glBlendEquationiARB __rglgen_glBlendEquationiARB\n#define glBlendEquationSeparateiARB __rglgen_glBlendEquationSeparateiARB\n#define glBlendFunciARB __rglgen_glBlendFunciARB\n#define glBlendFuncSeparateiARB __rglgen_glBlendFuncSeparateiARB\n#define glDrawArraysInstancedARB __rglgen_glDrawArraysInstancedARB\n#define glDrawElementsInstancedARB __rglgen_glDrawElementsInstancedARB\n#define glProgramStringARB __rglgen_glProgramStringARB\n#define glBindProgramARB __rglgen_glBindProgramARB\n#define glDeleteProgramsARB __rglgen_glDeleteProgramsARB\n#define glGenProgramsARB __rglgen_glGenProgramsARB\n#define glProgramEnvParameter4dARB __rglgen_glProgramEnvParameter4dARB\n#define glProgramEnvParameter4dvARB __rglgen_glProgramEnvParameter4dvARB\n#define glProgramEnvParameter4fARB __rglgen_glProgramEnvParameter4fARB\n#define glProgramEnvParameter4fvARB __rglgen_glProgramEnvParameter4fvARB\n#define glProgramLocalParameter4dARB __rglgen_glProgramLocalParameter4dARB\n#define glProgramLocalParameter4dvARB __rglgen_glProgramLocalParameter4dvARB\n#define glProgramLocalParameter4fARB __rglgen_glProgramLocalParameter4fARB\n#define glProgramLocalParameter4fvARB __rglgen_glProgramLocalParameter4fvARB\n#define glGetProgramEnvParameterdvARB __rglgen_glGetProgramEnvParameterdvARB\n#define glGetProgramEnvParameterfvARB __rglgen_glGetProgramEnvParameterfvARB\n#define glGetProgramLocalParameterdvARB __rglgen_glGetProgramLocalParameterdvARB\n#define glGetProgramLocalParameterfvARB __rglgen_glGetProgramLocalParameterfvARB\n#define glGetProgramivARB __rglgen_glGetProgramivARB\n#define glGetProgramStringARB __rglgen_glGetProgramStringARB\n#define glIsProgramARB __rglgen_glIsProgramARB\n#define glProgramParameteriARB __rglgen_glProgramParameteriARB\n#define glFramebufferTextureARB __rglgen_glFramebufferTextureARB\n#define glFramebufferTextureLayerARB __rglgen_glFramebufferTextureLayerARB\n#define glFramebufferTextureFaceARB __rglgen_glFramebufferTextureFaceARB\n#define glColorTable __rglgen_glColorTable\n#define glColorTableParameterfv __rglgen_glColorTableParameterfv\n#define glColorTableParameteriv __rglgen_glColorTableParameteriv\n#define glCopyColorTable __rglgen_glCopyColorTable\n#define glGetColorTable __rglgen_glGetColorTable\n#define glGetColorTableParameterfv __rglgen_glGetColorTableParameterfv\n#define glGetColorTableParameteriv __rglgen_glGetColorTableParameteriv\n#define glColorSubTable __rglgen_glColorSubTable\n#define glCopyColorSubTable __rglgen_glCopyColorSubTable\n#define glConvolutionFilter1D __rglgen_glConvolutionFilter1D\n#define glConvolutionFilter2D __rglgen_glConvolutionFilter2D\n#define glConvolutionParameterf __rglgen_glConvolutionParameterf\n#define glConvolutionParameterfv __rglgen_glConvolutionParameterfv\n#define glConvolutionParameteri __rglgen_glConvolutionParameteri\n#define glConvolutionParameteriv __rglgen_glConvolutionParameteriv\n#define glCopyConvolutionFilter1D __rglgen_glCopyConvolutionFilter1D\n#define glCopyConvolutionFilter2D __rglgen_glCopyConvolutionFilter2D\n#define glGetConvolutionFilter __rglgen_glGetConvolutionFilter\n#define glGetConvolutionParameterfv __rglgen_glGetConvolutionParameterfv\n#define glGetConvolutionParameteriv __rglgen_glGetConvolutionParameteriv\n#define glGetSeparableFilter __rglgen_glGetSeparableFilter\n#define glSeparableFilter2D __rglgen_glSeparableFilter2D\n#define glGetHistogram __rglgen_glGetHistogram\n#define glGetHistogramParameterfv __rglgen_glGetHistogramParameterfv\n#define glGetHistogramParameteriv __rglgen_glGetHistogramParameteriv\n#define glGetMinmax __rglgen_glGetMinmax\n#define glGetMinmaxParameterfv __rglgen_glGetMinmaxParameterfv\n#define glGetMinmaxParameteriv __rglgen_glGetMinmaxParameteriv\n#define glHistogram __rglgen_glHistogram\n#define glMinmax __rglgen_glMinmax\n#define glResetHistogram __rglgen_glResetHistogram\n#define glResetMinmax __rglgen_glResetMinmax\n#define glMultiDrawArraysIndirectCountARB __rglgen_glMultiDrawArraysIndirectCountARB\n#define glMultiDrawElementsIndirectCountARB __rglgen_glMultiDrawElementsIndirectCountARB\n#define glVertexAttribDivisorARB __rglgen_glVertexAttribDivisorARB\n#define glCurrentPaletteMatrixARB __rglgen_glCurrentPaletteMatrixARB\n#define glMatrixIndexubvARB __rglgen_glMatrixIndexubvARB\n#define glMatrixIndexusvARB __rglgen_glMatrixIndexusvARB\n#define glMatrixIndexuivARB __rglgen_glMatrixIndexuivARB\n#define glMatrixIndexPointerARB __rglgen_glMatrixIndexPointerARB\n#define glSampleCoverageARB __rglgen_glSampleCoverageARB\n#define glActiveTextureARB __rglgen_glActiveTextureARB\n#define glClientActiveTextureARB __rglgen_glClientActiveTextureARB\n#define glMultiTexCoord1dARB __rglgen_glMultiTexCoord1dARB\n#define glMultiTexCoord1dvARB __rglgen_glMultiTexCoord1dvARB\n#define glMultiTexCoord1fARB __rglgen_glMultiTexCoord1fARB\n#define glMultiTexCoord1fvARB __rglgen_glMultiTexCoord1fvARB\n#define glMultiTexCoord1iARB __rglgen_glMultiTexCoord1iARB\n#define glMultiTexCoord1ivARB __rglgen_glMultiTexCoord1ivARB\n#define glMultiTexCoord1sARB __rglgen_glMultiTexCoord1sARB\n#define glMultiTexCoord1svARB __rglgen_glMultiTexCoord1svARB\n#define glMultiTexCoord2dARB __rglgen_glMultiTexCoord2dARB\n#define glMultiTexCoord2dvARB __rglgen_glMultiTexCoord2dvARB\n#define glMultiTexCoord2fARB __rglgen_glMultiTexCoord2fARB\n#define glMultiTexCoord2fvARB __rglgen_glMultiTexCoord2fvARB\n#define glMultiTexCoord2iARB __rglgen_glMultiTexCoord2iARB\n#define glMultiTexCoord2ivARB __rglgen_glMultiTexCoord2ivARB\n#define glMultiTexCoord2sARB __rglgen_glMultiTexCoord2sARB\n#define glMultiTexCoord2svARB __rglgen_glMultiTexCoord2svARB\n#define glMultiTexCoord3dARB __rglgen_glMultiTexCoord3dARB\n#define glMultiTexCoord3dvARB __rglgen_glMultiTexCoord3dvARB\n#define glMultiTexCoord3fARB __rglgen_glMultiTexCoord3fARB\n#define glMultiTexCoord3fvARB __rglgen_glMultiTexCoord3fvARB\n#define glMultiTexCoord3iARB __rglgen_glMultiTexCoord3iARB\n#define glMultiTexCoord3ivARB __rglgen_glMultiTexCoord3ivARB\n#define glMultiTexCoord3sARB __rglgen_glMultiTexCoord3sARB\n#define glMultiTexCoord3svARB __rglgen_glMultiTexCoord3svARB\n#define glMultiTexCoord4dARB __rglgen_glMultiTexCoord4dARB\n#define glMultiTexCoord4dvARB __rglgen_glMultiTexCoord4dvARB\n#define glMultiTexCoord4fARB __rglgen_glMultiTexCoord4fARB\n#define glMultiTexCoord4fvARB __rglgen_glMultiTexCoord4fvARB\n#define glMultiTexCoord4iARB __rglgen_glMultiTexCoord4iARB\n#define glMultiTexCoord4ivARB __rglgen_glMultiTexCoord4ivARB\n#define glMultiTexCoord4sARB __rglgen_glMultiTexCoord4sARB\n#define glMultiTexCoord4svARB __rglgen_glMultiTexCoord4svARB\n#define glGenQueriesARB __rglgen_glGenQueriesARB\n#define glDeleteQueriesARB __rglgen_glDeleteQueriesARB\n#define glIsQueryARB __rglgen_glIsQueryARB\n#define glBeginQueryARB __rglgen_glBeginQueryARB\n#define glEndQueryARB __rglgen_glEndQueryARB\n#define glGetQueryivARB __rglgen_glGetQueryivARB\n#define glGetQueryObjectivARB __rglgen_glGetQueryObjectivARB\n#define glGetQueryObjectuivARB __rglgen_glGetQueryObjectuivARB\n#define glPointParameterfARB __rglgen_glPointParameterfARB\n#define glPointParameterfvARB __rglgen_glPointParameterfvARB\n#define glGetGraphicsResetStatusARB __rglgen_glGetGraphicsResetStatusARB\n#define glGetnTexImageARB __rglgen_glGetnTexImageARB\n#define glReadnPixelsARB __rglgen_glReadnPixelsARB\n#define glGetnCompressedTexImageARB __rglgen_glGetnCompressedTexImageARB\n#define glGetnUniformfvARB __rglgen_glGetnUniformfvARB\n#define glGetnUniformivARB __rglgen_glGetnUniformivARB\n#define glGetnUniformuivARB __rglgen_glGetnUniformuivARB\n#define glGetnUniformdvARB __rglgen_glGetnUniformdvARB\n#define glGetnMapdvARB __rglgen_glGetnMapdvARB\n#define glGetnMapfvARB __rglgen_glGetnMapfvARB\n#define glGetnMapivARB __rglgen_glGetnMapivARB\n#define glGetnPixelMapfvARB __rglgen_glGetnPixelMapfvARB\n#define glGetnPixelMapuivARB __rglgen_glGetnPixelMapuivARB\n#define glGetnPixelMapusvARB __rglgen_glGetnPixelMapusvARB\n#define glGetnPolygonStippleARB __rglgen_glGetnPolygonStippleARB\n#define glGetnColorTableARB __rglgen_glGetnColorTableARB\n#define glGetnConvolutionFilterARB __rglgen_glGetnConvolutionFilterARB\n#define glGetnSeparableFilterARB __rglgen_glGetnSeparableFilterARB\n#define glGetnHistogramARB __rglgen_glGetnHistogramARB\n#define glGetnMinmaxARB __rglgen_glGetnMinmaxARB\n#define glMinSampleShadingARB __rglgen_glMinSampleShadingARB\n#define glDeleteObjectARB __rglgen_glDeleteObjectARB\n#define glGetHandleARB __rglgen_glGetHandleARB\n#define glDetachObjectARB __rglgen_glDetachObjectARB\n#define glCreateShaderObjectARB __rglgen_glCreateShaderObjectARB\n#define glShaderSourceARB __rglgen_glShaderSourceARB\n#define glCompileShaderARB __rglgen_glCompileShaderARB\n#define glCreateProgramObjectARB __rglgen_glCreateProgramObjectARB\n#define glAttachObjectARB __rglgen_glAttachObjectARB\n#define glLinkProgramARB __rglgen_glLinkProgramARB\n#define glUseProgramObjectARB __rglgen_glUseProgramObjectARB\n#define glValidateProgramARB __rglgen_glValidateProgramARB\n#define glUniform1fARB __rglgen_glUniform1fARB\n#define glUniform2fARB __rglgen_glUniform2fARB\n#define glUniform3fARB __rglgen_glUniform3fARB\n#define glUniform4fARB __rglgen_glUniform4fARB\n#define glUniform1iARB __rglgen_glUniform1iARB\n#define glUniform2iARB __rglgen_glUniform2iARB\n#define glUniform3iARB __rglgen_glUniform3iARB\n#define glUniform4iARB __rglgen_glUniform4iARB\n#define glUniform1fvARB __rglgen_glUniform1fvARB\n#define glUniform2fvARB __rglgen_glUniform2fvARB\n#define glUniform3fvARB __rglgen_glUniform3fvARB\n#define glUniform4fvARB __rglgen_glUniform4fvARB\n#define glUniform1ivARB __rglgen_glUniform1ivARB\n#define glUniform2ivARB __rglgen_glUniform2ivARB\n#define glUniform3ivARB __rglgen_glUniform3ivARB\n#define glUniform4ivARB __rglgen_glUniform4ivARB\n#define glUniformMatrix2fvARB __rglgen_glUniformMatrix2fvARB\n#define glUniformMatrix3fvARB __rglgen_glUniformMatrix3fvARB\n#define glUniformMatrix4fvARB __rglgen_glUniformMatrix4fvARB\n#define glGetObjectParameterfvARB __rglgen_glGetObjectParameterfvARB\n#define glGetObjectParameterivARB __rglgen_glGetObjectParameterivARB\n#define glGetInfoLogARB __rglgen_glGetInfoLogARB\n#define glGetAttachedObjectsARB __rglgen_glGetAttachedObjectsARB\n#define glGetUniformLocationARB __rglgen_glGetUniformLocationARB\n#define glGetActiveUniformARB __rglgen_glGetActiveUniformARB\n#define glGetUniformfvARB __rglgen_glGetUniformfvARB\n#define glGetUniformivARB __rglgen_glGetUniformivARB\n#define glGetShaderSourceARB __rglgen_glGetShaderSourceARB\n#define glNamedStringARB __rglgen_glNamedStringARB\n#define glDeleteNamedStringARB __rglgen_glDeleteNamedStringARB\n#define glCompileShaderIncludeARB __rglgen_glCompileShaderIncludeARB\n#define glIsNamedStringARB __rglgen_glIsNamedStringARB\n#define glGetNamedStringARB __rglgen_glGetNamedStringARB\n#define glGetNamedStringivARB __rglgen_glGetNamedStringivARB\n#define glTexPageCommitmentARB __rglgen_glTexPageCommitmentARB\n#define glTexBufferARB __rglgen_glTexBufferARB\n#define glCompressedTexImage3DARB __rglgen_glCompressedTexImage3DARB\n#define glCompressedTexImage2DARB __rglgen_glCompressedTexImage2DARB\n#define glCompressedTexImage1DARB __rglgen_glCompressedTexImage1DARB\n#define glCompressedTexSubImage3DARB __rglgen_glCompressedTexSubImage3DARB\n#define glCompressedTexSubImage2DARB __rglgen_glCompressedTexSubImage2DARB\n#define glCompressedTexSubImage1DARB __rglgen_glCompressedTexSubImage1DARB\n#define glGetCompressedTexImageARB __rglgen_glGetCompressedTexImageARB\n#define glLoadTransposeMatrixfARB __rglgen_glLoadTransposeMatrixfARB\n#define glLoadTransposeMatrixdARB __rglgen_glLoadTransposeMatrixdARB\n#define glMultTransposeMatrixfARB __rglgen_glMultTransposeMatrixfARB\n#define glMultTransposeMatrixdARB __rglgen_glMultTransposeMatrixdARB\n#define glWeightbvARB __rglgen_glWeightbvARB\n#define glWeightsvARB __rglgen_glWeightsvARB\n#define glWeightivARB __rglgen_glWeightivARB\n#define glWeightfvARB __rglgen_glWeightfvARB\n#define glWeightdvARB __rglgen_glWeightdvARB\n#define glWeightubvARB __rglgen_glWeightubvARB\n#define glWeightusvARB __rglgen_glWeightusvARB\n#define glWeightuivARB __rglgen_glWeightuivARB\n#define glWeightPointerARB __rglgen_glWeightPointerARB\n#define glVertexBlendARB __rglgen_glVertexBlendARB\n#define glBindBufferARB __rglgen_glBindBufferARB\n#define glDeleteBuffersARB __rglgen_glDeleteBuffersARB\n#define glGenBuffersARB __rglgen_glGenBuffersARB\n#define glIsBufferARB __rglgen_glIsBufferARB\n#define glBufferDataARB __rglgen_glBufferDataARB\n#define glBufferSubDataARB __rglgen_glBufferSubDataARB\n#define glGetBufferSubDataARB __rglgen_glGetBufferSubDataARB\n#define glMapBufferARB __rglgen_glMapBufferARB\n#define glUnmapBufferARB __rglgen_glUnmapBufferARB\n#define glGetBufferParameterivARB __rglgen_glGetBufferParameterivARB\n#define glGetBufferPointervARB __rglgen_glGetBufferPointervARB\n#define glVertexAttrib1dARB __rglgen_glVertexAttrib1dARB\n#define glVertexAttrib1dvARB __rglgen_glVertexAttrib1dvARB\n#define glVertexAttrib1fARB __rglgen_glVertexAttrib1fARB\n#define glVertexAttrib1fvARB __rglgen_glVertexAttrib1fvARB\n#define glVertexAttrib1sARB __rglgen_glVertexAttrib1sARB\n#define glVertexAttrib1svARB __rglgen_glVertexAttrib1svARB\n#define glVertexAttrib2dARB __rglgen_glVertexAttrib2dARB\n#define glVertexAttrib2dvARB __rglgen_glVertexAttrib2dvARB\n#define glVertexAttrib2fARB __rglgen_glVertexAttrib2fARB\n#define glVertexAttrib2fvARB __rglgen_glVertexAttrib2fvARB\n#define glVertexAttrib2sARB __rglgen_glVertexAttrib2sARB\n#define glVertexAttrib2svARB __rglgen_glVertexAttrib2svARB\n#define glVertexAttrib3dARB __rglgen_glVertexAttrib3dARB\n#define glVertexAttrib3dvARB __rglgen_glVertexAttrib3dvARB\n#define glVertexAttrib3fARB __rglgen_glVertexAttrib3fARB\n#define glVertexAttrib3fvARB __rglgen_glVertexAttrib3fvARB\n#define glVertexAttrib3sARB __rglgen_glVertexAttrib3sARB\n#define glVertexAttrib3svARB __rglgen_glVertexAttrib3svARB\n#define glVertexAttrib4NbvARB __rglgen_glVertexAttrib4NbvARB\n#define glVertexAttrib4NivARB __rglgen_glVertexAttrib4NivARB\n#define glVertexAttrib4NsvARB __rglgen_glVertexAttrib4NsvARB\n#define glVertexAttrib4NubARB __rglgen_glVertexAttrib4NubARB\n#define glVertexAttrib4NubvARB __rglgen_glVertexAttrib4NubvARB\n#define glVertexAttrib4NuivARB __rglgen_glVertexAttrib4NuivARB\n#define glVertexAttrib4NusvARB __rglgen_glVertexAttrib4NusvARB\n#define glVertexAttrib4bvARB __rglgen_glVertexAttrib4bvARB\n#define glVertexAttrib4dARB __rglgen_glVertexAttrib4dARB\n#define glVertexAttrib4dvARB __rglgen_glVertexAttrib4dvARB\n#define glVertexAttrib4fARB __rglgen_glVertexAttrib4fARB\n#define glVertexAttrib4fvARB __rglgen_glVertexAttrib4fvARB\n#define glVertexAttrib4ivARB __rglgen_glVertexAttrib4ivARB\n#define glVertexAttrib4sARB __rglgen_glVertexAttrib4sARB\n#define glVertexAttrib4svARB __rglgen_glVertexAttrib4svARB\n#define glVertexAttrib4ubvARB __rglgen_glVertexAttrib4ubvARB\n#define glVertexAttrib4uivARB __rglgen_glVertexAttrib4uivARB\n#define glVertexAttrib4usvARB __rglgen_glVertexAttrib4usvARB\n#define glVertexAttribPointerARB __rglgen_glVertexAttribPointerARB\n#define glEnableVertexAttribArrayARB __rglgen_glEnableVertexAttribArrayARB\n#define glDisableVertexAttribArrayARB __rglgen_glDisableVertexAttribArrayARB\n#define glGetVertexAttribdvARB __rglgen_glGetVertexAttribdvARB\n#define glGetVertexAttribfvARB __rglgen_glGetVertexAttribfvARB\n#define glGetVertexAttribivARB __rglgen_glGetVertexAttribivARB\n#define glGetVertexAttribPointervARB __rglgen_glGetVertexAttribPointervARB\n#define glBindAttribLocationARB __rglgen_glBindAttribLocationARB\n#define glGetActiveAttribARB __rglgen_glGetActiveAttribARB\n#define glGetAttribLocationARB __rglgen_glGetAttribLocationARB\n#define glWindowPos2dARB __rglgen_glWindowPos2dARB\n#define glWindowPos2dvARB __rglgen_glWindowPos2dvARB\n#define glWindowPos2fARB __rglgen_glWindowPos2fARB\n#define glWindowPos2fvARB __rglgen_glWindowPos2fvARB\n#define glWindowPos2iARB __rglgen_glWindowPos2iARB\n#define glWindowPos2ivARB __rglgen_glWindowPos2ivARB\n#define glWindowPos2sARB __rglgen_glWindowPos2sARB\n#define glWindowPos2svARB __rglgen_glWindowPos2svARB\n#define glWindowPos3dARB __rglgen_glWindowPos3dARB\n#define glWindowPos3dvARB __rglgen_glWindowPos3dvARB\n#define glWindowPos3fARB __rglgen_glWindowPos3fARB\n#define glWindowPos3fvARB __rglgen_glWindowPos3fvARB\n#define glWindowPos3iARB __rglgen_glWindowPos3iARB\n#define glWindowPos3ivARB __rglgen_glWindowPos3ivARB\n#define glWindowPos3sARB __rglgen_glWindowPos3sARB\n#define glWindowPos3svARB __rglgen_glWindowPos3svARB\n#define glMultiTexCoord1bOES __rglgen_glMultiTexCoord1bOES\n#define glMultiTexCoord1bvOES __rglgen_glMultiTexCoord1bvOES\n#define glMultiTexCoord2bOES __rglgen_glMultiTexCoord2bOES\n#define glMultiTexCoord2bvOES __rglgen_glMultiTexCoord2bvOES\n#define glMultiTexCoord3bOES __rglgen_glMultiTexCoord3bOES\n#define glMultiTexCoord3bvOES __rglgen_glMultiTexCoord3bvOES\n#define glMultiTexCoord4bOES __rglgen_glMultiTexCoord4bOES\n#define glMultiTexCoord4bvOES __rglgen_glMultiTexCoord4bvOES\n#define glTexCoord1bOES __rglgen_glTexCoord1bOES\n#define glTexCoord1bvOES __rglgen_glTexCoord1bvOES\n#define glTexCoord2bOES __rglgen_glTexCoord2bOES\n#define glTexCoord2bvOES __rglgen_glTexCoord2bvOES\n#define glTexCoord3bOES __rglgen_glTexCoord3bOES\n#define glTexCoord3bvOES __rglgen_glTexCoord3bvOES\n#define glTexCoord4bOES __rglgen_glTexCoord4bOES\n#define glTexCoord4bvOES __rglgen_glTexCoord4bvOES\n#define glVertex2bOES __rglgen_glVertex2bOES\n#define glVertex2bvOES __rglgen_glVertex2bvOES\n#define glVertex3bOES __rglgen_glVertex3bOES\n#define glVertex3bvOES __rglgen_glVertex3bvOES\n#define glVertex4bOES __rglgen_glVertex4bOES\n#define glVertex4bvOES __rglgen_glVertex4bvOES\n#define glAlphaFuncxOES __rglgen_glAlphaFuncxOES\n#define glClearColorxOES __rglgen_glClearColorxOES\n#define glClearDepthxOES __rglgen_glClearDepthxOES\n#define glClipPlanexOES __rglgen_glClipPlanexOES\n#define glColor4xOES __rglgen_glColor4xOES\n#define glDepthRangexOES __rglgen_glDepthRangexOES\n#define glFogxOES __rglgen_glFogxOES\n#define glFogxvOES __rglgen_glFogxvOES\n#define glFrustumxOES __rglgen_glFrustumxOES\n#define glGetClipPlanexOES __rglgen_glGetClipPlanexOES\n#define glGetFixedvOES __rglgen_glGetFixedvOES\n#define glGetTexEnvxvOES __rglgen_glGetTexEnvxvOES\n#define glGetTexParameterxvOES __rglgen_glGetTexParameterxvOES\n#define glLightModelxOES __rglgen_glLightModelxOES\n#define glLightModelxvOES __rglgen_glLightModelxvOES\n#define glLightxOES __rglgen_glLightxOES\n#define glLightxvOES __rglgen_glLightxvOES\n#define glLineWidthxOES __rglgen_glLineWidthxOES\n#define glLoadMatrixxOES __rglgen_glLoadMatrixxOES\n#define glMaterialxOES __rglgen_glMaterialxOES\n#define glMaterialxvOES __rglgen_glMaterialxvOES\n#define glMultMatrixxOES __rglgen_glMultMatrixxOES\n#define glMultiTexCoord4xOES __rglgen_glMultiTexCoord4xOES\n#define glNormal3xOES __rglgen_glNormal3xOES\n#define glOrthoxOES __rglgen_glOrthoxOES\n#define glPointParameterxvOES __rglgen_glPointParameterxvOES\n#define glPointSizexOES __rglgen_glPointSizexOES\n#define glPolygonOffsetxOES __rglgen_glPolygonOffsetxOES\n#define glRotatexOES __rglgen_glRotatexOES\n#define glSampleCoverageOES __rglgen_glSampleCoverageOES\n#define glScalexOES __rglgen_glScalexOES\n#define glTexEnvxOES __rglgen_glTexEnvxOES\n#define glTexEnvxvOES __rglgen_glTexEnvxvOES\n#define glTexParameterxOES __rglgen_glTexParameterxOES\n#define glTexParameterxvOES __rglgen_glTexParameterxvOES\n#define glTranslatexOES __rglgen_glTranslatexOES\n#define glAccumxOES __rglgen_glAccumxOES\n#define glBitmapxOES __rglgen_glBitmapxOES\n#define glBlendColorxOES __rglgen_glBlendColorxOES\n#define glClearAccumxOES __rglgen_glClearAccumxOES\n#define glColor3xOES __rglgen_glColor3xOES\n#define glColor3xvOES __rglgen_glColor3xvOES\n#define glColor4xvOES __rglgen_glColor4xvOES\n#define glConvolutionParameterxOES __rglgen_glConvolutionParameterxOES\n#define glConvolutionParameterxvOES __rglgen_glConvolutionParameterxvOES\n#define glEvalCoord1xOES __rglgen_glEvalCoord1xOES\n#define glEvalCoord1xvOES __rglgen_glEvalCoord1xvOES\n#define glEvalCoord2xOES __rglgen_glEvalCoord2xOES\n#define glEvalCoord2xvOES __rglgen_glEvalCoord2xvOES\n#define glFeedbackBufferxOES __rglgen_glFeedbackBufferxOES\n#define glGetConvolutionParameterxvOES __rglgen_glGetConvolutionParameterxvOES\n#define glGetHistogramParameterxvOES __rglgen_glGetHistogramParameterxvOES\n#define glGetLightxOES __rglgen_glGetLightxOES\n#define glGetMapxvOES __rglgen_glGetMapxvOES\n#define glGetMaterialxOES __rglgen_glGetMaterialxOES\n#define glGetPixelMapxv __rglgen_glGetPixelMapxv\n#define glGetTexGenxvOES __rglgen_glGetTexGenxvOES\n#define glGetTexLevelParameterxvOES __rglgen_glGetTexLevelParameterxvOES\n#define glIndexxOES __rglgen_glIndexxOES\n#define glIndexxvOES __rglgen_glIndexxvOES\n#define glLoadTransposeMatrixxOES __rglgen_glLoadTransposeMatrixxOES\n#define glMap1xOES __rglgen_glMap1xOES\n#define glMap2xOES __rglgen_glMap2xOES\n#define glMapGrid1xOES __rglgen_glMapGrid1xOES\n#define glMapGrid2xOES __rglgen_glMapGrid2xOES\n#define glMultTransposeMatrixxOES __rglgen_glMultTransposeMatrixxOES\n#define glMultiTexCoord1xOES __rglgen_glMultiTexCoord1xOES\n#define glMultiTexCoord1xvOES __rglgen_glMultiTexCoord1xvOES\n#define glMultiTexCoord2xOES __rglgen_glMultiTexCoord2xOES\n#define glMultiTexCoord2xvOES __rglgen_glMultiTexCoord2xvOES\n#define glMultiTexCoord3xOES __rglgen_glMultiTexCoord3xOES\n#define glMultiTexCoord3xvOES __rglgen_glMultiTexCoord3xvOES\n#define glMultiTexCoord4xvOES __rglgen_glMultiTexCoord4xvOES\n#define glNormal3xvOES __rglgen_glNormal3xvOES\n#define glPassThroughxOES __rglgen_glPassThroughxOES\n#define glPixelMapx __rglgen_glPixelMapx\n#define glPixelStorex __rglgen_glPixelStorex\n#define glPixelTransferxOES __rglgen_glPixelTransferxOES\n#define glPixelZoomxOES __rglgen_glPixelZoomxOES\n#define glPrioritizeTexturesxOES __rglgen_glPrioritizeTexturesxOES\n#define glRasterPos2xOES __rglgen_glRasterPos2xOES\n#define glRasterPos2xvOES __rglgen_glRasterPos2xvOES\n#define glRasterPos3xOES __rglgen_glRasterPos3xOES\n#define glRasterPos3xvOES __rglgen_glRasterPos3xvOES\n#define glRasterPos4xOES __rglgen_glRasterPos4xOES\n#define glRasterPos4xvOES __rglgen_glRasterPos4xvOES\n#define glRectxOES __rglgen_glRectxOES\n#define glRectxvOES __rglgen_glRectxvOES\n#define glTexCoord1xOES __rglgen_glTexCoord1xOES\n#define glTexCoord1xvOES __rglgen_glTexCoord1xvOES\n#define glTexCoord2xOES __rglgen_glTexCoord2xOES\n#define glTexCoord2xvOES __rglgen_glTexCoord2xvOES\n#define glTexCoord3xOES __rglgen_glTexCoord3xOES\n#define glTexCoord3xvOES __rglgen_glTexCoord3xvOES\n#define glTexCoord4xOES __rglgen_glTexCoord4xOES\n#define glTexCoord4xvOES __rglgen_glTexCoord4xvOES\n#define glTexGenxOES __rglgen_glTexGenxOES\n#define glTexGenxvOES __rglgen_glTexGenxvOES\n#define glVertex2xOES __rglgen_glVertex2xOES\n#define glVertex2xvOES __rglgen_glVertex2xvOES\n#define glVertex3xOES __rglgen_glVertex3xOES\n#define glVertex3xvOES __rglgen_glVertex3xvOES\n#define glVertex4xOES __rglgen_glVertex4xOES\n#define glVertex4xvOES __rglgen_glVertex4xvOES\n#define glQueryMatrixxOES __rglgen_glQueryMatrixxOES\n#define glClearDepthfOES __rglgen_glClearDepthfOES\n#define glClipPlanefOES __rglgen_glClipPlanefOES\n#define glDepthRangefOES __rglgen_glDepthRangefOES\n#define glFrustumfOES __rglgen_glFrustumfOES\n#define glGetClipPlanefOES __rglgen_glGetClipPlanefOES\n#define glOrthofOES __rglgen_glOrthofOES\n#define glImageTransformParameteriHP __rglgen_glImageTransformParameteriHP\n#define glImageTransformParameterfHP __rglgen_glImageTransformParameterfHP\n#define glImageTransformParameterivHP __rglgen_glImageTransformParameterivHP\n#define glImageTransformParameterfvHP __rglgen_glImageTransformParameterfvHP\n#define glGetImageTransformParameterivHP __rglgen_glGetImageTransformParameterivHP\n#define glGetImageTransformParameterfvHP __rglgen_glGetImageTransformParameterfvHP\n\nextern RGLSYMGLDRAWRANGEELEMENTSPROC __rglgen_glDrawRangeElements;\nextern RGLSYMGLTEXIMAGE3DPROC __rglgen_glTexImage3D;\nextern RGLSYMGLTEXSUBIMAGE3DPROC __rglgen_glTexSubImage3D;\nextern RGLSYMGLCOPYTEXSUBIMAGE3DPROC __rglgen_glCopyTexSubImage3D;\nextern RGLSYMGLACTIVETEXTUREPROC __rglgen_glActiveTexture;\nextern RGLSYMGLSAMPLECOVERAGEPROC __rglgen_glSampleCoverage;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC __rglgen_glCompressedTexImage3D;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC __rglgen_glCompressedTexImage2D;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC __rglgen_glCompressedTexImage1D;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC __rglgen_glCompressedTexSubImage3D;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC __rglgen_glCompressedTexSubImage2D;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC __rglgen_glCompressedTexSubImage1D;\nextern RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC __rglgen_glGetCompressedTexImage;\nextern RGLSYMGLCLIENTACTIVETEXTUREPROC __rglgen_glClientActiveTexture;\nextern RGLSYMGLMULTITEXCOORD1DPROC __rglgen_glMultiTexCoord1d;\nextern RGLSYMGLMULTITEXCOORD1DVPROC __rglgen_glMultiTexCoord1dv;\nextern RGLSYMGLMULTITEXCOORD1FPROC __rglgen_glMultiTexCoord1f;\nextern RGLSYMGLMULTITEXCOORD1FVPROC __rglgen_glMultiTexCoord1fv;\nextern RGLSYMGLMULTITEXCOORD1IPROC __rglgen_glMultiTexCoord1i;\nextern RGLSYMGLMULTITEXCOORD1IVPROC __rglgen_glMultiTexCoord1iv;\nextern RGLSYMGLMULTITEXCOORD1SPROC __rglgen_glMultiTexCoord1s;\nextern RGLSYMGLMULTITEXCOORD1SVPROC __rglgen_glMultiTexCoord1sv;\nextern RGLSYMGLMULTITEXCOORD2DPROC __rglgen_glMultiTexCoord2d;\nextern RGLSYMGLMULTITEXCOORD2DVPROC __rglgen_glMultiTexCoord2dv;\nextern RGLSYMGLMULTITEXCOORD2FPROC __rglgen_glMultiTexCoord2f;\nextern RGLSYMGLMULTITEXCOORD2FVPROC __rglgen_glMultiTexCoord2fv;\nextern RGLSYMGLMULTITEXCOORD2IPROC __rglgen_glMultiTexCoord2i;\nextern RGLSYMGLMULTITEXCOORD2IVPROC __rglgen_glMultiTexCoord2iv;\nextern RGLSYMGLMULTITEXCOORD2SPROC __rglgen_glMultiTexCoord2s;\nextern RGLSYMGLMULTITEXCOORD2SVPROC __rglgen_glMultiTexCoord2sv;\nextern RGLSYMGLMULTITEXCOORD3DPROC __rglgen_glMultiTexCoord3d;\nextern RGLSYMGLMULTITEXCOORD3DVPROC __rglgen_glMultiTexCoord3dv;\nextern RGLSYMGLMULTITEXCOORD3FPROC __rglgen_glMultiTexCoord3f;\nextern RGLSYMGLMULTITEXCOORD3FVPROC __rglgen_glMultiTexCoord3fv;\nextern RGLSYMGLMULTITEXCOORD3IPROC __rglgen_glMultiTexCoord3i;\nextern RGLSYMGLMULTITEXCOORD3IVPROC __rglgen_glMultiTexCoord3iv;\nextern RGLSYMGLMULTITEXCOORD3SPROC __rglgen_glMultiTexCoord3s;\nextern RGLSYMGLMULTITEXCOORD3SVPROC __rglgen_glMultiTexCoord3sv;\nextern RGLSYMGLMULTITEXCOORD4DPROC __rglgen_glMultiTexCoord4d;\nextern RGLSYMGLMULTITEXCOORD4DVPROC __rglgen_glMultiTexCoord4dv;\nextern RGLSYMGLMULTITEXCOORD4FPROC __rglgen_glMultiTexCoord4f;\nextern RGLSYMGLMULTITEXCOORD4FVPROC __rglgen_glMultiTexCoord4fv;\nextern RGLSYMGLMULTITEXCOORD4IPROC __rglgen_glMultiTexCoord4i;\nextern RGLSYMGLMULTITEXCOORD4IVPROC __rglgen_glMultiTexCoord4iv;\nextern RGLSYMGLMULTITEXCOORD4SPROC __rglgen_glMultiTexCoord4s;\nextern RGLSYMGLMULTITEXCOORD4SVPROC __rglgen_glMultiTexCoord4sv;\nextern RGLSYMGLLOADTRANSPOSEMATRIXFPROC __rglgen_glLoadTransposeMatrixf;\nextern RGLSYMGLLOADTRANSPOSEMATRIXDPROC __rglgen_glLoadTransposeMatrixd;\nextern RGLSYMGLMULTTRANSPOSEMATRIXFPROC __rglgen_glMultTransposeMatrixf;\nextern RGLSYMGLMULTTRANSPOSEMATRIXDPROC __rglgen_glMultTransposeMatrixd;\nextern RGLSYMGLBLENDFUNCSEPARATEPROC __rglgen_glBlendFuncSeparate;\nextern RGLSYMGLMULTIDRAWARRAYSPROC __rglgen_glMultiDrawArrays;\nextern RGLSYMGLMULTIDRAWELEMENTSPROC __rglgen_glMultiDrawElements;\nextern RGLSYMGLPOINTPARAMETERFPROC __rglgen_glPointParameterf;\nextern RGLSYMGLPOINTPARAMETERFVPROC __rglgen_glPointParameterfv;\nextern RGLSYMGLPOINTPARAMETERIPROC __rglgen_glPointParameteri;\nextern RGLSYMGLPOINTPARAMETERIVPROC __rglgen_glPointParameteriv;\nextern RGLSYMGLFOGCOORDFPROC __rglgen_glFogCoordf;\nextern RGLSYMGLFOGCOORDFVPROC __rglgen_glFogCoordfv;\nextern RGLSYMGLFOGCOORDDPROC __rglgen_glFogCoordd;\nextern RGLSYMGLFOGCOORDDVPROC __rglgen_glFogCoorddv;\nextern RGLSYMGLFOGCOORDPOINTERPROC __rglgen_glFogCoordPointer;\nextern RGLSYMGLSECONDARYCOLOR3BPROC __rglgen_glSecondaryColor3b;\nextern RGLSYMGLSECONDARYCOLOR3BVPROC __rglgen_glSecondaryColor3bv;\nextern RGLSYMGLSECONDARYCOLOR3DPROC __rglgen_glSecondaryColor3d;\nextern RGLSYMGLSECONDARYCOLOR3DVPROC __rglgen_glSecondaryColor3dv;\nextern RGLSYMGLSECONDARYCOLOR3FPROC __rglgen_glSecondaryColor3f;\nextern RGLSYMGLSECONDARYCOLOR3FVPROC __rglgen_glSecondaryColor3fv;\nextern RGLSYMGLSECONDARYCOLOR3IPROC __rglgen_glSecondaryColor3i;\nextern RGLSYMGLSECONDARYCOLOR3IVPROC __rglgen_glSecondaryColor3iv;\nextern RGLSYMGLSECONDARYCOLOR3SPROC __rglgen_glSecondaryColor3s;\nextern RGLSYMGLSECONDARYCOLOR3SVPROC __rglgen_glSecondaryColor3sv;\nextern RGLSYMGLSECONDARYCOLOR3UBPROC __rglgen_glSecondaryColor3ub;\nextern RGLSYMGLSECONDARYCOLOR3UBVPROC __rglgen_glSecondaryColor3ubv;\nextern RGLSYMGLSECONDARYCOLOR3UIPROC __rglgen_glSecondaryColor3ui;\nextern RGLSYMGLSECONDARYCOLOR3UIVPROC __rglgen_glSecondaryColor3uiv;\nextern RGLSYMGLSECONDARYCOLOR3USPROC __rglgen_glSecondaryColor3us;\nextern RGLSYMGLSECONDARYCOLOR3USVPROC __rglgen_glSecondaryColor3usv;\nextern RGLSYMGLSECONDARYCOLORPOINTERPROC __rglgen_glSecondaryColorPointer;\nextern RGLSYMGLWINDOWPOS2DPROC __rglgen_glWindowPos2d;\nextern RGLSYMGLWINDOWPOS2DVPROC __rglgen_glWindowPos2dv;\nextern RGLSYMGLWINDOWPOS2FPROC __rglgen_glWindowPos2f;\nextern RGLSYMGLWINDOWPOS2FVPROC __rglgen_glWindowPos2fv;\nextern RGLSYMGLWINDOWPOS2IPROC __rglgen_glWindowPos2i;\nextern RGLSYMGLWINDOWPOS2IVPROC __rglgen_glWindowPos2iv;\nextern RGLSYMGLWINDOWPOS2SPROC __rglgen_glWindowPos2s;\nextern RGLSYMGLWINDOWPOS2SVPROC __rglgen_glWindowPos2sv;\nextern RGLSYMGLWINDOWPOS3DPROC __rglgen_glWindowPos3d;\nextern RGLSYMGLWINDOWPOS3DVPROC __rglgen_glWindowPos3dv;\nextern RGLSYMGLWINDOWPOS3FPROC __rglgen_glWindowPos3f;\nextern RGLSYMGLWINDOWPOS3FVPROC __rglgen_glWindowPos3fv;\nextern RGLSYMGLWINDOWPOS3IPROC __rglgen_glWindowPos3i;\nextern RGLSYMGLWINDOWPOS3IVPROC __rglgen_glWindowPos3iv;\nextern RGLSYMGLWINDOWPOS3SPROC __rglgen_glWindowPos3s;\nextern RGLSYMGLWINDOWPOS3SVPROC __rglgen_glWindowPos3sv;\nextern RGLSYMGLBLENDCOLORPROC __rglgen_glBlendColor;\nextern RGLSYMGLBLENDEQUATIONPROC __rglgen_glBlendEquation;\nextern RGLSYMGLGENQUERIESPROC __rglgen_glGenQueries;\nextern RGLSYMGLDELETEQUERIESPROC __rglgen_glDeleteQueries;\nextern RGLSYMGLISQUERYPROC __rglgen_glIsQuery;\nextern RGLSYMGLBEGINQUERYPROC __rglgen_glBeginQuery;\nextern RGLSYMGLENDQUERYPROC __rglgen_glEndQuery;\nextern RGLSYMGLGETQUERYIVPROC __rglgen_glGetQueryiv;\nextern RGLSYMGLGETQUERYOBJECTIVPROC __rglgen_glGetQueryObjectiv;\nextern RGLSYMGLGETQUERYOBJECTUIVPROC __rglgen_glGetQueryObjectuiv;\nextern RGLSYMGLBINDBUFFERPROC __rglgen_glBindBuffer;\nextern RGLSYMGLDELETEBUFFERSPROC __rglgen_glDeleteBuffers;\nextern RGLSYMGLGENBUFFERSPROC __rglgen_glGenBuffers;\nextern RGLSYMGLISBUFFERPROC __rglgen_glIsBuffer;\nextern RGLSYMGLBUFFERDATAPROC __rglgen_glBufferData;\nextern RGLSYMGLBUFFERSUBDATAPROC __rglgen_glBufferSubData;\nextern RGLSYMGLGETBUFFERSUBDATAPROC __rglgen_glGetBufferSubData;\nextern RGLSYMGLMAPBUFFERPROC __rglgen_glMapBuffer;\nextern RGLSYMGLUNMAPBUFFERPROC __rglgen_glUnmapBuffer;\nextern RGLSYMGLGETBUFFERPARAMETERIVPROC __rglgen_glGetBufferParameteriv;\nextern RGLSYMGLGETBUFFERPOINTERVPROC __rglgen_glGetBufferPointerv;\nextern RGLSYMGLBLENDEQUATIONSEPARATEPROC __rglgen_glBlendEquationSeparate;\nextern RGLSYMGLDRAWBUFFERSPROC __rglgen_glDrawBuffers;\nextern RGLSYMGLSTENCILOPSEPARATEPROC __rglgen_glStencilOpSeparate;\nextern RGLSYMGLSTENCILFUNCSEPARATEPROC __rglgen_glStencilFuncSeparate;\nextern RGLSYMGLSTENCILMASKSEPARATEPROC __rglgen_glStencilMaskSeparate;\nextern RGLSYMGLATTACHSHADERPROC __rglgen_glAttachShader;\nextern RGLSYMGLBINDATTRIBLOCATIONPROC __rglgen_glBindAttribLocation;\nextern RGLSYMGLCOMPILESHADERPROC __rglgen_glCompileShader;\nextern RGLSYMGLCREATEPROGRAMPROC __rglgen_glCreateProgram;\nextern RGLSYMGLCREATESHADERPROC __rglgen_glCreateShader;\nextern RGLSYMGLDELETEPROGRAMPROC __rglgen_glDeleteProgram;\nextern RGLSYMGLDELETESHADERPROC __rglgen_glDeleteShader;\nextern RGLSYMGLDETACHSHADERPROC __rglgen_glDetachShader;\nextern RGLSYMGLDISABLEVERTEXATTRIBARRAYPROC __rglgen_glDisableVertexAttribArray;\nextern RGLSYMGLENABLEVERTEXATTRIBARRAYPROC __rglgen_glEnableVertexAttribArray;\nextern RGLSYMGLGETACTIVEATTRIBPROC __rglgen_glGetActiveAttrib;\nextern RGLSYMGLGETACTIVEUNIFORMPROC __rglgen_glGetActiveUniform;\nextern RGLSYMGLGETATTACHEDSHADERSPROC __rglgen_glGetAttachedShaders;\nextern RGLSYMGLGETATTRIBLOCATIONPROC __rglgen_glGetAttribLocation;\nextern RGLSYMGLGETPROGRAMIVPROC __rglgen_glGetProgramiv;\nextern RGLSYMGLGETPROGRAMINFOLOGPROC __rglgen_glGetProgramInfoLog;\nextern RGLSYMGLGETSHADERIVPROC __rglgen_glGetShaderiv;\nextern RGLSYMGLGETSHADERINFOLOGPROC __rglgen_glGetShaderInfoLog;\nextern RGLSYMGLGETSHADERSOURCEPROC __rglgen_glGetShaderSource;\nextern RGLSYMGLGETUNIFORMLOCATIONPROC __rglgen_glGetUniformLocation;\nextern RGLSYMGLGETUNIFORMFVPROC __rglgen_glGetUniformfv;\nextern RGLSYMGLGETUNIFORMIVPROC __rglgen_glGetUniformiv;\nextern RGLSYMGLGETVERTEXATTRIBDVPROC __rglgen_glGetVertexAttribdv;\nextern RGLSYMGLGETVERTEXATTRIBFVPROC __rglgen_glGetVertexAttribfv;\nextern RGLSYMGLGETVERTEXATTRIBIVPROC __rglgen_glGetVertexAttribiv;\nextern RGLSYMGLGETVERTEXATTRIBPOINTERVPROC __rglgen_glGetVertexAttribPointerv;\nextern RGLSYMGLISPROGRAMPROC __rglgen_glIsProgram;\nextern RGLSYMGLISSHADERPROC __rglgen_glIsShader;\nextern RGLSYMGLLINKPROGRAMPROC __rglgen_glLinkProgram;\nextern RGLSYMGLSHADERSOURCEPROC __rglgen_glShaderSource;\nextern RGLSYMGLUSEPROGRAMPROC __rglgen_glUseProgram;\nextern RGLSYMGLUNIFORM1FPROC __rglgen_glUniform1f;\nextern RGLSYMGLUNIFORM2FPROC __rglgen_glUniform2f;\nextern RGLSYMGLUNIFORM3FPROC __rglgen_glUniform3f;\nextern RGLSYMGLUNIFORM4FPROC __rglgen_glUniform4f;\nextern RGLSYMGLUNIFORM1IPROC __rglgen_glUniform1i;\nextern RGLSYMGLUNIFORM2IPROC __rglgen_glUniform2i;\nextern RGLSYMGLUNIFORM3IPROC __rglgen_glUniform3i;\nextern RGLSYMGLUNIFORM4IPROC __rglgen_glUniform4i;\nextern RGLSYMGLUNIFORM1FVPROC __rglgen_glUniform1fv;\nextern RGLSYMGLUNIFORM2FVPROC __rglgen_glUniform2fv;\nextern RGLSYMGLUNIFORM3FVPROC __rglgen_glUniform3fv;\nextern RGLSYMGLUNIFORM4FVPROC __rglgen_glUniform4fv;\nextern RGLSYMGLUNIFORM1IVPROC __rglgen_glUniform1iv;\nextern RGLSYMGLUNIFORM2IVPROC __rglgen_glUniform2iv;\nextern RGLSYMGLUNIFORM3IVPROC __rglgen_glUniform3iv;\nextern RGLSYMGLUNIFORM4IVPROC __rglgen_glUniform4iv;\nextern RGLSYMGLUNIFORMMATRIX2FVPROC __rglgen_glUniformMatrix2fv;\nextern RGLSYMGLUNIFORMMATRIX3FVPROC __rglgen_glUniformMatrix3fv;\nextern RGLSYMGLUNIFORMMATRIX4FVPROC __rglgen_glUniformMatrix4fv;\nextern RGLSYMGLVALIDATEPROGRAMPROC __rglgen_glValidateProgram;\nextern RGLSYMGLVERTEXATTRIB1DPROC __rglgen_glVertexAttrib1d;\nextern RGLSYMGLVERTEXATTRIB1DVPROC __rglgen_glVertexAttrib1dv;\nextern RGLSYMGLVERTEXATTRIB1FPROC __rglgen_glVertexAttrib1f;\nextern RGLSYMGLVERTEXATTRIB1FVPROC __rglgen_glVertexAttrib1fv;\nextern RGLSYMGLVERTEXATTRIB1SPROC __rglgen_glVertexAttrib1s;\nextern RGLSYMGLVERTEXATTRIB1SVPROC __rglgen_glVertexAttrib1sv;\nextern RGLSYMGLVERTEXATTRIB2DPROC __rglgen_glVertexAttrib2d;\nextern RGLSYMGLVERTEXATTRIB2DVPROC __rglgen_glVertexAttrib2dv;\nextern RGLSYMGLVERTEXATTRIB2FPROC __rglgen_glVertexAttrib2f;\nextern RGLSYMGLVERTEXATTRIB2FVPROC __rglgen_glVertexAttrib2fv;\nextern RGLSYMGLVERTEXATTRIB2SPROC __rglgen_glVertexAttrib2s;\nextern RGLSYMGLVERTEXATTRIB2SVPROC __rglgen_glVertexAttrib2sv;\nextern RGLSYMGLVERTEXATTRIB3DPROC __rglgen_glVertexAttrib3d;\nextern RGLSYMGLVERTEXATTRIB3DVPROC __rglgen_glVertexAttrib3dv;\nextern RGLSYMGLVERTEXATTRIB3FPROC __rglgen_glVertexAttrib3f;\nextern RGLSYMGLVERTEXATTRIB3FVPROC __rglgen_glVertexAttrib3fv;\nextern RGLSYMGLVERTEXATTRIB3SPROC __rglgen_glVertexAttrib3s;\nextern RGLSYMGLVERTEXATTRIB3SVPROC __rglgen_glVertexAttrib3sv;\nextern RGLSYMGLVERTEXATTRIB4NBVPROC __rglgen_glVertexAttrib4Nbv;\nextern RGLSYMGLVERTEXATTRIB4NIVPROC __rglgen_glVertexAttrib4Niv;\nextern RGLSYMGLVERTEXATTRIB4NSVPROC __rglgen_glVertexAttrib4Nsv;\nextern RGLSYMGLVERTEXATTRIB4NUBPROC __rglgen_glVertexAttrib4Nub;\nextern RGLSYMGLVERTEXATTRIB4NUBVPROC __rglgen_glVertexAttrib4Nubv;\nextern RGLSYMGLVERTEXATTRIB4NUIVPROC __rglgen_glVertexAttrib4Nuiv;\nextern RGLSYMGLVERTEXATTRIB4NUSVPROC __rglgen_glVertexAttrib4Nusv;\nextern RGLSYMGLVERTEXATTRIB4BVPROC __rglgen_glVertexAttrib4bv;\nextern RGLSYMGLVERTEXATTRIB4DPROC __rglgen_glVertexAttrib4d;\nextern RGLSYMGLVERTEXATTRIB4DVPROC __rglgen_glVertexAttrib4dv;\nextern RGLSYMGLVERTEXATTRIB4FPROC __rglgen_glVertexAttrib4f;\nextern RGLSYMGLVERTEXATTRIB4FVPROC __rglgen_glVertexAttrib4fv;\nextern RGLSYMGLVERTEXATTRIB4IVPROC __rglgen_glVertexAttrib4iv;\nextern RGLSYMGLVERTEXATTRIB4SPROC __rglgen_glVertexAttrib4s;\nextern RGLSYMGLVERTEXATTRIB4SVPROC __rglgen_glVertexAttrib4sv;\nextern RGLSYMGLVERTEXATTRIB4UBVPROC __rglgen_glVertexAttrib4ubv;\nextern RGLSYMGLVERTEXATTRIB4UIVPROC __rglgen_glVertexAttrib4uiv;\nextern RGLSYMGLVERTEXATTRIB4USVPROC __rglgen_glVertexAttrib4usv;\nextern RGLSYMGLVERTEXATTRIBPOINTERPROC __rglgen_glVertexAttribPointer;\nextern RGLSYMGLUNIFORMMATRIX2X3FVPROC __rglgen_glUniformMatrix2x3fv;\nextern RGLSYMGLUNIFORMMATRIX3X2FVPROC __rglgen_glUniformMatrix3x2fv;\nextern RGLSYMGLUNIFORMMATRIX2X4FVPROC __rglgen_glUniformMatrix2x4fv;\nextern RGLSYMGLUNIFORMMATRIX4X2FVPROC __rglgen_glUniformMatrix4x2fv;\nextern RGLSYMGLUNIFORMMATRIX3X4FVPROC __rglgen_glUniformMatrix3x4fv;\nextern RGLSYMGLUNIFORMMATRIX4X3FVPROC __rglgen_glUniformMatrix4x3fv;\nextern RGLSYMGLCOLORMASKIPROC __rglgen_glColorMaski;\nextern RGLSYMGLGETBOOLEANI_VPROC __rglgen_glGetBooleani_v;\nextern RGLSYMGLGETINTEGERI_VPROC __rglgen_glGetIntegeri_v;\nextern RGLSYMGLENABLEIPROC __rglgen_glEnablei;\nextern RGLSYMGLDISABLEIPROC __rglgen_glDisablei;\nextern RGLSYMGLISENABLEDIPROC __rglgen_glIsEnabledi;\nextern RGLSYMGLBEGINTRANSFORMFEEDBACKPROC __rglgen_glBeginTransformFeedback;\nextern RGLSYMGLENDTRANSFORMFEEDBACKPROC __rglgen_glEndTransformFeedback;\nextern RGLSYMGLBINDBUFFERRANGEPROC __rglgen_glBindBufferRange;\nextern RGLSYMGLBINDBUFFERBASEPROC __rglgen_glBindBufferBase;\nextern RGLSYMGLTRANSFORMFEEDBACKVARYINGSPROC __rglgen_glTransformFeedbackVaryings;\nextern RGLSYMGLGETTRANSFORMFEEDBACKVARYINGPROC __rglgen_glGetTransformFeedbackVarying;\nextern RGLSYMGLCLAMPCOLORPROC __rglgen_glClampColor;\nextern RGLSYMGLBEGINCONDITIONALRENDERPROC __rglgen_glBeginConditionalRender;\nextern RGLSYMGLENDCONDITIONALRENDERPROC __rglgen_glEndConditionalRender;\nextern RGLSYMGLVERTEXATTRIBIPOINTERPROC __rglgen_glVertexAttribIPointer;\nextern RGLSYMGLGETVERTEXATTRIBIIVPROC __rglgen_glGetVertexAttribIiv;\nextern RGLSYMGLGETVERTEXATTRIBIUIVPROC __rglgen_glGetVertexAttribIuiv;\nextern RGLSYMGLVERTEXATTRIBI1IPROC __rglgen_glVertexAttribI1i;\nextern RGLSYMGLVERTEXATTRIBI2IPROC __rglgen_glVertexAttribI2i;\nextern RGLSYMGLVERTEXATTRIBI3IPROC __rglgen_glVertexAttribI3i;\nextern RGLSYMGLVERTEXATTRIBI4IPROC __rglgen_glVertexAttribI4i;\nextern RGLSYMGLVERTEXATTRIBI1UIPROC __rglgen_glVertexAttribI1ui;\nextern RGLSYMGLVERTEXATTRIBI2UIPROC __rglgen_glVertexAttribI2ui;\nextern RGLSYMGLVERTEXATTRIBI3UIPROC __rglgen_glVertexAttribI3ui;\nextern RGLSYMGLVERTEXATTRIBI4UIPROC __rglgen_glVertexAttribI4ui;\nextern RGLSYMGLVERTEXATTRIBI1IVPROC __rglgen_glVertexAttribI1iv;\nextern RGLSYMGLVERTEXATTRIBI2IVPROC __rglgen_glVertexAttribI2iv;\nextern RGLSYMGLVERTEXATTRIBI3IVPROC __rglgen_glVertexAttribI3iv;\nextern RGLSYMGLVERTEXATTRIBI4IVPROC __rglgen_glVertexAttribI4iv;\nextern RGLSYMGLVERTEXATTRIBI1UIVPROC __rglgen_glVertexAttribI1uiv;\nextern RGLSYMGLVERTEXATTRIBI2UIVPROC __rglgen_glVertexAttribI2uiv;\nextern RGLSYMGLVERTEXATTRIBI3UIVPROC __rglgen_glVertexAttribI3uiv;\nextern RGLSYMGLVERTEXATTRIBI4UIVPROC __rglgen_glVertexAttribI4uiv;\nextern RGLSYMGLVERTEXATTRIBI4BVPROC __rglgen_glVertexAttribI4bv;\nextern RGLSYMGLVERTEXATTRIBI4SVPROC __rglgen_glVertexAttribI4sv;\nextern RGLSYMGLVERTEXATTRIBI4UBVPROC __rglgen_glVertexAttribI4ubv;\nextern RGLSYMGLVERTEXATTRIBI4USVPROC __rglgen_glVertexAttribI4usv;\nextern RGLSYMGLGETUNIFORMUIVPROC __rglgen_glGetUniformuiv;\nextern RGLSYMGLBINDFRAGDATALOCATIONPROC __rglgen_glBindFragDataLocation;\nextern RGLSYMGLGETFRAGDATALOCATIONPROC __rglgen_glGetFragDataLocation;\nextern RGLSYMGLUNIFORM1UIPROC __rglgen_glUniform1ui;\nextern RGLSYMGLUNIFORM2UIPROC __rglgen_glUniform2ui;\nextern RGLSYMGLUNIFORM3UIPROC __rglgen_glUniform3ui;\nextern RGLSYMGLUNIFORM4UIPROC __rglgen_glUniform4ui;\nextern RGLSYMGLUNIFORM1UIVPROC __rglgen_glUniform1uiv;\nextern RGLSYMGLUNIFORM2UIVPROC __rglgen_glUniform2uiv;\nextern RGLSYMGLUNIFORM3UIVPROC __rglgen_glUniform3uiv;\nextern RGLSYMGLUNIFORM4UIVPROC __rglgen_glUniform4uiv;\nextern RGLSYMGLTEXPARAMETERIIVPROC __rglgen_glTexParameterIiv;\nextern RGLSYMGLTEXPARAMETERIUIVPROC __rglgen_glTexParameterIuiv;\nextern RGLSYMGLGETTEXPARAMETERIIVPROC __rglgen_glGetTexParameterIiv;\nextern RGLSYMGLGETTEXPARAMETERIUIVPROC __rglgen_glGetTexParameterIuiv;\nextern RGLSYMGLCLEARBUFFERIVPROC __rglgen_glClearBufferiv;\nextern RGLSYMGLCLEARBUFFERUIVPROC __rglgen_glClearBufferuiv;\nextern RGLSYMGLCLEARBUFFERFVPROC __rglgen_glClearBufferfv;\nextern RGLSYMGLCLEARBUFFERFIPROC __rglgen_glClearBufferfi;\nextern RGLSYMGLGETSTRINGIPROC __rglgen_glGetStringi;\nextern RGLSYMGLISRENDERBUFFERPROC __rglgen_glIsRenderbuffer;\nextern RGLSYMGLBINDRENDERBUFFERPROC __rglgen_glBindRenderbuffer;\nextern RGLSYMGLDELETERENDERBUFFERSPROC __rglgen_glDeleteRenderbuffers;\nextern RGLSYMGLGENRENDERBUFFERSPROC __rglgen_glGenRenderbuffers;\nextern RGLSYMGLRENDERBUFFERSTORAGEPROC __rglgen_glRenderbufferStorage;\nextern RGLSYMGLGETRENDERBUFFERPARAMETERIVPROC __rglgen_glGetRenderbufferParameteriv;\nextern RGLSYMGLISFRAMEBUFFERPROC __rglgen_glIsFramebuffer;\nextern RGLSYMGLBINDFRAMEBUFFERPROC __rglgen_glBindFramebuffer;\nextern RGLSYMGLDELETEFRAMEBUFFERSPROC __rglgen_glDeleteFramebuffers;\nextern RGLSYMGLGENFRAMEBUFFERSPROC __rglgen_glGenFramebuffers;\nextern RGLSYMGLCHECKFRAMEBUFFERSTATUSPROC __rglgen_glCheckFramebufferStatus;\nextern RGLSYMGLFRAMEBUFFERTEXTURE1DPROC __rglgen_glFramebufferTexture1D;\nextern RGLSYMGLFRAMEBUFFERTEXTURE2DPROC __rglgen_glFramebufferTexture2D;\nextern RGLSYMGLFRAMEBUFFERTEXTURE3DPROC __rglgen_glFramebufferTexture3D;\nextern RGLSYMGLFRAMEBUFFERRENDERBUFFERPROC __rglgen_glFramebufferRenderbuffer;\nextern RGLSYMGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC __rglgen_glGetFramebufferAttachmentParameteriv;\nextern RGLSYMGLGENERATEMIPMAPPROC __rglgen_glGenerateMipmap;\nextern RGLSYMGLBLITFRAMEBUFFERPROC __rglgen_glBlitFramebuffer;\nextern RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEPROC __rglgen_glRenderbufferStorageMultisample;\nextern RGLSYMGLFRAMEBUFFERTEXTURELAYERPROC __rglgen_glFramebufferTextureLayer;\nextern RGLSYMGLMAPBUFFERRANGEPROC __rglgen_glMapBufferRange;\nextern RGLSYMGLFLUSHMAPPEDBUFFERRANGEPROC __rglgen_glFlushMappedBufferRange;\nextern RGLSYMGLBINDVERTEXARRAYPROC __rglgen_glBindVertexArray;\nextern RGLSYMGLDELETEVERTEXARRAYSPROC __rglgen_glDeleteVertexArrays;\nextern RGLSYMGLGENVERTEXARRAYSPROC __rglgen_glGenVertexArrays;\nextern RGLSYMGLISVERTEXARRAYPROC __rglgen_glIsVertexArray;\nextern RGLSYMGLDRAWARRAYSINSTANCEDPROC __rglgen_glDrawArraysInstanced;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDPROC __rglgen_glDrawElementsInstanced;\nextern RGLSYMGLTEXBUFFERPROC __rglgen_glTexBuffer;\nextern RGLSYMGLPRIMITIVERESTARTINDEXPROC __rglgen_glPrimitiveRestartIndex;\nextern RGLSYMGLCOPYBUFFERSUBDATAPROC __rglgen_glCopyBufferSubData;\nextern RGLSYMGLGETUNIFORMINDICESPROC __rglgen_glGetUniformIndices;\nextern RGLSYMGLGETACTIVEUNIFORMSIVPROC __rglgen_glGetActiveUniformsiv;\nextern RGLSYMGLGETACTIVEUNIFORMNAMEPROC __rglgen_glGetActiveUniformName;\nextern RGLSYMGLGETUNIFORMBLOCKINDEXPROC __rglgen_glGetUniformBlockIndex;\nextern RGLSYMGLGETACTIVEUNIFORMBLOCKIVPROC __rglgen_glGetActiveUniformBlockiv;\nextern RGLSYMGLGETACTIVEUNIFORMBLOCKNAMEPROC __rglgen_glGetActiveUniformBlockName;\nextern RGLSYMGLUNIFORMBLOCKBINDINGPROC __rglgen_glUniformBlockBinding;\nextern RGLSYMGLDRAWELEMENTSBASEVERTEXPROC __rglgen_glDrawElementsBaseVertex;\nextern RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXPROC __rglgen_glDrawRangeElementsBaseVertex;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC __rglgen_glDrawElementsInstancedBaseVertex;\nextern RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXPROC __rglgen_glMultiDrawElementsBaseVertex;\nextern RGLSYMGLPROVOKINGVERTEXPROC __rglgen_glProvokingVertex;\nextern RGLSYMGLFENCESYNCPROC __rglgen_glFenceSync;\nextern RGLSYMGLISSYNCPROC __rglgen_glIsSync;\nextern RGLSYMGLDELETESYNCPROC __rglgen_glDeleteSync;\nextern RGLSYMGLCLIENTWAITSYNCPROC __rglgen_glClientWaitSync;\nextern RGLSYMGLWAITSYNCPROC __rglgen_glWaitSync;\nextern RGLSYMGLGETINTEGER64VPROC __rglgen_glGetInteger64v;\nextern RGLSYMGLGETSYNCIVPROC __rglgen_glGetSynciv;\nextern RGLSYMGLGETINTEGER64I_VPROC __rglgen_glGetInteger64i_v;\nextern RGLSYMGLGETBUFFERPARAMETERI64VPROC __rglgen_glGetBufferParameteri64v;\nextern RGLSYMGLFRAMEBUFFERTEXTUREPROC __rglgen_glFramebufferTexture;\nextern RGLSYMGLTEXIMAGE2DMULTISAMPLEPROC __rglgen_glTexImage2DMultisample;\nextern RGLSYMGLTEXIMAGE3DMULTISAMPLEPROC __rglgen_glTexImage3DMultisample;\nextern RGLSYMGLGETMULTISAMPLEFVPROC __rglgen_glGetMultisamplefv;\nextern RGLSYMGLSAMPLEMASKIPROC __rglgen_glSampleMaski;\nextern RGLSYMGLBINDFRAGDATALOCATIONINDEXEDPROC __rglgen_glBindFragDataLocationIndexed;\nextern RGLSYMGLGETFRAGDATAINDEXPROC __rglgen_glGetFragDataIndex;\nextern RGLSYMGLGENSAMPLERSPROC __rglgen_glGenSamplers;\nextern RGLSYMGLDELETESAMPLERSPROC __rglgen_glDeleteSamplers;\nextern RGLSYMGLISSAMPLERPROC __rglgen_glIsSampler;\nextern RGLSYMGLBINDSAMPLERPROC __rglgen_glBindSampler;\nextern RGLSYMGLSAMPLERPARAMETERIPROC __rglgen_glSamplerParameteri;\nextern RGLSYMGLSAMPLERPARAMETERIVPROC __rglgen_glSamplerParameteriv;\nextern RGLSYMGLSAMPLERPARAMETERFPROC __rglgen_glSamplerParameterf;\nextern RGLSYMGLSAMPLERPARAMETERFVPROC __rglgen_glSamplerParameterfv;\nextern RGLSYMGLSAMPLERPARAMETERIIVPROC __rglgen_glSamplerParameterIiv;\nextern RGLSYMGLSAMPLERPARAMETERIUIVPROC __rglgen_glSamplerParameterIuiv;\nextern RGLSYMGLGETSAMPLERPARAMETERIVPROC __rglgen_glGetSamplerParameteriv;\nextern RGLSYMGLGETSAMPLERPARAMETERIIVPROC __rglgen_glGetSamplerParameterIiv;\nextern RGLSYMGLGETSAMPLERPARAMETERFVPROC __rglgen_glGetSamplerParameterfv;\nextern RGLSYMGLGETSAMPLERPARAMETERIUIVPROC __rglgen_glGetSamplerParameterIuiv;\nextern RGLSYMGLQUERYCOUNTERPROC __rglgen_glQueryCounter;\nextern RGLSYMGLGETQUERYOBJECTI64VPROC __rglgen_glGetQueryObjecti64v;\nextern RGLSYMGLGETQUERYOBJECTUI64VPROC __rglgen_glGetQueryObjectui64v;\nextern RGLSYMGLVERTEXATTRIBDIVISORPROC __rglgen_glVertexAttribDivisor;\nextern RGLSYMGLVERTEXATTRIBP1UIPROC __rglgen_glVertexAttribP1ui;\nextern RGLSYMGLVERTEXATTRIBP1UIVPROC __rglgen_glVertexAttribP1uiv;\nextern RGLSYMGLVERTEXATTRIBP2UIPROC __rglgen_glVertexAttribP2ui;\nextern RGLSYMGLVERTEXATTRIBP2UIVPROC __rglgen_glVertexAttribP2uiv;\nextern RGLSYMGLVERTEXATTRIBP3UIPROC __rglgen_glVertexAttribP3ui;\nextern RGLSYMGLVERTEXATTRIBP3UIVPROC __rglgen_glVertexAttribP3uiv;\nextern RGLSYMGLVERTEXATTRIBP4UIPROC __rglgen_glVertexAttribP4ui;\nextern RGLSYMGLVERTEXATTRIBP4UIVPROC __rglgen_glVertexAttribP4uiv;\nextern RGLSYMGLVERTEXP2UIPROC __rglgen_glVertexP2ui;\nextern RGLSYMGLVERTEXP2UIVPROC __rglgen_glVertexP2uiv;\nextern RGLSYMGLVERTEXP3UIPROC __rglgen_glVertexP3ui;\nextern RGLSYMGLVERTEXP3UIVPROC __rglgen_glVertexP3uiv;\nextern RGLSYMGLVERTEXP4UIPROC __rglgen_glVertexP4ui;\nextern RGLSYMGLVERTEXP4UIVPROC __rglgen_glVertexP4uiv;\nextern RGLSYMGLTEXCOORDP1UIPROC __rglgen_glTexCoordP1ui;\nextern RGLSYMGLTEXCOORDP1UIVPROC __rglgen_glTexCoordP1uiv;\nextern RGLSYMGLTEXCOORDP2UIPROC __rglgen_glTexCoordP2ui;\nextern RGLSYMGLTEXCOORDP2UIVPROC __rglgen_glTexCoordP2uiv;\nextern RGLSYMGLTEXCOORDP3UIPROC __rglgen_glTexCoordP3ui;\nextern RGLSYMGLTEXCOORDP3UIVPROC __rglgen_glTexCoordP3uiv;\nextern RGLSYMGLTEXCOORDP4UIPROC __rglgen_glTexCoordP4ui;\nextern RGLSYMGLTEXCOORDP4UIVPROC __rglgen_glTexCoordP4uiv;\nextern RGLSYMGLMULTITEXCOORDP1UIPROC __rglgen_glMultiTexCoordP1ui;\nextern RGLSYMGLMULTITEXCOORDP1UIVPROC __rglgen_glMultiTexCoordP1uiv;\nextern RGLSYMGLMULTITEXCOORDP2UIPROC __rglgen_glMultiTexCoordP2ui;\nextern RGLSYMGLMULTITEXCOORDP2UIVPROC __rglgen_glMultiTexCoordP2uiv;\nextern RGLSYMGLMULTITEXCOORDP3UIPROC __rglgen_glMultiTexCoordP3ui;\nextern RGLSYMGLMULTITEXCOORDP3UIVPROC __rglgen_glMultiTexCoordP3uiv;\nextern RGLSYMGLMULTITEXCOORDP4UIPROC __rglgen_glMultiTexCoordP4ui;\nextern RGLSYMGLMULTITEXCOORDP4UIVPROC __rglgen_glMultiTexCoordP4uiv;\nextern RGLSYMGLNORMALP3UIPROC __rglgen_glNormalP3ui;\nextern RGLSYMGLNORMALP3UIVPROC __rglgen_glNormalP3uiv;\nextern RGLSYMGLCOLORP3UIPROC __rglgen_glColorP3ui;\nextern RGLSYMGLCOLORP3UIVPROC __rglgen_glColorP3uiv;\nextern RGLSYMGLCOLORP4UIPROC __rglgen_glColorP4ui;\nextern RGLSYMGLCOLORP4UIVPROC __rglgen_glColorP4uiv;\nextern RGLSYMGLSECONDARYCOLORP3UIPROC __rglgen_glSecondaryColorP3ui;\nextern RGLSYMGLSECONDARYCOLORP3UIVPROC __rglgen_glSecondaryColorP3uiv;\nextern RGLSYMGLMINSAMPLESHADINGPROC __rglgen_glMinSampleShading;\nextern RGLSYMGLBLENDEQUATIONIPROC __rglgen_glBlendEquationi;\nextern RGLSYMGLBLENDEQUATIONSEPARATEIPROC __rglgen_glBlendEquationSeparatei;\nextern RGLSYMGLBLENDFUNCIPROC __rglgen_glBlendFunci;\nextern RGLSYMGLBLENDFUNCSEPARATEIPROC __rglgen_glBlendFuncSeparatei;\nextern RGLSYMGLDRAWARRAYSINDIRECTPROC __rglgen_glDrawArraysIndirect;\nextern RGLSYMGLDRAWELEMENTSINDIRECTPROC __rglgen_glDrawElementsIndirect;\nextern RGLSYMGLUNIFORM1DPROC __rglgen_glUniform1d;\nextern RGLSYMGLUNIFORM2DPROC __rglgen_glUniform2d;\nextern RGLSYMGLUNIFORM3DPROC __rglgen_glUniform3d;\nextern RGLSYMGLUNIFORM4DPROC __rglgen_glUniform4d;\nextern RGLSYMGLUNIFORM1DVPROC __rglgen_glUniform1dv;\nextern RGLSYMGLUNIFORM2DVPROC __rglgen_glUniform2dv;\nextern RGLSYMGLUNIFORM3DVPROC __rglgen_glUniform3dv;\nextern RGLSYMGLUNIFORM4DVPROC __rglgen_glUniform4dv;\nextern RGLSYMGLUNIFORMMATRIX2DVPROC __rglgen_glUniformMatrix2dv;\nextern RGLSYMGLUNIFORMMATRIX3DVPROC __rglgen_glUniformMatrix3dv;\nextern RGLSYMGLUNIFORMMATRIX4DVPROC __rglgen_glUniformMatrix4dv;\nextern RGLSYMGLUNIFORMMATRIX2X3DVPROC __rglgen_glUniformMatrix2x3dv;\nextern RGLSYMGLUNIFORMMATRIX2X4DVPROC __rglgen_glUniformMatrix2x4dv;\nextern RGLSYMGLUNIFORMMATRIX3X2DVPROC __rglgen_glUniformMatrix3x2dv;\nextern RGLSYMGLUNIFORMMATRIX3X4DVPROC __rglgen_glUniformMatrix3x4dv;\nextern RGLSYMGLUNIFORMMATRIX4X2DVPROC __rglgen_glUniformMatrix4x2dv;\nextern RGLSYMGLUNIFORMMATRIX4X3DVPROC __rglgen_glUniformMatrix4x3dv;\nextern RGLSYMGLGETUNIFORMDVPROC __rglgen_glGetUniformdv;\nextern RGLSYMGLGETSUBROUTINEUNIFORMLOCATIONPROC __rglgen_glGetSubroutineUniformLocation;\nextern RGLSYMGLGETSUBROUTINEINDEXPROC __rglgen_glGetSubroutineIndex;\nextern RGLSYMGLGETACTIVESUBROUTINEUNIFORMIVPROC __rglgen_glGetActiveSubroutineUniformiv;\nextern RGLSYMGLGETACTIVESUBROUTINEUNIFORMNAMEPROC __rglgen_glGetActiveSubroutineUniformName;\nextern RGLSYMGLGETACTIVESUBROUTINENAMEPROC __rglgen_glGetActiveSubroutineName;\nextern RGLSYMGLUNIFORMSUBROUTINESUIVPROC __rglgen_glUniformSubroutinesuiv;\nextern RGLSYMGLGETUNIFORMSUBROUTINEUIVPROC __rglgen_glGetUniformSubroutineuiv;\nextern RGLSYMGLGETPROGRAMSTAGEIVPROC __rglgen_glGetProgramStageiv;\nextern RGLSYMGLPATCHPARAMETERIPROC __rglgen_glPatchParameteri;\nextern RGLSYMGLPATCHPARAMETERFVPROC __rglgen_glPatchParameterfv;\nextern RGLSYMGLBINDTRANSFORMFEEDBACKPROC __rglgen_glBindTransformFeedback;\nextern RGLSYMGLDELETETRANSFORMFEEDBACKSPROC __rglgen_glDeleteTransformFeedbacks;\nextern RGLSYMGLGENTRANSFORMFEEDBACKSPROC __rglgen_glGenTransformFeedbacks;\nextern RGLSYMGLISTRANSFORMFEEDBACKPROC __rglgen_glIsTransformFeedback;\nextern RGLSYMGLPAUSETRANSFORMFEEDBACKPROC __rglgen_glPauseTransformFeedback;\nextern RGLSYMGLRESUMETRANSFORMFEEDBACKPROC __rglgen_glResumeTransformFeedback;\nextern RGLSYMGLDRAWTRANSFORMFEEDBACKPROC __rglgen_glDrawTransformFeedback;\nextern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMPROC __rglgen_glDrawTransformFeedbackStream;\nextern RGLSYMGLBEGINQUERYINDEXEDPROC __rglgen_glBeginQueryIndexed;\nextern RGLSYMGLENDQUERYINDEXEDPROC __rglgen_glEndQueryIndexed;\nextern RGLSYMGLGETQUERYINDEXEDIVPROC __rglgen_glGetQueryIndexediv;\nextern RGLSYMGLRELEASESHADERCOMPILERPROC __rglgen_glReleaseShaderCompiler;\nextern RGLSYMGLSHADERBINARYPROC __rglgen_glShaderBinary;\nextern RGLSYMGLGETSHADERPRECISIONFORMATPROC __rglgen_glGetShaderPrecisionFormat;\nextern RGLSYMGLDEPTHRANGEFPROC __rglgen_glDepthRangef;\nextern RGLSYMGLCLEARDEPTHFPROC __rglgen_glClearDepthf;\nextern RGLSYMGLGETPROGRAMBINARYPROC __rglgen_glGetProgramBinary;\nextern RGLSYMGLPROGRAMBINARYPROC __rglgen_glProgramBinary;\nextern RGLSYMGLPROGRAMPARAMETERIPROC __rglgen_glProgramParameteri;\nextern RGLSYMGLUSEPROGRAMSTAGESPROC __rglgen_glUseProgramStages;\nextern RGLSYMGLACTIVESHADERPROGRAMPROC __rglgen_glActiveShaderProgram;\nextern RGLSYMGLCREATESHADERPROGRAMVPROC __rglgen_glCreateShaderProgramv;\nextern RGLSYMGLBINDPROGRAMPIPELINEPROC __rglgen_glBindProgramPipeline;\nextern RGLSYMGLDELETEPROGRAMPIPELINESPROC __rglgen_glDeleteProgramPipelines;\nextern RGLSYMGLGENPROGRAMPIPELINESPROC __rglgen_glGenProgramPipelines;\nextern RGLSYMGLISPROGRAMPIPELINEPROC __rglgen_glIsProgramPipeline;\nextern RGLSYMGLGETPROGRAMPIPELINEIVPROC __rglgen_glGetProgramPipelineiv;\nextern RGLSYMGLPROGRAMUNIFORM1IPROC __rglgen_glProgramUniform1i;\nextern RGLSYMGLPROGRAMUNIFORM1IVPROC __rglgen_glProgramUniform1iv;\nextern RGLSYMGLPROGRAMUNIFORM1FPROC __rglgen_glProgramUniform1f;\nextern RGLSYMGLPROGRAMUNIFORM1FVPROC __rglgen_glProgramUniform1fv;\nextern RGLSYMGLPROGRAMUNIFORM1DPROC __rglgen_glProgramUniform1d;\nextern RGLSYMGLPROGRAMUNIFORM1DVPROC __rglgen_glProgramUniform1dv;\nextern RGLSYMGLPROGRAMUNIFORM1UIPROC __rglgen_glProgramUniform1ui;\nextern RGLSYMGLPROGRAMUNIFORM1UIVPROC __rglgen_glProgramUniform1uiv;\nextern RGLSYMGLPROGRAMUNIFORM2IPROC __rglgen_glProgramUniform2i;\nextern RGLSYMGLPROGRAMUNIFORM2IVPROC __rglgen_glProgramUniform2iv;\nextern RGLSYMGLPROGRAMUNIFORM2FPROC __rglgen_glProgramUniform2f;\nextern RGLSYMGLPROGRAMUNIFORM2FVPROC __rglgen_glProgramUniform2fv;\nextern RGLSYMGLPROGRAMUNIFORM2DPROC __rglgen_glProgramUniform2d;\nextern RGLSYMGLPROGRAMUNIFORM2DVPROC __rglgen_glProgramUniform2dv;\nextern RGLSYMGLPROGRAMUNIFORM2UIPROC __rglgen_glProgramUniform2ui;\nextern RGLSYMGLPROGRAMUNIFORM2UIVPROC __rglgen_glProgramUniform2uiv;\nextern RGLSYMGLPROGRAMUNIFORM3IPROC __rglgen_glProgramUniform3i;\nextern RGLSYMGLPROGRAMUNIFORM3IVPROC __rglgen_glProgramUniform3iv;\nextern RGLSYMGLPROGRAMUNIFORM3FPROC __rglgen_glProgramUniform3f;\nextern RGLSYMGLPROGRAMUNIFORM3FVPROC __rglgen_glProgramUniform3fv;\nextern RGLSYMGLPROGRAMUNIFORM3DPROC __rglgen_glProgramUniform3d;\nextern RGLSYMGLPROGRAMUNIFORM3DVPROC __rglgen_glProgramUniform3dv;\nextern RGLSYMGLPROGRAMUNIFORM3UIPROC __rglgen_glProgramUniform3ui;\nextern RGLSYMGLPROGRAMUNIFORM3UIVPROC __rglgen_glProgramUniform3uiv;\nextern RGLSYMGLPROGRAMUNIFORM4IPROC __rglgen_glProgramUniform4i;\nextern RGLSYMGLPROGRAMUNIFORM4IVPROC __rglgen_glProgramUniform4iv;\nextern RGLSYMGLPROGRAMUNIFORM4FPROC __rglgen_glProgramUniform4f;\nextern RGLSYMGLPROGRAMUNIFORM4FVPROC __rglgen_glProgramUniform4fv;\nextern RGLSYMGLPROGRAMUNIFORM4DPROC __rglgen_glProgramUniform4d;\nextern RGLSYMGLPROGRAMUNIFORM4DVPROC __rglgen_glProgramUniform4dv;\nextern RGLSYMGLPROGRAMUNIFORM4UIPROC __rglgen_glProgramUniform4ui;\nextern RGLSYMGLPROGRAMUNIFORM4UIVPROC __rglgen_glProgramUniform4uiv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2FVPROC __rglgen_glProgramUniformMatrix2fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3FVPROC __rglgen_glProgramUniformMatrix3fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4FVPROC __rglgen_glProgramUniformMatrix4fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2DVPROC __rglgen_glProgramUniformMatrix2dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3DVPROC __rglgen_glProgramUniformMatrix3dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4DVPROC __rglgen_glProgramUniformMatrix4dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVPROC __rglgen_glProgramUniformMatrix2x3fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVPROC __rglgen_glProgramUniformMatrix3x2fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVPROC __rglgen_glProgramUniformMatrix2x4fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVPROC __rglgen_glProgramUniformMatrix4x2fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVPROC __rglgen_glProgramUniformMatrix3x4fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVPROC __rglgen_glProgramUniformMatrix4x3fv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X3DVPROC __rglgen_glProgramUniformMatrix2x3dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X2DVPROC __rglgen_glProgramUniformMatrix3x2dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX2X4DVPROC __rglgen_glProgramUniformMatrix2x4dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X2DVPROC __rglgen_glProgramUniformMatrix4x2dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX3X4DVPROC __rglgen_glProgramUniformMatrix3x4dv;\nextern RGLSYMGLPROGRAMUNIFORMMATRIX4X3DVPROC __rglgen_glProgramUniformMatrix4x3dv;\nextern RGLSYMGLVALIDATEPROGRAMPIPELINEPROC __rglgen_glValidateProgramPipeline;\nextern RGLSYMGLGETPROGRAMPIPELINEINFOLOGPROC __rglgen_glGetProgramPipelineInfoLog;\nextern RGLSYMGLVERTEXATTRIBL1DPROC __rglgen_glVertexAttribL1d;\nextern RGLSYMGLVERTEXATTRIBL2DPROC __rglgen_glVertexAttribL2d;\nextern RGLSYMGLVERTEXATTRIBL3DPROC __rglgen_glVertexAttribL3d;\nextern RGLSYMGLVERTEXATTRIBL4DPROC __rglgen_glVertexAttribL4d;\nextern RGLSYMGLVERTEXATTRIBL1DVPROC __rglgen_glVertexAttribL1dv;\nextern RGLSYMGLVERTEXATTRIBL2DVPROC __rglgen_glVertexAttribL2dv;\nextern RGLSYMGLVERTEXATTRIBL3DVPROC __rglgen_glVertexAttribL3dv;\nextern RGLSYMGLVERTEXATTRIBL4DVPROC __rglgen_glVertexAttribL4dv;\nextern RGLSYMGLVERTEXATTRIBLPOINTERPROC __rglgen_glVertexAttribLPointer;\nextern RGLSYMGLGETVERTEXATTRIBLDVPROC __rglgen_glGetVertexAttribLdv;\nextern RGLSYMGLVIEWPORTARRAYVPROC __rglgen_glViewportArrayv;\nextern RGLSYMGLVIEWPORTINDEXEDFPROC __rglgen_glViewportIndexedf;\nextern RGLSYMGLVIEWPORTINDEXEDFVPROC __rglgen_glViewportIndexedfv;\nextern RGLSYMGLSCISSORARRAYVPROC __rglgen_glScissorArrayv;\nextern RGLSYMGLSCISSORINDEXEDPROC __rglgen_glScissorIndexed;\nextern RGLSYMGLSCISSORINDEXEDVPROC __rglgen_glScissorIndexedv;\nextern RGLSYMGLDEPTHRANGEARRAYVPROC __rglgen_glDepthRangeArrayv;\nextern RGLSYMGLDEPTHRANGEINDEXEDPROC __rglgen_glDepthRangeIndexed;\nextern RGLSYMGLGETFLOATI_VPROC __rglgen_glGetFloati_v;\nextern RGLSYMGLGETDOUBLEI_VPROC __rglgen_glGetDoublei_v;\nextern RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawArraysInstancedBaseInstance;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseInstance;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstance;\nextern RGLSYMGLGETINTERNALFORMATIVPROC __rglgen_glGetInternalformativ;\nextern RGLSYMGLGETACTIVEATOMICCOUNTERBUFFERIVPROC __rglgen_glGetActiveAtomicCounterBufferiv;\nextern RGLSYMGLBINDIMAGETEXTUREPROC __rglgen_glBindImageTexture;\nextern RGLSYMGLMEMORYBARRIERPROC __rglgen_glMemoryBarrier;\nextern RGLSYMGLTEXSTORAGE1DPROC __rglgen_glTexStorage1D;\nextern RGLSYMGLTEXSTORAGE2DPROC __rglgen_glTexStorage2D;\nextern RGLSYMGLTEXSTORAGE3DPROC __rglgen_glTexStorage3D;\nextern RGLSYMGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC __rglgen_glDrawTransformFeedbackInstanced;\nextern RGLSYMGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC __rglgen_glDrawTransformFeedbackStreamInstanced;\nextern RGLSYMGLCLEARBUFFERDATAPROC __rglgen_glClearBufferData;\nextern RGLSYMGLCLEARBUFFERSUBDATAPROC __rglgen_glClearBufferSubData;\nextern RGLSYMGLDISPATCHCOMPUTEPROC __rglgen_glDispatchCompute;\nextern RGLSYMGLDISPATCHCOMPUTEINDIRECTPROC __rglgen_glDispatchComputeIndirect;\nextern RGLSYMGLCOPYIMAGESUBDATAPROC __rglgen_glCopyImageSubData;\nextern RGLSYMGLFRAMEBUFFERPARAMETERIPROC __rglgen_glFramebufferParameteri;\nextern RGLSYMGLGETFRAMEBUFFERPARAMETERIVPROC __rglgen_glGetFramebufferParameteriv;\nextern RGLSYMGLGETINTERNALFORMATI64VPROC __rglgen_glGetInternalformati64v;\nextern RGLSYMGLINVALIDATETEXSUBIMAGEPROC __rglgen_glInvalidateTexSubImage;\nextern RGLSYMGLINVALIDATETEXIMAGEPROC __rglgen_glInvalidateTexImage;\nextern RGLSYMGLINVALIDATEBUFFERSUBDATAPROC __rglgen_glInvalidateBufferSubData;\nextern RGLSYMGLINVALIDATEBUFFERDATAPROC __rglgen_glInvalidateBufferData;\nextern RGLSYMGLINVALIDATEFRAMEBUFFERPROC __rglgen_glInvalidateFramebuffer;\nextern RGLSYMGLINVALIDATESUBFRAMEBUFFERPROC __rglgen_glInvalidateSubFramebuffer;\nextern RGLSYMGLMULTIDRAWARRAYSINDIRECTPROC __rglgen_glMultiDrawArraysIndirect;\nextern RGLSYMGLMULTIDRAWELEMENTSINDIRECTPROC __rglgen_glMultiDrawElementsIndirect;\nextern RGLSYMGLGETPROGRAMINTERFACEIVPROC __rglgen_glGetProgramInterfaceiv;\nextern RGLSYMGLGETPROGRAMRESOURCEINDEXPROC __rglgen_glGetProgramResourceIndex;\nextern RGLSYMGLGETPROGRAMRESOURCENAMEPROC __rglgen_glGetProgramResourceName;\nextern RGLSYMGLGETPROGRAMRESOURCEIVPROC __rglgen_glGetProgramResourceiv;\nextern RGLSYMGLGETPROGRAMRESOURCELOCATIONPROC __rglgen_glGetProgramResourceLocation;\nextern RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXPROC __rglgen_glGetProgramResourceLocationIndex;\nextern RGLSYMGLSHADERSTORAGEBLOCKBINDINGPROC __rglgen_glShaderStorageBlockBinding;\nextern RGLSYMGLTEXBUFFERRANGEPROC __rglgen_glTexBufferRange;\nextern RGLSYMGLTEXSTORAGE2DMULTISAMPLEPROC __rglgen_glTexStorage2DMultisample;\nextern RGLSYMGLTEXSTORAGE3DMULTISAMPLEPROC __rglgen_glTexStorage3DMultisample;\nextern RGLSYMGLTEXTUREVIEWPROC __rglgen_glTextureView;\nextern RGLSYMGLBINDVERTEXBUFFERPROC __rglgen_glBindVertexBuffer;\nextern RGLSYMGLVERTEXATTRIBFORMATPROC __rglgen_glVertexAttribFormat;\nextern RGLSYMGLVERTEXATTRIBIFORMATPROC __rglgen_glVertexAttribIFormat;\nextern RGLSYMGLVERTEXATTRIBLFORMATPROC __rglgen_glVertexAttribLFormat;\nextern RGLSYMGLVERTEXATTRIBBINDINGPROC __rglgen_glVertexAttribBinding;\nextern RGLSYMGLVERTEXBINDINGDIVISORPROC __rglgen_glVertexBindingDivisor;\nextern RGLSYMGLDEBUGMESSAGECONTROLPROC __rglgen_glDebugMessageControl;\nextern RGLSYMGLDEBUGMESSAGEINSERTPROC __rglgen_glDebugMessageInsert;\nextern RGLSYMGLDEBUGMESSAGECALLBACKPROC __rglgen_glDebugMessageCallback;\nextern RGLSYMGLGETDEBUGMESSAGELOGPROC __rglgen_glGetDebugMessageLog;\nextern RGLSYMGLPUSHDEBUGGROUPPROC __rglgen_glPushDebugGroup;\nextern RGLSYMGLPOPDEBUGGROUPPROC __rglgen_glPopDebugGroup;\nextern RGLSYMGLOBJECTLABELPROC __rglgen_glObjectLabel;\nextern RGLSYMGLGETOBJECTLABELPROC __rglgen_glGetObjectLabel;\nextern RGLSYMGLOBJECTPTRLABELPROC __rglgen_glObjectPtrLabel;\nextern RGLSYMGLGETOBJECTPTRLABELPROC __rglgen_glGetObjectPtrLabel;\nextern RGLSYMGLBUFFERSTORAGEPROC __rglgen_glBufferStorage;\nextern RGLSYMGLCLEARTEXIMAGEPROC __rglgen_glClearTexImage;\nextern RGLSYMGLCLEARTEXSUBIMAGEPROC __rglgen_glClearTexSubImage;\nextern RGLSYMGLBINDBUFFERSBASEPROC __rglgen_glBindBuffersBase;\nextern RGLSYMGLBINDBUFFERSRANGEPROC __rglgen_glBindBuffersRange;\nextern RGLSYMGLBINDTEXTURESPROC __rglgen_glBindTextures;\nextern RGLSYMGLBINDSAMPLERSPROC __rglgen_glBindSamplers;\nextern RGLSYMGLBINDIMAGETEXTURESPROC __rglgen_glBindImageTextures;\nextern RGLSYMGLBINDVERTEXBUFFERSPROC __rglgen_glBindVertexBuffers;\nextern RGLSYMGLGETTEXTUREHANDLEARBPROC __rglgen_glGetTextureHandleARB;\nextern RGLSYMGLGETTEXTURESAMPLERHANDLEARBPROC __rglgen_glGetTextureSamplerHandleARB;\nextern RGLSYMGLMAKETEXTUREHANDLERESIDENTARBPROC __rglgen_glMakeTextureHandleResidentARB;\nextern RGLSYMGLMAKETEXTUREHANDLENONRESIDENTARBPROC __rglgen_glMakeTextureHandleNonResidentARB;\nextern RGLSYMGLGETIMAGEHANDLEARBPROC __rglgen_glGetImageHandleARB;\nextern RGLSYMGLMAKEIMAGEHANDLERESIDENTARBPROC __rglgen_glMakeImageHandleResidentARB;\nextern RGLSYMGLMAKEIMAGEHANDLENONRESIDENTARBPROC __rglgen_glMakeImageHandleNonResidentARB;\nextern RGLSYMGLUNIFORMHANDLEUI64ARBPROC __rglgen_glUniformHandleui64ARB;\nextern RGLSYMGLUNIFORMHANDLEUI64VARBPROC __rglgen_glUniformHandleui64vARB;\nextern RGLSYMGLPROGRAMUNIFORMHANDLEUI64ARBPROC __rglgen_glProgramUniformHandleui64ARB;\nextern RGLSYMGLPROGRAMUNIFORMHANDLEUI64VARBPROC __rglgen_glProgramUniformHandleui64vARB;\nextern RGLSYMGLISTEXTUREHANDLERESIDENTARBPROC __rglgen_glIsTextureHandleResidentARB;\nextern RGLSYMGLISIMAGEHANDLERESIDENTARBPROC __rglgen_glIsImageHandleResidentARB;\nextern RGLSYMGLVERTEXATTRIBL1UI64ARBPROC __rglgen_glVertexAttribL1ui64ARB;\nextern RGLSYMGLVERTEXATTRIBL1UI64VARBPROC __rglgen_glVertexAttribL1ui64vARB;\nextern RGLSYMGLGETVERTEXATTRIBLUI64VARBPROC __rglgen_glGetVertexAttribLui64vARB;\nextern RGLSYMGLCREATESYNCFROMCLEVENTARBPROC __rglgen_glCreateSyncFromCLeventARB;\nextern RGLSYMGLCLAMPCOLORARBPROC __rglgen_glClampColorARB;\nextern RGLSYMGLDISPATCHCOMPUTEGROUPSIZEARBPROC __rglgen_glDispatchComputeGroupSizeARB;\nextern RGLSYMGLDEBUGMESSAGECONTROLARBPROC __rglgen_glDebugMessageControlARB;\nextern RGLSYMGLDEBUGMESSAGEINSERTARBPROC __rglgen_glDebugMessageInsertARB;\nextern RGLSYMGLDEBUGMESSAGECALLBACKARBPROC __rglgen_glDebugMessageCallbackARB;\nextern RGLSYMGLGETDEBUGMESSAGELOGARBPROC __rglgen_glGetDebugMessageLogARB;\nextern RGLSYMGLDRAWBUFFERSARBPROC __rglgen_glDrawBuffersARB;\nextern RGLSYMGLBLENDEQUATIONIARBPROC __rglgen_glBlendEquationiARB;\nextern RGLSYMGLBLENDEQUATIONSEPARATEIARBPROC __rglgen_glBlendEquationSeparateiARB;\nextern RGLSYMGLBLENDFUNCIARBPROC __rglgen_glBlendFunciARB;\nextern RGLSYMGLBLENDFUNCSEPARATEIARBPROC __rglgen_glBlendFuncSeparateiARB;\nextern RGLSYMGLDRAWARRAYSINSTANCEDARBPROC __rglgen_glDrawArraysInstancedARB;\nextern RGLSYMGLDRAWELEMENTSINSTANCEDARBPROC __rglgen_glDrawElementsInstancedARB;\nextern RGLSYMGLPROGRAMSTRINGARBPROC __rglgen_glProgramStringARB;\nextern RGLSYMGLBINDPROGRAMARBPROC __rglgen_glBindProgramARB;\nextern RGLSYMGLDELETEPROGRAMSARBPROC __rglgen_glDeleteProgramsARB;\nextern RGLSYMGLGENPROGRAMSARBPROC __rglgen_glGenProgramsARB;\nextern RGLSYMGLPROGRAMENVPARAMETER4DARBPROC __rglgen_glProgramEnvParameter4dARB;\nextern RGLSYMGLPROGRAMENVPARAMETER4DVARBPROC __rglgen_glProgramEnvParameter4dvARB;\nextern RGLSYMGLPROGRAMENVPARAMETER4FARBPROC __rglgen_glProgramEnvParameter4fARB;\nextern RGLSYMGLPROGRAMENVPARAMETER4FVARBPROC __rglgen_glProgramEnvParameter4fvARB;\nextern RGLSYMGLPROGRAMLOCALPARAMETER4DARBPROC __rglgen_glProgramLocalParameter4dARB;\nextern RGLSYMGLPROGRAMLOCALPARAMETER4DVARBPROC __rglgen_glProgramLocalParameter4dvARB;\nextern RGLSYMGLPROGRAMLOCALPARAMETER4FARBPROC __rglgen_glProgramLocalParameter4fARB;\nextern RGLSYMGLPROGRAMLOCALPARAMETER4FVARBPROC __rglgen_glProgramLocalParameter4fvARB;\nextern RGLSYMGLGETPROGRAMENVPARAMETERDVARBPROC __rglgen_glGetProgramEnvParameterdvARB;\nextern RGLSYMGLGETPROGRAMENVPARAMETERFVARBPROC __rglgen_glGetProgramEnvParameterfvARB;\nextern RGLSYMGLGETPROGRAMLOCALPARAMETERDVARBPROC __rglgen_glGetProgramLocalParameterdvARB;\nextern RGLSYMGLGETPROGRAMLOCALPARAMETERFVARBPROC __rglgen_glGetProgramLocalParameterfvARB;\nextern RGLSYMGLGETPROGRAMIVARBPROC __rglgen_glGetProgramivARB;\nextern RGLSYMGLGETPROGRAMSTRINGARBPROC __rglgen_glGetProgramStringARB;\nextern RGLSYMGLISPROGRAMARBPROC __rglgen_glIsProgramARB;\nextern RGLSYMGLPROGRAMPARAMETERIARBPROC __rglgen_glProgramParameteriARB;\nextern RGLSYMGLFRAMEBUFFERTEXTUREARBPROC __rglgen_glFramebufferTextureARB;\nextern RGLSYMGLFRAMEBUFFERTEXTURELAYERARBPROC __rglgen_glFramebufferTextureLayerARB;\nextern RGLSYMGLFRAMEBUFFERTEXTUREFACEARBPROC __rglgen_glFramebufferTextureFaceARB;\nextern RGLSYMGLCOLORTABLEPROC __rglgen_glColorTable;\nextern RGLSYMGLCOLORTABLEPARAMETERFVPROC __rglgen_glColorTableParameterfv;\nextern RGLSYMGLCOLORTABLEPARAMETERIVPROC __rglgen_glColorTableParameteriv;\nextern RGLSYMGLCOPYCOLORTABLEPROC __rglgen_glCopyColorTable;\nextern RGLSYMGLGETCOLORTABLEPROC __rglgen_glGetColorTable;\nextern RGLSYMGLGETCOLORTABLEPARAMETERFVPROC __rglgen_glGetColorTableParameterfv;\nextern RGLSYMGLGETCOLORTABLEPARAMETERIVPROC __rglgen_glGetColorTableParameteriv;\nextern RGLSYMGLCOLORSUBTABLEPROC __rglgen_glColorSubTable;\nextern RGLSYMGLCOPYCOLORSUBTABLEPROC __rglgen_glCopyColorSubTable;\nextern RGLSYMGLCONVOLUTIONFILTER1DPROC __rglgen_glConvolutionFilter1D;\nextern RGLSYMGLCONVOLUTIONFILTER2DPROC __rglgen_glConvolutionFilter2D;\nextern RGLSYMGLCONVOLUTIONPARAMETERFPROC __rglgen_glConvolutionParameterf;\nextern RGLSYMGLCONVOLUTIONPARAMETERFVPROC __rglgen_glConvolutionParameterfv;\nextern RGLSYMGLCONVOLUTIONPARAMETERIPROC __rglgen_glConvolutionParameteri;\nextern RGLSYMGLCONVOLUTIONPARAMETERIVPROC __rglgen_glConvolutionParameteriv;\nextern RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC __rglgen_glCopyConvolutionFilter1D;\nextern RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC __rglgen_glCopyConvolutionFilter2D;\nextern RGLSYMGLGETCONVOLUTIONFILTERPROC __rglgen_glGetConvolutionFilter;\nextern RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC __rglgen_glGetConvolutionParameterfv;\nextern RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC __rglgen_glGetConvolutionParameteriv;\nextern RGLSYMGLGETSEPARABLEFILTERPROC __rglgen_glGetSeparableFilter;\nextern RGLSYMGLSEPARABLEFILTER2DPROC __rglgen_glSeparableFilter2D;\nextern RGLSYMGLGETHISTOGRAMPROC __rglgen_glGetHistogram;\nextern RGLSYMGLGETHISTOGRAMPARAMETERFVPROC __rglgen_glGetHistogramParameterfv;\nextern RGLSYMGLGETHISTOGRAMPARAMETERIVPROC __rglgen_glGetHistogramParameteriv;\nextern RGLSYMGLGETMINMAXPROC __rglgen_glGetMinmax;\nextern RGLSYMGLGETMINMAXPARAMETERFVPROC __rglgen_glGetMinmaxParameterfv;\nextern RGLSYMGLGETMINMAXPARAMETERIVPROC __rglgen_glGetMinmaxParameteriv;\nextern RGLSYMGLHISTOGRAMPROC __rglgen_glHistogram;\nextern RGLSYMGLMINMAXPROC __rglgen_glMinmax;\nextern RGLSYMGLRESETHISTOGRAMPROC __rglgen_glResetHistogram;\nextern RGLSYMGLRESETMINMAXPROC __rglgen_glResetMinmax;\nextern RGLSYMGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawArraysIndirectCountARB;\nextern RGLSYMGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __rglgen_glMultiDrawElementsIndirectCountARB;\nextern RGLSYMGLVERTEXATTRIBDIVISORARBPROC __rglgen_glVertexAttribDivisorARB;\nextern RGLSYMGLCURRENTPALETTEMATRIXARBPROC __rglgen_glCurrentPaletteMatrixARB;\nextern RGLSYMGLMATRIXINDEXUBVARBPROC __rglgen_glMatrixIndexubvARB;\nextern RGLSYMGLMATRIXINDEXUSVARBPROC __rglgen_glMatrixIndexusvARB;\nextern RGLSYMGLMATRIXINDEXUIVARBPROC __rglgen_glMatrixIndexuivARB;\nextern RGLSYMGLMATRIXINDEXPOINTERARBPROC __rglgen_glMatrixIndexPointerARB;\nextern RGLSYMGLSAMPLECOVERAGEARBPROC __rglgen_glSampleCoverageARB;\nextern RGLSYMGLACTIVETEXTUREARBPROC __rglgen_glActiveTextureARB;\nextern RGLSYMGLCLIENTACTIVETEXTUREARBPROC __rglgen_glClientActiveTextureARB;\nextern RGLSYMGLMULTITEXCOORD1DARBPROC __rglgen_glMultiTexCoord1dARB;\nextern RGLSYMGLMULTITEXCOORD1DVARBPROC __rglgen_glMultiTexCoord1dvARB;\nextern RGLSYMGLMULTITEXCOORD1FARBPROC __rglgen_glMultiTexCoord1fARB;\nextern RGLSYMGLMULTITEXCOORD1FVARBPROC __rglgen_glMultiTexCoord1fvARB;\nextern RGLSYMGLMULTITEXCOORD1IARBPROC __rglgen_glMultiTexCoord1iARB;\nextern RGLSYMGLMULTITEXCOORD1IVARBPROC __rglgen_glMultiTexCoord1ivARB;\nextern RGLSYMGLMULTITEXCOORD1SARBPROC __rglgen_glMultiTexCoord1sARB;\nextern RGLSYMGLMULTITEXCOORD1SVARBPROC __rglgen_glMultiTexCoord1svARB;\nextern RGLSYMGLMULTITEXCOORD2DARBPROC __rglgen_glMultiTexCoord2dARB;\nextern RGLSYMGLMULTITEXCOORD2DVARBPROC __rglgen_glMultiTexCoord2dvARB;\nextern RGLSYMGLMULTITEXCOORD2FARBPROC __rglgen_glMultiTexCoord2fARB;\nextern RGLSYMGLMULTITEXCOORD2FVARBPROC __rglgen_glMultiTexCoord2fvARB;\nextern RGLSYMGLMULTITEXCOORD2IARBPROC __rglgen_glMultiTexCoord2iARB;\nextern RGLSYMGLMULTITEXCOORD2IVARBPROC __rglgen_glMultiTexCoord2ivARB;\nextern RGLSYMGLMULTITEXCOORD2SARBPROC __rglgen_glMultiTexCoord2sARB;\nextern RGLSYMGLMULTITEXCOORD2SVARBPROC __rglgen_glMultiTexCoord2svARB;\nextern RGLSYMGLMULTITEXCOORD3DARBPROC __rglgen_glMultiTexCoord3dARB;\nextern RGLSYMGLMULTITEXCOORD3DVARBPROC __rglgen_glMultiTexCoord3dvARB;\nextern RGLSYMGLMULTITEXCOORD3FARBPROC __rglgen_glMultiTexCoord3fARB;\nextern RGLSYMGLMULTITEXCOORD3FVARBPROC __rglgen_glMultiTexCoord3fvARB;\nextern RGLSYMGLMULTITEXCOORD3IARBPROC __rglgen_glMultiTexCoord3iARB;\nextern RGLSYMGLMULTITEXCOORD3IVARBPROC __rglgen_glMultiTexCoord3ivARB;\nextern RGLSYMGLMULTITEXCOORD3SARBPROC __rglgen_glMultiTexCoord3sARB;\nextern RGLSYMGLMULTITEXCOORD3SVARBPROC __rglgen_glMultiTexCoord3svARB;\nextern RGLSYMGLMULTITEXCOORD4DARBPROC __rglgen_glMultiTexCoord4dARB;\nextern RGLSYMGLMULTITEXCOORD4DVARBPROC __rglgen_glMultiTexCoord4dvARB;\nextern RGLSYMGLMULTITEXCOORD4FARBPROC __rglgen_glMultiTexCoord4fARB;\nextern RGLSYMGLMULTITEXCOORD4FVARBPROC __rglgen_glMultiTexCoord4fvARB;\nextern RGLSYMGLMULTITEXCOORD4IARBPROC __rglgen_glMultiTexCoord4iARB;\nextern RGLSYMGLMULTITEXCOORD4IVARBPROC __rglgen_glMultiTexCoord4ivARB;\nextern RGLSYMGLMULTITEXCOORD4SARBPROC __rglgen_glMultiTexCoord4sARB;\nextern RGLSYMGLMULTITEXCOORD4SVARBPROC __rglgen_glMultiTexCoord4svARB;\nextern RGLSYMGLGENQUERIESARBPROC __rglgen_glGenQueriesARB;\nextern RGLSYMGLDELETEQUERIESARBPROC __rglgen_glDeleteQueriesARB;\nextern RGLSYMGLISQUERYARBPROC __rglgen_glIsQueryARB;\nextern RGLSYMGLBEGINQUERYARBPROC __rglgen_glBeginQueryARB;\nextern RGLSYMGLENDQUERYARBPROC __rglgen_glEndQueryARB;\nextern RGLSYMGLGETQUERYIVARBPROC __rglgen_glGetQueryivARB;\nextern RGLSYMGLGETQUERYOBJECTIVARBPROC __rglgen_glGetQueryObjectivARB;\nextern RGLSYMGLGETQUERYOBJECTUIVARBPROC __rglgen_glGetQueryObjectuivARB;\nextern RGLSYMGLPOINTPARAMETERFARBPROC __rglgen_glPointParameterfARB;\nextern RGLSYMGLPOINTPARAMETERFVARBPROC __rglgen_glPointParameterfvARB;\nextern RGLSYMGLGETGRAPHICSRESETSTATUSARBPROC __rglgen_glGetGraphicsResetStatusARB;\nextern RGLSYMGLGETNTEXIMAGEARBPROC __rglgen_glGetnTexImageARB;\nextern RGLSYMGLREADNPIXELSARBPROC __rglgen_glReadnPixelsARB;\nextern RGLSYMGLGETNCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetnCompressedTexImageARB;\nextern RGLSYMGLGETNUNIFORMFVARBPROC __rglgen_glGetnUniformfvARB;\nextern RGLSYMGLGETNUNIFORMIVARBPROC __rglgen_glGetnUniformivARB;\nextern RGLSYMGLGETNUNIFORMUIVARBPROC __rglgen_glGetnUniformuivARB;\nextern RGLSYMGLGETNUNIFORMDVARBPROC __rglgen_glGetnUniformdvARB;\nextern RGLSYMGLGETNMAPDVARBPROC __rglgen_glGetnMapdvARB;\nextern RGLSYMGLGETNMAPFVARBPROC __rglgen_glGetnMapfvARB;\nextern RGLSYMGLGETNMAPIVARBPROC __rglgen_glGetnMapivARB;\nextern RGLSYMGLGETNPIXELMAPFVARBPROC __rglgen_glGetnPixelMapfvARB;\nextern RGLSYMGLGETNPIXELMAPUIVARBPROC __rglgen_glGetnPixelMapuivARB;\nextern RGLSYMGLGETNPIXELMAPUSVARBPROC __rglgen_glGetnPixelMapusvARB;\nextern RGLSYMGLGETNPOLYGONSTIPPLEARBPROC __rglgen_glGetnPolygonStippleARB;\nextern RGLSYMGLGETNCOLORTABLEARBPROC __rglgen_glGetnColorTableARB;\nextern RGLSYMGLGETNCONVOLUTIONFILTERARBPROC __rglgen_glGetnConvolutionFilterARB;\nextern RGLSYMGLGETNSEPARABLEFILTERARBPROC __rglgen_glGetnSeparableFilterARB;\nextern RGLSYMGLGETNHISTOGRAMARBPROC __rglgen_glGetnHistogramARB;\nextern RGLSYMGLGETNMINMAXARBPROC __rglgen_glGetnMinmaxARB;\nextern RGLSYMGLMINSAMPLESHADINGARBPROC __rglgen_glMinSampleShadingARB;\nextern RGLSYMGLDELETEOBJECTARBPROC __rglgen_glDeleteObjectARB;\nextern RGLSYMGLGETHANDLEARBPROC __rglgen_glGetHandleARB;\nextern RGLSYMGLDETACHOBJECTARBPROC __rglgen_glDetachObjectARB;\nextern RGLSYMGLCREATESHADEROBJECTARBPROC __rglgen_glCreateShaderObjectARB;\nextern RGLSYMGLSHADERSOURCEARBPROC __rglgen_glShaderSourceARB;\nextern RGLSYMGLCOMPILESHADERARBPROC __rglgen_glCompileShaderARB;\nextern RGLSYMGLCREATEPROGRAMOBJECTARBPROC __rglgen_glCreateProgramObjectARB;\nextern RGLSYMGLATTACHOBJECTARBPROC __rglgen_glAttachObjectARB;\nextern RGLSYMGLLINKPROGRAMARBPROC __rglgen_glLinkProgramARB;\nextern RGLSYMGLUSEPROGRAMOBJECTARBPROC __rglgen_glUseProgramObjectARB;\nextern RGLSYMGLVALIDATEPROGRAMARBPROC __rglgen_glValidateProgramARB;\nextern RGLSYMGLUNIFORM1FARBPROC __rglgen_glUniform1fARB;\nextern RGLSYMGLUNIFORM2FARBPROC __rglgen_glUniform2fARB;\nextern RGLSYMGLUNIFORM3FARBPROC __rglgen_glUniform3fARB;\nextern RGLSYMGLUNIFORM4FARBPROC __rglgen_glUniform4fARB;\nextern RGLSYMGLUNIFORM1IARBPROC __rglgen_glUniform1iARB;\nextern RGLSYMGLUNIFORM2IARBPROC __rglgen_glUniform2iARB;\nextern RGLSYMGLUNIFORM3IARBPROC __rglgen_glUniform3iARB;\nextern RGLSYMGLUNIFORM4IARBPROC __rglgen_glUniform4iARB;\nextern RGLSYMGLUNIFORM1FVARBPROC __rglgen_glUniform1fvARB;\nextern RGLSYMGLUNIFORM2FVARBPROC __rglgen_glUniform2fvARB;\nextern RGLSYMGLUNIFORM3FVARBPROC __rglgen_glUniform3fvARB;\nextern RGLSYMGLUNIFORM4FVARBPROC __rglgen_glUniform4fvARB;\nextern RGLSYMGLUNIFORM1IVARBPROC __rglgen_glUniform1ivARB;\nextern RGLSYMGLUNIFORM2IVARBPROC __rglgen_glUniform2ivARB;\nextern RGLSYMGLUNIFORM3IVARBPROC __rglgen_glUniform3ivARB;\nextern RGLSYMGLUNIFORM4IVARBPROC __rglgen_glUniform4ivARB;\nextern RGLSYMGLUNIFORMMATRIX2FVARBPROC __rglgen_glUniformMatrix2fvARB;\nextern RGLSYMGLUNIFORMMATRIX3FVARBPROC __rglgen_glUniformMatrix3fvARB;\nextern RGLSYMGLUNIFORMMATRIX4FVARBPROC __rglgen_glUniformMatrix4fvARB;\nextern RGLSYMGLGETOBJECTPARAMETERFVARBPROC __rglgen_glGetObjectParameterfvARB;\nextern RGLSYMGLGETOBJECTPARAMETERIVARBPROC __rglgen_glGetObjectParameterivARB;\nextern RGLSYMGLGETINFOLOGARBPROC __rglgen_glGetInfoLogARB;\nextern RGLSYMGLGETATTACHEDOBJECTSARBPROC __rglgen_glGetAttachedObjectsARB;\nextern RGLSYMGLGETUNIFORMLOCATIONARBPROC __rglgen_glGetUniformLocationARB;\nextern RGLSYMGLGETACTIVEUNIFORMARBPROC __rglgen_glGetActiveUniformARB;\nextern RGLSYMGLGETUNIFORMFVARBPROC __rglgen_glGetUniformfvARB;\nextern RGLSYMGLGETUNIFORMIVARBPROC __rglgen_glGetUniformivARB;\nextern RGLSYMGLGETSHADERSOURCEARBPROC __rglgen_glGetShaderSourceARB;\nextern RGLSYMGLNAMEDSTRINGARBPROC __rglgen_glNamedStringARB;\nextern RGLSYMGLDELETENAMEDSTRINGARBPROC __rglgen_glDeleteNamedStringARB;\nextern RGLSYMGLCOMPILESHADERINCLUDEARBPROC __rglgen_glCompileShaderIncludeARB;\nextern RGLSYMGLISNAMEDSTRINGARBPROC __rglgen_glIsNamedStringARB;\nextern RGLSYMGLGETNAMEDSTRINGARBPROC __rglgen_glGetNamedStringARB;\nextern RGLSYMGLGETNAMEDSTRINGIVARBPROC __rglgen_glGetNamedStringivARB;\nextern RGLSYMGLTEXPAGECOMMITMENTARBPROC __rglgen_glTexPageCommitmentARB;\nextern RGLSYMGLTEXBUFFERARBPROC __rglgen_glTexBufferARB;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE3DARBPROC __rglgen_glCompressedTexImage3DARB;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE2DARBPROC __rglgen_glCompressedTexImage2DARB;\nextern RGLSYMGLCOMPRESSEDTEXIMAGE1DARBPROC __rglgen_glCompressedTexImage1DARB;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DARBPROC __rglgen_glCompressedTexSubImage3DARB;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DARBPROC __rglgen_glCompressedTexSubImage2DARB;\nextern RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DARBPROC __rglgen_glCompressedTexSubImage1DARB;\nextern RGLSYMGLGETCOMPRESSEDTEXIMAGEARBPROC __rglgen_glGetCompressedTexImageARB;\nextern RGLSYMGLLOADTRANSPOSEMATRIXFARBPROC __rglgen_glLoadTransposeMatrixfARB;\nextern RGLSYMGLLOADTRANSPOSEMATRIXDARBPROC __rglgen_glLoadTransposeMatrixdARB;\nextern RGLSYMGLMULTTRANSPOSEMATRIXFARBPROC __rglgen_glMultTransposeMatrixfARB;\nextern RGLSYMGLMULTTRANSPOSEMATRIXDARBPROC __rglgen_glMultTransposeMatrixdARB;\nextern RGLSYMGLWEIGHTBVARBPROC __rglgen_glWeightbvARB;\nextern RGLSYMGLWEIGHTSVARBPROC __rglgen_glWeightsvARB;\nextern RGLSYMGLWEIGHTIVARBPROC __rglgen_glWeightivARB;\nextern RGLSYMGLWEIGHTFVARBPROC __rglgen_glWeightfvARB;\nextern RGLSYMGLWEIGHTDVARBPROC __rglgen_glWeightdvARB;\nextern RGLSYMGLWEIGHTUBVARBPROC __rglgen_glWeightubvARB;\nextern RGLSYMGLWEIGHTUSVARBPROC __rglgen_glWeightusvARB;\nextern RGLSYMGLWEIGHTUIVARBPROC __rglgen_glWeightuivARB;\nextern RGLSYMGLWEIGHTPOINTERARBPROC __rglgen_glWeightPointerARB;\nextern RGLSYMGLVERTEXBLENDARBPROC __rglgen_glVertexBlendARB;\nextern RGLSYMGLBINDBUFFERARBPROC __rglgen_glBindBufferARB;\nextern RGLSYMGLDELETEBUFFERSARBPROC __rglgen_glDeleteBuffersARB;\nextern RGLSYMGLGENBUFFERSARBPROC __rglgen_glGenBuffersARB;\nextern RGLSYMGLISBUFFERARBPROC __rglgen_glIsBufferARB;\nextern RGLSYMGLBUFFERDATAARBPROC __rglgen_glBufferDataARB;\nextern RGLSYMGLBUFFERSUBDATAARBPROC __rglgen_glBufferSubDataARB;\nextern RGLSYMGLGETBUFFERSUBDATAARBPROC __rglgen_glGetBufferSubDataARB;\nextern RGLSYMGLMAPBUFFERARBPROC __rglgen_glMapBufferARB;\nextern RGLSYMGLUNMAPBUFFERARBPROC __rglgen_glUnmapBufferARB;\nextern RGLSYMGLGETBUFFERPARAMETERIVARBPROC __rglgen_glGetBufferParameterivARB;\nextern RGLSYMGLGETBUFFERPOINTERVARBPROC __rglgen_glGetBufferPointervARB;\nextern RGLSYMGLVERTEXATTRIB1DARBPROC __rglgen_glVertexAttrib1dARB;\nextern RGLSYMGLVERTEXATTRIB1DVARBPROC __rglgen_glVertexAttrib1dvARB;\nextern RGLSYMGLVERTEXATTRIB1FARBPROC __rglgen_glVertexAttrib1fARB;\nextern RGLSYMGLVERTEXATTRIB1FVARBPROC __rglgen_glVertexAttrib1fvARB;\nextern RGLSYMGLVERTEXATTRIB1SARBPROC __rglgen_glVertexAttrib1sARB;\nextern RGLSYMGLVERTEXATTRIB1SVARBPROC __rglgen_glVertexAttrib1svARB;\nextern RGLSYMGLVERTEXATTRIB2DARBPROC __rglgen_glVertexAttrib2dARB;\nextern RGLSYMGLVERTEXATTRIB2DVARBPROC __rglgen_glVertexAttrib2dvARB;\nextern RGLSYMGLVERTEXATTRIB2FARBPROC __rglgen_glVertexAttrib2fARB;\nextern RGLSYMGLVERTEXATTRIB2FVARBPROC __rglgen_glVertexAttrib2fvARB;\nextern RGLSYMGLVERTEXATTRIB2SARBPROC __rglgen_glVertexAttrib2sARB;\nextern RGLSYMGLVERTEXATTRIB2SVARBPROC __rglgen_glVertexAttrib2svARB;\nextern RGLSYMGLVERTEXATTRIB3DARBPROC __rglgen_glVertexAttrib3dARB;\nextern RGLSYMGLVERTEXATTRIB3DVARBPROC __rglgen_glVertexAttrib3dvARB;\nextern RGLSYMGLVERTEXATTRIB3FARBPROC __rglgen_glVertexAttrib3fARB;\nextern RGLSYMGLVERTEXATTRIB3FVARBPROC __rglgen_glVertexAttrib3fvARB;\nextern RGLSYMGLVERTEXATTRIB3SARBPROC __rglgen_glVertexAttrib3sARB;\nextern RGLSYMGLVERTEXATTRIB3SVARBPROC __rglgen_glVertexAttrib3svARB;\nextern RGLSYMGLVERTEXATTRIB4NBVARBPROC __rglgen_glVertexAttrib4NbvARB;\nextern RGLSYMGLVERTEXATTRIB4NIVARBPROC __rglgen_glVertexAttrib4NivARB;\nextern RGLSYMGLVERTEXATTRIB4NSVARBPROC __rglgen_glVertexAttrib4NsvARB;\nextern RGLSYMGLVERTEXATTRIB4NUBARBPROC __rglgen_glVertexAttrib4NubARB;\nextern RGLSYMGLVERTEXATTRIB4NUBVARBPROC __rglgen_glVertexAttrib4NubvARB;\nextern RGLSYMGLVERTEXATTRIB4NUIVARBPROC __rglgen_glVertexAttrib4NuivARB;\nextern RGLSYMGLVERTEXATTRIB4NUSVARBPROC __rglgen_glVertexAttrib4NusvARB;\nextern RGLSYMGLVERTEXATTRIB4BVARBPROC __rglgen_glVertexAttrib4bvARB;\nextern RGLSYMGLVERTEXATTRIB4DARBPROC __rglgen_glVertexAttrib4dARB;\nextern RGLSYMGLVERTEXATTRIB4DVARBPROC __rglgen_glVertexAttrib4dvARB;\nextern RGLSYMGLVERTEXATTRIB4FARBPROC __rglgen_glVertexAttrib4fARB;\nextern RGLSYMGLVERTEXATTRIB4FVARBPROC __rglgen_glVertexAttrib4fvARB;\nextern RGLSYMGLVERTEXATTRIB4IVARBPROC __rglgen_glVertexAttrib4ivARB;\nextern RGLSYMGLVERTEXATTRIB4SARBPROC __rglgen_glVertexAttrib4sARB;\nextern RGLSYMGLVERTEXATTRIB4SVARBPROC __rglgen_glVertexAttrib4svARB;\nextern RGLSYMGLVERTEXATTRIB4UBVARBPROC __rglgen_glVertexAttrib4ubvARB;\nextern RGLSYMGLVERTEXATTRIB4UIVARBPROC __rglgen_glVertexAttrib4uivARB;\nextern RGLSYMGLVERTEXATTRIB4USVARBPROC __rglgen_glVertexAttrib4usvARB;\nextern RGLSYMGLVERTEXATTRIBPOINTERARBPROC __rglgen_glVertexAttribPointerARB;\nextern RGLSYMGLENABLEVERTEXATTRIBARRAYARBPROC __rglgen_glEnableVertexAttribArrayARB;\nextern RGLSYMGLDISABLEVERTEXATTRIBARRAYARBPROC __rglgen_glDisableVertexAttribArrayARB;\nextern RGLSYMGLGETVERTEXATTRIBDVARBPROC __rglgen_glGetVertexAttribdvARB;\nextern RGLSYMGLGETVERTEXATTRIBFVARBPROC __rglgen_glGetVertexAttribfvARB;\nextern RGLSYMGLGETVERTEXATTRIBIVARBPROC __rglgen_glGetVertexAttribivARB;\nextern RGLSYMGLGETVERTEXATTRIBPOINTERVARBPROC __rglgen_glGetVertexAttribPointervARB;\nextern RGLSYMGLBINDATTRIBLOCATIONARBPROC __rglgen_glBindAttribLocationARB;\nextern RGLSYMGLGETACTIVEATTRIBARBPROC __rglgen_glGetActiveAttribARB;\nextern RGLSYMGLGETATTRIBLOCATIONARBPROC __rglgen_glGetAttribLocationARB;\nextern RGLSYMGLWINDOWPOS2DARBPROC __rglgen_glWindowPos2dARB;\nextern RGLSYMGLWINDOWPOS2DVARBPROC __rglgen_glWindowPos2dvARB;\nextern RGLSYMGLWINDOWPOS2FARBPROC __rglgen_glWindowPos2fARB;\nextern RGLSYMGLWINDOWPOS2FVARBPROC __rglgen_glWindowPos2fvARB;\nextern RGLSYMGLWINDOWPOS2IARBPROC __rglgen_glWindowPos2iARB;\nextern RGLSYMGLWINDOWPOS2IVARBPROC __rglgen_glWindowPos2ivARB;\nextern RGLSYMGLWINDOWPOS2SARBPROC __rglgen_glWindowPos2sARB;\nextern RGLSYMGLWINDOWPOS2SVARBPROC __rglgen_glWindowPos2svARB;\nextern RGLSYMGLWINDOWPOS3DARBPROC __rglgen_glWindowPos3dARB;\nextern RGLSYMGLWINDOWPOS3DVARBPROC __rglgen_glWindowPos3dvARB;\nextern RGLSYMGLWINDOWPOS3FARBPROC __rglgen_glWindowPos3fARB;\nextern RGLSYMGLWINDOWPOS3FVARBPROC __rglgen_glWindowPos3fvARB;\nextern RGLSYMGLWINDOWPOS3IARBPROC __rglgen_glWindowPos3iARB;\nextern RGLSYMGLWINDOWPOS3IVARBPROC __rglgen_glWindowPos3ivARB;\nextern RGLSYMGLWINDOWPOS3SARBPROC __rglgen_glWindowPos3sARB;\nextern RGLSYMGLWINDOWPOS3SVARBPROC __rglgen_glWindowPos3svARB;\nextern RGLSYMGLMULTITEXCOORD1BOESPROC __rglgen_glMultiTexCoord1bOES;\nextern RGLSYMGLMULTITEXCOORD1BVOESPROC __rglgen_glMultiTexCoord1bvOES;\nextern RGLSYMGLMULTITEXCOORD2BOESPROC __rglgen_glMultiTexCoord2bOES;\nextern RGLSYMGLMULTITEXCOORD2BVOESPROC __rglgen_glMultiTexCoord2bvOES;\nextern RGLSYMGLMULTITEXCOORD3BOESPROC __rglgen_glMultiTexCoord3bOES;\nextern RGLSYMGLMULTITEXCOORD3BVOESPROC __rglgen_glMultiTexCoord3bvOES;\nextern RGLSYMGLMULTITEXCOORD4BOESPROC __rglgen_glMultiTexCoord4bOES;\nextern RGLSYMGLMULTITEXCOORD4BVOESPROC __rglgen_glMultiTexCoord4bvOES;\nextern RGLSYMGLTEXCOORD1BOESPROC __rglgen_glTexCoord1bOES;\nextern RGLSYMGLTEXCOORD1BVOESPROC __rglgen_glTexCoord1bvOES;\nextern RGLSYMGLTEXCOORD2BOESPROC __rglgen_glTexCoord2bOES;\nextern RGLSYMGLTEXCOORD2BVOESPROC __rglgen_glTexCoord2bvOES;\nextern RGLSYMGLTEXCOORD3BOESPROC __rglgen_glTexCoord3bOES;\nextern RGLSYMGLTEXCOORD3BVOESPROC __rglgen_glTexCoord3bvOES;\nextern RGLSYMGLTEXCOORD4BOESPROC __rglgen_glTexCoord4bOES;\nextern RGLSYMGLTEXCOORD4BVOESPROC __rglgen_glTexCoord4bvOES;\nextern RGLSYMGLVERTEX2BOESPROC __rglgen_glVertex2bOES;\nextern RGLSYMGLVERTEX2BVOESPROC __rglgen_glVertex2bvOES;\nextern RGLSYMGLVERTEX3BOESPROC __rglgen_glVertex3bOES;\nextern RGLSYMGLVERTEX3BVOESPROC __rglgen_glVertex3bvOES;\nextern RGLSYMGLVERTEX4BOESPROC __rglgen_glVertex4bOES;\nextern RGLSYMGLVERTEX4BVOESPROC __rglgen_glVertex4bvOES;\nextern RGLSYMGLALPHAFUNCXOESPROC __rglgen_glAlphaFuncxOES;\nextern RGLSYMGLCLEARCOLORXOESPROC __rglgen_glClearColorxOES;\nextern RGLSYMGLCLEARDEPTHXOESPROC __rglgen_glClearDepthxOES;\nextern RGLSYMGLCLIPPLANEXOESPROC __rglgen_glClipPlanexOES;\nextern RGLSYMGLCOLOR4XOESPROC __rglgen_glColor4xOES;\nextern RGLSYMGLDEPTHRANGEXOESPROC __rglgen_glDepthRangexOES;\nextern RGLSYMGLFOGXOESPROC __rglgen_glFogxOES;\nextern RGLSYMGLFOGXVOESPROC __rglgen_glFogxvOES;\nextern RGLSYMGLFRUSTUMXOESPROC __rglgen_glFrustumxOES;\nextern RGLSYMGLGETCLIPPLANEXOESPROC __rglgen_glGetClipPlanexOES;\nextern RGLSYMGLGETFIXEDVOESPROC __rglgen_glGetFixedvOES;\nextern RGLSYMGLGETTEXENVXVOESPROC __rglgen_glGetTexEnvxvOES;\nextern RGLSYMGLGETTEXPARAMETERXVOESPROC __rglgen_glGetTexParameterxvOES;\nextern RGLSYMGLLIGHTMODELXOESPROC __rglgen_glLightModelxOES;\nextern RGLSYMGLLIGHTMODELXVOESPROC __rglgen_glLightModelxvOES;\nextern RGLSYMGLLIGHTXOESPROC __rglgen_glLightxOES;\nextern RGLSYMGLLIGHTXVOESPROC __rglgen_glLightxvOES;\nextern RGLSYMGLLINEWIDTHXOESPROC __rglgen_glLineWidthxOES;\nextern RGLSYMGLLOADMATRIXXOESPROC __rglgen_glLoadMatrixxOES;\nextern RGLSYMGLMATERIALXOESPROC __rglgen_glMaterialxOES;\nextern RGLSYMGLMATERIALXVOESPROC __rglgen_glMaterialxvOES;\nextern RGLSYMGLMULTMATRIXXOESPROC __rglgen_glMultMatrixxOES;\nextern RGLSYMGLMULTITEXCOORD4XOESPROC __rglgen_glMultiTexCoord4xOES;\nextern RGLSYMGLNORMAL3XOESPROC __rglgen_glNormal3xOES;\nextern RGLSYMGLORTHOXOESPROC __rglgen_glOrthoxOES;\nextern RGLSYMGLPOINTPARAMETERXVOESPROC __rglgen_glPointParameterxvOES;\nextern RGLSYMGLPOINTSIZEXOESPROC __rglgen_glPointSizexOES;\nextern RGLSYMGLPOLYGONOFFSETXOESPROC __rglgen_glPolygonOffsetxOES;\nextern RGLSYMGLROTATEXOESPROC __rglgen_glRotatexOES;\nextern RGLSYMGLSAMPLECOVERAGEOESPROC __rglgen_glSampleCoverageOES;\nextern RGLSYMGLSCALEXOESPROC __rglgen_glScalexOES;\nextern RGLSYMGLTEXENVXOESPROC __rglgen_glTexEnvxOES;\nextern RGLSYMGLTEXENVXVOESPROC __rglgen_glTexEnvxvOES;\nextern RGLSYMGLTEXPARAMETERXOESPROC __rglgen_glTexParameterxOES;\nextern RGLSYMGLTEXPARAMETERXVOESPROC __rglgen_glTexParameterxvOES;\nextern RGLSYMGLTRANSLATEXOESPROC __rglgen_glTranslatexOES;\nextern RGLSYMGLACCUMXOESPROC __rglgen_glAccumxOES;\nextern RGLSYMGLBITMAPXOESPROC __rglgen_glBitmapxOES;\nextern RGLSYMGLBLENDCOLORXOESPROC __rglgen_glBlendColorxOES;\nextern RGLSYMGLCLEARACCUMXOESPROC __rglgen_glClearAccumxOES;\nextern RGLSYMGLCOLOR3XOESPROC __rglgen_glColor3xOES;\nextern RGLSYMGLCOLOR3XVOESPROC __rglgen_glColor3xvOES;\nextern RGLSYMGLCOLOR4XVOESPROC __rglgen_glColor4xvOES;\nextern RGLSYMGLCONVOLUTIONPARAMETERXOESPROC __rglgen_glConvolutionParameterxOES;\nextern RGLSYMGLCONVOLUTIONPARAMETERXVOESPROC __rglgen_glConvolutionParameterxvOES;\nextern RGLSYMGLEVALCOORD1XOESPROC __rglgen_glEvalCoord1xOES;\nextern RGLSYMGLEVALCOORD1XVOESPROC __rglgen_glEvalCoord1xvOES;\nextern RGLSYMGLEVALCOORD2XOESPROC __rglgen_glEvalCoord2xOES;\nextern RGLSYMGLEVALCOORD2XVOESPROC __rglgen_glEvalCoord2xvOES;\nextern RGLSYMGLFEEDBACKBUFFERXOESPROC __rglgen_glFeedbackBufferxOES;\nextern RGLSYMGLGETCONVOLUTIONPARAMETERXVOESPROC __rglgen_glGetConvolutionParameterxvOES;\nextern RGLSYMGLGETHISTOGRAMPARAMETERXVOESPROC __rglgen_glGetHistogramParameterxvOES;\nextern RGLSYMGLGETLIGHTXOESPROC __rglgen_glGetLightxOES;\nextern RGLSYMGLGETMAPXVOESPROC __rglgen_glGetMapxvOES;\nextern RGLSYMGLGETMATERIALXOESPROC __rglgen_glGetMaterialxOES;\nextern RGLSYMGLGETPIXELMAPXVPROC __rglgen_glGetPixelMapxv;\nextern RGLSYMGLGETTEXGENXVOESPROC __rglgen_glGetTexGenxvOES;\nextern RGLSYMGLGETTEXLEVELPARAMETERXVOESPROC __rglgen_glGetTexLevelParameterxvOES;\nextern RGLSYMGLINDEXXOESPROC __rglgen_glIndexxOES;\nextern RGLSYMGLINDEXXVOESPROC __rglgen_glIndexxvOES;\nextern RGLSYMGLLOADTRANSPOSEMATRIXXOESPROC __rglgen_glLoadTransposeMatrixxOES;\nextern RGLSYMGLMAP1XOESPROC __rglgen_glMap1xOES;\nextern RGLSYMGLMAP2XOESPROC __rglgen_glMap2xOES;\nextern RGLSYMGLMAPGRID1XOESPROC __rglgen_glMapGrid1xOES;\nextern RGLSYMGLMAPGRID2XOESPROC __rglgen_glMapGrid2xOES;\nextern RGLSYMGLMULTTRANSPOSEMATRIXXOESPROC __rglgen_glMultTransposeMatrixxOES;\nextern RGLSYMGLMULTITEXCOORD1XOESPROC __rglgen_glMultiTexCoord1xOES;\nextern RGLSYMGLMULTITEXCOORD1XVOESPROC __rglgen_glMultiTexCoord1xvOES;\nextern RGLSYMGLMULTITEXCOORD2XOESPROC __rglgen_glMultiTexCoord2xOES;\nextern RGLSYMGLMULTITEXCOORD2XVOESPROC __rglgen_glMultiTexCoord2xvOES;\nextern RGLSYMGLMULTITEXCOORD3XOESPROC __rglgen_glMultiTexCoord3xOES;\nextern RGLSYMGLMULTITEXCOORD3XVOESPROC __rglgen_glMultiTexCoord3xvOES;\nextern RGLSYMGLMULTITEXCOORD4XVOESPROC __rglgen_glMultiTexCoord4xvOES;\nextern RGLSYMGLNORMAL3XVOESPROC __rglgen_glNormal3xvOES;\nextern RGLSYMGLPASSTHROUGHXOESPROC __rglgen_glPassThroughxOES;\nextern RGLSYMGLPIXELMAPXPROC __rglgen_glPixelMapx;\nextern RGLSYMGLPIXELSTOREXPROC __rglgen_glPixelStorex;\nextern RGLSYMGLPIXELTRANSFERXOESPROC __rglgen_glPixelTransferxOES;\nextern RGLSYMGLPIXELZOOMXOESPROC __rglgen_glPixelZoomxOES;\nextern RGLSYMGLPRIORITIZETEXTURESXOESPROC __rglgen_glPrioritizeTexturesxOES;\nextern RGLSYMGLRASTERPOS2XOESPROC __rglgen_glRasterPos2xOES;\nextern RGLSYMGLRASTERPOS2XVOESPROC __rglgen_glRasterPos2xvOES;\nextern RGLSYMGLRASTERPOS3XOESPROC __rglgen_glRasterPos3xOES;\nextern RGLSYMGLRASTERPOS3XVOESPROC __rglgen_glRasterPos3xvOES;\nextern RGLSYMGLRASTERPOS4XOESPROC __rglgen_glRasterPos4xOES;\nextern RGLSYMGLRASTERPOS4XVOESPROC __rglgen_glRasterPos4xvOES;\nextern RGLSYMGLRECTXOESPROC __rglgen_glRectxOES;\nextern RGLSYMGLRECTXVOESPROC __rglgen_glRectxvOES;\nextern RGLSYMGLTEXCOORD1XOESPROC __rglgen_glTexCoord1xOES;\nextern RGLSYMGLTEXCOORD1XVOESPROC __rglgen_glTexCoord1xvOES;\nextern RGLSYMGLTEXCOORD2XOESPROC __rglgen_glTexCoord2xOES;\nextern RGLSYMGLTEXCOORD2XVOESPROC __rglgen_glTexCoord2xvOES;\nextern RGLSYMGLTEXCOORD3XOESPROC __rglgen_glTexCoord3xOES;\nextern RGLSYMGLTEXCOORD3XVOESPROC __rglgen_glTexCoord3xvOES;\nextern RGLSYMGLTEXCOORD4XOESPROC __rglgen_glTexCoord4xOES;\nextern RGLSYMGLTEXCOORD4XVOESPROC __rglgen_glTexCoord4xvOES;\nextern RGLSYMGLTEXGENXOESPROC __rglgen_glTexGenxOES;\nextern RGLSYMGLTEXGENXVOESPROC __rglgen_glTexGenxvOES;\nextern RGLSYMGLVERTEX2XOESPROC __rglgen_glVertex2xOES;\nextern RGLSYMGLVERTEX2XVOESPROC __rglgen_glVertex2xvOES;\nextern RGLSYMGLVERTEX3XOESPROC __rglgen_glVertex3xOES;\nextern RGLSYMGLVERTEX3XVOESPROC __rglgen_glVertex3xvOES;\nextern RGLSYMGLVERTEX4XOESPROC __rglgen_glVertex4xOES;\nextern RGLSYMGLVERTEX4XVOESPROC __rglgen_glVertex4xvOES;\nextern RGLSYMGLQUERYMATRIXXOESPROC __rglgen_glQueryMatrixxOES;\nextern RGLSYMGLCLEARDEPTHFOESPROC __rglgen_glClearDepthfOES;\nextern RGLSYMGLCLIPPLANEFOESPROC __rglgen_glClipPlanefOES;\nextern RGLSYMGLDEPTHRANGEFOESPROC __rglgen_glDepthRangefOES;\nextern RGLSYMGLFRUSTUMFOESPROC __rglgen_glFrustumfOES;\nextern RGLSYMGLGETCLIPPLANEFOESPROC __rglgen_glGetClipPlanefOES;\nextern RGLSYMGLORTHOFOESPROC __rglgen_glOrthofOES;\nextern RGLSYMGLIMAGETRANSFORMPARAMETERIHPPROC __rglgen_glImageTransformParameteriHP;\nextern RGLSYMGLIMAGETRANSFORMPARAMETERFHPPROC __rglgen_glImageTransformParameterfHP;\nextern RGLSYMGLIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glImageTransformParameterivHP;\nextern RGLSYMGLIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glImageTransformParameterfvHP;\nextern RGLSYMGLGETIMAGETRANSFORMPARAMETERIVHPPROC __rglgen_glGetImageTransformParameterivHP;\nextern RGLSYMGLGETIMAGETRANSFORMPARAMETERFVHPPROC __rglgen_glGetImageTransformParameterfvHP;\n\nstruct rglgen_sym_map { const char *sym; void *ptr; };\nextern const struct rglgen_sym_map rglgen_symbol_map[];\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "include/glsym/rglgen.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (glsym).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef RGLGEN_H__\n#define RGLGEN_H__\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <retro_common_api.h>\n\n#include \"rglgen_headers.h\"\n\nRETRO_BEGIN_DECLS\n\nstruct rglgen_sym_map;\n\ntypedef void (*rglgen_func_t)(void);\ntypedef rglgen_func_t (*rglgen_proc_address_t)(const char*);\nvoid rglgen_resolve_symbols(rglgen_proc_address_t proc);\nvoid rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,\n      const struct rglgen_sym_map *map);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/glsym/rglgen_headers.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (glsym).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef RGLGEN_HEADERS_H__\n#define RGLGEN_HEADERS_H__\n\n#ifdef HAVE_EGL\n#include <EGL/egl.h>\n#include <EGL/eglext.h>\n#endif\n\n#include \"rglgen_private_headers.h\"\n\n#ifndef GL_MAP_WRITE_BIT\n#define GL_MAP_WRITE_BIT 0x0002\n#endif\n\n#ifndef GL_MAP_INVALIDATE_BUFFER_BIT\n#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008\n#endif\n\n#ifndef GL_RED_INTEGER\n#define GL_RED_INTEGER 0x8D94\n#endif\n\n#ifndef GL_BGRA_EXT\n#define GL_BGRA_EXT GL_BGRA\n#endif\n\n#ifndef GL_LUMINANCE_ALPHA\n#define GL_LUMINANCE_ALPHA 0x190A\n#endif\n\n#endif\n"
  },
  {
    "path": "include/glsym/rglgen_private_headers.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\r\n *\r\n * ---------------------------------------------------------------------------------------\r\n * The following license statement only applies to this libretro SDK code part (glsym).\r\n * ---------------------------------------------------------------------------------------\r\n *\r\n * Permission is hereby granted, free of charge,\r\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\r\n * to deal in the Software without restriction, including without limitation the rights to\r\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\r\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\r\n *\r\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\r\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */\r\n\r\n#ifndef RGLGEN_PRIVATE_HEADERS_H__\r\n#define RGLGEN_PRIVATE_HEADERS_H__\r\n\r\n#if defined(IOS)\r\n\r\n#if defined(HAVE_OPENGLES3)\r\n#include <OpenGLES/ES3/gl.h>\r\n#include <OpenGLES/ES3/glext.h>\r\n#else\r\n#include <OpenGLES/ES2/gl.h>\r\n#include <OpenGLES/ES2/glext.h>\r\n#endif\r\n\r\n#elif defined(__APPLE__)\r\n#include <compat/apple_compat.h>\r\n#if MAC_OS_X_VERSION_10_7\r\n#include <OpenGL/gl3.h>\r\n#include <OpenGL/gl3ext.h>\r\n#else\r\n#include <OpenGL/gl.h>\r\n#include <OpenGL/glext.h>\r\n#endif\r\n#elif defined(HAVE_PSGL)\r\n#include <PSGL/psgl.h>\r\n#include <GLES/glext.h>\r\n#elif defined(HAVE_OPENGL_MODERN)\r\n#include <GL3/gl3.h>\r\n#include <GL3/gl3ext.h>\r\n#elif defined(HAVE_OPENGLES3)\r\n#include <GLES3/gl3.h>\r\n#define __gl2_h_\r\n#include <GLES2/gl2ext.h>\r\n#elif defined(HAVE_OPENGLES2)\r\n#include <GLES2/gl2.h>\r\n#include <GLES2/gl2ext.h>\r\n#elif defined(HAVE_OPENGLES1)\r\n#include <GLES/gl.h>\r\n#include <GLES/glext.h>\r\n#else\r\n#if defined(_WIN32) && !defined(_XBOX)\r\n#define WIN32_LEAN_AND_MEAN\r\n#include <windows.h>\r\n#endif\r\n#ifndef HAVE_LIBNX\r\n#include <GL/gl.h>\r\n#include <GL/glext.h>\r\n#else\r\n/* We need to avoid including <GL/gl.h> on this platform */\r\n#include \"switch/nx_gl.h\"\r\n#include <GL/glext.h>\r\n#endif /* SWITCH */\r\n#endif\r\n\r\n#endif\r\n"
  },
  {
    "path": "include/glsym/switch/nx_gl.h",
    "content": "/* Copyright (C) 2018-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro SDK code part (nx_gl.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __NX_GL_H__\n#define __NX_GL_H__\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n\n/* GL.h types */\ntypedef unsigned int\tGLenum;\ntypedef unsigned char\tGLboolean;\ntypedef unsigned int\tGLbitfield;\ntypedef void\t\tGLvoid;\ntypedef signed char\tGLbyte;\t\t/* 1-byte signed */\ntypedef short\t\tGLshort;\t/* 2-byte signed */\ntypedef int\t\tGLint;\t\t/* 4-byte signed */\ntypedef unsigned char\tGLubyte;\t/* 1-byte unsigned */\ntypedef unsigned short\tGLushort;\t/* 2-byte unsigned */\ntypedef unsigned int\tGLuint;\t\t/* 4-byte unsigned */\ntypedef int\t\tGLsizei;\t/* 4-byte signed */\ntypedef float\t\tGLfloat;\t/* single precision float */\ntypedef float\t\tGLclampf;\t/* single precision float in [0,1] */\ntypedef double\t\tGLdouble;\t/* double precision float */\ntypedef double\t\tGLclampd;\t/* double precision float in [0,1] */\n\n/* GL.h defines */\n#define GL_ARB_imaging   1\n#define GL_FALSE                                0\n#define GL_TRUE                                 1\n#define GL_BYTE                                 0x1400\n#define GL_UNSIGNED_BYTE                        0x1401\n#define GL_SHORT                                0x1402\n#define GL_UNSIGNED_SHORT                       0x1403\n#define GL_INT                                  0x1404\n#define GL_UNSIGNED_INT                         0x1405\n#define GL_FLOAT                                0x1406\n#define GL_2_BYTES                              0x1407\n#define GL_3_BYTES                              0x1408\n#define GL_4_BYTES                              0x1409\n#define GL_DOUBLE                               0x140A\n#define GL_POINTS                               0x0000\n#define GL_LINES                                0x0001\n#define GL_LINE_LOOP                            0x0002\n#define GL_LINE_STRIP                           0x0003\n#define GL_TRIANGLES                            0x0004\n#define GL_TRIANGLE_STRIP                       0x0005\n#define GL_TRIANGLE_FAN                         0x0006\n#define GL_QUADS                                0x0007\n#define GL_QUAD_STRIP                           0x0008\n#define GL_POLYGON                              0x0009\n#define GL_VERTEX_ARRAY                         0x8074\n#define GL_NORMAL_ARRAY                         0x8075\n#define GL_COLOR_ARRAY                          0x8076\n#define GL_INDEX_ARRAY                          0x8077\n#define GL_TEXTURE_COORD_ARRAY                  0x8078\n#define GL_EDGE_FLAG_ARRAY                      0x8079\n#define GL_VERTEX_ARRAY_SIZE                    0x807A\n#define GL_VERTEX_ARRAY_TYPE                    0x807B\n#define GL_VERTEX_ARRAY_STRIDE                  0x807C\n#define GL_NORMAL_ARRAY_TYPE                    0x807E\n#define GL_NORMAL_ARRAY_STRIDE                  0x807F\n#define GL_COLOR_ARRAY_SIZE                     0x8081\n#define GL_COLOR_ARRAY_TYPE                     0x8082\n#define GL_COLOR_ARRAY_STRIDE                   0x8083\n#define GL_INDEX_ARRAY_TYPE                     0x8085\n#define GL_INDEX_ARRAY_STRIDE                   0x8086\n#define GL_TEXTURE_COORD_ARRAY_SIZE             0x8088\n#define GL_TEXTURE_COORD_ARRAY_TYPE             0x8089\n#define GL_TEXTURE_COORD_ARRAY_STRIDE           0x808A\n#define GL_EDGE_FLAG_ARRAY_STRIDE               0x808C\n#define GL_VERTEX_ARRAY_POINTER                 0x808E\n#define GL_NORMAL_ARRAY_POINTER                 0x808F\n#define GL_COLOR_ARRAY_POINTER                  0x8090\n#define GL_INDEX_ARRAY_POINTER                  0x8091\n#define GL_TEXTURE_COORD_ARRAY_POINTER          0x8092\n#define GL_EDGE_FLAG_ARRAY_POINTER              0x8093\n#define GL_V2F                                  0x2A20\n#define GL_V3F                                  0x2A21\n#define GL_C4UB_V2F                             0x2A22\n#define GL_C4UB_V3F                             0x2A23\n#define GL_C3F_V3F                              0x2A24\n#define GL_N3F_V3F                              0x2A25\n#define GL_C4F_N3F_V3F                          0x2A26\n#define GL_T2F_V3F                              0x2A27\n#define GL_T4F_V4F                              0x2A28\n#define GL_T2F_C4UB_V3F                         0x2A29\n#define GL_T2F_C3F_V3F                          0x2A2A\n#define GL_T2F_N3F_V3F                          0x2A2B\n#define GL_T2F_C4F_N3F_V3F                      0x2A2C\n#define GL_T4F_C4F_N3F_V4F                      0x2A2D\n#define GL_MATRIX_MODE                          0x0BA0\n#define GL_MODELVIEW                            0x1700\n#define GL_PROJECTION                           0x1701\n#define GL_TEXTURE                              0x1702\n#define GL_POINT_SMOOTH                         0x0B10\n#define GL_POINT_SIZE                           0x0B11\n#define GL_POINT_SIZE_GRANULARITY               0x0B13\n#define GL_POINT_SIZE_RANGE                     0x0B12\n#define GL_LINE_SMOOTH                          0x0B20\n#define GL_LINE_STIPPLE                         0x0B24\n#define GL_LINE_STIPPLE_PATTERN                 0x0B25\n#define GL_LINE_STIPPLE_REPEAT                  0x0B26\n#define GL_LINE_WIDTH                           0x0B21\n#define GL_LINE_WIDTH_GRANULARITY               0x0B23\n#define GL_LINE_WIDTH_RANGE                     0x0B22\n#define GL_POINT                                0x1B00\n#define GL_LINE                                 0x1B01\n#define GL_FILL                                 0x1B02\n#define GL_CW                                   0x0900\n#define GL_CCW                                  0x0901\n#define GL_FRONT                                0x0404\n#define GL_BACK                                 0x0405\n#define GL_POLYGON_MODE                         0x0B40\n#define GL_POLYGON_SMOOTH                       0x0B41\n#define GL_POLYGON_STIPPLE                      0x0B42\n#define GL_EDGE_FLAG                            0x0B43\n#define GL_CULL_FACE                            0x0B44\n#define GL_CULL_FACE_MODE                       0x0B45\n#define GL_FRONT_FACE                           0x0B46\n#define GL_POLYGON_OFFSET_FACTOR                0x8038\n#define GL_POLYGON_OFFSET_UNITS                 0x2A00\n#define GL_POLYGON_OFFSET_POINT                 0x2A01\n#define GL_POLYGON_OFFSET_LINE                  0x2A02\n#define GL_POLYGON_OFFSET_FILL                  0x8037\n#define GL_COMPILE                              0x1300\n#define GL_COMPILE_AND_EXECUTE                  0x1301\n#define GL_LIST_BASE                            0x0B32\n#define GL_LIST_INDEX                           0x0B33\n#define GL_LIST_MODE                            0x0B30\n#define GL_NEVER                                0x0200\n#define GL_LESS                                 0x0201\n#define GL_EQUAL                                0x0202\n#define GL_LEQUAL                               0x0203\n#define GL_GREATER                              0x0204\n#define GL_NOTEQUAL                             0x0205\n#define GL_GEQUAL                               0x0206\n#define GL_ALWAYS                               0x0207\n#define GL_DEPTH_TEST                           0x0B71\n#define GL_DEPTH_BITS                           0x0D56\n#define GL_DEPTH_CLEAR_VALUE                    0x0B73\n#define GL_DEPTH_FUNC                           0x0B74\n#define GL_DEPTH_RANGE                          0x0B70\n#define GL_DEPTH_WRITEMASK                      0x0B72\n#define GL_DEPTH_COMPONENT                      0x1902\n#define GL_LIGHTING                             0x0B50\n#define GL_LIGHT0                               0x4000\n#define GL_LIGHT1                               0x4001\n#define GL_LIGHT2                               0x4002\n#define GL_LIGHT3                               0x4003\n#define GL_LIGHT4                               0x4004\n#define GL_LIGHT5                               0x4005\n#define GL_LIGHT6                               0x4006\n#define GL_LIGHT7                               0x4007\n#define GL_SPOT_EXPONENT                        0x1205\n#define GL_SPOT_CUTOFF                          0x1206\n#define GL_CONSTANT_ATTENUATION                 0x1207\n#define GL_LINEAR_ATTENUATION                   0x1208\n#define GL_QUADRATIC_ATTENUATION                0x1209\n#define GL_AMBIENT                              0x1200\n#define GL_DIFFUSE                              0x1201\n#define GL_SPECULAR                             0x1202\n#define GL_SHININESS                            0x1601\n#define GL_EMISSION                             0x1600\n#define GL_POSITION                             0x1203\n#define GL_SPOT_DIRECTION                       0x1204\n#define GL_AMBIENT_AND_DIFFUSE                  0x1602\n#define GL_COLOR_INDEXES                        0x1603\n#define GL_LIGHT_MODEL_TWO_SIDE                 0x0B52\n#define GL_LIGHT_MODEL_LOCAL_VIEWER             0x0B51\n#define GL_LIGHT_MODEL_AMBIENT                  0x0B53\n#define GL_FRONT_AND_BACK                       0x0408\n#define GL_SHADE_MODEL                          0x0B54\n#define GL_FLAT                                 0x1D00\n#define GL_SMOOTH                               0x1D01\n#define GL_COLOR_MATERIAL                       0x0B57\n#define GL_COLOR_MATERIAL_FACE                  0x0B55\n#define GL_COLOR_MATERIAL_PARAMETER             0x0B56\n#define GL_NORMALIZE                            0x0BA1\n#define GL_CLIP_PLANE0                          0x3000\n#define GL_CLIP_PLANE1                          0x3001\n#define GL_CLIP_PLANE2                          0x3002\n#define GL_CLIP_PLANE3                          0x3003\n#define GL_CLIP_PLANE4                          0x3004\n#define GL_CLIP_PLANE5                          0x3005\n#define GL_ACCUM_RED_BITS                       0x0D58\n#define GL_ACCUM_GREEN_BITS                     0x0D59\n#define GL_ACCUM_BLUE_BITS                      0x0D5A\n#define GL_ACCUM_ALPHA_BITS                     0x0D5B\n#define GL_ACCUM_CLEAR_VALUE                    0x0B80\n#define GL_ACCUM                                0x0100\n#define GL_ADD                                  0x0104\n#define GL_LOAD                                 0x0101\n#define GL_MULT                                 0x0103\n#define GL_RETURN                               0x0102\n#define GL_ALPHA_TEST                           0x0BC0\n#define GL_ALPHA_TEST_REF                       0x0BC2\n#define GL_ALPHA_TEST_FUNC                      0x0BC1\n#define GL_BLEND                                0x0BE2\n#define GL_BLEND_SRC                            0x0BE1\n#define GL_BLEND_DST                            0x0BE0\n#define GL_ZERO                                 0\n#define GL_ONE                                  1\n#define GL_SRC_COLOR                            0x0300\n#define GL_ONE_MINUS_SRC_COLOR                  0x0301\n#define GL_SRC_ALPHA                            0x0302\n#define GL_ONE_MINUS_SRC_ALPHA                  0x0303\n#define GL_DST_ALPHA                            0x0304\n#define GL_ONE_MINUS_DST_ALPHA                  0x0305\n#define GL_DST_COLOR                            0x0306\n#define GL_ONE_MINUS_DST_COLOR                  0x0307\n#define GL_SRC_ALPHA_SATURATE                   0x0308\n#define GL_FEEDBACK                             0x1C01\n#define GL_RENDER                               0x1C00\n#define GL_SELECT                               0x1C02\n#define GL_2D                                   0x0600\n#define GL_3D                                   0x0601\n#define GL_3D_COLOR                             0x0602\n#define GL_3D_COLOR_TEXTURE                     0x0603\n#define GL_4D_COLOR_TEXTURE                     0x0604\n#define GL_POINT_TOKEN                          0x0701\n#define GL_LINE_TOKEN                           0x0702\n#define GL_LINE_RESET_TOKEN                     0x0707\n#define GL_POLYGON_TOKEN                        0x0703\n#define GL_BITMAP_TOKEN                         0x0704\n#define GL_DRAW_PIXEL_TOKEN                     0x0705\n#define GL_COPY_PIXEL_TOKEN                     0x0706\n#define GL_PASS_THROUGH_TOKEN                   0x0700\n#define GL_FEEDBACK_BUFFER_POINTER              0x0DF0\n#define GL_FEEDBACK_BUFFER_SIZE                 0x0DF1\n#define GL_FEEDBACK_BUFFER_TYPE                 0x0DF2\n#define GL_SELECTION_BUFFER_POINTER             0x0DF3\n#define GL_SELECTION_BUFFER_SIZE                0x0DF4\n#define GL_FOG                                  0x0B60\n#define GL_FOG_MODE                             0x0B65\n#define GL_FOG_DENSITY                          0x0B62\n#define GL_FOG_COLOR                            0x0B66\n#define GL_FOG_INDEX                            0x0B61\n#define GL_FOG_START                            0x0B63\n#define GL_FOG_END                              0x0B64\n#define GL_LINEAR                               0x2601\n#define GL_EXP                                  0x0800\n#define GL_EXP2                                 0x0801\n#define GL_LOGIC_OP                             0x0BF1\n#define GL_INDEX_LOGIC_OP                       0x0BF1\n#define GL_COLOR_LOGIC_OP                       0x0BF2\n#define GL_LOGIC_OP_MODE                        0x0BF0\n#define GL_CLEAR                                0x1500\n#define GL_SET                                  0x150F\n#define GL_COPY                                 0x1503\n#define GL_COPY_INVERTED                        0x150C\n#define GL_NOOP                                 0x1505\n#define GL_INVERT                               0x150A\n#define GL_AND                                  0x1501\n#define GL_NAND                                 0x150E\n#define GL_OR                                   0x1507\n#define GL_NOR                                  0x1508\n#define GL_XOR                                  0x1506\n#define GL_EQUIV                                0x1509\n#define GL_AND_REVERSE                          0x1502\n#define GL_AND_INVERTED                         0x1504\n#define GL_OR_REVERSE                           0x150B\n#define GL_OR_INVERTED                          0x150D\n#define GL_STENCIL_BITS                         0x0D57\n#define GL_STENCIL_TEST                         0x0B90\n#define GL_STENCIL_CLEAR_VALUE                  0x0B91\n#define GL_STENCIL_FUNC                         0x0B92\n#define GL_STENCIL_VALUE_MASK                   0x0B93\n#define GL_STENCIL_FAIL                         0x0B94\n#define GL_STENCIL_PASS_DEPTH_FAIL              0x0B95\n#define GL_STENCIL_PASS_DEPTH_PASS              0x0B96\n#define GL_STENCIL_REF                          0x0B97\n#define GL_STENCIL_WRITEMASK                    0x0B98\n#define GL_STENCIL_INDEX                        0x1901\n#define GL_KEEP                                 0x1E00\n#define GL_REPLACE                              0x1E01\n#define GL_INCR                                 0x1E02\n#define GL_DECR                                 0x1E03\n#define GL_NONE                                 0\n#define GL_LEFT                                 0x0406\n#define GL_RIGHT                                0x0407\n#define GL_FRONT_LEFT                           0x0400\n#define GL_FRONT_RIGHT                          0x0401\n#define GL_BACK_LEFT                            0x0402\n#define GL_BACK_RIGHT                           0x0403\n#define GL_AUX0                                 0x0409\n#define GL_AUX1                                 0x040A\n#define GL_AUX2                                 0x040B\n#define GL_AUX3                                 0x040C\n#define GL_COLOR_INDEX                          0x1900\n#define GL_RED                                  0x1903\n#define GL_GREEN                                0x1904\n#define GL_BLUE                                 0x1905\n#define GL_ALPHA                                0x1906\n#define GL_LUMINANCE                            0x1909\n#define GL_LUMINANCE_ALPHA                      0x190A\n#define GL_ALPHA_BITS                           0x0D55\n#define GL_RED_BITS                             0x0D52\n#define GL_GREEN_BITS                           0x0D53\n#define GL_BLUE_BITS                            0x0D54\n#define GL_INDEX_BITS                           0x0D51\n#define GL_SUBPIXEL_BITS                        0x0D50\n#define GL_AUX_BUFFERS                          0x0C00\n#define GL_READ_BUFFER                          0x0C02\n#define GL_DRAW_BUFFER                          0x0C01\n#define GL_DOUBLEBUFFER                         0x0C32\n#define GL_STEREO                               0x0C33\n#define GL_BITMAP                               0x1A00\n#define GL_COLOR                                0x1800\n#define GL_DEPTH                                0x1801\n#define GL_STENCIL                              0x1802\n#define GL_DITHER                               0x0BD0\n#define GL_RGB                                  0x1907\n#define GL_RGBA                                 0x1908\n#define GL_MAX_LIST_NESTING                     0x0B31\n#define GL_MAX_EVAL_ORDER                       0x0D30\n#define GL_MAX_LIGHTS                           0x0D31\n#define GL_MAX_CLIP_PLANES                      0x0D32\n#define GL_MAX_TEXTURE_SIZE                     0x0D33\n#define GL_MAX_PIXEL_MAP_TABLE                  0x0D34\n#define GL_MAX_ATTRIB_STACK_DEPTH               0x0D35\n#define GL_MAX_MODELVIEW_STACK_DEPTH            0x0D36\n#define GL_MAX_NAME_STACK_DEPTH                 0x0D37\n#define GL_MAX_PROJECTION_STACK_DEPTH           0x0D38\n#define GL_MAX_TEXTURE_STACK_DEPTH              0x0D39\n#define GL_MAX_VIEWPORT_DIMS                    0x0D3A\n#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH        0x0D3B\n#define GL_ATTRIB_STACK_DEPTH                   0x0BB0\n#define GL_CLIENT_ATTRIB_STACK_DEPTH            0x0BB1\n#define GL_COLOR_CLEAR_VALUE                    0x0C22\n#define GL_COLOR_WRITEMASK                      0x0C23\n#define GL_CURRENT_INDEX                        0x0B01\n#define GL_CURRENT_COLOR                        0x0B00\n#define GL_CURRENT_NORMAL                       0x0B02\n#define GL_CURRENT_RASTER_COLOR                 0x0B04\n#define GL_CURRENT_RASTER_DISTANCE              0x0B09\n#define GL_CURRENT_RASTER_INDEX                 0x0B05\n#define GL_CURRENT_RASTER_POSITION              0x0B07\n#define GL_CURRENT_RASTER_TEXTURE_COORDS        0x0B06\n#define GL_CURRENT_RASTER_POSITION_VALID        0x0B08\n#define GL_CURRENT_TEXTURE_COORDS               0x0B03\n#define GL_INDEX_CLEAR_VALUE                    0x0C20\n#define GL_INDEX_MODE                           0x0C30\n#define GL_INDEX_WRITEMASK                      0x0C21\n#define GL_MODELVIEW_MATRIX                     0x0BA6\n#define GL_MODELVIEW_STACK_DEPTH                0x0BA3\n#define GL_NAME_STACK_DEPTH                     0x0D70\n#define GL_PROJECTION_MATRIX                    0x0BA7\n#define GL_PROJECTION_STACK_DEPTH               0x0BA4\n#define GL_RENDER_MODE                          0x0C40\n#define GL_RGBA_MODE                            0x0C31\n#define GL_TEXTURE_MATRIX                       0x0BA8\n#define GL_TEXTURE_STACK_DEPTH                  0x0BA5\n#define GL_VIEWPORT                             0x0BA2\n#define GL_AUTO_NORMAL                          0x0D80\n#define GL_MAP1_COLOR_4                         0x0D90\n#define GL_MAP1_INDEX                           0x0D91\n#define GL_MAP1_NORMAL                          0x0D92\n#define GL_MAP1_TEXTURE_COORD_1                 0x0D93\n#define GL_MAP1_TEXTURE_COORD_2                 0x0D94\n#define GL_MAP1_TEXTURE_COORD_3                 0x0D95\n#define GL_MAP1_TEXTURE_COORD_4                 0x0D96\n#define GL_MAP1_VERTEX_3                        0x0D97\n#define GL_MAP1_VERTEX_4                        0x0D98\n#define GL_MAP2_COLOR_4                         0x0DB0\n#define GL_MAP2_INDEX                           0x0DB1\n#define GL_MAP2_NORMAL                          0x0DB2\n#define GL_MAP2_TEXTURE_COORD_1                 0x0DB3\n#define GL_MAP2_TEXTURE_COORD_2                 0x0DB4\n#define GL_MAP2_TEXTURE_COORD_3                 0x0DB5\n#define GL_MAP2_TEXTURE_COORD_4                 0x0DB6\n#define GL_MAP2_VERTEX_3                        0x0DB7\n#define GL_MAP2_VERTEX_4                        0x0DB8\n#define GL_MAP1_GRID_DOMAIN                     0x0DD0\n#define GL_MAP1_GRID_SEGMENTS                   0x0DD1\n#define GL_MAP2_GRID_DOMAIN                     0x0DD2\n#define GL_MAP2_GRID_SEGMENTS                   0x0DD3\n#define GL_COEFF                                0x0A00\n#define GL_ORDER                                0x0A01\n#define GL_DOMAIN                               0x0A02\n#define GL_PERSPECTIVE_CORRECTION_HINT          0x0C50\n#define GL_POINT_SMOOTH_HINT                    0x0C51\n#define GL_LINE_SMOOTH_HINT                     0x0C52\n#define GL_POLYGON_SMOOTH_HINT                  0x0C53\n#define GL_FOG_HINT                             0x0C54\n#define GL_DONT_CARE                            0x1100\n#define GL_FASTEST                              0x1101\n#define GL_NICEST                               0x1102\n#define GL_SCISSOR_BOX                          0x0C10\n#define GL_SCISSOR_TEST                         0x0C11\n#define GL_MAP_COLOR                            0x0D10\n#define GL_MAP_STENCIL                          0x0D11\n#define GL_INDEX_SHIFT                          0x0D12\n#define GL_INDEX_OFFSET                         0x0D13\n#define GL_RED_SCALE                            0x0D14\n#define GL_RED_BIAS                             0x0D15\n#define GL_GREEN_SCALE                          0x0D18\n#define GL_GREEN_BIAS                           0x0D19\n#define GL_BLUE_SCALE                           0x0D1A\n#define GL_BLUE_BIAS                            0x0D1B\n#define GL_ALPHA_SCALE                          0x0D1C\n#define GL_ALPHA_BIAS                           0x0D1D\n#define GL_DEPTH_SCALE                          0x0D1E\n#define GL_DEPTH_BIAS                           0x0D1F\n#define GL_PIXEL_MAP_S_TO_S_SIZE                0x0CB1\n#define GL_PIXEL_MAP_I_TO_I_SIZE                0x0CB0\n#define GL_PIXEL_MAP_I_TO_R_SIZE                0x0CB2\n#define GL_PIXEL_MAP_I_TO_G_SIZE                0x0CB3\n#define GL_PIXEL_MAP_I_TO_B_SIZE                0x0CB4\n#define GL_PIXEL_MAP_I_TO_A_SIZE                0x0CB5\n#define GL_PIXEL_MAP_R_TO_R_SIZE                0x0CB6\n#define GL_PIXEL_MAP_G_TO_G_SIZE                0x0CB7\n#define GL_PIXEL_MAP_B_TO_B_SIZE                0x0CB8\n#define GL_PIXEL_MAP_A_TO_A_SIZE                0x0CB9\n#define GL_PIXEL_MAP_S_TO_S                     0x0C71\n#define GL_PIXEL_MAP_I_TO_I                     0x0C70\n#define GL_PIXEL_MAP_I_TO_R                     0x0C72\n#define GL_PIXEL_MAP_I_TO_G                     0x0C73\n#define GL_PIXEL_MAP_I_TO_B                     0x0C74\n#define GL_PIXEL_MAP_I_TO_A                     0x0C75\n#define GL_PIXEL_MAP_R_TO_R                     0x0C76\n#define GL_PIXEL_MAP_G_TO_G                     0x0C77\n#define GL_PIXEL_MAP_B_TO_B                     0x0C78\n#define GL_PIXEL_MAP_A_TO_A                     0x0C79\n#define GL_PACK_ALIGNMENT                       0x0D05\n#define GL_PACK_LSB_FIRST                       0x0D01\n#define GL_PACK_ROW_LENGTH                      0x0D02\n#define GL_PACK_SKIP_PIXELS                     0x0D04\n#define GL_PACK_SKIP_ROWS                       0x0D03\n#define GL_PACK_SWAP_BYTES                      0x0D00\n#define GL_UNPACK_ALIGNMENT                     0x0CF5\n#define GL_UNPACK_LSB_FIRST                     0x0CF1\n#define GL_UNPACK_ROW_LENGTH                    0x0CF2\n#define GL_UNPACK_SKIP_PIXELS                   0x0CF4\n#define GL_UNPACK_SKIP_ROWS                     0x0CF3\n#define GL_UNPACK_SWAP_BYTES                    0x0CF0\n#define GL_ZOOM_X                               0x0D16\n#define GL_ZOOM_Y                               0x0D17\n#define GL_TEXTURE_ENV                          0x2300\n#define GL_TEXTURE_ENV_MODE                     0x2200\n#define GL_TEXTURE_1D                           0x0DE0\n#define GL_TEXTURE_2D                           0x0DE1\n#define GL_TEXTURE_WRAP_S                       0x2802\n#define GL_TEXTURE_WRAP_T                       0x2803\n#define GL_TEXTURE_MAG_FILTER                   0x2800\n#define GL_TEXTURE_MIN_FILTER                   0x2801\n#define GL_TEXTURE_ENV_COLOR                    0x2201\n#define GL_TEXTURE_GEN_S                        0x0C60\n#define GL_TEXTURE_GEN_T                        0x0C61\n#define GL_TEXTURE_GEN_R                        0x0C62\n#define GL_TEXTURE_GEN_Q                        0x0C63\n#define GL_TEXTURE_GEN_MODE                     0x2500\n#define GL_TEXTURE_BORDER_COLOR                 0x1004\n#define GL_TEXTURE_WIDTH                        0x1000\n#define GL_TEXTURE_HEIGHT                       0x1001\n#define GL_TEXTURE_BORDER                       0x1005\n#define GL_TEXTURE_COMPONENTS                   0x1003\n#define GL_TEXTURE_RED_SIZE                     0x805C\n#define GL_TEXTURE_GREEN_SIZE                   0x805D\n#define GL_TEXTURE_BLUE_SIZE                    0x805E\n#define GL_TEXTURE_ALPHA_SIZE                   0x805F\n#define GL_TEXTURE_LUMINANCE_SIZE               0x8060\n#define GL_TEXTURE_INTENSITY_SIZE               0x8061\n#define GL_NEAREST_MIPMAP_NEAREST               0x2700\n#define GL_NEAREST_MIPMAP_LINEAR                0x2702\n#define GL_LINEAR_MIPMAP_NEAREST                0x2701\n#define GL_LINEAR_MIPMAP_LINEAR                 0x2703\n#define GL_OBJECT_LINEAR                        0x2401\n#define GL_OBJECT_PLANE                         0x2501\n#define GL_EYE_LINEAR                           0x2400\n#define GL_EYE_PLANE                            0x2502\n#define GL_SPHERE_MAP                           0x2402\n#define GL_DECAL                                0x2101\n#define GL_MODULATE                             0x2100\n#define GL_NEAREST                              0x2600\n#define GL_REPEAT                               0x2901\n#define GL_CLAMP                                0x2900\n#define GL_S                                    0x2000\n#define GL_T                                    0x2001\n#define GL_R                                    0x2002\n#define GL_Q                                    0x2003\n#define GL_VENDOR                               0x1F00\n#define GL_RENDERER                             0x1F01\n#define GL_VERSION                              0x1F02\n#define GL_EXTENSIONS                           0x1F03\n#define GL_NO_ERROR                             0\n#define GL_INVALID_ENUM                         0x0500\n#define GL_INVALID_VALUE                        0x0501\n#define GL_INVALID_OPERATION                    0x0502\n#define GL_STACK_OVERFLOW                       0x0503\n#define GL_STACK_UNDERFLOW                      0x0504\n#define GL_OUT_OF_MEMORY                        0x0505\n#define GL_CURRENT_BIT                          0x00000001\n#define GL_POINT_BIT                            0x00000002\n#define GL_LINE_BIT                             0x00000004\n#define GL_POLYGON_BIT                          0x00000008\n#define GL_POLYGON_STIPPLE_BIT                  0x00000010\n#define GL_PIXEL_MODE_BIT                       0x00000020\n#define GL_LIGHTING_BIT                         0x00000040\n#define GL_FOG_BIT                              0x00000080\n#define GL_DEPTH_BUFFER_BIT                     0x00000100\n#define GL_ACCUM_BUFFER_BIT                     0x00000200\n#define GL_STENCIL_BUFFER_BIT                   0x00000400\n#define GL_VIEWPORT_BIT                         0x00000800\n#define GL_TRANSFORM_BIT                        0x00001000\n#define GL_ENABLE_BIT                           0x00002000\n#define GL_COLOR_BUFFER_BIT                     0x00004000\n#define GL_HINT_BIT                             0x00008000\n#define GL_EVAL_BIT                             0x00010000\n#define GL_LIST_BIT                             0x00020000\n#define GL_TEXTURE_BIT                          0x00040000\n#define GL_SCISSOR_BIT                          0x00080000\n#define GL_ALL_ATTRIB_BITS                      0xFFFFFFFF\n#define GL_PROXY_TEXTURE_1D                     0x8063\n#define GL_PROXY_TEXTURE_2D                     0x8064\n#define GL_TEXTURE_PRIORITY                     0x8066\n#define GL_TEXTURE_RESIDENT                     0x8067\n#define GL_TEXTURE_BINDING_1D                   0x8068\n#define GL_TEXTURE_BINDING_2D                   0x8069\n#define GL_TEXTURE_INTERNAL_FORMAT              0x1003\n#define GL_ALPHA4                               0x803B\n#define GL_ALPHA8                               0x803C\n#define GL_ALPHA12                              0x803D\n#define GL_ALPHA16                              0x803E\n#define GL_LUMINANCE4                           0x803F\n#define GL_LUMINANCE8                           0x8040\n#define GL_LUMINANCE12                          0x8041\n#define GL_LUMINANCE16                          0x8042\n#define GL_LUMINANCE4_ALPHA4                    0x8043\n#define GL_LUMINANCE6_ALPHA2                    0x8044\n#define GL_LUMINANCE8_ALPHA8                    0x8045\n#define GL_LUMINANCE12_ALPHA4                   0x8046\n#define GL_LUMINANCE12_ALPHA12                  0x8047\n#define GL_LUMINANCE16_ALPHA16                  0x8048\n#define GL_INTENSITY                            0x8049\n#define GL_INTENSITY4                           0x804A\n#define GL_INTENSITY8                           0x804B\n#define GL_INTENSITY12                          0x804C\n#define GL_INTENSITY16                          0x804D\n#define GL_R3_G3_B2                             0x2A10\n#define GL_RGB4                                 0x804F\n#define GL_RGB5                                 0x8050\n#define GL_RGB8                                 0x8051\n#define GL_RGB10                                0x8052\n#define GL_RGB12                                0x8053\n#define GL_RGB16                                0x8054\n#define GL_RGBA2                                0x8055\n#define GL_RGBA4                                0x8056\n#define GL_RGB5_A1                              0x8057\n#define GL_RGBA8                                0x8058\n#define GL_RGB10_A2                             0x8059\n#define GL_RGBA12                               0x805A\n#define GL_RGBA16                               0x805B\n#define GL_CLIENT_PIXEL_STORE_BIT               0x00000001\n#define GL_CLIENT_VERTEX_ARRAY_BIT              0x00000002\n#define GL_ALL_CLIENT_ATTRIB_BITS               0xFFFFFFFF\n#define GL_CLIENT_ALL_ATTRIB_BITS               0xFFFFFFFF\n#define GL_RESCALE_NORMAL                       0x803A\n#define GL_CLAMP_TO_EDGE                        0x812F\n#define GL_MAX_ELEMENTS_VERTICES                0x80E8\n#define GL_MAX_ELEMENTS_INDICES                 0x80E9\n#define GL_BGR                                  0x80E0\n#define GL_BGRA                                 0x80E1\n#define GL_UNSIGNED_BYTE_3_3_2                  0x8032\n#define GL_UNSIGNED_BYTE_2_3_3_REV              0x8362\n#define GL_UNSIGNED_SHORT_5_6_5                 0x8363\n#define GL_UNSIGNED_SHORT_5_6_5_REV             0x8364\n#define GL_UNSIGNED_SHORT_4_4_4_4               0x8033\n#define GL_UNSIGNED_SHORT_4_4_4_4_REV           0x8365\n#define GL_UNSIGNED_SHORT_5_5_5_1               0x8034\n#define GL_UNSIGNED_SHORT_1_5_5_5_REV           0x8366\n#define GL_UNSIGNED_INT_8_8_8_8                 0x8035\n#define GL_UNSIGNED_INT_8_8_8_8_REV             0x8367\n#define GL_UNSIGNED_INT_10_10_10_2              0x8036\n#define GL_UNSIGNED_INT_2_10_10_10_REV          0x8368\n#define GL_LIGHT_MODEL_COLOR_CONTROL            0x81F8\n#define GL_SINGLE_COLOR                         0x81F9\n#define GL_SEPARATE_SPECULAR_COLOR              0x81FA\n#define GL_TEXTURE_MIN_LOD                      0x813A\n#define GL_TEXTURE_MAX_LOD                      0x813B\n#define GL_TEXTURE_BASE_LEVEL                   0x813C\n#define GL_TEXTURE_MAX_LEVEL                    0x813D\n#define GL_SMOOTH_POINT_SIZE_RANGE              0x0B12\n#define GL_SMOOTH_POINT_SIZE_GRANULARITY        0x0B13\n#define GL_SMOOTH_LINE_WIDTH_RANGE              0x0B22\n#define GL_SMOOTH_LINE_WIDTH_GRANULARITY        0x0B23\n#define GL_ALIASED_POINT_SIZE_RANGE             0x846D\n#define GL_ALIASED_LINE_WIDTH_RANGE             0x846E\n#define GL_PACK_SKIP_IMAGES                     0x806B\n#define GL_PACK_IMAGE_HEIGHT                    0x806C\n#define GL_UNPACK_SKIP_IMAGES                   0x806D\n#define GL_UNPACK_IMAGE_HEIGHT                  0x806E\n#define GL_TEXTURE_3D                           0x806F\n#define GL_PROXY_TEXTURE_3D                     0x8070\n#define GL_TEXTURE_DEPTH                        0x8071\n#define GL_TEXTURE_WRAP_R                       0x8072\n#define GL_MAX_3D_TEXTURE_SIZE                  0x8073\n#define GL_TEXTURE_BINDING_3D                   0x806A\n#define GL_CONSTANT_COLOR                       0x8001\n#define GL_ONE_MINUS_CONSTANT_COLOR             0x8002\n#define GL_CONSTANT_ALPHA                       0x8003\n#define GL_ONE_MINUS_CONSTANT_ALPHA             0x8004\n#define GL_COLOR_TABLE                          0x80D0\n#define GL_POST_CONVOLUTION_COLOR_TABLE         0x80D1\n#define GL_POST_COLOR_MATRIX_COLOR_TABLE        0x80D2\n#define GL_PROXY_COLOR_TABLE                    0x80D3\n#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE   0x80D4\n#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE  0x80D5\n#define GL_COLOR_TABLE_SCALE                    0x80D6\n#define GL_COLOR_TABLE_BIAS                     0x80D7\n#define GL_COLOR_TABLE_FORMAT                   0x80D8\n#define GL_COLOR_TABLE_WIDTH                    0x80D9\n#define GL_COLOR_TABLE_RED_SIZE                 0x80DA\n#define GL_COLOR_TABLE_GREEN_SIZE               0x80DB\n#define GL_COLOR_TABLE_BLUE_SIZE                0x80DC\n#define GL_COLOR_TABLE_ALPHA_SIZE               0x80DD\n#define GL_COLOR_TABLE_LUMINANCE_SIZE           0x80DE\n#define GL_COLOR_TABLE_INTENSITY_SIZE           0x80DF\n#define GL_CONVOLUTION_1D                       0x8010\n#define GL_CONVOLUTION_2D                       0x8011\n#define GL_SEPARABLE_2D                         0x8012\n#define GL_CONVOLUTION_BORDER_MODE              0x8013\n#define GL_CONVOLUTION_FILTER_SCALE             0x8014\n#define GL_CONVOLUTION_FILTER_BIAS              0x8015\n#define GL_REDUCE                               0x8016\n#define GL_CONVOLUTION_FORMAT                   0x8017\n#define GL_CONVOLUTION_WIDTH                    0x8018\n#define GL_CONVOLUTION_HEIGHT                   0x8019\n#define GL_MAX_CONVOLUTION_WIDTH                0x801A\n#define GL_MAX_CONVOLUTION_HEIGHT               0x801B\n#define GL_POST_CONVOLUTION_RED_SCALE           0x801C\n#define GL_POST_CONVOLUTION_GREEN_SCALE         0x801D\n#define GL_POST_CONVOLUTION_BLUE_SCALE          0x801E\n#define GL_POST_CONVOLUTION_ALPHA_SCALE         0x801F\n#define GL_POST_CONVOLUTION_RED_BIAS            0x8020\n#define GL_POST_CONVOLUTION_GREEN_BIAS          0x8021\n#define GL_POST_CONVOLUTION_BLUE_BIAS           0x8022\n#define GL_POST_CONVOLUTION_ALPHA_BIAS          0x8023\n#define GL_CONSTANT_BORDER                      0x8151\n#define GL_REPLICATE_BORDER                     0x8153\n#define GL_CONVOLUTION_BORDER_COLOR             0x8154\n#define GL_COLOR_MATRIX                         0x80B1\n#define GL_COLOR_MATRIX_STACK_DEPTH             0x80B2\n#define GL_MAX_COLOR_MATRIX_STACK_DEPTH         0x80B3\n#define GL_POST_COLOR_MATRIX_RED_SCALE          0x80B4\n#define GL_POST_COLOR_MATRIX_GREEN_SCALE        0x80B5\n#define GL_POST_COLOR_MATRIX_BLUE_SCALE         0x80B6\n#define GL_POST_COLOR_MATRIX_ALPHA_SCALE        0x80B7\n#define GL_POST_COLOR_MATRIX_RED_BIAS           0x80B8\n#define GL_POST_COLOR_MATRIX_GREEN_BIAS         0x80B9\n#define GL_POST_COLOR_MATRIX_BLUE_BIAS          0x80BA\n#define GL_POST_COLOR_MATRIX_ALPHA_BIAS         0x80BB\n#define GL_HISTOGRAM                            0x8024\n#define GL_PROXY_HISTOGRAM                      0x8025\n#define GL_HISTOGRAM_WIDTH                      0x8026\n#define GL_HISTOGRAM_FORMAT                     0x8027\n#define GL_HISTOGRAM_RED_SIZE                   0x8028\n#define GL_HISTOGRAM_GREEN_SIZE                 0x8029\n#define GL_HISTOGRAM_BLUE_SIZE                  0x802A\n#define GL_HISTOGRAM_ALPHA_SIZE                 0x802B\n#define GL_HISTOGRAM_LUMINANCE_SIZE             0x802C\n#define GL_HISTOGRAM_SINK                       0x802D\n#define GL_MINMAX                               0x802E\n#define GL_MINMAX_FORMAT                        0x802F\n#define GL_MINMAX_SINK                          0x8030\n#define GL_TABLE_TOO_LARGE                      0x8031\n#define GL_BLEND_EQUATION                       0x8009\n#define GL_MIN                                  0x8007\n#define GL_MAX                                  0x8008\n#define GL_FUNC_ADD                             0x8006\n#define GL_FUNC_SUBTRACT                        0x800A\n#define GL_FUNC_REVERSE_SUBTRACT                0x800B\n#define GL_BLEND_COLOR                          0x8005\n#define GL_TEXTURE0                             0x84C0\n#define GL_TEXTURE1                             0x84C1\n#define GL_TEXTURE2                             0x84C2\n#define GL_TEXTURE3                             0x84C3\n#define GL_TEXTURE4                             0x84C4\n#define GL_TEXTURE5                             0x84C5\n#define GL_TEXTURE6                             0x84C6\n#define GL_TEXTURE7                             0x84C7\n#define GL_TEXTURE8                             0x84C8\n#define GL_TEXTURE9                             0x84C9\n#define GL_TEXTURE10                            0x84CA\n#define GL_TEXTURE11                            0x84CB\n#define GL_TEXTURE12                            0x84CC\n#define GL_TEXTURE13                            0x84CD\n#define GL_TEXTURE14                            0x84CE\n#define GL_TEXTURE15                            0x84CF\n#define GL_TEXTURE16                            0x84D0\n#define GL_TEXTURE17                            0x84D1\n#define GL_TEXTURE18                            0x84D2\n#define GL_TEXTURE19                            0x84D3\n#define GL_TEXTURE20                            0x84D4\n#define GL_TEXTURE21                            0x84D5\n#define GL_TEXTURE22                            0x84D6\n#define GL_TEXTURE23                            0x84D7\n#define GL_TEXTURE24                            0x84D8\n#define GL_TEXTURE25                            0x84D9\n#define GL_TEXTURE26                            0x84DA\n#define GL_TEXTURE27                            0x84DB\n#define GL_TEXTURE28                            0x84DC\n#define GL_TEXTURE29                            0x84DD\n#define GL_TEXTURE30                            0x84DE\n#define GL_TEXTURE31                            0x84DF\n#define GL_ACTIVE_TEXTURE                       0x84E0\n#define GL_CLIENT_ACTIVE_TEXTURE                0x84E1\n#define GL_MAX_TEXTURE_UNITS                    0x84E2\n#define GL_NORMAL_MAP                           0x8511\n#define GL_REFLECTION_MAP                       0x8512\n#define GL_TEXTURE_CUBE_MAP                     0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP             0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X          0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X          0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y          0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y          0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z          0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z          0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP               0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE            0x851C\n#define GL_COMPRESSED_ALPHA                     0x84E9\n#define GL_COMPRESSED_LUMINANCE                 0x84EA\n#define GL_COMPRESSED_LUMINANCE_ALPHA           0x84EB\n#define GL_COMPRESSED_INTENSITY                 0x84EC\n#define GL_COMPRESSED_RGB                       0x84ED\n#define GL_COMPRESSED_RGBA                      0x84EE\n#define GL_TEXTURE_COMPRESSION_HINT             0x84EF\n#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE        0x86A0\n#define GL_TEXTURE_COMPRESSED                   0x86A1\n#define GL_NUM_COMPRESSED_TEXTURE_FORMATS       0x86A2\n#define GL_COMPRESSED_TEXTURE_FORMATS           0x86A3\n#define GL_MULTISAMPLE                          0x809D\n#define GL_SAMPLE_ALPHA_TO_COVERAGE             0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE                  0x809F\n#define GL_SAMPLE_COVERAGE                      0x80A0\n#define GL_SAMPLE_BUFFERS                       0x80A8\n#define GL_SAMPLES                              0x80A9\n#define GL_SAMPLE_COVERAGE_VALUE                0x80AA\n#define GL_SAMPLE_COVERAGE_INVERT               0x80AB\n#define GL_MULTISAMPLE_BIT                      0x20000000\n#define GL_TRANSPOSE_MODELVIEW_MATRIX           0x84E3\n#define GL_TRANSPOSE_PROJECTION_MATRIX          0x84E4\n#define GL_TRANSPOSE_TEXTURE_MATRIX             0x84E5\n#define GL_TRANSPOSE_COLOR_MATRIX               0x84E6\n#define GL_COMBINE                              0x8570\n#define GL_COMBINE_RGB                          0x8571\n#define GL_COMBINE_ALPHA                        0x8572\n#define GL_SOURCE0_RGB                          0x8580\n#define GL_SOURCE1_RGB                          0x8581\n#define GL_SOURCE2_RGB                          0x8582\n#define GL_SOURCE0_ALPHA                        0x8588\n#define GL_SOURCE1_ALPHA                        0x8589\n#define GL_SOURCE2_ALPHA                        0x858A\n#define GL_OPERAND0_RGB                         0x8590\n#define GL_OPERAND1_RGB                         0x8591\n#define GL_OPERAND2_RGB                         0x8592\n#define GL_OPERAND0_ALPHA                       0x8598\n#define GL_OPERAND1_ALPHA                       0x8599\n#define GL_OPERAND2_ALPHA                       0x859A\n#define GL_RGB_SCALE                            0x8573\n#define GL_ADD_SIGNED                           0x8574\n#define GL_INTERPOLATE                          0x8575\n#define GL_SUBTRACT                             0x84E7\n#define GL_CONSTANT                             0x8576\n#define GL_PRIMARY_COLOR                        0x8577\n#define GL_PREVIOUS                             0x8578\n#define GL_DOT3_RGB                             0x86AE\n#define GL_DOT3_RGBA                            0x86AF\n#define GL_CLAMP_TO_BORDER                      0x812D\n#define GL_ARB_multitexture 1\n#define GL_TEXTURE0_ARB                         0x84C0\n#define GL_TEXTURE1_ARB                         0x84C1\n#define GL_TEXTURE2_ARB                         0x84C2\n#define GL_TEXTURE3_ARB                         0x84C3\n#define GL_TEXTURE4_ARB                         0x84C4\n#define GL_TEXTURE5_ARB                         0x84C5\n#define GL_TEXTURE6_ARB                         0x84C6\n#define GL_TEXTURE7_ARB                         0x84C7\n#define GL_TEXTURE8_ARB                         0x84C8\n#define GL_TEXTURE9_ARB                         0x84C9\n#define GL_TEXTURE10_ARB                        0x84CA\n#define GL_TEXTURE11_ARB                        0x84CB\n#define GL_TEXTURE12_ARB                        0x84CC\n#define GL_TEXTURE13_ARB                        0x84CD\n#define GL_TEXTURE14_ARB                        0x84CE\n#define GL_TEXTURE15_ARB                        0x84CF\n#define GL_TEXTURE16_ARB                        0x84D0\n#define GL_TEXTURE17_ARB                        0x84D1\n#define GL_TEXTURE18_ARB                        0x84D2\n#define GL_TEXTURE19_ARB                        0x84D3\n#define GL_TEXTURE20_ARB                        0x84D4\n#define GL_TEXTURE21_ARB                        0x84D5\n#define GL_TEXTURE22_ARB                        0x84D6\n#define GL_TEXTURE23_ARB                        0x84D7\n#define GL_TEXTURE24_ARB                        0x84D8\n#define GL_TEXTURE25_ARB                        0x84D9\n#define GL_TEXTURE26_ARB                        0x84DA\n#define GL_TEXTURE27_ARB                        0x84DB\n#define GL_TEXTURE28_ARB                        0x84DC\n#define GL_TEXTURE29_ARB                        0x84DD\n#define GL_TEXTURE30_ARB                        0x84DE\n#define GL_TEXTURE31_ARB                        0x84DF\n#define GL_ACTIVE_TEXTURE_ARB                   0x84E0\n#define GL_CLIENT_ACTIVE_TEXTURE_ARB            0x84E1\n#define GL_MAX_TEXTURE_UNITS_ARB                0x84E2\n#define GL_MESA_packed_depth_stencil 1\n#define GL_DEPTH_STENCIL_MESA                   0x8750\n#define GL_UNSIGNED_INT_24_8_MESA               0x8751\n#define GL_UNSIGNED_INT_8_24_REV_MESA           0x8752\n#define GL_UNSIGNED_SHORT_15_1_MESA             0x8753\n#define GL_UNSIGNED_SHORT_1_15_REV_MESA         0x8754\n#define GL_ATI_blend_equation_separate 1\n#define GL_ALPHA_BLEND_EQUATION_ATI             0x883D\n#define GL_OES_EGL_image 1\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __NX_GL_H__ */\n"
  },
  {
    "path": "include/glsym/switch/nx_glsym.h",
    "content": "#ifndef __NX_GLSYM_H__\n#define __NX_GLSYM_H__\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef void *GLeglImageOES;\ntypedef void (APIENTRYP RGLSYMGLCLEARINDEXPROC) ( GLfloat c );\ntypedef void (APIENTRYP RGLSYMGLCLEARCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );\ntypedef void (APIENTRYP RGLSYMGLCLEARPROC) ( GLbitfield mask );\ntypedef void (APIENTRYP RGLSYMGLINDEXMASKPROC) ( GLuint mask );\ntypedef void (APIENTRYP RGLSYMGLCOLORMASKPROC) ( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );\ntypedef void (APIENTRYP RGLSYMGLALPHAFUNCPROC) ( GLenum func, GLclampf ref );\ntypedef void (APIENTRYP RGLSYMGLBLENDFUNCPROC) ( GLenum sfactor, GLenum dfactor );\ntypedef void (APIENTRYP RGLSYMGLLOGICOPPROC) ( GLenum opcode );\ntypedef void (APIENTRYP RGLSYMGLCULLFACEPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLFRONTFACEPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLPOINTSIZEPROC) ( GLfloat size );\ntypedef void (APIENTRYP RGLSYMGLLINEWIDTHPROC) ( GLfloat width );\ntypedef void (APIENTRYP RGLSYMGLLINESTIPPLEPROC) ( GLint factor, GLushort pattern );\ntypedef void (APIENTRYP RGLSYMGLPOLYGONMODEPROC) ( GLenum face, GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLPOLYGONOFFSETPROC) ( GLfloat factor, GLfloat units );\ntypedef void (APIENTRYP RGLSYMGLPOLYGONSTIPPLEPROC) ( const GLubyte *mask );\ntypedef void (APIENTRYP RGLSYMGLGETPOLYGONSTIPPLEPROC) ( GLubyte *mask );\ntypedef void (APIENTRYP RGLSYMGLEDGEFLAGPROC) ( GLboolean flag );\ntypedef void (APIENTRYP RGLSYMGLEDGEFLAGVPROC) ( const GLboolean *flag );\ntypedef void (APIENTRYP RGLSYMGLSCISSORPROC) ( GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLCLIPPLANEPROC) ( GLenum plane, const GLdouble *equation );\ntypedef void (APIENTRYP RGLSYMGLGETCLIPPLANEPROC) ( GLenum plane, GLdouble *equation );\ntypedef void (APIENTRYP RGLSYMGLDRAWBUFFERPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLREADBUFFERPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLENABLEPROC) ( GLenum cap );\ntypedef void (APIENTRYP RGLSYMGLDISABLEPROC) ( GLenum cap );\ntypedef GLboolean (APIENTRYP RGLSYMGLISENABLEDPROC) ( GLenum cap );\ntypedef void (APIENTRYP RGLSYMGLENABLECLIENTSTATEPROC) ( GLenum cap );\ntypedef void (APIENTRYP RGLSYMGLDISABLECLIENTSTATEPROC) ( GLenum cap );\ntypedef void (APIENTRYP RGLSYMGLGETBOOLEANVPROC) ( GLenum pname, GLboolean *params );\ntypedef void (APIENTRYP RGLSYMGLGETDOUBLEVPROC) ( GLenum pname, GLdouble *params );\ntypedef void (APIENTRYP RGLSYMGLGETFLOATVPROC) ( GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETINTEGERVPROC) ( GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLPUSHATTRIBPROC) ( GLbitfield mask );\ntypedef void (APIENTRYP RGLSYMGLPOPATTRIBPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLPUSHCLIENTATTRIBPROC) ( GLbitfield mask );\ntypedef void (APIENTRYP RGLSYMGLPOPCLIENTATTRIBPROC) ( void );\ntypedef GLint (APIENTRYP RGLSYMGLRENDERMODEPROC) ( GLenum mode );\ntypedef GLenum (APIENTRYP RGLSYMGLGETERRORPROC) ( void );\ntypedef const GLubyte * (APIENTRYP RGLSYMGLGETSTRINGPROC) ( GLenum name );\ntypedef void (APIENTRYP RGLSYMGLFINISHPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLFLUSHPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLHINTPROC) ( GLenum target, GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLCLEARDEPTHPROC) ( GLclampd depth );\ntypedef void (APIENTRYP RGLSYMGLDEPTHFUNCPROC) ( GLenum func );\ntypedef void (APIENTRYP RGLSYMGLDEPTHMASKPROC) ( GLboolean flag );\ntypedef void (APIENTRYP RGLSYMGLDEPTHRANGEPROC) ( GLclampd near_val, GLclampd far_val );\ntypedef void (APIENTRYP RGLSYMGLCLEARACCUMPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );\ntypedef void (APIENTRYP RGLSYMGLACCUMPROC) ( GLenum op, GLfloat value );\ntypedef void (APIENTRYP RGLSYMGLMATRIXMODEPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLORTHOPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );\ntypedef void (APIENTRYP RGLSYMGLFRUSTUMPROC) ( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val );\ntypedef void (APIENTRYP RGLSYMGLVIEWPORTPROC) ( GLint x, GLint y, GLsizei width, GLsizei height );\ntypedef void (APIENTRYP RGLSYMGLPUSHMATRIXPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLPOPMATRIXPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLLOADIDENTITYPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLLOADMATRIXDPROC) ( const GLdouble *m );\ntypedef void (APIENTRYP RGLSYMGLLOADMATRIXFPROC) ( const GLfloat *m );\ntypedef void (APIENTRYP RGLSYMGLMULTMATRIXDPROC) ( const GLdouble *m );\ntypedef void (APIENTRYP RGLSYMGLMULTMATRIXFPROC) ( const GLfloat *m );\ntypedef void (APIENTRYP RGLSYMGLROTATEDPROC) ( GLdouble angle, GLdouble x, GLdouble y, GLdouble z );\ntypedef void (APIENTRYP RGLSYMGLROTATEFPROC) ( GLfloat angle, GLfloat x, GLfloat y, GLfloat z );\ntypedef void (APIENTRYP RGLSYMGLSCALEDPROC) ( GLdouble x, GLdouble y, GLdouble z );\ntypedef void (APIENTRYP RGLSYMGLSCALEFPROC) ( GLfloat x, GLfloat y, GLfloat z );\ntypedef void (APIENTRYP RGLSYMGLTRANSLATEDPROC) ( GLdouble x, GLdouble y, GLdouble z );\ntypedef void (APIENTRYP RGLSYMGLTRANSLATEFPROC) ( GLfloat x, GLfloat y, GLfloat z );\ntypedef GLboolean (APIENTRYP RGLSYMGLISLISTPROC) ( GLuint list );\ntypedef void (APIENTRYP RGLSYMGLDELETELISTSPROC) ( GLuint list, GLsizei range );\ntypedef GLuint (APIENTRYP RGLSYMGLGENLISTSPROC) ( GLsizei range );\ntypedef void (APIENTRYP RGLSYMGLNEWLISTPROC) ( GLuint list, GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLENDLISTPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLCALLLISTPROC) ( GLuint list );\ntypedef void (APIENTRYP RGLSYMGLCALLLISTSPROC) ( GLsizei n, GLenum type, const GLvoid *lists );\ntypedef void (APIENTRYP RGLSYMGLLISTBASEPROC) ( GLuint base );\ntypedef void (APIENTRYP RGLSYMGLBEGINPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLENDPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2DPROC) ( GLdouble x, GLdouble y );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2FPROC) ( GLfloat x, GLfloat y );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2IPROC) ( GLint x, GLint y );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2SPROC) ( GLshort x, GLshort y );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3DPROC) ( GLdouble x, GLdouble y, GLdouble z );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3FPROC) ( GLfloat x, GLfloat y, GLfloat z );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3IPROC) ( GLint x, GLint y, GLint z );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3SPROC) ( GLshort x, GLshort y, GLshort z );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4IPROC) ( GLint x, GLint y, GLint z, GLint w );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX2SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX3SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLVERTEX4SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3BPROC) ( GLbyte nx, GLbyte ny, GLbyte nz );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3DPROC) ( GLdouble nx, GLdouble ny, GLdouble nz );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3FPROC) ( GLfloat nx, GLfloat ny, GLfloat nz );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3IPROC) ( GLint nx, GLint ny, GLint nz );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3SPROC) ( GLshort nx, GLshort ny, GLshort nz );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3BVPROC) ( const GLbyte *v );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLNORMAL3SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLINDEXDPROC) ( GLdouble c );\ntypedef void (APIENTRYP RGLSYMGLINDEXFPROC) ( GLfloat c );\ntypedef void (APIENTRYP RGLSYMGLINDEXIPROC) ( GLint c );\ntypedef void (APIENTRYP RGLSYMGLINDEXSPROC) ( GLshort c );\ntypedef void (APIENTRYP RGLSYMGLINDEXUBPROC) ( GLubyte c );\ntypedef void (APIENTRYP RGLSYMGLINDEXDVPROC) ( const GLdouble *c );\ntypedef void (APIENTRYP RGLSYMGLINDEXFVPROC) ( const GLfloat *c );\ntypedef void (APIENTRYP RGLSYMGLINDEXIVPROC) ( const GLint *c );\ntypedef void (APIENTRYP RGLSYMGLINDEXSVPROC) ( const GLshort *c );\ntypedef void (APIENTRYP RGLSYMGLINDEXUBVPROC) ( const GLubyte *c );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3BPROC) ( GLbyte red, GLbyte green, GLbyte blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3DPROC) ( GLdouble red, GLdouble green, GLdouble blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3FPROC) ( GLfloat red, GLfloat green, GLfloat blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3IPROC) ( GLint red, GLint green, GLint blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3SPROC) ( GLshort red, GLshort green, GLshort blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3UBPROC) ( GLubyte red, GLubyte green, GLubyte blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3UIPROC) ( GLuint red, GLuint green, GLuint blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3USPROC) ( GLushort red, GLushort green, GLushort blue );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4BPROC) ( GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4DPROC) ( GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4FPROC) ( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4IPROC) ( GLint red, GLint green, GLint blue, GLint alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4SPROC) ( GLshort red, GLshort green, GLshort blue, GLshort alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4UBPROC) ( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4UIPROC) ( GLuint red, GLuint green, GLuint blue, GLuint alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4USPROC) ( GLushort red, GLushort green, GLushort blue, GLushort alpha );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3BVPROC) ( const GLbyte *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3UBVPROC) ( const GLubyte *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3UIVPROC) ( const GLuint *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR3USVPROC) ( const GLushort *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4BVPROC) ( const GLbyte *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4UBVPROC) ( const GLubyte *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4UIVPROC) ( const GLuint *v );\ntypedef void (APIENTRYP RGLSYMGLCOLOR4USVPROC) ( const GLushort *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1DPROC) ( GLdouble s );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1FPROC) ( GLfloat s );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1IPROC) ( GLint s );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1SPROC) ( GLshort s );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2DPROC) ( GLdouble s, GLdouble t );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2FPROC) ( GLfloat s, GLfloat t );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2IPROC) ( GLint s, GLint t );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2SPROC) ( GLshort s, GLshort t );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3DPROC) ( GLdouble s, GLdouble t, GLdouble r );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3FPROC) ( GLfloat s, GLfloat t, GLfloat r );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3IPROC) ( GLint s, GLint t, GLint r );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3SPROC) ( GLshort s, GLshort t, GLshort r );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4DPROC) ( GLdouble s, GLdouble t, GLdouble r, GLdouble q );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4FPROC) ( GLfloat s, GLfloat t, GLfloat r, GLfloat q );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4IPROC) ( GLint s, GLint t, GLint r, GLint q );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4SPROC) ( GLshort s, GLshort t, GLshort r, GLshort q );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD1SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD2SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD3SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORD4SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2DPROC) ( GLdouble x, GLdouble y );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2FPROC) ( GLfloat x, GLfloat y );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2IPROC) ( GLint x, GLint y );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2SPROC) ( GLshort x, GLshort y );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3DPROC) ( GLdouble x, GLdouble y, GLdouble z );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3FPROC) ( GLfloat x, GLfloat y, GLfloat z );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3IPROC) ( GLint x, GLint y, GLint z );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3SPROC) ( GLshort x, GLshort y, GLshort z );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4DPROC) ( GLdouble x, GLdouble y, GLdouble z, GLdouble w );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4FPROC) ( GLfloat x, GLfloat y, GLfloat z, GLfloat w );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4IPROC) ( GLint x, GLint y, GLint z, GLint w );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4SPROC) ( GLshort x, GLshort y, GLshort z, GLshort w );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS2SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS3SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4DVPROC) ( const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4FVPROC) ( const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4IVPROC) ( const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLRASTERPOS4SVPROC) ( const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLRECTDPROC) ( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 );\ntypedef void (APIENTRYP RGLSYMGLRECTFPROC) ( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 );\ntypedef void (APIENTRYP RGLSYMGLRECTIPROC) ( GLint x1, GLint y1, GLint x2, GLint y2 );\ntypedef void (APIENTRYP RGLSYMGLRECTSPROC) ( GLshort x1, GLshort y1, GLshort x2, GLshort y2 );\ntypedef void (APIENTRYP RGLSYMGLRECTDVPROC) ( const GLdouble *v1, const GLdouble *v2 );\ntypedef void (APIENTRYP RGLSYMGLRECTFVPROC) ( const GLfloat *v1, const GLfloat *v2 );\ntypedef void (APIENTRYP RGLSYMGLRECTIVPROC) ( const GLint *v1, const GLint *v2 );\ntypedef void (APIENTRYP RGLSYMGLRECTSVPROC) ( const GLshort *v1, const GLshort *v2 );\ntypedef void (APIENTRYP RGLSYMGLVERTEXPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );\ntypedef void (APIENTRYP RGLSYMGLNORMALPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );\ntypedef void (APIENTRYP RGLSYMGLCOLORPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );\ntypedef void (APIENTRYP RGLSYMGLINDEXPOINTERPROC) ( GLenum type, GLsizei stride, const GLvoid *ptr );\ntypedef void (APIENTRYP RGLSYMGLTEXCOORDPOINTERPROC) ( GLint size, GLenum type, GLsizei stride, const GLvoid *ptr );\ntypedef void (APIENTRYP RGLSYMGLEDGEFLAGPOINTERPROC) ( GLsizei stride, const GLvoid *ptr );\ntypedef void (APIENTRYP RGLSYMGLGETPOINTERVPROC) ( GLenum pname, GLvoid **params );\ntypedef void (APIENTRYP RGLSYMGLARRAYELEMENTPROC) ( GLint i );\ntypedef void (APIENTRYP RGLSYMGLDRAWARRAYSPROC) ( GLenum mode, GLint first, GLsizei count );\ntypedef void (APIENTRYP RGLSYMGLDRAWELEMENTSPROC) ( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices );\ntypedef void (APIENTRYP RGLSYMGLINTERLEAVEDARRAYSPROC) ( GLenum format, GLsizei stride, const GLvoid *pointer );\ntypedef void (APIENTRYP RGLSYMGLSHADEMODELPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLLIGHTFPROC) ( GLenum light, GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLLIGHTIPROC) ( GLenum light, GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLLIGHTFVPROC) ( GLenum light, GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLLIGHTIVPROC) ( GLenum light, GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLGETLIGHTFVPROC) ( GLenum light, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETLIGHTIVPROC) ( GLenum light, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLLIGHTMODELFPROC) ( GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLLIGHTMODELIPROC) ( GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLLIGHTMODELFVPROC) ( GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLLIGHTMODELIVPROC) ( GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLMATERIALFPROC) ( GLenum face, GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLMATERIALIPROC) ( GLenum face, GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLMATERIALFVPROC) ( GLenum face, GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLMATERIALIVPROC) ( GLenum face, GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLGETMATERIALFVPROC) ( GLenum face, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETMATERIALIVPROC) ( GLenum face, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLCOLORMATERIALPROC) ( GLenum face, GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLPIXELZOOMPROC) ( GLfloat xfactor, GLfloat yfactor );\ntypedef void (APIENTRYP RGLSYMGLPIXELSTOREFPROC) ( GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLPIXELSTOREIPROC) ( GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLPIXELTRANSFERFPROC) ( GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLPIXELTRANSFERIPROC) ( GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLPIXELMAPFVPROC) ( GLenum map, GLsizei mapsize, const GLfloat *values );\ntypedef void (APIENTRYP RGLSYMGLPIXELMAPUIVPROC) ( GLenum map, GLsizei mapsize, const GLuint *values );\ntypedef void (APIENTRYP RGLSYMGLPIXELMAPUSVPROC) ( GLenum map, GLsizei mapsize, const GLushort *values );\ntypedef void (APIENTRYP RGLSYMGLGETPIXELMAPFVPROC) ( GLenum map, GLfloat *values );\ntypedef void (APIENTRYP RGLSYMGLGETPIXELMAPUIVPROC) ( GLenum map, GLuint *values );\ntypedef void (APIENTRYP RGLSYMGLGETPIXELMAPUSVPROC) ( GLenum map, GLushort *values );\ntypedef void (APIENTRYP RGLSYMGLBITMAPPROC) ( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap );\ntypedef void (APIENTRYP RGLSYMGLREADPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLDRAWPIXELSPROC) ( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLCOPYPIXELSPROC) ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type );\ntypedef void (APIENTRYP RGLSYMGLSTENCILFUNCPROC) ( GLenum func, GLint ref, GLuint mask );\ntypedef void (APIENTRYP RGLSYMGLSTENCILMASKPROC) ( GLuint mask );\ntypedef void (APIENTRYP RGLSYMGLSTENCILOPPROC) ( GLenum fail, GLenum zfail, GLenum zpass );\ntypedef void (APIENTRYP RGLSYMGLCLEARSTENCILPROC) ( GLint s );\ntypedef void (APIENTRYP RGLSYMGLTEXGENDPROC) ( GLenum coord, GLenum pname, GLdouble param );\ntypedef void (APIENTRYP RGLSYMGLTEXGENFPROC) ( GLenum coord, GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLTEXGENIPROC) ( GLenum coord, GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLTEXGENDVPROC) ( GLenum coord, GLenum pname, const GLdouble *params );\ntypedef void (APIENTRYP RGLSYMGLTEXGENFVPROC) ( GLenum coord, GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLTEXGENIVPROC) ( GLenum coord, GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXGENDVPROC) ( GLenum coord, GLenum pname, GLdouble *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXGENFVPROC) ( GLenum coord, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXGENIVPROC) ( GLenum coord, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLTEXENVFPROC) ( GLenum target, GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLTEXENVIPROC) ( GLenum target, GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLTEXENVFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLTEXENVIVPROC) ( GLenum target, GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXENVFVPROC) ( GLenum target, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXENVIVPROC) ( GLenum target, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERFPROC) ( GLenum target, GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERIPROC) ( GLenum target, GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLGETTEXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERFVPROC) ( GLenum target, GLint level, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETTEXLEVELPARAMETERIVPROC) ( GLenum target, GLint level, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLTEXIMAGE1DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLTEXIMAGE2DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLGETTEXIMAGEPROC) ( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLGENTEXTURESPROC) ( GLsizei n, GLuint *textures );\ntypedef void (APIENTRYP RGLSYMGLDELETETEXTURESPROC) ( GLsizei n, const GLuint *textures);\ntypedef void (APIENTRYP RGLSYMGLBINDTEXTUREPROC) ( GLenum target, GLuint texture );\ntypedef void (APIENTRYP RGLSYMGLPRIORITIZETEXTURESPROC) ( GLsizei n, const GLuint *textures, const GLclampf *priorities );\ntypedef GLboolean (APIENTRYP RGLSYMGLARETEXTURESRESIDENTPROC) ( GLsizei n, const GLuint *textures, GLboolean *residences );\ntypedef GLboolean (APIENTRYP RGLSYMGLISTEXTUREPROC) ( GLuint texture );\ntypedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels );\ntypedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border );\ntypedef void (APIENTRYP RGLSYMGLCOPYTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border );\ntypedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width );\ntypedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height );\ntypedef void (APIENTRYP RGLSYMGLMAP1DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points );\ntypedef void (APIENTRYP RGLSYMGLMAP1FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points );\ntypedef void (APIENTRYP RGLSYMGLMAP2DPROC) ( GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points );\ntypedef void (APIENTRYP RGLSYMGLMAP2FPROC) ( GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points );\ntypedef void (APIENTRYP RGLSYMGLGETMAPDVPROC) ( GLenum target, GLenum query, GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLGETMAPFVPROC) ( GLenum target, GLenum query, GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLGETMAPIVPROC) ( GLenum target, GLenum query, GLint *v );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD1DPROC) ( GLdouble u );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD1FPROC) ( GLfloat u );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD1DVPROC) ( const GLdouble *u );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD1FVPROC) ( const GLfloat *u );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD2DPROC) ( GLdouble u, GLdouble v );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD2FPROC) ( GLfloat u, GLfloat v );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD2DVPROC) ( const GLdouble *u );\ntypedef void (APIENTRYP RGLSYMGLEVALCOORD2FVPROC) ( const GLfloat *u );\ntypedef void (APIENTRYP RGLSYMGLMAPGRID1DPROC) ( GLint un, GLdouble u1, GLdouble u2 );\ntypedef void (APIENTRYP RGLSYMGLMAPGRID1FPROC) ( GLint un, GLfloat u1, GLfloat u2 );\ntypedef void (APIENTRYP RGLSYMGLMAPGRID2DPROC) ( GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2 );\ntypedef void (APIENTRYP RGLSYMGLMAPGRID2FPROC) ( GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2 );\ntypedef void (APIENTRYP RGLSYMGLEVALPOINT1PROC) ( GLint i );\ntypedef void (APIENTRYP RGLSYMGLEVALPOINT2PROC) ( GLint i, GLint j );\ntypedef void (APIENTRYP RGLSYMGLEVALMESH1PROC) ( GLenum mode, GLint i1, GLint i2 );\ntypedef void (APIENTRYP RGLSYMGLEVALMESH2PROC) ( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 );\ntypedef void (APIENTRYP RGLSYMGLFOGFPROC) ( GLenum pname, GLfloat param );\ntypedef void (APIENTRYP RGLSYMGLFOGIPROC) ( GLenum pname, GLint param );\ntypedef void (APIENTRYP RGLSYMGLFOGFVPROC) ( GLenum pname, const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLFOGIVPROC) ( GLenum pname, const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLFEEDBACKBUFFERPROC) ( GLsizei size, GLenum type, GLfloat *buffer );\ntypedef void (APIENTRYP RGLSYMGLPASSTHROUGHPROC) ( GLfloat token );\ntypedef void (APIENTRYP RGLSYMGLSELECTBUFFERPROC) ( GLsizei size, GLuint *buffer );\ntypedef void (APIENTRYP RGLSYMGLINITNAMESPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLLOADNAMEPROC) ( GLuint name );\ntypedef void (APIENTRYP RGLSYMGLPUSHNAMEPROC) ( GLuint name );\ntypedef void (APIENTRYP RGLSYMGLPOPNAMEPROC) ( void );\ntypedef void (APIENTRYP RGLSYMGLDRAWRANGEELEMENTSPROC) ( GLenum mode, GLuint start,GLuint end, GLsizei count, GLenum type, const GLvoid *indices );\ntypedef void (APIENTRYP RGLSYMGLTEXIMAGE3DPROC) ( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels );\ntypedef 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);\ntypedef void (APIENTRYP RGLSYMGLCOPYTEXSUBIMAGE3DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height );\ntypedef void (APIENTRYP RGLSYMGLCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table );\ntypedef void (APIENTRYP RGLSYMGLCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data );\ntypedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP RGLSYMGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP RGLSYMGLCOPYCOLORSUBTABLEPROC) ( GLenum target, GLsizei start, GLint x, GLint y, GLsizei width );\ntypedef void (APIENTRYP RGLSYMGLCOPYCOLORTABLEPROC) ( GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width );\ntypedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPROC) ( GLenum target, GLenum format, GLenum type, GLvoid *table );\ntypedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETCOLORTABLEPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLBLENDEQUATIONPROC) ( GLenum mode );\ntypedef void (APIENTRYP RGLSYMGLBLENDCOLORPROC) ( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );\ntypedef void (APIENTRYP RGLSYMGLHISTOGRAMPROC) ( GLenum target, GLsizei width, GLenum internalformat, GLboolean sink );\ntypedef void (APIENTRYP RGLSYMGLRESETHISTOGRAMPROC) ( GLenum target );\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values );\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETHISTOGRAMPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLMINMAXPROC) ( GLenum target, GLenum internalformat,GLboolean sink );\ntypedef void (APIENTRYP RGLSYMGLRESETMINMAXPROC) ( GLenum target );\ntypedef void (APIENTRYP RGLSYMGLGETMINMAXPROC) ( GLenum target, GLboolean reset, GLenum format, GLenum types, GLvoid *values );\ntypedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERFVPROC) ( GLenum target, GLenum pname, GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETMINMAXPARAMETERIVPROC) ( GLenum target, GLenum pname, GLint *params );\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLenum format, GLenum type,const GLvoid *image );\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *image );\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFPROC) ( GLenum target, GLenum pname,GLfloat params );\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,const GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIPROC) ( GLenum target, GLenum pname,GLint params );\ntypedef void (APIENTRYP RGLSYMGLCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,const GLint *params );\ntypedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER1DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width );\ntypedef void (APIENTRYP RGLSYMGLCOPYCONVOLUTIONFILTER2DPROC) ( GLenum target,GLenum internalformat, GLint x, GLint y, GLsizei width,GLsizei height);\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *image );\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERFVPROC) ( GLenum target, GLenum pname,GLfloat *params );\ntypedef void (APIENTRYP RGLSYMGLGETCONVOLUTIONPARAMETERIVPROC) ( GLenum target, GLenum pname,GLint *params );\ntypedef void (APIENTRYP RGLSYMGLSEPARABLEFILTER2DPROC) ( GLenum target,GLenum internalformat, GLsizei width, GLsizei height, GLenum format,GLenum type, const GLvoid *row, const GLvoid *column );\ntypedef void (APIENTRYP RGLSYMGLGETSEPARABLEFILTERPROC) ( GLenum target, GLenum format,GLenum type, GLvoid *row, GLvoid *column, GLvoid *span );\ntypedef void (APIENTRYP RGLSYMGLACTIVETEXTUREPROC) ( GLenum texture );\ntypedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREPROC) ( GLenum texture );\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE1DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data );\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE2DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data );\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXIMAGE3DPROC) ( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data );\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC) ( GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data );\ntypedef void (APIENTRYP RGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC) ( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data );\ntypedef 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 );\ntypedef void (APIENTRYP RGLSYMGLGETCOMPRESSEDTEXIMAGEPROC) ( GLenum target, GLint lod, GLvoid *img );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DPROC) ( GLenum target, GLdouble s );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVPROC) ( GLenum target, const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FPROC) ( GLenum target, GLfloat s );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVPROC) ( GLenum target, const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IPROC) ( GLenum target, GLint s );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVPROC) ( GLenum target, const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SPROC) ( GLenum target, GLshort s );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVPROC) ( GLenum target, const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DPROC) ( GLenum target, GLdouble s, GLdouble t );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVPROC) ( GLenum target, const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FPROC) ( GLenum target, GLfloat s, GLfloat t );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVPROC) ( GLenum target, const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IPROC) ( GLenum target, GLint s, GLint t );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVPROC) ( GLenum target, const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SPROC) ( GLenum target, GLshort s, GLshort t );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVPROC) ( GLenum target, const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVPROC) ( GLenum target, const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVPROC) ( GLenum target, const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IPROC) ( GLenum target, GLint s, GLint t, GLint r );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVPROC) ( GLenum target, const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVPROC) ( GLenum target, const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DPROC) ( GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVPROC) ( GLenum target, const GLdouble *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FPROC) ( GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVPROC) ( GLenum target, const GLfloat *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IPROC) ( GLenum target, GLint s, GLint t, GLint r, GLint q );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVPROC) ( GLenum target, const GLint *v );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SPROC) ( GLenum target, GLshort s, GLshort t, GLshort r, GLshort q );\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVPROC) ( GLenum target, const GLshort *v );\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );\ntypedef void (APIENTRYP RGLSYMGLLOADTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXDPROC) ( const GLdouble m[16] );\ntypedef void (APIENTRYP RGLSYMGLMULTTRANSPOSEMATRIXFPROC) ( const GLfloat m[16] );\ntypedef void (APIENTRYP RGLSYMGLSAMPLECOVERAGEPROC) ( GLclampf value, GLboolean invert );\ntypedef void (APIENTRYP RGLSYMGLACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP RGLSYMGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP RGLSYMGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);\ntypedef void (APIENTRYP RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);\ntypedef void (APIENTRYP RGLSYMGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);\n\nRGLSYMGLCLEARINDEXPROC glClearIndex;\nRGLSYMGLCLEARCOLORPROC glClearColor;\nRGLSYMGLCLEARPROC glClear;\nRGLSYMGLINDEXMASKPROC glIndexMask;\nRGLSYMGLCOLORMASKPROC glColorMask;\nRGLSYMGLALPHAFUNCPROC glAlphaFunc;\nRGLSYMGLBLENDFUNCPROC glBlendFunc;\nRGLSYMGLLOGICOPPROC glLogicOp;\nRGLSYMGLCULLFACEPROC glCullFace;\nRGLSYMGLFRONTFACEPROC glFrontFace;\nRGLSYMGLPOINTSIZEPROC glPointSize;\nRGLSYMGLLINEWIDTHPROC glLineWidth;\nRGLSYMGLLINESTIPPLEPROC glLineStipple;\nRGLSYMGLPOLYGONMODEPROC glPolygonMode;\nRGLSYMGLPOLYGONOFFSETPROC glPolygonOffset;\nRGLSYMGLPOLYGONSTIPPLEPROC glPolygonStipple;\nRGLSYMGLGETPOLYGONSTIPPLEPROC glGetPolygonStipple;\nRGLSYMGLEDGEFLAGPROC glEdgeFlag;\nRGLSYMGLEDGEFLAGVPROC glEdgeFlagv;\nRGLSYMGLSCISSORPROC glScissor;\nRGLSYMGLCLIPPLANEPROC glClipPlane;\nRGLSYMGLGETCLIPPLANEPROC glGetClipPlane;\nRGLSYMGLDRAWBUFFERPROC glDrawBuffer;\nRGLSYMGLREADBUFFERPROC glReadBuffer;\nRGLSYMGLENABLEPROC glEnable;\nRGLSYMGLDISABLEPROC glDisable;\nRGLSYMGLISENABLEDPROC glIsEnabled;\nRGLSYMGLENABLECLIENTSTATEPROC glEnableClientState;\nRGLSYMGLDISABLECLIENTSTATEPROC glDisableClientState;\nRGLSYMGLGETBOOLEANVPROC glGetBooleanv;\nRGLSYMGLGETDOUBLEVPROC glGetDoublev;\nRGLSYMGLGETFLOATVPROC glGetFloatv;\nRGLSYMGLGETINTEGERVPROC glGetIntegerv;\nRGLSYMGLPUSHATTRIBPROC glPushAttrib;\nRGLSYMGLPOPATTRIBPROC glPopAttrib;\nRGLSYMGLPUSHCLIENTATTRIBPROC glPushClientAttrib;\nRGLSYMGLPOPCLIENTATTRIBPROC glPopClientAttrib;\nRGLSYMGLRENDERMODEPROC glRenderMode;\nRGLSYMGLGETERRORPROC glGetError;\nRGLSYMGLGETSTRINGPROC glGetString;\nRGLSYMGLFINISHPROC glFinish;\nRGLSYMGLFLUSHPROC glFlush;\nRGLSYMGLHINTPROC glHint;\nRGLSYMGLCLEARDEPTHPROC glClearDepth;\nRGLSYMGLDEPTHFUNCPROC glDepthFunc;\nRGLSYMGLDEPTHMASKPROC glDepthMask;\nRGLSYMGLDEPTHRANGEPROC glDepthRange;\nRGLSYMGLCLEARACCUMPROC glClearAccum;\nRGLSYMGLACCUMPROC glAccum;\nRGLSYMGLMATRIXMODEPROC glMatrixMode;\nRGLSYMGLORTHOPROC glOrtho;\nRGLSYMGLFRUSTUMPROC glFrustum;\nRGLSYMGLVIEWPORTPROC glViewport;\nRGLSYMGLPUSHMATRIXPROC glPushMatrix;\nRGLSYMGLPOPMATRIXPROC glPopMatrix;\nRGLSYMGLLOADIDENTITYPROC glLoadIdentity;\nRGLSYMGLLOADMATRIXDPROC glLoadMatrixd;\nRGLSYMGLLOADMATRIXFPROC glLoadMatrixf;\nRGLSYMGLMULTMATRIXDPROC glMultMatrixd;\nRGLSYMGLMULTMATRIXFPROC glMultMatrixf;\nRGLSYMGLROTATEDPROC glRotated;\nRGLSYMGLROTATEFPROC glRotatef;\nRGLSYMGLSCALEDPROC glScaled;\nRGLSYMGLSCALEFPROC glScalef;\nRGLSYMGLTRANSLATEDPROC glTranslated;\nRGLSYMGLTRANSLATEFPROC glTranslatef;\nRGLSYMGLISLISTPROC glIsList;\nRGLSYMGLDELETELISTSPROC glDeleteLists;\nRGLSYMGLGENLISTSPROC glGenLists;\nRGLSYMGLNEWLISTPROC glNewList;\nRGLSYMGLENDLISTPROC glEndList;\nRGLSYMGLCALLLISTPROC glCallList;\nRGLSYMGLCALLLISTSPROC glCallLists;\nRGLSYMGLLISTBASEPROC glListBase;\nRGLSYMGLBEGINPROC glBegin;\nRGLSYMGLENDPROC glEnd;\nRGLSYMGLVERTEX2DPROC glVertex2d;\nRGLSYMGLVERTEX2FPROC glVertex2f;\nRGLSYMGLVERTEX2IPROC glVertex2i;\nRGLSYMGLVERTEX2SPROC glVertex2s;\nRGLSYMGLVERTEX3DPROC glVertex3d;\nRGLSYMGLVERTEX3FPROC glVertex3f;\nRGLSYMGLVERTEX3IPROC glVertex3i;\nRGLSYMGLVERTEX3SPROC glVertex3s;\nRGLSYMGLVERTEX4DPROC glVertex4d;\nRGLSYMGLVERTEX4FPROC glVertex4f;\nRGLSYMGLVERTEX4IPROC glVertex4i;\nRGLSYMGLVERTEX4SPROC glVertex4s;\nRGLSYMGLVERTEX2DVPROC glVertex2dv;\nRGLSYMGLVERTEX2FVPROC glVertex2fv;\nRGLSYMGLVERTEX2IVPROC glVertex2iv;\nRGLSYMGLVERTEX2SVPROC glVertex2sv;\nRGLSYMGLVERTEX3DVPROC glVertex3dv;\nRGLSYMGLVERTEX3FVPROC glVertex3fv;\nRGLSYMGLVERTEX3IVPROC glVertex3iv;\nRGLSYMGLVERTEX3SVPROC glVertex3sv;\nRGLSYMGLVERTEX4DVPROC glVertex4dv;\nRGLSYMGLVERTEX4FVPROC glVertex4fv;\nRGLSYMGLVERTEX4IVPROC glVertex4iv;\nRGLSYMGLVERTEX4SVPROC glVertex4sv;\nRGLSYMGLNORMAL3BPROC glNormal3b;\nRGLSYMGLNORMAL3DPROC glNormal3d;\nRGLSYMGLNORMAL3FPROC glNormal3f;\nRGLSYMGLNORMAL3IPROC glNormal3i;\nRGLSYMGLNORMAL3SPROC glNormal3s;\nRGLSYMGLNORMAL3BVPROC glNormal3bv;\nRGLSYMGLNORMAL3DVPROC glNormal3dv;\nRGLSYMGLNORMAL3FVPROC glNormal3fv;\nRGLSYMGLNORMAL3IVPROC glNormal3iv;\nRGLSYMGLNORMAL3SVPROC glNormal3sv;\nRGLSYMGLINDEXDPROC glIndexd;\nRGLSYMGLINDEXFPROC glIndexf;\nRGLSYMGLINDEXIPROC glIndexi;\nRGLSYMGLINDEXSPROC glIndexs;\nRGLSYMGLINDEXUBPROC glIndexub;\nRGLSYMGLINDEXDVPROC glIndexdv;\nRGLSYMGLINDEXFVPROC glIndexfv;\nRGLSYMGLINDEXIVPROC glIndexiv;\nRGLSYMGLINDEXSVPROC glIndexsv;\nRGLSYMGLINDEXUBVPROC glIndexubv;\nRGLSYMGLCOLOR3BPROC glColor3b;\nRGLSYMGLCOLOR3DPROC glColor3d;\nRGLSYMGLCOLOR3FPROC glColor3f;\nRGLSYMGLCOLOR3IPROC glColor3i;\nRGLSYMGLCOLOR3SPROC glColor3s;\nRGLSYMGLCOLOR3UBPROC glColor3ub;\nRGLSYMGLCOLOR3UIPROC glColor3ui;\nRGLSYMGLCOLOR3USPROC glColor3us;\nRGLSYMGLCOLOR4BPROC glColor4b;\nRGLSYMGLCOLOR4DPROC glColor4d;\nRGLSYMGLCOLOR4FPROC glColor4f;\nRGLSYMGLCOLOR4IPROC glColor4i;\nRGLSYMGLCOLOR4SPROC glColor4s;\nRGLSYMGLCOLOR4UBPROC glColor4ub;\nRGLSYMGLCOLOR4UIPROC glColor4ui;\nRGLSYMGLCOLOR4USPROC glColor4us;\nRGLSYMGLCOLOR3BVPROC glColor3bv;\nRGLSYMGLCOLOR3DVPROC glColor3dv;\nRGLSYMGLCOLOR3FVPROC glColor3fv;\nRGLSYMGLCOLOR3IVPROC glColor3iv;\nRGLSYMGLCOLOR3SVPROC glColor3sv;\nRGLSYMGLCOLOR3UBVPROC glColor3ubv;\nRGLSYMGLCOLOR3UIVPROC glColor3uiv;\nRGLSYMGLCOLOR3USVPROC glColor3usv;\nRGLSYMGLCOLOR4BVPROC glColor4bv;\nRGLSYMGLCOLOR4DVPROC glColor4dv;\nRGLSYMGLCOLOR4FVPROC glColor4fv;\nRGLSYMGLCOLOR4IVPROC glColor4iv;\nRGLSYMGLCOLOR4SVPROC glColor4sv;\nRGLSYMGLCOLOR4UBVPROC glColor4ubv;\nRGLSYMGLCOLOR4UIVPROC glColor4uiv;\nRGLSYMGLCOLOR4USVPROC glColor4usv;\nRGLSYMGLTEXCOORD1DPROC glTexCoord1d;\nRGLSYMGLTEXCOORD1FPROC glTexCoord1f;\nRGLSYMGLTEXCOORD1IPROC glTexCoord1i;\nRGLSYMGLTEXCOORD1SPROC glTexCoord1s;\nRGLSYMGLTEXCOORD2DPROC glTexCoord2d;\nRGLSYMGLTEXCOORD2FPROC glTexCoord2f;\nRGLSYMGLTEXCOORD2IPROC glTexCoord2i;\nRGLSYMGLTEXCOORD2SPROC glTexCoord2s;\nRGLSYMGLTEXCOORD3DPROC glTexCoord3d;\nRGLSYMGLTEXCOORD3FPROC glTexCoord3f;\nRGLSYMGLTEXCOORD3IPROC glTexCoord3i;\nRGLSYMGLTEXCOORD3SPROC glTexCoord3s;\nRGLSYMGLTEXCOORD4DPROC glTexCoord4d;\nRGLSYMGLTEXCOORD4FPROC glTexCoord4f;\nRGLSYMGLTEXCOORD4IPROC glTexCoord4i;\nRGLSYMGLTEXCOORD4SPROC glTexCoord4s;\nRGLSYMGLTEXCOORD1DVPROC glTexCoord1dv;\nRGLSYMGLTEXCOORD1FVPROC glTexCoord1fv;\nRGLSYMGLTEXCOORD1IVPROC glTexCoord1iv;\nRGLSYMGLTEXCOORD1SVPROC glTexCoord1sv;\nRGLSYMGLTEXCOORD2DVPROC glTexCoord2dv;\nRGLSYMGLTEXCOORD2FVPROC glTexCoord2fv;\nRGLSYMGLTEXCOORD2IVPROC glTexCoord2iv;\nRGLSYMGLTEXCOORD2SVPROC glTexCoord2sv;\nRGLSYMGLTEXCOORD3DVPROC glTexCoord3dv;\nRGLSYMGLTEXCOORD3FVPROC glTexCoord3fv;\nRGLSYMGLTEXCOORD3IVPROC glTexCoord3iv;\nRGLSYMGLTEXCOORD3SVPROC glTexCoord3sv;\nRGLSYMGLTEXCOORD4DVPROC glTexCoord4dv;\nRGLSYMGLTEXCOORD4FVPROC glTexCoord4fv;\nRGLSYMGLTEXCOORD4IVPROC glTexCoord4iv;\nRGLSYMGLTEXCOORD4SVPROC glTexCoord4sv;\nRGLSYMGLRASTERPOS2DPROC glRasterPos2d;\nRGLSYMGLRASTERPOS2FPROC glRasterPos2f;\nRGLSYMGLRASTERPOS2IPROC glRasterPos2i;\nRGLSYMGLRASTERPOS2SPROC glRasterPos2s;\nRGLSYMGLRASTERPOS3DPROC glRasterPos3d;\nRGLSYMGLRASTERPOS3FPROC glRasterPos3f;\nRGLSYMGLRASTERPOS3IPROC glRasterPos3i;\nRGLSYMGLRASTERPOS3SPROC glRasterPos3s;\nRGLSYMGLRASTERPOS4DPROC glRasterPos4d;\nRGLSYMGLRASTERPOS4FPROC glRasterPos4f;\nRGLSYMGLRASTERPOS4IPROC glRasterPos4i;\nRGLSYMGLRASTERPOS4SPROC glRasterPos4s;\nRGLSYMGLRASTERPOS2DVPROC glRasterPos2dv;\nRGLSYMGLRASTERPOS2FVPROC glRasterPos2fv;\nRGLSYMGLRASTERPOS2IVPROC glRasterPos2iv;\nRGLSYMGLRASTERPOS2SVPROC glRasterPos2sv;\nRGLSYMGLRASTERPOS3DVPROC glRasterPos3dv;\nRGLSYMGLRASTERPOS3FVPROC glRasterPos3fv;\nRGLSYMGLRASTERPOS3IVPROC glRasterPos3iv;\nRGLSYMGLRASTERPOS3SVPROC glRasterPos3sv;\nRGLSYMGLRASTERPOS4DVPROC glRasterPos4dv;\nRGLSYMGLRASTERPOS4FVPROC glRasterPos4fv;\nRGLSYMGLRASTERPOS4IVPROC glRasterPos4iv;\nRGLSYMGLRASTERPOS4SVPROC glRasterPos4sv;\nRGLSYMGLRECTDPROC glRectd;\nRGLSYMGLRECTFPROC glRectf;\nRGLSYMGLRECTIPROC glRecti;\nRGLSYMGLRECTSPROC glRects;\nRGLSYMGLRECTDVPROC glRectdv;\nRGLSYMGLRECTFVPROC glRectfv;\nRGLSYMGLRECTIVPROC glRectiv;\nRGLSYMGLRECTSVPROC glRectsv;\nRGLSYMGLVERTEXPOINTERPROC glVertexPointer;\nRGLSYMGLNORMALPOINTERPROC glNormalPointer;\nRGLSYMGLCOLORPOINTERPROC glColorPointer;\nRGLSYMGLINDEXPOINTERPROC glIndexPointer;\nRGLSYMGLTEXCOORDPOINTERPROC glTexCoordPointer;\nRGLSYMGLEDGEFLAGPOINTERPROC glEdgeFlagPointer;\nRGLSYMGLGETPOINTERVPROC glGetPointerv;\nRGLSYMGLARRAYELEMENTPROC glArrayElement;\nRGLSYMGLDRAWARRAYSPROC glDrawArrays;\nRGLSYMGLDRAWELEMENTSPROC glDrawElements;\nRGLSYMGLINTERLEAVEDARRAYSPROC glInterleavedArrays;\nRGLSYMGLSHADEMODELPROC glShadeModel;\nRGLSYMGLLIGHTFPROC glLightf;\nRGLSYMGLLIGHTIPROC glLighti;\nRGLSYMGLLIGHTFVPROC glLightfv;\nRGLSYMGLLIGHTIVPROC glLightiv;\nRGLSYMGLGETLIGHTFVPROC glGetLightfv;\nRGLSYMGLGETLIGHTIVPROC glGetLightiv;\nRGLSYMGLLIGHTMODELFPROC glLightModelf;\nRGLSYMGLLIGHTMODELIPROC glLightModeli;\nRGLSYMGLLIGHTMODELFVPROC glLightModelfv;\nRGLSYMGLLIGHTMODELIVPROC glLightModeliv;\nRGLSYMGLMATERIALFPROC glMaterialf;\nRGLSYMGLMATERIALIPROC glMateriali;\nRGLSYMGLMATERIALFVPROC glMaterialfv;\nRGLSYMGLMATERIALIVPROC glMaterialiv;\nRGLSYMGLGETMATERIALFVPROC glGetMaterialfv;\nRGLSYMGLGETMATERIALIVPROC glGetMaterialiv;\nRGLSYMGLCOLORMATERIALPROC glColorMaterial;\nRGLSYMGLPIXELZOOMPROC glPixelZoom;\nRGLSYMGLPIXELSTOREFPROC glPixelStoref;\nRGLSYMGLPIXELSTOREIPROC glPixelStorei;\nRGLSYMGLPIXELTRANSFERFPROC glPixelTransferf;\nRGLSYMGLPIXELTRANSFERIPROC glPixelTransferi;\nRGLSYMGLPIXELMAPFVPROC glPixelMapfv;\nRGLSYMGLPIXELMAPUIVPROC glPixelMapuiv;\nRGLSYMGLPIXELMAPUSVPROC glPixelMapusv;\nRGLSYMGLGETPIXELMAPFVPROC glGetPixelMapfv;\nRGLSYMGLGETPIXELMAPUIVPROC glGetPixelMapuiv;\nRGLSYMGLGETPIXELMAPUSVPROC glGetPixelMapusv;\nRGLSYMGLBITMAPPROC glBitmap;\nRGLSYMGLREADPIXELSPROC glReadPixels;\nRGLSYMGLDRAWPIXELSPROC glDrawPixels;\nRGLSYMGLCOPYPIXELSPROC glCopyPixels;\nRGLSYMGLSTENCILFUNCPROC glStencilFunc;\nRGLSYMGLSTENCILMASKPROC glStencilMask;\nRGLSYMGLSTENCILOPPROC glStencilOp;\nRGLSYMGLCLEARSTENCILPROC glClearStencil;\nRGLSYMGLTEXGENDPROC glTexGend;\nRGLSYMGLTEXGENFPROC glTexGenf;\nRGLSYMGLTEXGENIPROC glTexGeni;\nRGLSYMGLTEXGENDVPROC glTexGendv;\nRGLSYMGLTEXGENFVPROC glTexGenfv;\nRGLSYMGLTEXGENIVPROC glTexGeniv;\nRGLSYMGLGETTEXGENDVPROC glGetTexGendv;\nRGLSYMGLGETTEXGENFVPROC glGetTexGenfv;\nRGLSYMGLGETTEXGENIVPROC glGetTexGeniv;\nRGLSYMGLTEXENVFPROC glTexEnvf;\nRGLSYMGLTEXENVIPROC glTexEnvi;\nRGLSYMGLTEXENVFVPROC glTexEnvfv;\nRGLSYMGLTEXENVIVPROC glTexEnviv;\nRGLSYMGLGETTEXENVFVPROC glGetTexEnvfv;\nRGLSYMGLGETTEXENVIVPROC glGetTexEnviv;\nRGLSYMGLTEXPARAMETERFPROC glTexParameterf;\nRGLSYMGLTEXPARAMETERIPROC glTexParameteri;\nRGLSYMGLTEXPARAMETERFVPROC glTexParameterfv;\nRGLSYMGLTEXPARAMETERIVPROC glTexParameteriv;\nRGLSYMGLGETTEXPARAMETERFVPROC glGetTexParameterfv;\nRGLSYMGLGETTEXPARAMETERIVPROC glGetTexParameteriv;\nRGLSYMGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv;\nRGLSYMGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv;\nRGLSYMGLTEXIMAGE1DPROC glTexImage1D;\nRGLSYMGLTEXIMAGE2DPROC glTexImage2D;\nRGLSYMGLGETTEXIMAGEPROC glGetTexImage;\nRGLSYMGLGENTEXTURESPROC glGenTextures;\nRGLSYMGLDELETETEXTURESPROC glDeleteTextures;\nRGLSYMGLBINDTEXTUREPROC glBindTexture;\nRGLSYMGLPRIORITIZETEXTURESPROC glPrioritizeTextures;\nRGLSYMGLARETEXTURESRESIDENTPROC glAreTexturesResident;\nRGLSYMGLISTEXTUREPROC glIsTexture;\nRGLSYMGLTEXSUBIMAGE1DPROC glTexSubImage1D;\nRGLSYMGLTEXSUBIMAGE2DPROC glTexSubImage2D;\nRGLSYMGLCOPYTEXIMAGE1DPROC glCopyTexImage1D;\nRGLSYMGLCOPYTEXIMAGE2DPROC glCopyTexImage2D;\nRGLSYMGLCOPYTEXSUBIMAGE1DPROC glCopyTexSubImage1D;\nRGLSYMGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D;\nRGLSYMGLMAP1DPROC glMap1d;\nRGLSYMGLMAP1FPROC glMap1f;\nRGLSYMGLMAP2DPROC glMap2d;\nRGLSYMGLMAP2FPROC glMap2f;\nRGLSYMGLGETMAPDVPROC glGetMapdv;\nRGLSYMGLGETMAPFVPROC glGetMapfv;\nRGLSYMGLGETMAPIVPROC glGetMapiv;\nRGLSYMGLEVALCOORD1DPROC glEvalCoord1d;\nRGLSYMGLEVALCOORD1FPROC glEvalCoord1f;\nRGLSYMGLEVALCOORD1DVPROC glEvalCoord1dv;\nRGLSYMGLEVALCOORD1FVPROC glEvalCoord1fv;\nRGLSYMGLEVALCOORD2DPROC glEvalCoord2d;\nRGLSYMGLEVALCOORD2FPROC glEvalCoord2f;\nRGLSYMGLEVALCOORD2DVPROC glEvalCoord2dv;\nRGLSYMGLEVALCOORD2FVPROC glEvalCoord2fv;\nRGLSYMGLMAPGRID1DPROC glMapGrid1d;\nRGLSYMGLMAPGRID1FPROC glMapGrid1f;\nRGLSYMGLMAPGRID2DPROC glMapGrid2d;\nRGLSYMGLMAPGRID2FPROC glMapGrid2f;\nRGLSYMGLEVALPOINT1PROC glEvalPoint1;\nRGLSYMGLEVALPOINT2PROC glEvalPoint2;\nRGLSYMGLEVALMESH1PROC glEvalMesh1;\nRGLSYMGLEVALMESH2PROC glEvalMesh2;\nRGLSYMGLFOGFPROC glFogf;\nRGLSYMGLFOGIPROC glFogi;\nRGLSYMGLFOGFVPROC glFogfv;\nRGLSYMGLFOGIVPROC glFogiv;\nRGLSYMGLFEEDBACKBUFFERPROC glFeedbackBuffer;\nRGLSYMGLPASSTHROUGHPROC glPassThrough;\nRGLSYMGLSELECTBUFFERPROC glSelectBuffer;\nRGLSYMGLINITNAMESPROC glInitNames;\nRGLSYMGLLOADNAMEPROC glLoadName;\nRGLSYMGLPUSHNAMEPROC glPushName;\nRGLSYMGLPOPNAMEPROC glPopName;\nRGLSYMGLDRAWRANGEELEMENTSPROC glDrawRangeElements;\nRGLSYMGLTEXIMAGE3DPROC glTexImage3D;\nRGLSYMGLTEXSUBIMAGE3DPROC glTexSubImage3D;\nRGLSYMGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D;\nRGLSYMGLCOLORTABLEPROC glColorTable;\nRGLSYMGLCOLORSUBTABLEPROC glColorSubTable;\nRGLSYMGLCOLORTABLEPARAMETERIVPROC glColorTableParameteriv;\nRGLSYMGLCOLORTABLEPARAMETERFVPROC glColorTableParameterfv;\nRGLSYMGLCOPYCOLORSUBTABLEPROC glCopyColorSubTable;\nRGLSYMGLCOPYCOLORTABLEPROC glCopyColorTable;\nRGLSYMGLGETCOLORTABLEPROC glGetColorTable;\nRGLSYMGLGETCOLORTABLEPARAMETERFVPROC glGetColorTableParameterfv;\nRGLSYMGLGETCOLORTABLEPARAMETERIVPROC glGetColorTableParameteriv;\nRGLSYMGLBLENDEQUATIONPROC glBlendEquation;\nRGLSYMGLBLENDCOLORPROC glBlendColor;\nRGLSYMGLHISTOGRAMPROC glHistogram;\nRGLSYMGLRESETHISTOGRAMPROC glResetHistogram;\nRGLSYMGLGETHISTOGRAMPROC glGetHistogram;\nRGLSYMGLGETHISTOGRAMPARAMETERFVPROC glGetHistogramParameterfv;\nRGLSYMGLGETHISTOGRAMPARAMETERIVPROC glGetHistogramParameteriv;\nRGLSYMGLMINMAXPROC glMinmax;\nRGLSYMGLRESETMINMAXPROC glResetMinmax;\nRGLSYMGLGETMINMAXPROC glGetMinmax;\nRGLSYMGLGETMINMAXPARAMETERFVPROC glGetMinmaxParameterfv;\nRGLSYMGLGETMINMAXPARAMETERIVPROC glGetMinmaxParameteriv;\nRGLSYMGLCONVOLUTIONFILTER1DPROC glConvolutionFilter1D;\nRGLSYMGLCONVOLUTIONFILTER2DPROC glConvolutionFilter2D;\nRGLSYMGLCONVOLUTIONPARAMETERFPROC glConvolutionParameterf;\nRGLSYMGLCONVOLUTIONPARAMETERFVPROC glConvolutionParameterfv;\nRGLSYMGLCONVOLUTIONPARAMETERIPROC glConvolutionParameteri;\nRGLSYMGLCONVOLUTIONPARAMETERIVPROC glConvolutionParameteriv;\nRGLSYMGLCOPYCONVOLUTIONFILTER1DPROC glCopyConvolutionFilter1D;\nRGLSYMGLCOPYCONVOLUTIONFILTER2DPROC glCopyConvolutionFilter2D;\nRGLSYMGLGETCONVOLUTIONFILTERPROC glGetConvolutionFilter;\nRGLSYMGLGETCONVOLUTIONPARAMETERFVPROC glGetConvolutionParameterfv;\nRGLSYMGLGETCONVOLUTIONPARAMETERIVPROC glGetConvolutionParameteriv;\nRGLSYMGLSEPARABLEFILTER2DPROC glSeparableFilter2D;\nRGLSYMGLGETSEPARABLEFILTERPROC glGetSeparableFilter;\nRGLSYMGLACTIVETEXTUREPROC glActiveTexture;\nRGLSYMGLCLIENTACTIVETEXTUREPROC glClientActiveTexture;\nRGLSYMGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;\nRGLSYMGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;\nRGLSYMGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D;\nRGLSYMGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D;\nRGLSYMGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;\nRGLSYMGLMULTITEXCOORD1DPROC glMultiTexCoord1d;\nRGLSYMGLMULTITEXCOORD1DVPROC glMultiTexCoord1dv;\nRGLSYMGLMULTITEXCOORD1FPROC glMultiTexCoord1f;\nRGLSYMGLMULTITEXCOORD1FVPROC glMultiTexCoord1fv;\nRGLSYMGLMULTITEXCOORD1IPROC glMultiTexCoord1i;\nRGLSYMGLMULTITEXCOORD1IVPROC glMultiTexCoord1iv;\nRGLSYMGLMULTITEXCOORD1SPROC glMultiTexCoord1s;\nRGLSYMGLMULTITEXCOORD1SVPROC glMultiTexCoord1sv;\nRGLSYMGLMULTITEXCOORD2DPROC glMultiTexCoord2d;\nRGLSYMGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv;\nRGLSYMGLMULTITEXCOORD2FPROC glMultiTexCoord2f;\nRGLSYMGLMULTITEXCOORD2FVPROC glMultiTexCoord2fv;\nRGLSYMGLMULTITEXCOORD2IPROC glMultiTexCoord2i;\nRGLSYMGLMULTITEXCOORD2IVPROC glMultiTexCoord2iv;\nRGLSYMGLMULTITEXCOORD2SPROC glMultiTexCoord2s;\nRGLSYMGLMULTITEXCOORD2SVPROC glMultiTexCoord2sv;\nRGLSYMGLMULTITEXCOORD3DPROC glMultiTexCoord3d;\nRGLSYMGLMULTITEXCOORD3DVPROC glMultiTexCoord3dv;\nRGLSYMGLMULTITEXCOORD3FPROC glMultiTexCoord3f;\nRGLSYMGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv;\nRGLSYMGLMULTITEXCOORD3IPROC glMultiTexCoord3i;\nRGLSYMGLMULTITEXCOORD3IVPROC glMultiTexCoord3iv;\nRGLSYMGLMULTITEXCOORD3SPROC glMultiTexCoord3s;\nRGLSYMGLMULTITEXCOORD3SVPROC glMultiTexCoord3sv;\nRGLSYMGLMULTITEXCOORD4DPROC glMultiTexCoord4d;\nRGLSYMGLMULTITEXCOORD4DVPROC glMultiTexCoord4dv;\nRGLSYMGLMULTITEXCOORD4FPROC glMultiTexCoord4f;\nRGLSYMGLMULTITEXCOORD4FVPROC glMultiTexCoord4fv;\nRGLSYMGLMULTITEXCOORD4IPROC glMultiTexCoord4i;\nRGLSYMGLMULTITEXCOORD4IVPROC glMultiTexCoord4iv;\nRGLSYMGLMULTITEXCOORD4SPROC glMultiTexCoord4s;\nRGLSYMGLMULTITEXCOORD4SVPROC glMultiTexCoord4sv;\nRGLSYMGLLOADTRANSPOSEMATRIXDPROC glLoadTransposeMatrixd;\nRGLSYMGLLOADTRANSPOSEMATRIXFPROC glLoadTransposeMatrixf;\nRGLSYMGLMULTTRANSPOSEMATRIXDPROC glMultTransposeMatrixd;\nRGLSYMGLMULTTRANSPOSEMATRIXFPROC glMultTransposeMatrixf;\nRGLSYMGLSAMPLECOVERAGEPROC glSampleCoverage;\nRGLSYMGLACTIVETEXTUREARBPROC glActiveTextureARB;\nRGLSYMGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB;\nRGLSYMGLMULTITEXCOORD1DARBPROC glMultiTexCoord1dARB;\nRGLSYMGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dvARB;\nRGLSYMGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB;\nRGLSYMGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB;\nRGLSYMGLMULTITEXCOORD1IARBPROC glMultiTexCoord1iARB;\nRGLSYMGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1ivARB;\nRGLSYMGLMULTITEXCOORD1SARBPROC glMultiTexCoord1sARB;\nRGLSYMGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1svARB;\nRGLSYMGLMULTITEXCOORD2DARBPROC glMultiTexCoord2dARB;\nRGLSYMGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dvARB;\nRGLSYMGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB;\nRGLSYMGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB;\nRGLSYMGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB;\nRGLSYMGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2ivARB;\nRGLSYMGLMULTITEXCOORD2SARBPROC glMultiTexCoord2sARB;\nRGLSYMGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2svARB;\nRGLSYMGLMULTITEXCOORD3DARBPROC glMultiTexCoord3dARB;\nRGLSYMGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dvARB;\nRGLSYMGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB;\nRGLSYMGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB;\nRGLSYMGLMULTITEXCOORD3IARBPROC glMultiTexCoord3iARB;\nRGLSYMGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3ivARB;\nRGLSYMGLMULTITEXCOORD3SARBPROC glMultiTexCoord3sARB;\nRGLSYMGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3svARB;\nRGLSYMGLMULTITEXCOORD4DARBPROC glMultiTexCoord4dARB;\nRGLSYMGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dvARB;\nRGLSYMGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB;\nRGLSYMGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB;\nRGLSYMGLMULTITEXCOORD4IARBPROC glMultiTexCoord4iARB;\nRGLSYMGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4ivARB;\nRGLSYMGLMULTITEXCOORD4SARBPROC glMultiTexCoord4sARB;\nRGLSYMGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4svARB;\nRGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;\nRGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;\nRGLSYMGLBINDTEXTURESPROC glBindTextures;\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* __NX_GLSYM_H__ */\n"
  },
  {
    "path": "include/libchdr/bitstream.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n***************************************************************************\n\n    bitstream.h\n\n    Helper classes for reading/writing at the bit level.\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __BITSTREAM_H__\n#define __BITSTREAM_H__\n\n#include <stdint.h>\n\n/***************************************************************************\n *  TYPE DEFINITIONS\n ***************************************************************************\n */\n\n/* helper class for reading from a bit buffer */\nstruct bitstream\n{\n\tuint32_t          buffer;       /* current bit accumulator */\n\tint               bits;         /* number of bits in the accumulator */\n\tconst uint8_t *   read;         /* read pointer */\n\tuint32_t          doffset;      /* byte offset within the data */\n\tuint32_t          dlength;      /* length of the data */\n};\n\nstruct bitstream* \tcreate_bitstream(const void *src, uint32_t srclength);\nint \t\t\t\tbitstream_overflow(struct bitstream* bitstream);\nuint32_t \t\t\tbitstream_read_offset(struct bitstream* bitstream);\n\nuint32_t \t\t\tbitstream_read(struct bitstream* bitstream, int numbits);\nuint32_t \t\t\tbitstream_peek(struct bitstream* bitstream, int numbits);\nvoid \t\t\t\tbitstream_remove(struct bitstream* bitstream, int numbits);\nuint32_t \t\t\tbitstream_flush(struct bitstream* bitstream);\n\n#endif\n"
  },
  {
    "path": "include/libchdr/cdrom.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n***************************************************************************\n\n    cdrom.h\n\n    Generic MAME cd-rom implementation\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __CDROM_H__\n#define __CDROM_H__\n\n#include <stdint.h>\n#include <libchdr/chdconfig.h>\n\n/***************************************************************************\n    CONSTANTS\n***************************************************************************/\n\n/* tracks are padded to a multiple of this many frames */\n#define CD_TRACK_PADDING   \t(4)\n#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */\n#define CD_MAX_SECTOR_DATA      (2352)\n#define CD_MAX_SUBCODE_DATA     (96)\n\n#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)\n#define CD_FRAMES_PER_HUNK      (8)\n\n#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))\n\nenum\n{\n\tCD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */\n\tCD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */\n\tCD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */\n\tCD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */\n\tCD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */\n\tCD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */\n\tCD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */\n\tCD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */\n\n\tCD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */\n};\n\nenum\n{\n\tCD_SUB_NORMAL = 0,          /* \"cooked\" 96 bytes per sector */\n\tCD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */\n\tCD_SUB_NONE                 /* no subcode data stored */\n};\n\n#define CD_FLAG_GDROM   0x00000001  /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */\n#define CD_FLAG_GDROMLE 0x00000002  /* legacy GD-ROM, with little-endian CDDA data */\n\n/***************************************************************************\n    FUNCTION PROTOTYPES\n***************************************************************************/\n\n#ifdef WANT_RAW_DATA_SECTOR\n/* ECC utilities */\nint ecc_verify(const uint8_t *sector);\nvoid ecc_generate(uint8_t *sector);\nvoid ecc_clear(uint8_t *sector);\n#endif\n\n\n\n/***************************************************************************\n    INLINE FUNCTIONS\n***************************************************************************/\n\nstatic INLINE uint32_t msf_to_lba(uint32_t msf)\n{\n\treturn ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0);\n}\n\nstatic INLINE uint32_t lba_to_msf(uint32_t lba)\n{\n\tuint8_t m, s, f;\n\n\tm = lba / (60 * 75);\n\tlba -= m * (60 * 75);\n\ts = lba / 75;\n\tf = lba % 75;\n\n\treturn ((m / 10) << 20) | ((m % 10) << 16) |\n\t\t\t((s / 10) << 12) | ((s % 10) <<  8) |\n\t\t\t((f / 10) <<  4) | ((f % 10) <<  0);\n}\n\n/**\n * segacd needs it like this.. investigate\n * Angelo also says PCE tracks often start playing at the\n * wrong address.. related?\n **/\nstatic INLINE uint32_t lba_to_msf_alt(int lba)\n{\n\tuint32_t ret = 0;\n\n\tret |= ((lba / (60 * 75))&0xff)<<16;\n\tret |= (((lba / 75) % 60)&0xff)<<8;\n\tret |= ((lba % 75)&0xff)<<0;\n\n\treturn ret;\n}\n\n#endif  /* __CDROM_H__ */\n"
  },
  {
    "path": "include/libchdr/chd.h",
    "content": "/***************************************************************************\n\n    chd.h\n\n    MAME Compressed Hunks of Data file format\n\n****************************************************************************\n\n    Copyright Aaron Giles\n    All rights reserved.\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n        * Redistributions of source code must retain the above copyright\n          notice, this list of conditions and the following disclaimer.\n        * Redistributions in binary form must reproduce the above copyright\n          notice, this list of conditions and the following disclaimer in\n          the documentation and/or other materials provided with the\n          distribution.\n        * Neither the name 'MAME' nor the names of its contributors may be\n          used to endorse or promote products derived from this software\n          without specific prior written permission.\n\n    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR\n    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,\n    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n    POSSIBILITY OF SUCH DAMAGE.\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __CHD_H__\n#define __CHD_H__\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <libchdr/coretypes.h>\n#include <libchdr/chdconfig.h>\n\n/***************************************************************************\n\n    Compressed Hunks of Data header format. All numbers are stored in\n    Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)\n    bytes long.\n\n    V1 header:\n\n    [  0] char   tag[8];        // 'MComprHD'\n    [  8] uint32_t length;        // length of header (including tag and length fields)\n    [ 12] uint32_t version;       // drive format version\n    [ 16] uint32_t flags;         // flags (see below)\n    [ 20] uint32_t compression;   // compression type\n    [ 24] uint32_t hunksize;      // 512-byte sectors per hunk\n    [ 28] uint32_t totalhunks;    // total # of hunks represented\n    [ 32] uint32_t cylinders;     // number of cylinders on hard disk\n    [ 36] uint32_t heads;         // number of heads on hard disk\n    [ 40] uint32_t sectors;       // number of sectors on hard disk\n    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data\n    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file\n    [ 76] (V1 header length)\n\n    V2 header:\n\n    [  0] char   tag[8];        // 'MComprHD'\n    [  8] uint32_t length;        // length of header (including tag and length fields)\n    [ 12] uint32_t version;       // drive format version\n    [ 16] uint32_t flags;         // flags (see below)\n    [ 20] uint32_t compression;   // compression type\n    [ 24] uint32_t hunksize;      // seclen-byte sectors per hunk\n    [ 28] uint32_t totalhunks;    // total # of hunks represented\n    [ 32] uint32_t cylinders;     // number of cylinders on hard disk\n    [ 36] uint32_t heads;         // number of heads on hard disk\n    [ 40] uint32_t sectors;       // number of sectors on hard disk\n    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data\n    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file\n    [ 76] uint32_t seclen;        // number of bytes per sector\n    [ 80] (V2 header length)\n\n    V3 header:\n\n    [  0] char   tag[8];        // 'MComprHD'\n    [  8] uint32_t length;        // length of header (including tag and length fields)\n    [ 12] uint32_t version;       // drive format version\n    [ 16] uint32_t flags;         // flags (see below)\n    [ 20] uint32_t compression;   // compression type\n    [ 24] uint32_t totalhunks;    // total # of hunks represented\n    [ 28] uint64_t logicalbytes;  // logical size of the data (in bytes)\n    [ 36] uint64_t metaoffset;    // offset to the first blob of metadata\n    [ 44] uint8_t  md5[16];       // MD5 checksum of raw data\n    [ 60] uint8_t  parentmd5[16]; // MD5 checksum of parent file\n    [ 76] uint32_t hunkbytes;     // number of bytes per hunk\n    [ 80] uint8_t  sha1[20];      // SHA1 checksum of raw data\n    [100] uint8_t  parentsha1[20];// SHA1 checksum of parent file\n    [120] (V3 header length)\n\n    V4 header:\n\n    [  0] char   tag[8];        // 'MComprHD'\n    [  8] uint32_t length;        // length of header (including tag and length fields)\n    [ 12] uint32_t version;       // drive format version\n    [ 16] uint32_t flags;         // flags (see below)\n    [ 20] uint32_t compression;   // compression type\n    [ 24] uint32_t totalhunks;    // total # of hunks represented\n    [ 28] uint64_t logicalbytes;  // logical size of the data (in bytes)\n    [ 36] uint64_t metaoffset;    // offset to the first blob of metadata\n    [ 44] uint32_t hunkbytes;     // number of bytes per hunk\n    [ 48] uint8_t  sha1[20];      // combined raw+meta SHA1\n    [ 68] uint8_t  parentsha1[20];// combined raw+meta SHA1 of parent\n    [ 88] uint8_t  rawsha1[20];   // raw data SHA1\n    [108] (V4 header length)\n\n    Flags:\n        0x00000001 - set if this drive has a parent\n        0x00000002 - set if this drive allows writes\n\n   =========================================================================\n\n    V5 header:\n\n    [  0] char   tag[8];        // 'MComprHD'\n    [  8] uint32_t_t length;        // length of header (including tag and length fields)\n    [ 12] uint32_t_t version;       // drive format version\n    [ 16] uint32_t_t compressors[4];// which custom compressors are used?\n    [ 32] uint64_t_t logicalbytes;  // logical size of the data (in bytes)\n    [ 40] uint64_t_t mapoffset;     // offset to the map\n    [ 48] uint64_t_t metaoffset;    // offset to the first blob of metadata\n    [ 56] uint32_t_t hunkbytes;     // number of bytes per hunk (512k maximum)\n    [ 60] uint32_t_t unitbytes;     // number of bytes per unit within each hunk\n    [ 64] uint8_t_t  rawsha1[20];   // raw data SHA1\n    [ 84] uint8_t_t  sha1[20];      // combined raw+meta SHA1\n    [104] uint8_t_t  parentsha1[20];// combined raw+meta SHA1 of parent\n    [124] (V5 header length)\n\n    If parentsha1 != 0, we have a parent (no need for flags)\n    If compressors[0] == 0, we are uncompressed (including maps)\n\n    V5 uncompressed map format:\n\n    [  0] uint32_t_t offset;        // starting offset / hunk size\n\n    V5 compressed map format header:\n\n    [  0] uint32_t_t length;        // length of compressed map\n    [  4] UINT48 datastart;     // offset of first block\n    [ 10] uint16_t crc;           // crc-16 of the map\n    [ 12] uint8_t_t lengthbits;     // bits used to encode complength\n    [ 13] uint8_t_t hunkbits;       // bits used to encode self-refs\n    [ 14] uint8_t_t parentunitbits; // bits used to encode parent unit refs\n    [ 15] uint8_t_t reserved;       // future use\n    [ 16] (compressed header length)\n\n    Each compressed map entry, once expanded, looks like:\n\n    [  0] uint8_t_t compression;    // compression type\n    [  1] UINT24 complength;    // compressed length\n    [  4] UINT48 offset;        // offset\n    [ 10] uint16_t crc;           // crc-16 of the data\n\n***************************************************************************/\n\n\n/***************************************************************************\n    CONSTANTS\n***************************************************************************/\n\n/* header information */\n#define CHD_HEADER_VERSION\t\t\t5\n#define CHD_V1_HEADER_SIZE\t\t\t76\n#define CHD_V2_HEADER_SIZE\t\t\t80\n#define CHD_V3_HEADER_SIZE\t\t\t120\n#define CHD_V4_HEADER_SIZE\t\t\t108\n#define CHD_V5_HEADER_SIZE          124\n\n#define CHD_MAX_HEADER_SIZE\t\t\tCHD_V5_HEADER_SIZE\n\n/* checksumming information */\n#define CHD_MD5_BYTES\t\t\t\t16\n#define CHD_SHA1_BYTES\t\t\t\t20\n\n/* CHD global flags */\n#define CHDFLAGS_HAS_PARENT\t\t\t0x00000001\n#define CHDFLAGS_IS_WRITEABLE\t\t0x00000002\n#define CHDFLAGS_UNDEFINED\t\t\t0xfffffffc\n\n#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))\n\n/* compression types */\n#define CHDCOMPRESSION_NONE\t\t\t0\n#define CHDCOMPRESSION_ZLIB\t\t\t1\n#define CHDCOMPRESSION_ZLIB_PLUS\t2\n#define CHDCOMPRESSION_AV\t\t\t3\n\n#define CHD_CODEC_NONE 0\n#define CHD_CODEC_ZLIB\t\t\t\tCHD_MAKE_TAG('z','l','i','b')\n#define CHD_CODEC_LZMA\t\t\t\tCHD_MAKE_TAG('l','z','m','a')\n#define CHD_CODEC_HUFFMAN \t\t\tCHD_MAKE_TAG('h','u','f','f')\n#define CHD_CODEC_FLAC\t\t\t\tCHD_MAKE_TAG('f','l','a','c')\n#define CHD_CODEC_ZSTD\t\t\t\tCHD_MAKE_TAG('z', 's', 't', 'd')\n/* general codecs with CD frontend */\n#define CHD_CODEC_CD_ZLIB\t\t\tCHD_MAKE_TAG('c','d','z','l')\n#define CHD_CODEC_CD_LZMA\t\t\tCHD_MAKE_TAG('c','d','l','z')\n#define CHD_CODEC_CD_FLAC\t\t\tCHD_MAKE_TAG('c','d','f','l')\n#define CHD_CODEC_CD_ZSTD\t\t\tCHD_MAKE_TAG('c','d','z','s')\n\n/* A/V codec configuration parameters */\n#define AV_CODEC_COMPRESS_CONFIG\t1\n#define AV_CODEC_DECOMPRESS_CONFIG\t2\n\n/* metadata parameters */\n#define CHDMETATAG_WILDCARD\t\t\t0\n#define CHD_METAINDEX_APPEND\t\t((uint32_t)-1)\n\n/* metadata flags */\n#define CHD_MDFLAGS_CHECKSUM\t\t0x01\t\t/* indicates data is checksummed */\n\n/* standard hard disk metadata */\n#define HARD_DISK_METADATA_TAG\t\tCHD_MAKE_TAG('G','D','D','D')\n#define HARD_DISK_METADATA_FORMAT\t\"CYLS:%u,HEADS:%u,SECS:%u,BPS:%u\"\n\n/* hard disk identify information */\n#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')\n\n/* hard disk key information */\n#define HARD_DISK_KEY_METADATA_TAG\tCHD_MAKE_TAG('K','E','Y',' ')\n\n/* pcmcia CIS information */\n#define PCMCIA_CIS_METADATA_TAG\t\tCHD_MAKE_TAG('C','I','S',' ')\n\n/* standard CD-ROM metadata */\n#define CDROM_OLD_METADATA_TAG\t\tCHD_MAKE_TAG('C','H','C','D')\n#define CDROM_TRACK_METADATA_TAG\tCHD_MAKE_TAG('C','H','T','R')\n#define CDROM_TRACK_METADATA_FORMAT\t\"TRACK:%u TYPE:%s SUBTYPE:%s FRAMES:%u\"\n#define CDROM_TRACK_METADATA2_TAG\tCHD_MAKE_TAG('C','H','T','2')\n#define CDROM_TRACK_METADATA2_FORMAT\t\"TRACK:%u TYPE:%s SUBTYPE:%s FRAMES:%u PREGAP:%u PGTYPE:%s PGSUB:%s POSTGAP:%u\"\n#define GDROM_OLD_METADATA_TAG\t\tCHD_MAKE_TAG('C','H','G','T')\n#define GDROM_TRACK_METADATA_TAG\tCHD_MAKE_TAG('C', 'H', 'G', 'D')\n#define GDROM_TRACK_METADATA_FORMAT\t\"TRACK:%u TYPE:%s SUBTYPE:%s FRAMES:%u PAD:%u PREGAP:%u PGTYPE:%s PGSUB:%s POSTGAP:%u\"\n\n/* standard A/V metadata */\n#define AV_METADATA_TAG\t\t\t\tCHD_MAKE_TAG('A','V','A','V')\n#define AV_METADATA_FORMAT\t\t\t\"FPS:%d.%06d WIDTH:%du HEIGHT:%du INTERLACED:%du CHANNELS:%du SAMPLERATE:%du\"\n\n/* A/V laserdisc frame metadata */\n#define AV_LD_METADATA_TAG\t\t\tCHD_MAKE_TAG('A','V','L','D')\n\n/* DVD metadata */\n#define DVD_METADATA_TAG\t\t\tCHD_MAKE_TAG('D','V','D',' ')\n\n/* CHD open values */\n#define CHD_OPEN_READ\t\t\t\t1\n#define CHD_OPEN_READWRITE\t\t\t2\n\n/* error types */\nenum _chd_error\n{\n\tCHDERR_NONE,\n\tCHDERR_NO_INTERFACE,\n\tCHDERR_OUT_OF_MEMORY,\n\tCHDERR_INVALID_FILE,\n\tCHDERR_INVALID_PARAMETER,\n\tCHDERR_INVALID_DATA,\n\tCHDERR_FILE_NOT_FOUND,\n\tCHDERR_REQUIRES_PARENT,\n\tCHDERR_FILE_NOT_WRITEABLE,\n\tCHDERR_READ_ERROR,\n\tCHDERR_WRITE_ERROR,\n\tCHDERR_CODEC_ERROR,\n\tCHDERR_INVALID_PARENT,\n\tCHDERR_HUNK_OUT_OF_RANGE,\n\tCHDERR_DECOMPRESSION_ERROR,\n\tCHDERR_COMPRESSION_ERROR,\n\tCHDERR_CANT_CREATE_FILE,\n\tCHDERR_CANT_VERIFY,\n\tCHDERR_NOT_SUPPORTED,\n\tCHDERR_METADATA_NOT_FOUND,\n\tCHDERR_INVALID_METADATA_SIZE,\n\tCHDERR_UNSUPPORTED_VERSION,\n\tCHDERR_VERIFY_INCOMPLETE,\n\tCHDERR_INVALID_METADATA,\n\tCHDERR_INVALID_STATE,\n\tCHDERR_OPERATION_PENDING,\n\tCHDERR_NO_ASYNC_OPERATION,\n\tCHDERR_UNSUPPORTED_FORMAT\n};\ntypedef enum _chd_error chd_error;\n\n\n\n/***************************************************************************\n    TYPE DEFINITIONS\n***************************************************************************/\n\n/* opaque types */\ntypedef struct _chd_file chd_file;\n\n\n/* extract header structure (NOT the on-disk header structure) */\ntypedef struct _chd_header chd_header;\nstruct _chd_header\n{\n\tuint32_t\t\tlength;\t\t\t\t\t\t/* length of header data */\n\tuint32_t\t\tversion;\t\t\t\t\t/* drive format version */\n\tuint32_t\t\tflags;\t\t\t\t\t\t/* flags field */\n\tuint32_t\t\tcompression[4];\t\t\t\t/* compression type */\n\tuint32_t\t\thunkbytes;\t\t\t\t\t/* number of bytes per hunk */\n\tuint32_t\t\ttotalhunks;\t\t\t\t\t/* total # of hunks represented */\n\tuint64_t\t\tlogicalbytes;\t\t\t\t/* logical size of the data */\n\tuint64_t\t\tmetaoffset;\t\t\t\t\t/* offset in file of first metadata */\n\tuint64_t\t\tmapoffset;\t\t\t\t\t/* TOOD V5 */\n\tuint8_t\t\tmd5[CHD_MD5_BYTES];\t\t\t/* overall MD5 checksum */\n\tuint8_t\t\tparentmd5[CHD_MD5_BYTES];\t/* overall MD5 checksum of parent */\n\tuint8_t\t\tsha1[CHD_SHA1_BYTES];\t\t/* overall SHA1 checksum */\n\tuint8_t\t\trawsha1[CHD_SHA1_BYTES];\t/* SHA1 checksum of raw data */\n\tuint8_t\t\tparentsha1[CHD_SHA1_BYTES];\t/* overall SHA1 checksum of parent */\n\tuint32_t\t\tunitbytes;\t\t\t\t\t/* TODO V5 */\n\tuint64_t\t\tunitcount;\t\t\t\t\t/* TODO V5 */\n    uint32_t      hunkcount;                  /* TODO V5 */\n\n    /* map information */\n    uint32_t      mapentrybytes;              /* length of each entry in a map (V5) */\n    uint8_t*      rawmap;                     /* raw map data */\n\n\tuint32_t\t\tobsolete_cylinders;\t\t\t/* obsolete field -- do not use! */\n\tuint32_t\t\tobsolete_sectors;\t\t\t/* obsolete field -- do not use! */\n\tuint32_t\t\tobsolete_heads;\t\t\t\t/* obsolete field -- do not use! */\n\tuint32_t\t\tobsolete_hunksize;\t\t\t/* obsolete field -- do not use! */\n};\n\n\n/* structure for returning information about a verification pass */\ntypedef struct _chd_verify_result chd_verify_result;\nstruct _chd_verify_result\n{\n\tuint8_t\t\tmd5[CHD_MD5_BYTES];\t\t\t/* overall MD5 checksum */\n\tuint8_t\t\tsha1[CHD_SHA1_BYTES];\t\t/* overall SHA1 checksum */\n\tuint8_t\t\trawsha1[CHD_SHA1_BYTES];\t/* SHA1 checksum of raw data */\n\tuint8_t\t\tmetasha1[CHD_SHA1_BYTES];\t/* SHA1 checksum of metadata */\n};\n\n\n\n/***************************************************************************\n    FUNCTION PROTOTYPES\n***************************************************************************/\n\n#ifdef _MSC_VER\n#ifdef CHD_DLL\n#ifdef CHD_DLL_EXPORTS\n#define CHD_EXPORT __declspec(dllexport)\n#else\n#define CHD_EXPORT __declspec(dllimport)\n#endif\n#else\n#define CHD_EXPORT\n#endif\n#else\n#define CHD_EXPORT __attribute__ ((visibility(\"default\")))\n#endif\n\n/* ----- CHD file management ----- */\n\n/* create a new CHD file fitting the given description */\n/* chd_error chd_create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */\n\n/* same as chd_create(), but accepts an already-opened core_file object */\n/* chd_error chd_create_file(core_file *file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */\n\n/* open an existing CHD file */\nCHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd);\nCHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd);\nCHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);\n\n/* precache underlying file */\nCHD_EXPORT chd_error chd_precache(chd_file *chd);\n\n/* close a CHD file */\nCHD_EXPORT void chd_close(chd_file *chd);\n\n/* return the associated core_file */\nCHD_EXPORT core_file *chd_core_file(chd_file *chd);\n\n/* return an error string for the given CHD error */\nCHD_EXPORT const char *chd_error_string(chd_error err);\n\n\n\n/* ----- CHD header management ----- */\n\n/* return a pointer to the extracted CHD header data */\nCHD_EXPORT const chd_header *chd_get_header(chd_file *chd);\n\n/* read CHD header data from file into the pointed struct */\nCHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header);\n\n\n\n/* ----- core data read/write ----- */\n\n/* read one hunk from the CHD file */\nCHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer);\n\n\n\n/* ----- metadata management ----- */\n\n/* get indexed metadata of a particular sort */\nCHD_EXPORT chd_error chd_get_metadata(chd_file *chd, uint32_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags);\n\n\n\n\n/* ----- codec interfaces ----- */\n\n/* set internal codec parameters */\nCHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config);\n\n/* return a string description of a codec */\nCHD_EXPORT const char *chd_get_codec_name(uint32_t codec);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* __CHD_H__ */\n"
  },
  {
    "path": "include/libchdr/chdconfig.h",
    "content": "#ifndef __CHDCONFIG_H__\n#define __CHDCONFIG_H__\n\n#include <retro_inline.h>\n\n/* Configure CHDR features here */\n#define WANT_RAW_DATA_SECTOR    1\n#define WANT_SUBCODE            1\n/*#define NEED_CACHE_HUNK         1*/\n/*#define VERIFY_BLOCK_CRC        1*/\n\n#endif\n"
  },
  {
    "path": "include/libchdr/coretypes.h",
    "content": "#ifndef __CORETYPES_H__\n#define __CORETYPES_H__\n\n#include <stdint.h>\n#include <stdio.h>\n#include <retro_miscellaneous.h>\n#ifdef USE_LIBRETRO_VFS\n#include <streams/file_stream_transforms.h>\n#endif\n\ntypedef uint64_t UINT64;\n#ifndef OSD_CPU_H\ntypedef uint32_t UINT32;\ntypedef uint16_t UINT16;\ntypedef uint8_t UINT8;\n#endif\n\ntypedef int64_t INT64;\n#ifndef OSD_CPU_H\ntypedef int32_t INT32;\ntypedef int16_t INT16;\ntypedef int8_t INT8;\n#endif\n\n#ifndef ARRAY_LENGTH\n#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))\n#endif\n\ntypedef struct chd_core_file {\n\t/*\n\t * arbitrary pointer to data the implementation uses to implement the below functions\n\t */\n\tvoid *argp;\n\n\t/*\n\t * return the size of a given file as a 64-bit unsigned integer.\n\t * the position of the file pointer after calling this function is\n\t * undefined because many implementations will seek to the end of the\n\t * file and call ftell.\n\t *\n\t * on error, (uint64_t)-1 is returned.\n\t */\n\tuint64_t(*fsize)(struct chd_core_file*);\n\n\t/*\n\t * should match the behavior of fread, except the FILE* argument at the end\n\t * will be replaced with a struct chd_core_file*.\n\t */\n\tsize_t(*fread)(void*,size_t,size_t,struct chd_core_file*);\n\n\t/* closes the given file. */\n\tint (*fclose)(struct chd_core_file*);\n\n\t/* fseek clone. */\n\tint (*fseek)(struct chd_core_file*, int64_t, int);\n} core_file;\n\nstatic INLINE int core_fclose(core_file *fp) {\n\treturn fp->fclose(fp);\n}\n\nstatic INLINE size_t core_fread(core_file *fp, void *ptr, size_t len) {\n\treturn fp->fread(ptr, 1, len, fp);\n}\n\nstatic INLINE int core_fseek(core_file* fp, int64_t offset, int whence) {\n\treturn fp->fseek(fp, offset, whence);\n}\n\nstatic INLINE uint64_t core_fsize(core_file *fp)\n{\n\treturn fp->fsize(fp);\n}\n\n#endif\n"
  },
  {
    "path": "include/libchdr/flac.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n ***************************************************************************\n\n    flac.h\n\n    FLAC compression wrappers\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __FLAC_H__\n#define __FLAC_H__\n\n#include <stdint.h>\n\n#include <libchdr/libchdr_zlib.h>\n\n/***************************************************************************\n *  TYPE DEFINITIONS\n ***************************************************************************\n */\n\ntypedef struct _flac_decoder flac_decoder;\nstruct _flac_decoder {\n\t\t/* output state */\n\tvoid *                  decoder;\t\t\t\t/* actual encoder */\n\tuint32_t                sample_rate;\t\t\t/* decoded sample rate */\n\tuint8_t                 channels;\t\t\t\t/* decoded number of channels */\n\tuint8_t                 bits_per_sample;\t\t/* decoded bits per sample */\n\tuint32_t                compressed_offset;\t\t/* current offset in compressed data */\n\tconst uint8_t *         compressed_start;\t\t/* start of compressed data */\n\tuint32_t                compressed_length;\t\t/* length of compressed data */\n\tconst uint8_t *         compressed2_start;\t\t/* start of compressed data */\n\tuint32_t                compressed2_length;\t\t/* length of compressed data */\n\tint16_t *               uncompressed_start[8];\t/* pointer to start of uncompressed data (up to 8 streams) */\n\tuint32_t                uncompressed_offset;\t/* current position in uncompressed data */\n\tuint32_t                uncompressed_length;\t/* length of uncompressed data */\n\tint                    \tuncompressed_swap;\t\t/* swap uncompressed sample data */\n\tuint8_t                 custom_header[0x2a];\t/* custom header */\n};\n\n/* ======================> flac_decoder */\n\nint \t\tflac_decoder_init(flac_decoder* decoder);\nvoid \t\tflac_decoder_free(flac_decoder* decoder);\nint \t\tflac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);\nint \t\tflac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);\nuint32_t \tflac_decoder_finish(flac_decoder* decoder);\n\n/* codec-private data for the FLAC codec */\ntypedef struct _flac_codec_data flac_codec_data;\nstruct _flac_codec_data {\n\t/* internal state */\n\tint\t\tnative_endian;\n\tflac_decoder\tdecoder;\n};\n\n/* codec-private data for the CDFL codec */\ntypedef struct _cdfl_codec_data cdfl_codec_data;\nstruct _cdfl_codec_data {\n\t/* internal state */\n\tint\t\tswap_endian;\n\tflac_decoder\tdecoder;\n#ifdef WANT_SUBCODE\n\tzlib_codec_data\t\tsubcode_decompressor;\n#endif\n\tuint8_t*\tbuffer;\n};\n\n#endif /* __FLAC_H__ */\n"
  },
  {
    "path": "include/libchdr/huffman.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n ***************************************************************************\n\n    huffman.h\n\n    Static Huffman compression and decompression helpers.\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __HUFFMAN_H__\n#define __HUFFMAN_H__\n\n#include <libchdr/bitstream.h>\n\n\n/***************************************************************************\n *  CONSTANTS\n ***************************************************************************\n */\n\nenum huffman_error\n{\n\tHUFFERR_NONE = 0,\n\tHUFFERR_TOO_MANY_BITS,\n\tHUFFERR_INVALID_DATA,\n\tHUFFERR_INPUT_BUFFER_TOO_SMALL,\n\tHUFFERR_OUTPUT_BUFFER_TOO_SMALL,\n\tHUFFERR_INTERNAL_INCONSISTENCY,\n\tHUFFERR_TOO_MANY_CONTEXTS\n};\n\n/***************************************************************************\n *  TYPE DEFINITIONS\n ***************************************************************************\n */\n\ntypedef uint16_t lookup_value;\n\n/* a node in the huffman tree */\nstruct node_t\n{\n\tstruct node_t*\t\tparent;\t\t/* pointer to parent node */\n\tuint32_t\t\t\tcount;\t\t/* number of hits on this node */\n\tuint32_t\t\t\tweight;\t\t/* assigned weight of this node */\n\tuint32_t\t\t\tbits;\t\t/* bits used to encode the node */\n\tuint8_t\t\t\t\tnumbits;\t/* number of bits needed for this node */\n};\n\n/* ======================> huffman_context_base */\n\n/* context class for decoding */\nstruct huffman_decoder\n{\n\t/* internal state */\n\tuint32_t\t\t\tnumcodes;             /* number of total codes being processed */\n\tuint8_t\t\t\t\tmaxbits;           /* maximum bits per code */\n\tuint8_t \t\t\tprevdata;             /* value of the previous data (for delta-RLE encoding) */\n\tint             \trleremaining;         /* number of RLE bytes remaining (for delta-RLE encoding) */\n\tlookup_value *  \tlookup;               /* pointer to the lookup table */\n\tstruct node_t *     huffnode;             /* array of nodes */\n\tuint32_t *      \tdatahisto;            /* histogram of data values */\n};\n\n/* ======================> huffman_decoder */\n\nstruct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);\nvoid delete_huffman_decoder(struct huffman_decoder* decoder);\n\n/* single item operations */\nuint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);\n\nenum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);\nenum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);\n\nint huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);\nenum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);\nenum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);\n\nvoid huffman_build_lookup_table(struct huffman_decoder* decoder);\n\n#endif\n"
  },
  {
    "path": "include/libchdr/libchdr_zlib.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n ***************************************************************************\n\n    libchr_zlib.h\n\n    Zlib compression wrappers\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __LIBCHDR_ZLIB_H__\n#define __LIBCHDR_ZLIB_H__\n\n#include <stdint.h>\n\n#include <zlib.h>\n#include \"coretypes.h\"\n#include \"chd.h\"\n\n#define MAX_ZLIB_ALLOCS\t\t\t\t64\n\n/* codec-private data for the ZLIB codec */\n\ntypedef struct _zlib_allocator zlib_allocator;\nstruct _zlib_allocator\n{\n\tuint32_t *\t\t\t\tallocptr[MAX_ZLIB_ALLOCS];\n\tuint32_t *\t\t\t\tallocptr2[MAX_ZLIB_ALLOCS];\n};\n\ntypedef struct _zlib_codec_data zlib_codec_data;\nstruct _zlib_codec_data\n{\n\tz_stream\t\t\t\tinflater;\n\tzlib_allocator\t\t\tallocator;\n};\n\n/* codec-private data for the CDZL codec */\ntypedef struct _cdzl_codec_data cdzl_codec_data;\nstruct _cdzl_codec_data {\n\t/* internal state */\n\tzlib_codec_data\t\tbase_decompressor;\n#ifdef WANT_SUBCODE\n\tzlib_codec_data\t\tsubcode_decompressor;\n#endif\n\tuint8_t*\t\t\tbuffer;\n};\n\nextern chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);\nextern void zlib_codec_free(void *codec);\nextern chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\nextern void zlib_allocator_free(voidpf opaque);\n\n/* zlib compression codec */\nchd_error zlib_codec_init(void *codec, uint32_t hunkbytes);\n\nvoid zlib_codec_free(void *codec);\n\nchd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\nvoidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);\n\nvoid zlib_fast_free(voidpf opaque, voidpf address);\n\n/* cdzl compression codec */\nchd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);\n\nvoid cdzl_codec_free(void* codec);\n\nchd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n#endif /* __LIBCHDR_ZLIB_H__ */\n"
  },
  {
    "path": "include/libchdr/libchdr_zstd.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n ***************************************************************************\n\n    libchr_zstd.h\n\n    Zstd compression wrappers\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __LIBCHDR_ZSTD_H__\n#define __LIBCHDR_ZSTD_H__\n\n#include <stdint.h>\n\n#include <zstd.h>\n#include \"coretypes.h\"\n#include \"chd.h\"\n\ntypedef struct _zstd_codec_data zstd_codec_data;\nstruct _zstd_codec_data\n{\n\tZSTD_DStream *dstream;\n};\n\ntypedef struct _cdzs_codec_data cdzs_codec_data;\nstruct _cdzs_codec_data\n{\n\tzstd_codec_data base_decompressor;\n#ifdef WANT_SUBCODE\n\tzstd_codec_data subcode_decompressor;\n#endif\n\tuint8_t*\t\t\t\tbuffer;\n};\n\n#endif /* __LIBCHDR_ZSTD_H__ */\n"
  },
  {
    "path": "include/libchdr/lzma.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n ***************************************************************************\n\n    lzma.h\n\n    LZMA compression wrappers\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __LIBCHDR_LZMA_H__\n#define __LIBCHDR_LZMA_H__\n\n#include <stdint.h>\n\n#include <LzmaEnc.h>\n#include <LzmaDec.h>\n\n#include <libchdr/libchdr_zlib.h>\n\n/* codec-private data for the LZMA codec */\n#define MAX_LZMA_ALLOCS 64\n\ntypedef struct _lzma_allocator lzma_allocator;\nstruct _lzma_allocator\n{\n\tvoid *(*Alloc)(void *p, size_t size);\n \tvoid (*Free)(void *p, void *address); /* address can be 0 */\n\tvoid (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */\n\tuint32_t*\tallocptr[MAX_LZMA_ALLOCS];\n\tuint32_t*\tallocptr2[MAX_LZMA_ALLOCS];\n};\n\ntypedef struct _lzma_codec_data lzma_codec_data;\nstruct _lzma_codec_data\n{\n\tCLzmaDec\t\tdecoder;\n\tlzma_allocator\tallocator;\n};\n\n/* codec-private data for the CDLZ codec */\ntypedef struct _cdlz_codec_data cdlz_codec_data;\nstruct _cdlz_codec_data {\n\t/* internal state */\n\tlzma_codec_data\t\tbase_decompressor;\n#ifdef WANT_SUBCODE\n\tzlib_codec_data\t\tsubcode_decompressor;\n#endif\n\tuint8_t*\t\t\tbuffer;\n};\n\nchd_error lzma_codec_init(void* codec, uint32_t hunkbytes);\n\nvoid lzma_codec_free(void* codec);\n\n/*-------------------------------------------------\n *  decompress - decompress data using the LZMA\n *  codec\n *-------------------------------------------------\n */\n\nchd_error lzma_codec_decompress(void* codec, const uint8_t *src,\n      uint32_t complen, uint8_t *dest, uint32_t destlen);\n\nchd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);\n\nvoid cdlz_codec_free(void* codec);\n\nchd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);\n\n#endif /* __LIBCHDR_LZMA_H__ */\n"
  },
  {
    "path": "include/libchdr/minmax.h",
    "content": "/* license:BSD-3-Clause\n * copyright-holders:Aaron Giles\n ***************************************************************************\n\n    minmax.h\n\n***************************************************************************/\n\n#pragma once\n\n#ifndef __MINMAX_H__\n#define __MINMAX_H__\n\n#if defined(RARCH_INTERNAL) || defined(__LIBRETRO__)\n#include <retro_miscellaneous.h>\n#else\n#define MAX(x, y) (((x) > (y)) ? (x) : (y))\n#define MIN(x, y) ((x) < (y) ? (x) : (y))\n#endif\n\n#endif\n"
  },
  {
    "path": "include/libco.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (libco.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBCO_H\n#define LIBCO_H\n\n#include <retro_common_api.h>\n\n#ifdef LIBCO_C\n  #ifdef LIBCO_MP\n    #define thread_local __thread\n  #else\n    #define thread_local\n  #endif\n#endif\n\nRETRO_BEGIN_DECLS\n\ntypedef void* cothread_t;\n\n/**\n * co_active:\n *\n * Gets the currently active context.\n *\n * Returns: active context.\n **/\ncothread_t co_active(void);\n\n/**\n * co_create:\n * @int                : stack size\n * @funcptr            : thread entry function callback\n *\n * Create a co_thread.\n *\n * Returns: cothread if successful, otherwise NULL.\n */\ncothread_t co_create(unsigned int, void (*)(void));\n\n/**\n * co_delete:\n * @cothread           : cothread object\n *\n * Frees a co_thread.\n */\nvoid co_delete(cothread_t cothread);\n\n/**\n * co_switch:\n * @cothread           : cothread object to switch to\n *\n * Do a context switch to @cothread.\n */\nvoid co_switch(cothread_t cothread);\n\nRETRO_END_DECLS\n\n/* ifndef LIBCO_H */\n#endif\n"
  },
  {
    "path": "include/libretro.h",
    "content": "/*!\n * libretro.h is a simple API that allows for the creation of games and emulators.\n *\n * @file libretro.h\n * @version 1\n * @author libretro\n * @copyright Copyright (C) 2010-2024 The RetroArch team\n *\n * @paragraph LICENSE\n * The following license statement only applies to this libretro API header (libretro.h).\n *\n * Copyright (C) 2010-2024 The RetroArch team\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_H__\n#define LIBRETRO_H__\n\n#include <stdint.h>\n#include <stddef.h>\n#include <limits.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef __cplusplus\n#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)\n/* Hack applied for MSVC when compiling in C89 mode\n * as it isn't C99-compliant. */\n#define bool unsigned char\n#define true 1\n#define false 0\n#else\n#include <stdbool.h>\n#endif\n#endif\n\n#ifndef RETRO_CALLCONV\n#  if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)\n#    define RETRO_CALLCONV __attribute__((cdecl))\n#  elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64)\n#    define RETRO_CALLCONV __cdecl\n#  else\n#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */\n#  endif\n#endif\n\n#ifndef RETRO_API\n#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)\n#    ifdef RETRO_IMPORT_SYMBOLS\n#      ifdef __GNUC__\n#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))\n#      else\n#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)\n#      endif\n#    else\n#      ifdef __GNUC__\n#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))\n#      else\n#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)\n#      endif\n#    endif\n#  else\n#      if defined(__GNUC__) && __GNUC__ >= 4\n#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__(\"default\")))\n#      else\n#        define RETRO_API RETRO_CALLCONV\n#      endif\n#  endif\n#endif\n\n/**\n * The major version of the libretro API and ABI.\n * Cores may support multiple versions,\n * or they may reject cores with unsupported versions.\n * It is only incremented for incompatible API/ABI changes;\n * this generally implies a function was removed or changed,\n * or that a \\c struct had fields removed or changed.\n * @note A design goal of libretro is to avoid having to increase this value at all costs.\n * This is why there are APIs that are \"extended\" or \"V2\".\n */\n#define RETRO_API_VERSION         1\n\n/**\n * @defgroup RETRO_DEVICE Input Devices\n * @brief Libretro's fundamental device abstractions.\n *\n * Libretro's input system consists of abstractions over standard device types,\n * such as a joypad (with or without analog), mouse, keyboard, light gun, or an abstract pointer.\n * Instead of managing input devices themselves,\n * cores need only to map their own concept of a controller to libretro's abstractions.\n * This makes it possible for frontends to map the abstract types to a real input device\n * without having to worry about the correct use of arbitrary (real) controller layouts.\n * @{\n */\n\n#define RETRO_DEVICE_TYPE_SHIFT         8\n#define RETRO_DEVICE_MASK               ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)\n\n/**\n * Defines an ID for a subclass of a known device type.\n *\n * To define a subclass ID, use this macro like so:\n * @code{c}\n * #define RETRO_DEVICE_SUPER_SCOPE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)\n * #define RETRO_DEVICE_JUSTIFIER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 2)\n * @endcode\n *\n * Correct use of this macro allows a frontend to select a suitable physical device\n * to map to the emulated device.\n *\n * @note Cores must use the base ID when polling for input,\n * and frontends must only accept the base ID for this purpose.\n * Polling for input using subclass IDs is reserved for future definition.\n *\n * @param base One of the \\ref RETRO_DEVICE \"base device types\".\n * @param id A unique ID, with respect to \\c base.\n * Must be a non-negative integer.\n * @return A unique subclass ID.\n * @see retro_controller_description\n * @see retro_set_controller_port_device\n */\n#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)\n\n/**\n * @defgroup RETRO_DEVICE Input Device Classes\n * @{\n */\n\n/**\n * Indicates no input.\n *\n * When provided as the \\c device argument to \\c retro_input_state_t,\n * all other arguments are ignored and zero is returned.\n *\n * @see retro_input_state_t\n */\n#define RETRO_DEVICE_NONE         0\n\n/**\n * An abstraction around a game controller, known as a \"RetroPad\".\n *\n * The RetroPad is modelled after a SNES controller,\n * but with additional L2/R2/L3/R3 buttons\n * (similar to a PlayStation controller).\n *\n * When provided as the \\c device argument to \\c retro_input_state_t,\n * the \\c id argument denotes the button (including D-Pad directions) to query.\n * The result of said query will be 1 if the button is down, 0 if not.\n *\n * There is one exception; if \\c RETRO_DEVICE_ID_JOYPAD_MASK is queried\n * (and the frontend supports this query),\n * the result will be a bitmask of all pressed buttons.\n *\n * @see retro_input_state_t\n * @see RETRO_DEVICE_ANALOG\n * @see RETRO_DEVICE_ID_JOYPAD\n * @see RETRO_DEVICE_ID_JOYPAD_MASK\n * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS\n */\n#define RETRO_DEVICE_JOYPAD       1\n\n/**\n * An abstraction around a mouse, similar to the SNES Mouse but with more buttons.\n *\n * When provided as the \\c device argument to \\c retro_input_state_t,\n * the \\c id argument denotes the button or axis to query.\n * For buttons, the result of said query\n * will be 1 if the button is down or 0 if not.\n * For mouse wheel axes, the result\n * will be 1 if the wheel was rotated in that direction and 0 if not.\n * For the mouse pointer axis, the result will be thee mouse's movement\n * relative to the last poll.\n * The core is responsible for tracking the mouse's position,\n * and the frontend is responsible for preventing interference\n * by the real hardware pointer (if applicable).\n *\n * @note This should only be used for cores that emulate mouse input,\n * such as for home computers\n * or consoles with mouse attachments.\n * Cores that emulate light guns should use \\c RETRO_DEVICE_LIGHTGUN,\n * and cores that emulate touch screens should use \\c RETRO_DEVICE_POINTER.\n *\n * @see RETRO_DEVICE_POINTER\n * @see RETRO_DEVICE_LIGHTGUN\n */\n#define RETRO_DEVICE_MOUSE        2\n\n/**\n * An abstraction around a keyboard.\n *\n * When provided as the \\c device argument to \\c retro_input_state_t,\n * the \\c id argument denotes the key to poll.\n *\n * @note This should only be used for cores that emulate keyboard input,\n * such as for home computers\n * or consoles with keyboard attachments.\n * Cores that emulate gamepads should use \\c RETRO_DEVICE_JOYPAD or \\c RETRO_DEVICE_ANALOG,\n * and leave keyboard compatibility to the frontend.\n *\n * @see RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK\n * @see retro_key\n */\n#define RETRO_DEVICE_KEYBOARD     3\n\n/**\n * An abstraction around a light gun, similar to the PlayStation's Guncon.\n *\n * When provided as the \\c device argument to \\c retro_input_state_t,\n * the \\c id argument denotes one of several possible inputs.\n *\n * The gun's coordinates are reported in screen space (similar to the pointer)\n * in the range of [-0x8000, 0x7fff].\n * Zero is the center of the game's screen\n * and -0x8000 represents out-of-bounds.\n * The trigger and various auxiliary buttons are also reported.\n *\n * @note A forced off-screen shot can be requested for auto-reloading\n * function in some games.\n *\n * @see RETRO_DEVICE_POINTER\n */\n#define RETRO_DEVICE_LIGHTGUN     4\n\n/**\n * An extension of the RetroPad that supports analog input.\n *\n * The analog RetroPad provides two virtual analog sticks (similar to DualShock controllers)\n * and allows any button to be treated as analog (similar to Xbox shoulder triggers).\n *\n * When provided as the \\c device argument to \\c retro_input_state_t,\n * the \\c id argument denotes an analog axis or an analog button.\n *\n * Analog axes are reported in the range of [-0x8000, 0x7fff],\n * with the X axis being positive towards the right\n * and the Y axis being positive towards the bottom.\n *\n * Analog buttons are reported in the range of [0, 0x7fff],\n * where 0 is unpressed and 0x7fff is fully pressed.\n *\n * @note Cores should only use this type if they need analog input.\n * Otherwise, \\c RETRO_DEVICE_JOYPAD should be used.\n * @see RETRO_DEVICE_JOYPAD\n */\n#define RETRO_DEVICE_ANALOG       5\n\n/**\n * Input Device: Pointer.\n *\n * Abstracts the concept of a pointing mechanism, e.g. touch.\n * This allows libretro to query in absolute coordinates where on the\n * screen a mouse (or something similar) is being placed.\n * For a touch centric device, coordinates reported are the coordinates\n * of the press.\n *\n * Coordinates in X and Y are reported as:\n * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,\n * and 0x7fff corresponds to the far right/bottom of the screen.\n * The \"screen\" is here defined as area that is passed to the frontend and\n * later displayed on the monitor. If the pointer is outside this screen,\n * such as in the black surrounding areas when actual display is larger,\n * edge position is reported. An explicit edge detection is also provided,\n * that will return 1 if the pointer is near the screen edge or actually outside it.\n *\n * The frontend is free to scale/resize this screen as it sees fit, however,\n * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the\n * game image, etc.\n *\n * To check if the pointer coordinates are valid (e.g. a touch display\n * actually being touched), \\c RETRO_DEVICE_ID_POINTER_PRESSED returns 1 or 0.\n *\n * If using a mouse on a desktop, \\c RETRO_DEVICE_ID_POINTER_PRESSED will\n * usually correspond to the left mouse button, but this is a frontend decision.\n * \\c RETRO_DEVICE_ID_POINTER_PRESSED will only return 1 if the pointer is\n * inside the game screen.\n *\n * For multi-touch, the index variable can be used to successively query\n * more presses.\n * If index = 0 returns true for \\c _PRESSED, coordinates can be extracted\n * with \\c _X, \\c _Y for index = 0. One can then query \\c _PRESSED, \\c _X, \\c _Y with\n * index = 1, and so on.\n * Eventually \\c _PRESSED will return false for an index. No further presses\n * are registered at this point.\n *\n * @see RETRO_DEVICE_MOUSE\n * @see RETRO_DEVICE_ID_POINTER_X\n * @see RETRO_DEVICE_ID_POINTER_Y\n * @see RETRO_DEVICE_ID_POINTER_PRESSED\n */\n#define RETRO_DEVICE_POINTER      6\n\n/** @} */\n\n/** @defgroup RETRO_DEVICE_ID_JOYPAD RetroPad Input\n * @brief Digital buttons for the RetroPad.\n *\n * Button placement is comparable to that of a SNES controller,\n * combined with the shoulder buttons of a PlayStation controller.\n * These values can also be used for the \\c id field of \\c RETRO_DEVICE_INDEX_ANALOG_BUTTON\n * to represent analog buttons (usually shoulder triggers).\n * @{\n */\n\n/** The equivalent of the SNES controller's south face button. */\n#define RETRO_DEVICE_ID_JOYPAD_B        0\n\n/** The equivalent of the SNES controller's west face button. */\n#define RETRO_DEVICE_ID_JOYPAD_Y        1\n\n/** The equivalent of the SNES controller's left-center button. */\n#define RETRO_DEVICE_ID_JOYPAD_SELECT   2\n\n/** The equivalent of the SNES controller's right-center button. */\n#define RETRO_DEVICE_ID_JOYPAD_START    3\n\n/** Up on the RetroPad's D-pad. */\n#define RETRO_DEVICE_ID_JOYPAD_UP       4\n\n/** Down on the RetroPad's D-pad. */\n#define RETRO_DEVICE_ID_JOYPAD_DOWN     5\n\n/** Left on the RetroPad's D-pad. */\n#define RETRO_DEVICE_ID_JOYPAD_LEFT     6\n\n/** Right on the RetroPad's D-pad. */\n#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7\n\n/** The equivalent of the SNES controller's east face button. */\n#define RETRO_DEVICE_ID_JOYPAD_A        8\n\n/** The equivalent of the SNES controller's north face button. */\n#define RETRO_DEVICE_ID_JOYPAD_X        9\n\n/** The equivalent of the SNES controller's left shoulder button. */\n#define RETRO_DEVICE_ID_JOYPAD_L       10\n\n/** The equivalent of the SNES controller's right shoulder button. */\n#define RETRO_DEVICE_ID_JOYPAD_R       11\n\n/** The equivalent of the PlayStation's rear left shoulder button. */\n#define RETRO_DEVICE_ID_JOYPAD_L2      12\n\n/** The equivalent of the PlayStation's rear right shoulder button. */\n#define RETRO_DEVICE_ID_JOYPAD_R2      13\n\n/**\n * The equivalent of the PlayStation's left analog stick button,\n * although the actual button need not be in this position.\n */\n#define RETRO_DEVICE_ID_JOYPAD_L3      14\n\n/**\n * The equivalent of the PlayStation's right analog stick button,\n * although the actual button need not be in this position.\n */\n#define RETRO_DEVICE_ID_JOYPAD_R3      15\n\n/**\n * Represents a bitmask that describes the state of all \\c RETRO_DEVICE_ID_JOYPAD button constants,\n * rather than the state of a single button.\n *\n * @see RETRO_ENVIRONMENT_GET_INPUT_BITMASKS\n * @see RETRO_DEVICE_JOYPAD\n */\n#define RETRO_DEVICE_ID_JOYPAD_MASK    256\n\n/** @} */\n\n/** @defgroup RETRO_DEVICE_ID_ANALOG Analog RetroPad Input\n * @{\n */\n\n/* Index / Id values for ANALOG device. */\n#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0\n#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1\n#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2\n#define RETRO_DEVICE_ID_ANALOG_X             0\n#define RETRO_DEVICE_ID_ANALOG_Y             1\n\n/** @} */\n\n/* Id values for MOUSE. */\n#define RETRO_DEVICE_ID_MOUSE_X                0\n#define RETRO_DEVICE_ID_MOUSE_Y                1\n#define RETRO_DEVICE_ID_MOUSE_LEFT             2\n#define RETRO_DEVICE_ID_MOUSE_RIGHT            3\n#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4\n#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5\n#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6\n#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7\n#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8\n#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9\n#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10\n\n/* Id values for LIGHTGUN. */\n#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/\n#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute Position*/\n/** Indicates if lightgun points off the screen or near the edge */\n#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/\n#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2\n#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/\n#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3\n#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4\n#define RETRO_DEVICE_ID_LIGHTGUN_START            6\n#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7\n#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8\n#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9\n#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10\n#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11\n#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12\n/* deprecated */\n#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/\n#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative Position*/\n#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A instead*/\n#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B instead*/\n#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start instead*/\n\n/* Id values for POINTER. */\n#define RETRO_DEVICE_ID_POINTER_X             0\n#define RETRO_DEVICE_ID_POINTER_Y             1\n#define RETRO_DEVICE_ID_POINTER_PRESSED       2\n#define RETRO_DEVICE_ID_POINTER_COUNT         3\n/** Indicates if pointer is off the screen or near the edge */\n#define RETRO_DEVICE_ID_POINTER_IS_OFFSCREEN 15\n/** @} */\n\n/* Returned from retro_get_region(). */\n#define RETRO_REGION_NTSC  0\n#define RETRO_REGION_PAL   1\n\n/**\n * Identifiers for supported languages.\n * @see RETRO_ENVIRONMENT_GET_LANGUAGE\n */\nenum retro_language\n{\n   RETRO_LANGUAGE_ENGLISH             = 0,\n   RETRO_LANGUAGE_JAPANESE            = 1,\n   RETRO_LANGUAGE_FRENCH              = 2,\n   RETRO_LANGUAGE_SPANISH             = 3,\n   RETRO_LANGUAGE_GERMAN              = 4,\n   RETRO_LANGUAGE_ITALIAN             = 5,\n   RETRO_LANGUAGE_DUTCH               = 6,\n   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,\n   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,\n   RETRO_LANGUAGE_RUSSIAN             = 9,\n   RETRO_LANGUAGE_KOREAN              = 10,\n   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,\n   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,\n   RETRO_LANGUAGE_ESPERANTO           = 13,\n   RETRO_LANGUAGE_POLISH              = 14,\n   RETRO_LANGUAGE_VIETNAMESE          = 15,\n   RETRO_LANGUAGE_ARABIC              = 16,\n   RETRO_LANGUAGE_GREEK               = 17,\n   RETRO_LANGUAGE_TURKISH             = 18,\n   RETRO_LANGUAGE_SLOVAK              = 19,\n   RETRO_LANGUAGE_PERSIAN             = 20,\n   RETRO_LANGUAGE_HEBREW              = 21,\n   RETRO_LANGUAGE_ASTURIAN            = 22,\n   RETRO_LANGUAGE_FINNISH             = 23,\n   RETRO_LANGUAGE_INDONESIAN          = 24,\n   RETRO_LANGUAGE_SWEDISH             = 25,\n   RETRO_LANGUAGE_UKRAINIAN           = 26,\n   RETRO_LANGUAGE_CZECH               = 27,\n   RETRO_LANGUAGE_CATALAN_VALENCIA    = 28,\n   RETRO_LANGUAGE_CATALAN             = 29,\n   RETRO_LANGUAGE_BRITISH_ENGLISH     = 30,\n   RETRO_LANGUAGE_HUNGARIAN           = 31,\n   RETRO_LANGUAGE_BELARUSIAN          = 32,\n   RETRO_LANGUAGE_GALICIAN            = 33,\n   RETRO_LANGUAGE_NORWEGIAN           = 34,\n   RETRO_LANGUAGE_IRISH               = 35,\n   RETRO_LANGUAGE_THAI                = 36,\n   RETRO_LANGUAGE_LAST,\n\n   /** Defined to ensure that <tt>sizeof(retro_language) == sizeof(int)</tt>. Do not use. */\n   RETRO_LANGUAGE_DUMMY          = INT_MAX\n};\n\n/** @defgroup RETRO_MEMORY Memory Types\n * @{\n */\n\n/* Passed to retro_get_memory_data/size().\n * If the memory type doesn't apply to the\n * implementation NULL/0 can be returned.\n */\n#define RETRO_MEMORY_MASK        0xff\n\n/* Regular save RAM. This RAM is usually found on a game cartridge,\n * backed up by a battery.\n * If save game data is too complex for a single memory buffer,\n * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment\n * callback can be used. */\n#define RETRO_MEMORY_SAVE_RAM    0\n\n/* Some games have a built-in clock to keep track of time.\n * This memory is usually just a couple of bytes to keep track of time.\n */\n#define RETRO_MEMORY_RTC         1\n\n/* System ram lets a frontend peek into a game systems main RAM. */\n#define RETRO_MEMORY_SYSTEM_RAM  2\n\n/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */\n#define RETRO_MEMORY_VIDEO_RAM   3\n\n/* ROM lets a frontend peek into a game systems ROM. */\n#define RETRO_MEMORY_ROM   4\n\n/** @} */\n\n/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */\nenum retro_key\n{\n   RETROK_UNKNOWN        = 0,\n   RETROK_FIRST          = 0,\n   RETROK_BACKSPACE      = 8,\n   RETROK_TAB            = 9,\n   RETROK_CLEAR          = 12,\n   RETROK_RETURN         = 13,\n   RETROK_PAUSE          = 19,\n   RETROK_ESCAPE         = 27,\n   RETROK_SPACE          = 32,\n   RETROK_EXCLAIM        = 33,\n   RETROK_QUOTEDBL       = 34,\n   RETROK_HASH           = 35,\n   RETROK_DOLLAR         = 36,\n   RETROK_AMPERSAND      = 38,\n   RETROK_QUOTE          = 39,\n   RETROK_LEFTPAREN      = 40,\n   RETROK_RIGHTPAREN     = 41,\n   RETROK_ASTERISK       = 42,\n   RETROK_PLUS           = 43,\n   RETROK_COMMA          = 44,\n   RETROK_MINUS          = 45,\n   RETROK_PERIOD         = 46,\n   RETROK_SLASH          = 47,\n   RETROK_0              = 48,\n   RETROK_1              = 49,\n   RETROK_2              = 50,\n   RETROK_3              = 51,\n   RETROK_4              = 52,\n   RETROK_5              = 53,\n   RETROK_6              = 54,\n   RETROK_7              = 55,\n   RETROK_8              = 56,\n   RETROK_9              = 57,\n   RETROK_COLON          = 58,\n   RETROK_SEMICOLON      = 59,\n   RETROK_LESS           = 60,\n   RETROK_EQUALS         = 61,\n   RETROK_GREATER        = 62,\n   RETROK_QUESTION       = 63,\n   RETROK_AT             = 64,\n   RETROK_LEFTBRACKET    = 91,\n   RETROK_BACKSLASH      = 92,\n   RETROK_RIGHTBRACKET   = 93,\n   RETROK_CARET          = 94,\n   RETROK_UNDERSCORE     = 95,\n   RETROK_BACKQUOTE      = 96,\n   RETROK_a              = 97,\n   RETROK_b              = 98,\n   RETROK_c              = 99,\n   RETROK_d              = 100,\n   RETROK_e              = 101,\n   RETROK_f              = 102,\n   RETROK_g              = 103,\n   RETROK_h              = 104,\n   RETROK_i              = 105,\n   RETROK_j              = 106,\n   RETROK_k              = 107,\n   RETROK_l              = 108,\n   RETROK_m              = 109,\n   RETROK_n              = 110,\n   RETROK_o              = 111,\n   RETROK_p              = 112,\n   RETROK_q              = 113,\n   RETROK_r              = 114,\n   RETROK_s              = 115,\n   RETROK_t              = 116,\n   RETROK_u              = 117,\n   RETROK_v              = 118,\n   RETROK_w              = 119,\n   RETROK_x              = 120,\n   RETROK_y              = 121,\n   RETROK_z              = 122,\n   RETROK_LEFTBRACE      = 123,\n   RETROK_BAR            = 124,\n   RETROK_RIGHTBRACE     = 125,\n   RETROK_TILDE          = 126,\n   RETROK_DELETE         = 127,\n\n   RETROK_KP0            = 256,\n   RETROK_KP1            = 257,\n   RETROK_KP2            = 258,\n   RETROK_KP3            = 259,\n   RETROK_KP4            = 260,\n   RETROK_KP5            = 261,\n   RETROK_KP6            = 262,\n   RETROK_KP7            = 263,\n   RETROK_KP8            = 264,\n   RETROK_KP9            = 265,\n   RETROK_KP_PERIOD      = 266,\n   RETROK_KP_DIVIDE      = 267,\n   RETROK_KP_MULTIPLY    = 268,\n   RETROK_KP_MINUS       = 269,\n   RETROK_KP_PLUS        = 270,\n   RETROK_KP_ENTER       = 271,\n   RETROK_KP_EQUALS      = 272,\n\n   RETROK_UP             = 273,\n   RETROK_DOWN           = 274,\n   RETROK_RIGHT          = 275,\n   RETROK_LEFT           = 276,\n   RETROK_INSERT         = 277,\n   RETROK_HOME           = 278,\n   RETROK_END            = 279,\n   RETROK_PAGEUP         = 280,\n   RETROK_PAGEDOWN       = 281,\n\n   RETROK_F1             = 282,\n   RETROK_F2             = 283,\n   RETROK_F3             = 284,\n   RETROK_F4             = 285,\n   RETROK_F5             = 286,\n   RETROK_F6             = 287,\n   RETROK_F7             = 288,\n   RETROK_F8             = 289,\n   RETROK_F9             = 290,\n   RETROK_F10            = 291,\n   RETROK_F11            = 292,\n   RETROK_F12            = 293,\n   RETROK_F13            = 294,\n   RETROK_F14            = 295,\n   RETROK_F15            = 296,\n\n   RETROK_NUMLOCK        = 300,\n   RETROK_CAPSLOCK       = 301,\n   RETROK_SCROLLOCK      = 302,\n   RETROK_RSHIFT         = 303,\n   RETROK_LSHIFT         = 304,\n   RETROK_RCTRL          = 305,\n   RETROK_LCTRL          = 306,\n   RETROK_RALT           = 307,\n   RETROK_LALT           = 308,\n   RETROK_RMETA          = 309,\n   RETROK_LMETA          = 310,\n   RETROK_LSUPER         = 311,\n   RETROK_RSUPER         = 312,\n   RETROK_MODE           = 313,\n   RETROK_COMPOSE        = 314,\n\n   RETROK_HELP           = 315,\n   RETROK_PRINT          = 316,\n   RETROK_SYSREQ         = 317,\n   RETROK_BREAK          = 318,\n   RETROK_MENU           = 319,\n   RETROK_POWER          = 320,\n   RETROK_EURO           = 321,\n   RETROK_UNDO           = 322,\n   RETROK_OEM_102        = 323,\n\n   RETROK_BROWSER_BACK      = 324,\n   RETROK_BROWSER_FORWARD   = 325,\n   RETROK_BROWSER_REFRESH   = 326,\n   RETROK_BROWSER_STOP      = 327,\n   RETROK_BROWSER_SEARCH    = 328,\n   RETROK_BROWSER_FAVORITES = 329,\n   RETROK_BROWSER_HOME      = 330,\n   RETROK_VOLUME_MUTE       = 331,\n   RETROK_VOLUME_DOWN       = 332,\n   RETROK_VOLUME_UP         = 333,\n   RETROK_MEDIA_NEXT        = 334,\n   RETROK_MEDIA_PREV        = 335,\n   RETROK_MEDIA_STOP        = 336,\n   RETROK_MEDIA_PLAY_PAUSE  = 337,\n   RETROK_LAUNCH_MAIL       = 338,\n   RETROK_LAUNCH_MEDIA      = 339,\n   RETROK_LAUNCH_APP1       = 340,\n   RETROK_LAUNCH_APP2       = 341,\n\n   RETROK_LAST,\n\n   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */\n};\n\nenum retro_mod\n{\n   RETROKMOD_NONE       = 0x0000,\n\n   RETROKMOD_SHIFT      = 0x01,\n   RETROKMOD_CTRL       = 0x02,\n   RETROKMOD_ALT        = 0x04,\n   RETROKMOD_META       = 0x08,\n\n   RETROKMOD_NUMLOCK    = 0x10,\n   RETROKMOD_CAPSLOCK   = 0x20,\n   RETROKMOD_SCROLLOCK  = 0x40,\n\n   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */\n};\n\n/**\n * @defgroup RETRO_ENVIRONMENT Environment Callbacks\n * @{\n */\n\n/**\n * This bit indicates that the associated environment call is experimental,\n * and may be changed or removed in the future.\n * Frontends should mask out this bit before handling the environment call.\n */\n#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000\n\n/** Frontend-internal environment callbacks should include this bit. */\n#define RETRO_ENVIRONMENT_PRIVATE 0x20000\n\n/* Environment commands. */\n/**\n * Requests the frontend to set the screen rotation.\n *\n * @param[in] data <tt>const unsigned*</tt>.\n * Valid values are 0, 1, 2, and 3.\n * These numbers respectively set the screen rotation to 0, 90, 180, and 270 degrees counter-clockwise.\n * @returns \\c true if the screen rotation was set successfully.\n */\n#define RETRO_ENVIRONMENT_SET_ROTATION  1\n\n/**\n * Queries whether the core should use overscan or not.\n *\n * @param[out] data <tt>bool*</tt>.\n * Set to \\c true if the core should use overscan,\n * \\c false if it should be cropped away.\n * @returns \\c true if the environment call is available.\n * Does \\em not indicate whether overscan should be used.\n * @deprecated As of 2019 this callback is considered deprecated in favor of\n * using core options to manage overscan in a more nuanced, core-specific way.\n */\n#define RETRO_ENVIRONMENT_GET_OVERSCAN  2\n\n/**\n * Queries whether the frontend supports frame duping,\n * in the form of passing \\c NULL to the video frame callback.\n *\n * @param[out] data <tt>bool*</tt>.\n * Set to \\c true if the frontend supports frame duping.\n * @returns \\c true if the environment call is available.\n * @see retro_video_refresh_t\n */\n#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3\n\n/*\n * Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),\n * and reserved to avoid possible ABI clash.\n */\n\n/**\n * @brief Displays a user-facing message for a short time.\n *\n * Use this callback to convey important status messages,\n * such as errors or the result of long-running operations.\n * For trivial messages or logging, use \\c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \\c stderr.\n *\n * \\code{.c}\n * void set_message_example(void)\n * {\n *    struct retro_message msg;\n *    msg.frames = 60 * 5; // 5 seconds\n *    msg.msg = \"Hello world!\";\n *\n *    environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);\n * }\n * \\endcode\n *\n * @deprecated Prefer using \\c RETRO_ENVIRONMENT_SET_MESSAGE_EXT for new code,\n * as it offers more features.\n * Only use this environment call for compatibility with older cores or frontends.\n *\n * @param[in] data <tt>const struct retro_message*</tt>.\n * Details about the message to show to the user.\n * Behavior is undefined if <tt>NULL</tt>.\n * @returns \\c true if the environment call is available.\n * @see retro_message\n * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE\n * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT\n * @see RETRO_ENVIRONMENT_SET_MESSAGE\n * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION\n * @note The frontend must make its own copy of the message and the underlying string.\n */\n#define RETRO_ENVIRONMENT_SET_MESSAGE   6\n\n/**\n * Requests the frontend to shutdown the core.\n * Should only be used if the core can exit on its own,\n * such as from a menu item in a game\n * or an emulated power-off in an emulator.\n *\n * @param data Ignored.\n * @returns \\c true if the environment call is available.\n */\n#define RETRO_ENVIRONMENT_SHUTDOWN      7\n\n/**\n * Gives a hint to the frontend of how demanding this core is on the system.\n * For example, reporting a level of 2 means that\n * this implementation should run decently on frontends\n * of level 2 and above.\n *\n * It can be used by the frontend to potentially warn\n * about too demanding implementations.\n *\n * The levels are \"floating\".\n *\n * This function can be called on a per-game basis,\n * as a core may have different demands for different games or settings.\n * If called, it should be called in <tt>retro_load_game()</tt>.\n * @param[in] data <tt>const unsigned*</tt>.\n*/\n#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8\n\n/**\n * Returns the path to the frontend's system directory,\n * which can be used to store system-specific configuration\n * such as BIOS files or cached data.\n *\n * @param[out] data <tt>const char**</tt>.\n * Pointer to the \\c char* in which the system directory will be saved.\n * The string is managed by the frontend and must not be modified or freed by the core.\n * May be \\c NULL if no system directory is defined,\n * in which case the core should find an alternative directory.\n * @return \\c true if the environment call is available,\n * even if the value returned in \\c data is <tt>NULL</tt>.\n * @note Historically, some cores would use this folder for save data such as memory cards or SRAM.\n * This is now discouraged in favor of \\c RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY.\n * @see RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY\n */\n#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9\n\n/**\n * Sets the internal pixel format used by the frontend for rendering.\n * The default pixel format is \\c RETRO_PIXEL_FORMAT_0RGB1555 for compatibility reasons,\n * although it's considered deprecated and shouldn't be used by new code.\n *\n * @param[in] data <tt>const enum retro_pixel_format *</tt>.\n * Pointer to the pixel format to use.\n * @returns \\c true if the pixel format was set successfully,\n * \\c false if it's not supported or this callback is unavailable.\n * @note This function should be called inside \\c retro_load_game()\n * or <tt>retro_get_system_av_info()</tt>.\n * @see retro_pixel_format\n */\n#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10\n\n/**\n * Sets an array of input descriptors for the frontend\n * to present to the user for configuring the core's controls.\n *\n * This function can be called at any time,\n * preferably early in the core's life cycle.\n * Ideally, no later than \\c retro_load_game().\n *\n * @param[in] data <tt>const struct retro_input_descriptor *</tt>.\n * An array of input descriptors terminated by one whose\n * \\c retro_input_descriptor::description field is set to \\c NULL.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if the environment call is recognized.\n * @see retro_input_descriptor\n */\n#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11\n\n/**\n * Sets a callback function used to notify the core about keyboard events.\n * This should only be used for cores that specifically need keyboard input,\n * such as for home computer emulators or games with text entry.\n *\n * @param[in] data <tt>const struct retro_keyboard_callback *</tt>.\n * Pointer to the callback function.\n * Behavior is undefined if <tt>NULL</tt>.\n * @return \\c true if the environment call is recognized.\n * @see retro_keyboard_callback\n * @see retro_key\n */\n#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12\n\n/**\n * Sets an interface that the frontend can use to insert and remove disks\n * from the emulated console's disk drive.\n * Can be used for optical disks, floppy disks, or any other game storage medium\n * that can be swapped at runtime.\n *\n * This is intended for multi-disk games that expect the player\n * to manually swap disks at certain points in the game.\n *\n * @deprecated Prefer using \\c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE\n * over this environment call, as it supports additional features.\n * Only use this callback to maintain compatibility\n * with older cores or frontends.\n *\n * @param[in] data <tt>const struct retro_disk_control_callback *</tt>.\n * Pointer to the callback functions to use.\n * May be \\c NULL, in which case the existing disk callback is deregistered.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n * @see retro_disk_control_callback\n * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE\n */\n#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13\n\n/**\n * Requests that a frontend enable a particular hardware rendering API.\n *\n * If successful, the frontend will create a context (and other related resources)\n * that the core can use for rendering.\n * The framebuffer will be at least as large as\n * the maximum dimensions provided in <tt>retro_get_system_av_info</tt>.\n *\n * @param[in, out] data <tt>struct retro_hw_render_callback *</tt>.\n * Pointer to the hardware render callback struct.\n * Used to define callbacks for the hardware-rendering life cycle,\n * as well as to request a particular rendering API.\n * @return \\c true if the environment call is recognized\n * and the requested rendering API is supported.\n * \\c false if \\c data is \\c NULL\n * or the frontend can't provide the requested rendering API.\n * @see retro_hw_render_callback\n * @see retro_video_refresh_t\n * @see RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER\n * @note Should be called in <tt>retro_load_game()</tt>.\n * @note If HW rendering is used, pass only \\c RETRO_HW_FRAME_BUFFER_VALID or\n * \\c NULL to <tt>retro_video_refresh_t</tt>.\n */\n#define RETRO_ENVIRONMENT_SET_HW_RENDER 14\n\n/**\n * Retrieves a core option's value from the frontend.\n * \\c retro_variable::key should be set to an option key\n * that was previously set in \\c RETRO_ENVIRONMENT_SET_VARIABLES\n * (or a similar environment call).\n *\n * @param[in,out] data <tt>struct retro_variable *</tt>.\n * Pointer to a single \\c retro_variable struct.\n * See the documentation for \\c retro_variable for details\n * on which fields are set by the frontend or core.\n * May be \\c NULL.\n * @returns \\c true if the environment call is available,\n * even if \\c data is \\c NULL or the key it specifies is not found.\n * @note Passing \\c NULL in to \\c data can be useful to\n * test for support of this environment call without looking up any variables.\n * @see retro_variable\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE\n */\n#define RETRO_ENVIRONMENT_GET_VARIABLE 15\n\n/**\n * Notifies the frontend of the core's available options.\n *\n * The core may check these options later using \\c RETRO_ENVIRONMENT_GET_VARIABLE.\n * The frontend may also present these options to the user\n * in its own configuration UI.\n *\n * This should be called the first time as early as possible,\n * ideally in \\c retro_set_environment.\n * The core may later call this function again\n * to communicate updated options to the frontend,\n * but the number of core options must not change.\n *\n * Here's an example that sets two options.\n *\n * @code\n * void set_variables_example(void)\n * {\n *    struct retro_variable options[] = {\n *        { \"foo_speedhack\", \"Speed hack; false|true\" }, // false by default\n *        { \"foo_displayscale\", \"Display scale factor; 1|2|3|4\" }, // 1 by default\n *        { NULL, NULL },\n *    };\n *\n *    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, &options);\n * }\n * @endcode\n *\n * The possible values will generally be displayed and stored as-is by the frontend.\n *\n * @deprecated Prefer using \\c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 for new code,\n * as it offers more features such as categories and translation.\n * Only use this environment call to maintain compatibility\n * with older frontends or cores.\n * @note Keep the available options (and their possible values) as low as possible;\n * it should be feasible to cycle through them without a keyboard.\n * @param[in] data <tt>const struct retro_variable *</tt>.\n * Pointer to an array of \\c retro_variable structs that define available core options,\n * terminated by a <tt>{ NULL, NULL }</tt> element.\n * The frontend must maintain its own copy of this array.\n *\n * @returns \\c true if the environment call is available,\n * even if \\c data is <tt>NULL</tt>.\n * @see retro_variable\n * @see RETRO_ENVIRONMENT_GET_VARIABLE\n * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n */\n#define RETRO_ENVIRONMENT_SET_VARIABLES 16\n\n/**\n * Queries whether at least one core option was updated by the frontend\n * since the last call to \\ref RETRO_ENVIRONMENT_GET_VARIABLE.\n * This typically means that the user opened the core options menu and made some changes.\n *\n * Cores usually call this each frame before the core's main emulation logic.\n * Specific options can then be queried with \\ref RETRO_ENVIRONMENT_GET_VARIABLE.\n *\n * @param[out] data <tt>bool *</tt>.\n * Set to \\c true if at least one core option was updated\n * since the last call to \\ref RETRO_ENVIRONMENT_GET_VARIABLE.\n * Behavior is undefined if this pointer is \\c NULL.\n * @returns \\c true if the environment call is available.\n * @see RETRO_ENVIRONMENT_GET_VARIABLE\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n */\n#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17\n\n/**\n * Notifies the frontend that this core can run without loading any content,\n * such as when emulating a console that has built-in software.\n * When a core is loaded without content,\n * \\c retro_load_game receives an argument of <tt>NULL</tt>.\n * This should be called within \\c retro_set_environment() only.\n *\n * @param[in] data <tt>const bool *</tt>.\n * Pointer to a single \\c bool that indicates whether this frontend can run without content.\n * Can point to a value of \\c false but this isn't necessary,\n * as contentless support is opt-in.\n * The behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available.\n * @see retro_load_game\n */\n#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18\n\n/**\n * Retrieves the absolute path from which this core was loaded.\n * Useful when loading assets from paths relative to the core,\n * as is sometimes the case when using <tt>RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME</tt>.\n *\n * @param[out] data <tt>const char **</tt>.\n * Pointer to a string in which the core's path will be saved.\n * The string is managed by the frontend and must not be modified or freed by the core.\n * May be \\c NULL if the core is statically linked to the frontend\n * or if the core's path otherwise cannot be determined.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available.\n */\n#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19\n\n/* Environment call 20 was an obsolete version of SET_AUDIO_CALLBACK.\n * It was not used by any known core at the time, and was removed from the API.\n * The number 20 is reserved to prevent ABI clashes.\n */\n\n/**\n * Sets a callback that notifies the core of how much time has passed\n * since the last iteration of <tt>retro_run</tt>.\n * If the frontend is not running the core in real time\n * (e.g. it's frame-stepping or running in slow motion),\n * then the reference value will be provided to the callback instead.\n *\n * @param[in] data <tt>const struct retro_frame_time_callback *</tt>.\n * Pointer to a single \\c retro_frame_time_callback struct.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available.\n * @note Frontends may disable this environment call in certain situations.\n * It will return \\c false in those cases.\n * @see retro_frame_time_callback\n */\n#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21\n\n/**\n * Registers a set of functions that the frontend can use\n * to tell the core it's ready for audio output.\n *\n * It is intended for games that feature asynchronous audio.\n * It should not be used for emulators unless their audio is asynchronous.\n *\n *\n * The callback only notifies about writability; the libretro core still\n * has to call the normal audio callbacks\n * to write audio. The audio callbacks must be called from within the\n * notification callback.\n * The amount of audio data to write is up to the core.\n * Generally, the audio callback will be called continuously in a loop.\n *\n * A frontend may disable this callback in certain situations.\n * The core must be able to render audio with the \"normal\" interface.\n *\n * @param[in] data <tt>const struct retro_audio_callback *</tt>.\n * Pointer to a set of functions that the frontend will call to notify the core\n * when it's ready to receive audio data.\n * May be \\c NULL, in which case the frontend will return\n * whether this environment callback is available.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n * @warning The provided callbacks can be invoked from any thread,\n * so their implementations \\em must be thread-safe.\n * @note If a core uses this callback,\n * it should also use <tt>RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK</tt>.\n * @see retro_audio_callback\n * @see retro_audio_sample_t\n * @see retro_audio_sample_batch_t\n * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK\n */\n#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22\n\n/**\n * Gets an interface that a core can use to access a controller's rumble motors.\n *\n * The interface supports two independently-controlled motors,\n * one strong and one weak.\n *\n * Should be called from either \\c retro_init() or \\c retro_load_game(),\n * but not from \\c retro_set_environment().\n *\n * @param[out] data <tt>struct retro_rumble_interface *</tt>.\n * Pointer to the interface struct.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if the environment call is available,\n * even if the current device doesn't support vibration.\n * @see retro_rumble_interface\n * @defgroup GET_RUMBLE_INTERFACE Rumble Interface\n */\n#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23\n\n/**\n * Returns the frontend's supported input device types.\n *\n * The supported device types are returned as a bitmask,\n * with each value of \\ref RETRO_DEVICE corresponding to a bit.\n *\n * Should only be called in \\c retro_run().\n *\n * @code\n * #define REQUIRED_DEVICES ((1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG))\n * void get_input_device_capabilities_example(void)\n * {\n *    uint64_t capabilities;\n *    environ_cb(RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES, &capabilities);\n *    if ((capabilities & REQUIRED_DEVICES) == REQUIRED_DEVICES)\n *      printf(\"Joypad and analog device types are supported\");\n * }\n * @endcode\n *\n * @param[out] data <tt>uint64_t *</tt>.\n * Pointer to a bitmask of supported input device types.\n * If the frontend supports a particular \\c RETRO_DEVICE_* type,\n * then the bit <tt>(1 << RETRO_DEVICE_*)</tt> will be set.\n *\n * Each bit represents a \\c RETRO_DEVICE constant,\n * e.g. bit 1 represents \\c RETRO_DEVICE_JOYPAD,\n * bit 2 represents \\c RETRO_DEVICE_MOUSE, and so on.\n *\n * Bits that do not correspond to known device types will be set to zero\n * and are reserved for future use.\n *\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if the environment call is available.\n * @note If the frontend supports multiple input drivers,\n * availability of this environment call (and the reported capabilities)\n * may depend on the active driver.\n * @see RETRO_DEVICE\n */\n#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24\n\n/**\n * Returns an interface that the core can use to access and configure available sensors,\n * such as an accelerometer or gyroscope.\n *\n * @param[out] data <tt>struct retro_sensor_interface *</tt>.\n * Pointer to the sensor interface that the frontend will populate.\n * Behavior is undefined if is \\c NULL.\n * @returns \\c true if the environment call is available,\n * even if the device doesn't have any supported sensors.\n * @see retro_sensor_interface\n * @see retro_sensor_action\n * @see RETRO_SENSOR\n * @addtogroup RETRO_SENSOR\n */\n#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Gets an interface to the device's video camera.\n *\n * The frontend delivers new video frames via a user-defined callback\n * that runs in the same thread as \\c retro_run().\n * Should be called in \\c retro_load_game().\n *\n * @param[in,out] data <tt>struct retro_camera_callback *</tt>.\n * Pointer to the camera driver interface.\n * Some fields in the struct must be filled in by the core,\n * others are provided by the frontend.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if this environment call is available,\n * even if an actual camera isn't.\n * @note This API only supports one video camera at a time.\n * If the device provides multiple cameras (e.g. inner/outer cameras on a phone),\n * the frontend will choose one to use.\n * @see retro_camera_callback\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n */\n#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Gets an interface that the core can use for cross-platform logging.\n * Certain platforms don't have a console or <tt>stderr</tt>,\n * or they have their own preferred logging methods.\n * The frontend itself may also display log output.\n *\n * @attention This should not be used for information that the player must immediately see,\n * such as major errors or warnings.\n * In most cases, this is best for information that will help you (the developer)\n * identify problems when debugging or providing support.\n * Unless a core or frontend is intended for advanced users,\n * the player might not check (or even know about) their logs.\n *\n * @param[out] data <tt>struct retro_log_callback *</tt>.\n * Pointer to the callback where the function pointer will be saved.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available.\n * @see retro_log_callback\n * @note Cores can fall back to \\c stderr if this interface is not available.\n */\n#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27\n\n/**\n * Returns an interface that the core can use for profiling code\n * and to access performance-related information.\n *\n * This callback supports performance counters, a high-resolution timer,\n * and listing available CPU features (mostly SIMD instructions).\n *\n * @param[out] data <tt>struct retro_perf_callback *</tt>.\n * Pointer to the callback interface.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if the environment call is available.\n * @see retro_perf_callback\n */\n#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28\n\n/**\n * Returns an interface that the core can use to retrieve the device's location,\n * including its current latitude and longitude.\n *\n * @param[out] data <tt>struct retro_location_callback *</tt>.\n * Pointer to the callback interface.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if the environment call is available,\n * even if there's no location information available.\n * @see retro_location_callback\n */\n#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29\n\n/**\n * @deprecated An obsolete alias to \\c RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY kept for compatibility.\n * @see RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY\n **/\n#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30\n\n/**\n * Returns the frontend's \"core assets\" directory,\n * which can be used to store assets that the core needs\n * such as art assets or level data.\n *\n * @param[out] data <tt>const char **</tt>.\n * Pointer to a string in which the core assets directory will be saved.\n * This string is managed by the frontend and must not be modified or freed by the core.\n * May be \\c NULL if no core assets directory is defined,\n * in which case the core should find an alternative directory.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available,\n * even if the value returned in \\c data is <tt>NULL</tt>.\n */\n#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30\n\n/**\n * Returns the frontend's save data directory, if available.\n * This directory should be used to store game-specific save data,\n * including memory card images.\n *\n * Although libretro provides an interface for cores to expose SRAM to the frontend,\n * not all cores can support it correctly.\n * In this case, cores should use this environment callback\n * to save their game data to disk manually.\n *\n * Cores that use this environment callback\n * should flush their save data to disk periodically and when unloading.\n *\n * @param[out] data <tt>const char **</tt>.\n * Pointer to the string in which the save data directory will be saved.\n * This string is managed by the frontend and must not be modified or freed by the core.\n * May return \\c NULL if no save data directory is defined.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available,\n * even if the value returned in \\c data is <tt>NULL</tt>.\n * @note Early libretro cores used \\c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY for save data.\n * This is still supported for backwards compatibility,\n * but new cores should use this environment call instead.\n * \\c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY should be used for game-agnostic data\n * such as BIOS files or core-specific configuration.\n * @note The returned directory may or may not be the same\n * as the one used for \\c retro_get_memory_data.\n *\n * @see retro_get_memory_data\n * @see RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY\n */\n#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31\n\n/**\n * Sets new video and audio parameters for the core.\n * This can only be called from within <tt>retro_run</tt>.\n *\n * This environment call may entail a full reinitialization of the frontend's audio/video drivers,\n * hence it should \\em only be used if the core needs to make drastic changes\n * to audio/video parameters.\n *\n * This environment call should \\em not be used when:\n * <ul>\n * <li>Changing the emulated system's internal resolution,\n * within the limits defined by the existing values of \\c max_width and \\c max_height.\n * Use \\c RETRO_ENVIRONMENT_SET_GEOMETRY instead,\n * and adjust \\c retro_get_system_av_info to account for\n * supported scale factors and screen layouts\n * when computing \\c max_width and \\c max_height.\n * Only use this environment call if \\c max_width or \\c max_height needs to increase.\n * <li>Adjusting the screen's aspect ratio,\n * e.g. when changing the layout of the screen(s).\n * Use \\c RETRO_ENVIRONMENT_SET_GEOMETRY or \\c RETRO_ENVIRONMENT_SET_ROTATION instead.\n * </ul>\n *\n * The frontend will reinitialize its audio and video drivers within this callback;\n * after that happens, audio and video callbacks will target the newly-initialized driver,\n * even within the same \\c retro_run call.\n *\n * This callback makes it possible to support configurable resolutions\n * while avoiding the need to compute the \"worst case\" values of \\c max_width and \\c max_height.\n *\n * @param[in] data <tt>const struct retro_system_av_info *</tt>.\n * Pointer to the new video and audio parameters that the frontend should adopt.\n * @returns \\c true if the environment call is available\n * and the new av_info struct was accepted.\n * \\c false if the environment call is unavailable or \\c data is <tt>NULL</tt>.\n * @see retro_system_av_info\n * @see RETRO_ENVIRONMENT_SET_GEOMETRY\n */\n#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32\n\n/**\n * Provides an interface that a frontend can use\n * to get function pointers from the core.\n *\n * This allows cores to define their own extensions to the libretro API,\n * or to expose implementations of a frontend's libretro extensions.\n *\n * @param[in] data <tt>const struct retro_get_proc_address_interface *</tt>.\n * Pointer to the interface that the frontend can use to get function pointers from the core.\n * The frontend must maintain its own copy of this interface.\n * @returns \\c true if the environment call is available\n * and the returned interface was accepted.\n * @note The provided interface may be called at any time,\n * even before this environment call returns.\n * @note Extensions should be prefixed with the name of the frontend or core that defines them.\n * For example, a frontend named \"foo\" that defines a debugging extension\n * should expect the core to define functions prefixed with \"foo_debug_\".\n * @warning If a core wants to use this environment call,\n * it \\em must do so from within \\c retro_set_environment().\n * @see retro_get_proc_address_interface\n */\n#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33\n\n/**\n * Registers a core's ability to handle \"subsystems\",\n * which are secondary platforms that augment a core's primary emulated hardware.\n *\n * A core doesn't need to emulate a secondary platform\n * in order to use it as a subsystem;\n * as long as it can load a secondary file for some practical use,\n * then this environment call is most likely suitable.\n *\n * Possible use cases of a subsystem include:\n *\n * \\li Installing software onto an emulated console's internal storage,\n * such as the Nintendo DSi.\n * \\li Emulating accessories that are used to support another console's games,\n * such as the Super Game Boy or the N64 Transfer Pak.\n * \\li Inserting a secondary ROM into a console\n * that features multiple cartridge ports,\n * such as the Nintendo DS's Slot-2.\n * \\li Loading a save data file created and used by another core.\n *\n * Cores should \\em not use subsystems for:\n *\n * \\li Emulators that support multiple \"primary\" platforms,\n * such as a Game Boy/Game Boy Advance core\n * or a Sega Genesis/Sega CD/32X core.\n * Use \\c retro_system_content_info_override, \\c retro_system_info,\n * and/or runtime detection instead.\n * \\li Selecting different memory card images.\n * Use dynamically-populated core options instead.\n * \\li Different variants of a single console,\n * such the Game Boy vs. the Game Boy Color.\n * Use core options or runtime detection instead.\n * \\li Games that span multiple disks.\n * Use \\c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE\n * and m3u-formatted playlists instead.\n * \\li Console system files (BIOS, firmware, etc.).\n * Use \\c RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY\n * and a common naming convention instead.\n *\n * When the frontend loads a game via a subsystem,\n * it must call \\c retro_load_game_special() instead of \\c retro_load_game().\n *\n * @param[in] data <tt>const struct retro_subsystem_info *</tt>.\n * Pointer to an array of subsystem descriptors,\n * terminated by a zeroed-out \\c retro_subsystem_info struct.\n * The frontend should maintain its own copy\n * of this array and the strings within it.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if this environment call is available.\n * @note This environment call \\em must be called from within \\c retro_set_environment(),\n * as frontends may need the registered information before loading a game.\n * @see retro_subsystem_info\n * @see retro_load_game_special\n */\n#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34\n\n/**\n * Declares one or more types of controllers supported by this core.\n * The frontend may then allow the player to select one of these controllers in its menu.\n *\n * Many consoles had controllers that came in different versions,\n * were extensible with peripherals,\n * or could be held in multiple ways;\n * this environment call can be used to represent these differences\n * and adjust the core's behavior to match.\n *\n * Possible use cases include:\n *\n * \\li Supporting different classes of a single controller that supported their own sets of games.\n *     For example, the SNES had two different lightguns (the Super Scope and the Justifier)\n *     whose games were incompatible with each other.\n * \\li Representing a platform's alternative controllers.\n *     For example, several platforms had music/rhythm games that included controllers\n *     shaped like musical instruments.\n * \\li Representing variants of a standard controller with additional inputs.\n *     For example, numerous consoles in the 90's introduced 6-button controllers for fighting games,\n *     steering wheels for racing games,\n *     or analog sticks for 3D platformers.\n * \\li Representing add-ons for consoles or standard controllers.\n *     For example, the 3DS had a Circle Pad Pro attachment that added a second analog stick.\n * \\li Selecting different configurations for a single controller.\n *     For example, the Wii Remote could be held sideways like a traditional game pad\n *     or in one hand like a wand.\n * \\li Providing multiple ways to simulate the experience of using a particular controller.\n *     For example, the Game Boy Advance featured several games\n *     with motion or light sensors in their cartridges;\n *     a core could provide controller configurations\n *     that allow emulating the sensors with either analog axes\n *     or with their host device's sensors.\n *\n * Should be called in retro_load_game.\n * The frontend must maintain its own copy of the provided array,\n * including all strings and subobjects.\n * A core may exclude certain controllers for known incompatible games.\n *\n * When the frontend changes the active device for a particular port,\n * it must call \\c retro_set_controller_port_device() with that port's index\n * and one of the IDs defined in its retro_controller_info::types field.\n *\n * Input ports are generally associated with different players\n * (and the frontend's UI may reflect this with \"Player 1\" labels),\n * but this is not required.\n * Some games use multiple controllers for a single player,\n * or some cores may use port indexes to represent an emulated console's\n * alternative input peripherals.\n *\n * @param[in] data <tt>const struct retro_controller_info *</tt>.\n * Pointer to an array of controller types defined by this core,\n * terminated by a zeroed-out \\c retro_controller_info.\n * Each element of this array represents a controller port on the emulated device.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if this environment call is available.\n * @see retro_controller_info\n * @see retro_set_controller_port_device\n * @see RETRO_DEVICE_SUBCLASS\n */\n#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35\n\n/**\n * Notifies the frontend of the address spaces used by the core's emulated hardware,\n * and of the memory maps within these spaces.\n * This can be used by the frontend to provide cheats, achievements, or debugging capabilities.\n * Should only be used by emulators, as it makes little sense for game engines.\n *\n * @note Cores should also expose these address spaces\n * through retro_get_memory_data and \\c retro_get_memory_size if applicable;\n * this environment call is not intended to replace those two functions,\n * as the emulated hardware may feature memory regions outside of its own address space\n * that are nevertheless useful for the frontend.\n *\n * @param[in] data <tt>const struct retro_memory_map *</tt>.\n * Pointer to a single memory-map listing.\n * The frontend must maintain its own copy of this object and its contents,\n * including strings and nested objects.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if this environment call is available.\n * @see retro_memory_map\n * @see retro_get_memory_data\n * @see retro_memory_descriptor\n */\n#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Resizes the viewport without reinitializing the video driver.\n *\n * Similar to \\c RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO,\n * but any changes that would require video reinitialization will not be performed.\n * Can only be called from within \\c retro_run().\n *\n * This environment call allows a core to revise the size of the viewport at will,\n * which can be useful for emulated platforms that support dynamic resolution changes\n * or for cores that support multiple screen layouts.\n *\n * A frontend must guarantee that this environment call completes in\n * constant time.\n *\n * @param[in] data <tt>const struct retro_game_geometry *</tt>.\n * Pointer to the new video parameters that the frontend should adopt.\n * \\c retro_game_geometry::max_width and \\c retro_game_geometry::max_height\n * will be ignored.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @return \\c true if the environment call is available.\n * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO\n */\n#define RETRO_ENVIRONMENT_SET_GEOMETRY 37\n\n/**\n * Returns the name of the user, if possible.\n * This callback is suitable for cores that offer personalization,\n * such as online facilities or user profiles on the emulated system.\n * @param[out] data <tt>const char **</tt>.\n * Pointer to the user name string.\n * May be \\c NULL, in which case the core should use a default name.\n * The returned pointer is owned by the frontend and must not be modified or freed by the core.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if the environment call is available,\n * even if the frontend couldn't provide a name.\n */\n#define RETRO_ENVIRONMENT_GET_USERNAME 38\n\n/**\n * Returns the frontend's configured language.\n * It can be used to localize the core's UI,\n * or to customize the emulated firmware if applicable.\n *\n * @param[out] data <tt>retro_language *</tt>.\n * Pointer to the language identifier.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if the environment call is available.\n * @note The returned language may not be the same as the operating system's language.\n * Cores should fall back to the operating system's language (or to English)\n * if the environment call is unavailable or the returned language is unsupported.\n * @see retro_language\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL\n */\n#define RETRO_ENVIRONMENT_GET_LANGUAGE 39\n\n/**\n * Returns a frontend-managed framebuffer\n * that the core may render directly into\n *\n * This environment call is provided as an optimization\n * for cores that use software rendering\n * (i.e. that don't use \\refitem RETRO_ENVIRONMENT_SET_HW_RENDER \"a graphics hardware API\");\n * specifically, the intended use case is to allow a core\n * to render directly into frontend-managed video memory,\n * avoiding the bandwidth use that copying a whole framebuffer from core to video memory entails.\n *\n * Must be called every frame if used,\n * as this may return a different framebuffer each frame\n * (e.g. for swap chains).\n * However, a core may render to a different buffer even if this call succeeds.\n *\n * @param[in,out] data <tt>struct retro_framebuffer *</tt>.\n * Pointer to a frontend's frame buffer and accompanying data.\n * Some fields are set by the core, others are set by the frontend.\n * Only guaranteed to be valid for the duration of the current \\c retro_run call,\n * and must not be used afterwards.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if the environment call was recognized\n * and the framebuffer was successfully returned.\n * @see retro_framebuffer\n */\n#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns an interface for accessing the data of specific rendering APIs.\n * Not all hardware rendering APIs support or need this.\n *\n * The details of these interfaces are specific to each rendering API.\n *\n * @note \\c retro_hw_render_callback::context_reset must be called by the frontend\n * before this environment call can be used.\n * Additionally, the contents of the returned interface are invalidated\n * after \\c retro_hw_render_callback::context_destroyed has been called.\n * @param[out] data <tt>const struct retro_hw_render_interface **</tt>.\n * The render interface for the currently-enabled hardware rendering API, if any.\n * The frontend will store a pointer to the interface at the address provided here.\n * The returned interface is owned by the frontend and must not be modified or freed by the core.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is available,\n * the active graphics API has a libretro rendering interface,\n * and the frontend is able to return said interface.\n * \\c false otherwise.\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n * @see retro_hw_render_interface\n * @note Since not every libretro-supported hardware rendering API\n * has a \\c retro_hw_render_interface implementation,\n * a result of \\c false is not necessarily an error.\n */\n#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Explicitly notifies the frontend of whether this core supports achievements.\n * The core must expose its emulated address space via\n * \\c retro_get_memory_data or \\c RETRO_ENVIRONMENT_GET_MEMORY_MAPS.\n * Must be called before the first call to <tt>retro_run</tt>.\n *\n * If \\ref retro_get_memory_data returns a valid address\n * but this environment call is not used,\n * the frontend (at its discretion) may or may not opt in the core to its achievements support.\n * whether this core is opted in to the frontend's achievement support\n * is left to the frontend's discretion.\n * @param[in] data <tt>const bool *</tt>.\n * Pointer to a single \\c bool that indicates whether this core supports achievements.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if the environment call is available.\n * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS\n * @see retro_get_memory_data\n */\n#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Defines an interface that the frontend can use\n * to ask the core for the parameters it needs for a hardware rendering context.\n * The exact semantics depend on \\ref RETRO_ENVIRONMENT_SET_HW_RENDER \"the active rendering API\".\n * Will be used some time after \\c RETRO_ENVIRONMENT_SET_HW_RENDER is called,\n * but before \\c retro_hw_render_callback::context_reset is called.\n *\n * @param[in] data <tt>const struct retro_hw_render_context_negotiation_interface *</tt>.\n * Pointer to the context negotiation interface.\n * Will be populated by the frontend.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is supported,\n * even if the current graphics API doesn't use\n * a context negotiation interface (in which case the argument is ignored).\n * @see retro_hw_render_context_negotiation_interface\n * @see RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n */\n#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Notifies the frontend of any quirks associated with serialization.\n *\n * Should be set in either \\c retro_init or \\c retro_load_game, but not both.\n * @param[in, out] data <tt>uint64_t *</tt>.\n * Pointer to the core's serialization quirks.\n * The frontend will set the flags of the quirks it supports\n * and clear the flags of those it doesn't.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is supported.\n * @see retro_serialize\n * @see retro_unserialize\n * @see RETRO_SERIALIZATION_QUIRK\n */\n#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44\n\n/**\n * The frontend will try to use a \"shared\" context when setting up a hardware context.\n * Mostly applicable to OpenGL.\n *\n * In order for this to have any effect,\n * the core must call \\c RETRO_ENVIRONMENT_SET_HW_RENDER at some point\n * if it hasn't already.\n *\n * @param data Ignored.\n * @returns \\c true if the environment call is available\n * and the frontend supports shared hardware contexts.\n */\n#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns an interface that the core can use to access the file system.\n * Should be called as early as possible.\n *\n * @param[in,out] data <tt>struct retro_vfs_interface_info *</tt>.\n * Information about the desired VFS interface,\n * as well as the interface itself.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is available\n * and the frontend can provide a VFS interface of the requested version or newer.\n * @see retro_vfs_interface_info\n * @see file_path\n * @see retro_dirent\n * @see file_stream\n */\n#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns an interface that the core can use\n * to set the state of any accessible device LEDs.\n *\n * @param[out] data <tt>struct retro_led_interface *</tt>.\n * Pointer to the LED interface that the frontend will populate.\n * May be \\c NULL, in which case the frontend will only return\n * whether this environment callback is available.\n * @returns \\c true if the environment call is available,\n * even if \\c data is \\c NULL\n * or no LEDs are accessible.\n * @see retro_led_interface\n */\n#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns hints about certain steps that the core may skip for this frame.\n *\n * A frontend may not need a core to generate audio or video in certain situations;\n * this environment call sets a bitmask that indicates\n * which steps the core may skip for this frame.\n *\n * This can be used to increase performance for some frontend features.\n *\n * @note Emulation accuracy should not be compromised;\n * for example, if a core emulates a platform that supports display capture\n * (i.e. looking at its own VRAM), then it should perform its rendering as normal\n * unless it can prove that the emulated game is not using display capture.\n *\n * @param[out] data <tt>retro_av_enable_flags *</tt>.\n * Pointer to the bitmask of steps that the frontend will skip.\n * Other bits are set to zero and are reserved for future use.\n * If \\c NULL, the frontend will only return whether this environment callback is available.\n * @returns \\c true if the environment call is available,\n * regardless of the value output to \\c data.\n * If \\c false, the core should assume that the frontend will not skip any steps.\n * @see retro_av_enable_flags\n */\n#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Gets an interface that the core can use for raw MIDI I/O.\n *\n * @param[out] data <tt>struct retro_midi_interface *</tt>.\n * Pointer to the MIDI interface.\n * May be \\c NULL.\n * @return \\c true if the environment call is available,\n * even if \\c data is \\c NULL.\n * @see retro_midi_interface\n */\n#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Asks the frontend if it's currently in fast-forward mode.\n * @param[out] data <tt>bool *</tt>.\n * Set to \\c true if the frontend is currently fast-forwarding its main loop.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @returns \\c true if this environment call is available,\n * regardless of the value returned in \\c data.\n *\n * @see RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE\n */\n#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns the refresh rate the frontend is targeting, in Hz.\n * The intended use case is for the core to use the result to select an ideal refresh rate.\n *\n * @param[out] data <tt>float *</tt>.\n * Pointer to the \\c float in which the frontend will store its target refresh rate.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @return \\c true if this environment call is available,\n * regardless of the value returned in \\c data.\n*/\n#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns whether the frontend can return the state of all buttons at once as a bitmask,\n * rather than requiring a series of individual calls to \\c retro_input_state_t.\n *\n * If this callback returns \\c true,\n * you can get the state of all buttons by passing \\c RETRO_DEVICE_ID_JOYPAD_MASK\n * as the \\c id parameter to \\c retro_input_state_t.\n * Bit #N represents the RETRO_DEVICE_ID_JOYPAD constant of value N,\n * e.g. <tt>(1 << RETRO_DEVICE_ID_JOYPAD_A)</tt> represents the A button.\n *\n * @param data Ignored.\n * @returns \\c true if the frontend can report the complete digital joypad state as a bitmask.\n * @see retro_input_state_t\n * @see RETRO_DEVICE_JOYPAD\n * @see RETRO_DEVICE_ID_JOYPAD_MASK\n */\n#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns the version of the core options API supported by the frontend.\n *\n * Over the years, libretro has used several interfaces\n * for allowing cores to define customizable options.\n * \\ref SET_CORE_OPTIONS_V2 \"Version 2 of the interface\"\n * is currently preferred due to its extra features,\n * but cores and frontends should strive to support\n * versions \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS \"1\"\n * and \\ref RETRO_ENVIRONMENT_SET_VARIABLES \"0\" as well.\n * This environment call provides the information that cores need for that purpose.\n *\n * If this environment call returns \\c false,\n * then the core should assume version 0 of the core options API.\n *\n * @param[out] data <tt>unsigned *</tt>.\n * Pointer to the integer that will store the frontend's\n * supported core options API version.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if the environment call is available,\n * \\c false otherwise.\n * @see RETRO_ENVIRONMENT_SET_VARIABLES\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n */\n#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52\n\n/**\n * @copybrief RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n *\n * @deprecated This environment call has been superseded\n * by RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n * which supports categorizing options into groups.\n * This environment call should only be used to maintain compatibility\n * with older cores and frontends.\n *\n * This environment call is intended to replace \\c RETRO_ENVIRONMENT_SET_VARIABLES,\n * and should only be called if \\c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION\n * returns an API version of at least 1.\n *\n * This should be called the first time as early as possible,\n * ideally in \\c retro_set_environment (but \\c retro_load_game is acceptable).\n * It may then be called again later to update\n * the core's options and their associated values,\n * as long as the number of options doesn't change\n * from the number given in the first call.\n *\n * The core can retrieve option values at any time with \\c RETRO_ENVIRONMENT_GET_VARIABLE.\n * If a saved value for a core option doesn't match the option definition's values,\n * the frontend may treat it as incorrect and revert to the default.\n *\n * Core options and their values are usually defined in a large static array,\n * but they may be generated at runtime based on the loaded game or system state.\n * Here are some use cases for that:\n *\n * @li Selecting a particular file from one of the\n *     \\ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY \"frontend's\"\n *     \\ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY \"content\"\n *     \\ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY \"directories\",\n *     such as a memory card image or figurine data file.\n * @li Excluding options that are not relevant to the current game,\n *     for cores that define a large number of possible options.\n * @li Choosing a default value at runtime for a specific game,\n *     such as a BIOS file whose region matches that of the loaded content.\n *\n * @note A guiding principle of libretro's API design is that\n * all common interactions (gameplay, menu navigation, etc.)\n * should be possible without a keyboard.\n * This implies that cores should keep the number of options and values\n * as low as possible.\n *\n * Example entry:\n * @code\n * {\n *     \"foo_option\",\n *     \"Speed hack coprocessor X\",\n *     \"Provides increased performance at the expense of reduced accuracy\",\n *     {\n *         { \"false\",    NULL },\n *         { \"true\",     NULL },\n *         { \"unstable\", \"Turbo (Unstable)\" },\n *         { NULL, NULL },\n *     },\n *     \"false\"\n * }\n * @endcode\n *\n * @param[in] data <tt>const struct retro_core_option_definition *</tt>.\n * Pointer to one or more core option definitions,\n * terminated by a \\ref retro_core_option_definition whose values are all zero.\n * May be \\c NULL, in which case the frontend will remove all existing core options.\n * The frontend must maintain its own copy of this object,\n * including all strings and subobjects.\n * @return \\c true if this environment call is available.\n *\n * @see retro_core_option_definition\n * @see RETRO_ENVIRONMENT_GET_VARIABLE\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL\n */\n#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53\n\n/**\n * A variant of \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS\n * that supports internationalization.\n *\n * @deprecated This environment call has been superseded\n * by \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n * which supports categorizing options into groups\n * (plus translating the groups themselves).\n * Only use this environment call to maintain compatibility\n * with older cores and frontends.\n *\n * This should be called instead of \\c RETRO_ENVIRONMENT_SET_CORE_OPTIONS\n * if the core provides translations for its options.\n * General use is largely the same,\n * but see \\ref retro_core_options_intl for some important details.\n *\n * @param[in] data <tt>const struct retro_core_options_intl *</tt>.\n * Pointer to a core's option values and their translations.\n * @see retro_core_options_intl\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS\n */\n#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54\n\n/**\n * Notifies the frontend that it should show or hide the named core option.\n *\n * Some core options aren't relevant in all scenarios,\n * such as a submenu for hardware rendering flags\n * when the software renderer is configured.\n * This environment call asks the frontend to stop (or start)\n * showing the named core option to the player.\n * This is only a hint, not a requirement;\n * the frontend may ignore this environment call.\n * By default, all core options are visible.\n *\n * @note This environment call must \\em only affect a core option's visibility,\n * not its functionality or availability.\n * \\ref RETRO_ENVIRONMENT_GET_VARIABLE \"Getting an invisible core option\"\n * must behave normally.\n *\n * @param[in] data <tt>const struct retro_core_option_display *</tt>.\n * Pointer to a descriptor for the option that the frontend should show or hide.\n * May be \\c NULL, in which case the frontend will only return\n * whether this environment callback is available.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL\n * or the specified option doesn't exist.\n * @see retro_core_option_display\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK\n */\n#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55\n\n/**\n * Returns the frontend's preferred hardware rendering API.\n * Cores should use this information to decide which API to use with \\c RETRO_ENVIRONMENT_SET_HW_RENDER.\n * @param[out] data <tt>retro_hw_context_type *</tt>.\n * Pointer to the hardware context type.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * This value will be set even if the environment call returns <tt>false</tt>,\n * unless the frontend doesn't implement it.\n * @returns \\c true if the environment call is available\n * and the frontend is able to use a hardware rendering API besides the one returned.\n * If \\c false is returned and the core cannot use the preferred rendering API,\n * then it should exit or fall back to software rendering.\n * @note The returned value does not indicate which API is currently in use.\n * For example, the frontend may return \\c RETRO_HW_CONTEXT_OPENGL\n * while a Direct3D context from a previous session is active;\n * this would signal that the frontend's current preference is for OpenGL,\n * possibly because the user changed their frontend's video driver while a game is running.\n * @see retro_hw_context_type\n * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n */\n#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56\n\n/**\n * Returns the minimum version of the disk control interface supported by the frontend.\n *\n * If this environment call returns \\c false or \\c data is 0 or greater,\n * then cores may use disk control callbacks\n * with \\c RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.\n * If the reported version is 1 or greater,\n * then cores should use \\c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE instead.\n *\n * @param[out] data <tt>unsigned *</tt>.\n * Pointer to the unsigned integer that the frontend's supported disk control interface version will be stored in.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is available.\n * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE\n */\n#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57\n\n/**\n * @copybrief RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE\n *\n * This is intended for multi-disk games that expect the player\n * to manually swap disks at certain points in the game.\n * This version of the disk control interface provides\n * more information about disk images.\n * Should be called in \\c retro_init.\n *\n * @param[in] data <tt>const struct retro_disk_control_ext_callback *</tt>.\n * Pointer to the callback functions to use.\n * May be \\c NULL, in which case the existing disk callback is deregistered.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n * @see retro_disk_control_ext_callback\n */\n#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58\n\n/**\n * Returns the version of the message interface supported by the frontend.\n *\n * A version of 0 indicates that the frontend\n * only supports the legacy \\c RETRO_ENVIRONMENT_SET_MESSAGE interface.\n * A version of 1 indicates that the frontend\n * supports \\c RETRO_ENVIRONMENT_SET_MESSAGE_EXT as well.\n * If this environment call returns \\c false,\n * the core should behave as if it had returned 0.\n *\n * @param[out] data <tt>unsigned *</tt>.\n * Pointer to the result returned by the frontend.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is available.\n * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT\n * @see RETRO_ENVIRONMENT_SET_MESSAGE\n */\n#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59\n\n/**\n * Displays a user-facing message for a short time.\n *\n * Use this callback to convey important status messages,\n * such as errors or the result of long-running operations.\n * For trivial messages or logging, use \\c RETRO_ENVIRONMENT_GET_LOG_INTERFACE or \\c stderr.\n *\n * This environment call supersedes \\c RETRO_ENVIRONMENT_SET_MESSAGE,\n * as it provides many more ways to customize\n * how a message is presented to the player.\n * However, a frontend that supports this environment call\n * must still support \\c RETRO_ENVIRONMENT_SET_MESSAGE.\n *\n * @param[in] data <tt>const struct retro_message_ext *</tt>.\n * Pointer to the message to display to the player.\n * Behavior is undefined if \\c NULL.\n * @returns \\c true if this environment call is available.\n * @see retro_message_ext\n * @see RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION\n */\n#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60\n\n/**\n * Returns the number of active input devices currently provided by the frontend.\n *\n * This may change between frames,\n * but will remain constant for the duration of each frame.\n *\n * If this callback returns \\c true,\n * a core need not poll any input device\n * with an index greater than or equal to the returned value.\n *\n * If callback returns \\c false,\n * the number of active input devices is unknown.\n * In this case, all input devices should be considered active.\n *\n * @param[out] data <tt>unsigned *</tt>.\n * Pointer to the result returned by the frontend.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if this environment call is available.\n */\n#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61\n\n/**\n * Registers a callback that the frontend can use to notify the core\n * of the audio output buffer's occupancy.\n * Can be used by a core to attempt frame-skipping to avoid buffer under-runs\n * (i.e. \"crackling\" sounds).\n *\n * @param[in] data <tt>const struct retro_audio_buffer_status_callback *</tt>.\n * Pointer to the the buffer status callback,\n * or \\c NULL to unregister any existing callback.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n *\n * @see retro_audio_buffer_status_callback\n */\n#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62\n\n/**\n * Requests a minimum frontend audio latency in milliseconds.\n *\n * This is a hint; the frontend may assign a different audio latency\n * to accommodate hardware limits,\n * although it should try to honor requests up to 512ms.\n *\n * This callback has no effect if the requested latency\n * is less than the frontend's current audio latency.\n * If value is zero or \\c data is \\c NULL,\n * the frontend should set its default audio latency.\n *\n * May be used by a core to increase audio latency and\n * reduce the risk of buffer under-runs (crackling)\n * when performing 'intensive' operations.\n *\n * A core using RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK\n * to implement audio-buffer-based frame skipping can get good results\n * by setting the audio latency to a high (typically 6x or 8x)\n * integer multiple of the expected frame time.\n *\n * This can only be called from within \\c retro_run().\n *\n * @warning This environment call may require the frontend to reinitialize its audio system.\n * This environment call should be used sparingly.\n * If the driver is reinitialized,\n * \\ref retro_audio_callback_t \"all audio callbacks\" will be updated\n * to target the newly-initialized driver.\n *\n * @param[in] data <tt>const unsigned *</tt>.\n * Minimum audio latency, in milliseconds.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n *\n * @see RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK\n */\n#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63\n\n/**\n * Allows the core to tell the frontend when it should enable fast-forwarding,\n * rather than relying solely on the frontend and user interaction.\n *\n * Possible use cases include:\n *\n * \\li Temporarily disabling a core's fastforward support\n *     while investigating a related bug.\n * \\li Disabling fastforward during netplay sessions,\n *     or when using an emulated console's network features.\n * \\li Automatically speeding up the game when in a loading screen\n *     that cannot be shortened with high-level emulation.\n *\n * @param[in] data <tt>const struct retro_fastforwarding_override *</tt>.\n * Pointer to the parameters that decide when and how\n * the frontend is allowed to enable fast-forward mode.\n * May be \\c NULL, in which case the frontend will return \\c true\n * without updating the fastforward state,\n * which can be used to detect support for this environment call.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n *\n * @see retro_fastforwarding_override\n * @see RETRO_ENVIRONMENT_GET_FASTFORWARDING\n */\n#define RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE 64\n\n#define RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE 65\n                                           /* const struct retro_system_content_info_override * --\n                                            * Allows an implementation to override 'global' content\n                                            * info parameters reported by retro_get_system_info().\n                                            * Overrides also affect subsystem content info parameters\n                                            * set via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO.\n                                            * This function must be called inside retro_set_environment().\n                                            * If callback returns false, content info overrides\n                                            * are unsupported by the frontend, and will be ignored.\n                                            * If callback returns true, extended game info may be\n                                            * retrieved by calling RETRO_ENVIRONMENT_GET_GAME_INFO_EXT\n                                            * in retro_load_game() or retro_load_game_special().\n                                            *\n                                            * 'data' points to an array of retro_system_content_info_override\n                                            * structs terminated by a { NULL, false, false } element.\n                                            * If 'data' is NULL, no changes will be made to the frontend;\n                                            * a core may therefore pass NULL in order to test whether\n                                            * the RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE and\n                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT callbacks are supported\n                                            * by the frontend.\n                                            *\n                                            * For struct member descriptions, see the definition of\n                                            * struct retro_system_content_info_override.\n                                            *\n                                            * Example:\n                                            *\n                                            * - struct retro_system_info:\n                                            * {\n                                            *    \"My Core\",                      // library_name\n                                            *    \"v1.0\",                         // library_version\n                                            *    \"m3u|md|cue|iso|chd|sms|gg|sg\", // valid_extensions\n                                            *    true,                           // need_fullpath\n                                            *    false                           // block_extract\n                                            * }\n                                            *\n                                            * - Array of struct retro_system_content_info_override:\n                                            * {\n                                            *    {\n                                            *       \"md|sms|gg\", // extensions\n                                            *       false,       // need_fullpath\n                                            *       true         // persistent_data\n                                            *    },\n                                            *    {\n                                            *       \"sg\",        // extensions\n                                            *       false,       // need_fullpath\n                                            *       false        // persistent_data\n                                            *    },\n                                            *    { NULL, false, false }\n                                            * }\n                                            *\n                                            * Result:\n                                            * - Files of type m3u, cue, iso, chd will not be\n                                            *   loaded by the frontend. Frontend will pass a\n                                            *   valid path to the core, and core will handle\n                                            *   loading internally\n                                            * - Files of type md, sms, gg will be loaded by\n                                            *   the frontend. A valid memory buffer will be\n                                            *   passed to the core. This memory buffer will\n                                            *   remain valid until retro_deinit() returns\n                                            * - Files of type sg will be loaded by the frontend.\n                                            *   A valid memory buffer will be passed to the core.\n                                            *   This memory buffer will remain valid until\n                                            *   retro_load_game() (or retro_load_game_special())\n                                            *   returns\n                                            *\n                                            * NOTE: If an extension is listed multiple times in\n                                            * an array of retro_system_content_info_override\n                                            * structs, only the first instance will be registered\n                                            */\n\n#define RETRO_ENVIRONMENT_GET_GAME_INFO_EXT 66\n                                           /* const struct retro_game_info_ext ** --\n                                            * Allows an implementation to fetch extended game\n                                            * information, providing additional content path\n                                            * and memory buffer status details.\n                                            * This function may only be called inside\n                                            * retro_load_game() or retro_load_game_special().\n                                            * If callback returns false, extended game information\n                                            * is unsupported by the frontend. In this case, only\n                                            * regular retro_game_info will be available.\n                                            * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT is guaranteed\n                                            * to return true if RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE\n                                            * returns true.\n                                            *\n                                            * 'data' points to an array of retro_game_info_ext structs.\n                                            *\n                                            * For struct member descriptions, see the definition of\n                                            * struct retro_game_info_ext.\n                                            *\n                                            * - If function is called inside retro_load_game(),\n                                            *   the retro_game_info_ext array is guaranteed to\n                                            *   have a size of 1 - i.e. the returned pointer may\n                                            *   be used to access directly the members of the\n                                            *   first retro_game_info_ext struct, for example:\n                                            *\n                                            *      struct retro_game_info_ext *game_info_ext;\n                                            *      if (environ_cb(RETRO_ENVIRONMENT_GET_GAME_INFO_EXT, &game_info_ext))\n                                            *         printf(\"Content Directory: %s\\n\", game_info_ext->dir);\n                                            *\n                                            * - If the function is called inside retro_load_game_special(),\n                                            *   the retro_game_info_ext array is guaranteed to have a\n                                            *   size equal to the num_info argument passed to\n                                            *   retro_load_game_special()\n                                            */\n\n/**\n * Defines a set of core options that can be shown and configured by the frontend,\n * so that the player may customize their gameplay experience to their liking.\n *\n * @note This environment call is intended to replace\n * \\c RETRO_ENVIRONMENT_SET_VARIABLES and \\c RETRO_ENVIRONMENT_SET_CORE_OPTIONS,\n * and should only be called if \\c RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION\n * returns an API version of at least 2.\n *\n * This should be called the first time as early as possible,\n * ideally in \\c retro_set_environment (but \\c retro_load_game is acceptable).\n * It may then be called again later to update\n * the core's options and their associated values,\n * as long as the number of options doesn't change\n * from the number given in the first call.\n *\n * The core can retrieve option values at any time with \\c RETRO_ENVIRONMENT_GET_VARIABLE.\n * If a saved value for a core option doesn't match the option definition's values,\n * the frontend may treat it as incorrect and revert to the default.\n *\n * Core options and their values are usually defined in a large static array,\n * but they may be generated at runtime based on the loaded game or system state.\n * Here are some use cases for that:\n *\n * @li Selecting a particular file from one of the\n *     \\ref RETRO_ENVIRONMENT_GET_ASSET_DIRECTORY \"frontend's\"\n *     \\ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY \"content\"\n *     \\ref RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY \"directories\",\n *     such as a memory card image or figurine data file.\n * @li Excluding options that are not relevant to the current game,\n *     for cores that define a large number of possible options.\n * @li Choosing a default value at runtime for a specific game,\n *     such as a BIOS file whose region matches that of the loaded content.\n *\n * @note A guiding principle of libretro's API design is that\n * all common interactions (gameplay, menu navigation, etc.)\n * should be possible without a keyboard.\n * This implies that cores should keep the number of options and values\n * as low as possible.\n *\n * @param[in] data <tt>const struct retro_core_options_v2 *</tt>.\n * Pointer to a core's options and their associated categories.\n * May be \\c NULL, in which case the frontend will remove all existing core options.\n * The frontend must maintain its own copy of this object,\n * including all strings and subobjects.\n * @return \\c true if this environment call is available\n * and the frontend supports categories.\n * Note that this environment call is guaranteed to successfully register\n * the provided core options,\n * so the return value does not indicate success or failure.\n *\n * @see retro_core_options_v2\n * @see retro_core_option_v2_category\n * @see retro_core_option_v2_definition\n * @see RETRO_ENVIRONMENT_GET_VARIABLE\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL\n */\n#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 67\n\n/**\n * A variant of \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n * that supports internationalization.\n *\n * This should be called instead of \\c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n * if the core provides translations for its options.\n * General use is largely the same,\n * but see \\ref retro_core_options_v2_intl for some important details.\n *\n * @param[in] data <tt>const struct retro_core_options_v2_intl *</tt>.\n * Pointer to a core's option values and categories,\n * plus a translation for each option and category.\n * @see retro_core_options_v2_intl\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n */\n#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL 68\n\n/**\n * Registers a callback that the frontend can use\n * to notify the core that at least one core option\n * should be made hidden or visible.\n * Allows a frontend to signal that a core must update\n * the visibility of any dynamically hidden core options,\n * and enables the frontend to detect visibility changes.\n * Used by the frontend to update the menu display status\n * of core options without requiring a call of retro_run().\n * Must be called in retro_set_environment().\n *\n * @param[in] data <tt>const struct retro_core_options_update_display_callback *</tt>.\n * The callback that the frontend should use.\n * May be \\c NULL, in which case the frontend will unset any existing callback.\n * Can be used to query visibility support.\n * @return \\c true if this environment call is available,\n * even if \\c data is \\c NULL.\n * @see retro_core_options_update_display_callback\n */\n#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69\n\n/**\n * Forcibly sets a core option's value.\n *\n * After changing a core option value with this callback,\n * it will be reflected in the frontend\n * and \\ref RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE will return \\c true.\n * \\ref retro_variable::key must match\n * a \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 \"previously-set core option\",\n * and \\ref retro_variable::value must match one of its defined values.\n *\n * Possible use cases include:\n *\n * @li Allowing the player to set certain core options\n *     without entering the frontend's option menu,\n *     using an in-core hotkey.\n * @li Adjusting invalid combinations of settings.\n * @li Migrating settings from older releases of a core.\n *\n * @param[in] data <tt>const struct retro_variable *</tt>.\n * Pointer to a single option that the core is changing.\n * May be \\c NULL, in which case the frontend will return \\c true\n * to indicate that this environment call is available.\n * @return \\c true if this environment call is available\n * and the option named by \\c key was successfully\n * set to the given \\c value.\n * \\c false if the \\c key or \\c value fields are \\c NULL, empty,\n * or don't match a previously set option.\n *\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n * @see RETRO_ENVIRONMENT_GET_VARIABLE\n * @see RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE\n */\n#define RETRO_ENVIRONMENT_SET_VARIABLE 70\n\n#define RETRO_ENVIRONMENT_GET_THROTTLE_STATE (71 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n                                           /* struct retro_throttle_state * --\n                                            * Allows an implementation to get details on the actual rate\n                                            * the frontend is attempting to call retro_run().\n                                            */\n\n/**\n * Returns information about how the frontend will use savestates.\n *\n * @param[out] data <tt>retro_savestate_context *</tt>.\n * Pointer to the current savestate context.\n * May be \\c NULL, in which case the environment call\n * will return \\c true to indicate its availability.\n * @returns \\c true if the environment call is available,\n * even if \\c data is \\c NULL.\n * @see retro_savestate_context\n */\n#define RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT (72 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Before calling \\c SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE, will query which interface is supported.\n *\n * Frontend looks at \\c retro_hw_render_interface_type and returns the maximum supported\n * context negotiation interface version. If the \\c retro_hw_render_interface_type is not\n * supported or recognized by the frontend, a version of 0 must be returned in\n * \\c retro_hw_render_interface's \\c interface_version and \\c true is returned by frontend.\n *\n * If this environment call returns true with a \\c interface_version greater than 0,\n * a core can always use a negotiation interface version larger than what the frontend returns,\n * but only earlier versions of the interface will be used by the frontend.\n *\n * A frontend must not reject a negotiation interface version that is larger than what the\n * frontend supports. Instead, the frontend will use the older entry points that it recognizes.\n * If this is incompatible with a particular core's requirements, it can error out early.\n *\n * @note Regarding backwards compatibility, this environment call was introduced after Vulkan v1\n * context negotiation. If this environment call is not supported by frontend, i.e. the environment\n * call returns \\c false , only Vulkan v1 context negotiation is supported (if Vulkan HW rendering\n * is supported at all). If a core uses Vulkan negotiation interface with version > 1, negotiation\n * may fail unexpectedly. All future updates to the context negotiation interface implies that\n * frontend must support this environment call to query support.\n *\n * @param[out] data <tt>struct retro_hw_render_context_negotiation_interface *</tt>.\n * @return \\c true if the environment call is available.\n * @see SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE\n * @see retro_hw_render_interface_type\n * @see retro_hw_render_context_negotiation_interface\n */\n#define RETRO_ENVIRONMENT_GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT (73 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Asks the frontend whether JIT compilation can be used.\n * Primarily used by iOS and tvOS.\n * @param[out] data <tt>bool *</tt>.\n * Set to \\c true if the frontend has verified that JIT compilation is possible.\n * @return \\c true if the environment call is available.\n */\n#define RETRO_ENVIRONMENT_GET_JIT_CAPABLE 74\n\n/**\n * Returns an interface that the core can use to receive microphone input.\n *\n * @param[out] data <tt>retro_microphone_interface *</tt>.\n * Pointer to the microphone interface.\n * @return \\true if microphone support is available,\n * even if no microphones are plugged in.\n * \\c false if microphone support is disabled unavailable,\n * or if \\c data is \\c NULL.\n * @see retro_microphone_interface\n */\n#define RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE (75 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/* Environment 76 was an obsolete version of RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.\n* It was not used by any known core at the time, and was removed from the API. */\n\n/**\n * Returns the device's current power state as reported by the frontend.\n *\n * This is useful for emulating the battery level in handheld consoles,\n * or for reducing power consumption when on battery power.\n *\n * @note This environment call describes the power state for the entire device,\n * not for individual peripherals like controllers.\n *\n * @param[out] data <struct retro_device_power *>.\n * Indicates whether the frontend can provide this information, even if the parameter\n * is \\c NULL. If the frontend does not support this functionality, then the provided\n * argument will remain unchanged.\n * @return \\c true if the environment call is available.\n * @see retro_device_power\n */\n#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n#define RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE 78\n                                           /* const struct retro_netpacket_callback * --\n                                            * When set, a core gains control over network packets sent and\n                                            * received during a multiplayer session. This can be used to\n                                            * emulate multiplayer games that were originally played on two\n                                            * or more separate consoles or computers connected together.\n                                            *\n                                            * The frontend will take care of connecting players together,\n                                            * and the core only needs to send the actual data as needed for\n                                            * the emulation, while handshake and connection management happen\n                                            * in the background.\n                                            *\n                                            * When two or more players are connected and this interface has\n                                            * been set, time manipulation features (such as pausing, slow motion,\n                                            * fast forward, rewinding, save state loading, etc.) are disabled to\n                                            * avoid interrupting communication.\n                                            *\n                                            * Should be set in either retro_init or retro_load_game, but not both.\n                                            *\n                                            * When not set, a frontend may use state serialization-based\n                                            * multiplayer, where a deterministic core supporting multiple\n                                            * input devices does not need to take any action on its own.\n                                            */\n\n/**\n * Returns the device's current power state as reported by the frontend.\n * This is useful for emulating the battery level in handheld consoles,\n * or for reducing power consumption when on battery power.\n *\n * The return value indicates whether the frontend can provide this information,\n * even if the parameter is \\c NULL.\n *\n * If the frontend does not support this functionality,\n * then the provided argument will remain unchanged.\n * @param[out] data <tt>retro_device_power *</tt>.\n * Pointer to the information that the frontend returns about its power state.\n * May be \\c NULL.\n * @return \\c true if the environment call is available,\n * even if \\c data is \\c NULL.\n * @see retro_device_power\n * @note This environment call describes the power state for the entire device,\n * not for individual peripherals like controllers.\n*/\n#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns the \"playlist\" directory of the frontend.\n *\n * This directory can be used to store core generated playlists, in case\n * this internal functionality is available (e.g. internal core game detection\n * engine).\n *\n * @param[out] data <tt>const char **</tt>.\n * May be \\c NULL. If so, no such directory is defined, and it's up to the\n * implementation to find a suitable directory.\n * @return \\c true if the environment call is available.\n */\n#define RETRO_ENVIRONMENT_GET_PLAYLIST_DIRECTORY 79\n\n/**\n * Returns the \"file browser\" start directory of the frontend.\n *\n * This directory can serve as a start directory for the core in case it\n * provides an internal way of loading content.\n *\n * @param[out] data <tt>const char **</tt>.\n * May be \\c NULL. If so, no such directory is defined, and it's up to the\n * implementation to find a suitable directory.\n * @return \\c true if the environment call is available.\n */\n#define RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY 80\n\n/**\n * Returns the audio sample rate the frontend is targeting, in Hz.\n * The intended use case is for the core to use the result to select an ideal sample rate.\n *\n * @param[out] data <tt>unsigned *</tt>.\n * Pointer to the \\c unsigned integer in which the frontend will store its target sample rate.\n * Behavior is undefined if \\c data is <tt>NULL</tt>.\n * @return \\c true if this environment call is available,\n * regardless of the value returned in \\c data.\n*/\n#define RETRO_ENVIRONMENT_GET_TARGET_SAMPLE_RATE (81 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**\n * Returns the local player's netplay client index when using frontend-managed\n * multiplayer/rollback netplay.\n *\n * @param[out] data <tt>unsigned *</tt>.\n * Pointer to an unsigned integer where the frontend stores the local client index.\n * 0 indicates host. Values > 0 indicate connected clients.\n * @return \\\\c true if the environment call is available and value was written,\n * \\\\c false otherwise.\n*/\n#define RETRO_ENVIRONMENT_GET_NETPLAY_CLIENT_INDEX (82 | RETRO_ENVIRONMENT_EXPERIMENTAL)\n\n/**@}*/\n\n/**\n * @defgroup GET_VFS_INTERFACE File System Interface\n * @brief File system functionality.\n *\n * @section File Paths\n * File paths passed to all libretro filesystem APIs shall be well formed UNIX-style,\n * using \"/\" (unquoted forward slash) as the directory separator\n * regardless of the platform's native separator.\n *\n * Paths shall also include at least one forward slash\n * (e.g. use \"./game.bin\" instead of \"game.bin\").\n *\n * Other than the directory separator, cores shall not make assumptions about path format.\n * The following paths are all valid:\n * @li \\c C:/path/game.bin\n * @li \\c http://example.com/game.bin\n * @li \\c #game/game.bin\n * @li \\c ./game.bin\n *\n * Cores may replace the basename or remove path components from the end, and/or add new components;\n * however, cores shall not append \"./\", \"../\" or multiple consecutive forward slashes (\"//\") to paths they request from the front end.\n *\n * The frontend is encouraged to do the best it can when given an ill-formed path,\n * but it is allowed to give up.\n *\n * Frontends are encouraged, but not required, to support native file system paths\n * (including replacing the directory separator, if applicable).\n *\n * Cores are allowed to try using them, but must remain functional if the frontend rejects such requests.\n *\n * Cores are encouraged to use the libretro-common filestream functions for file I/O,\n * as they seamlessly integrate with VFS,\n * deal with directory separator replacement as appropriate\n * and provide platform-specific fallbacks\n * in cases where front ends do not provide their own VFS interface.\n *\n * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE\n * @see retro_vfs_interface_info\n * @see file_path\n * @see retro_dirent\n * @see file_stream\n *\n * @{\n */\n\n/**\n * Opaque file handle.\n * @since VFS API v1\n */\nstruct retro_vfs_file_handle;\n\n/**\n * Opaque directory handle.\n * @since VFS API v3\n */\nstruct retro_vfs_dir_handle;\n\n/** @defgroup RETRO_VFS_FILE_ACCESS File Access Flags\n * File access flags.\n * @since VFS API v1\n * @{\n */\n\n/** Opens a file for read-only access. */\n#define RETRO_VFS_FILE_ACCESS_READ            (1 << 0)\n\n/**\n * Opens a file for write-only access.\n * Any existing file at this path will be discarded and overwritten\n * unless \\c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.\n */\n#define RETRO_VFS_FILE_ACCESS_WRITE           (1 << 1)\n\n/**\n * Opens a file for reading and writing.\n * Any existing file at this path will be discarded and overwritten\n * unless \\c RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING is also specified.\n */\n#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE)\n\n/**\n * Opens a file without discarding its existing contents.\n * Only meaningful if \\c RETRO_VFS_FILE_ACCESS_WRITE is specified.\n */\n#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */\n\n/** @} */\n\n/** @defgroup RETRO_VFS_FILE_ACCESS_HINT File Access Hints\n *\n * Hints to the frontend for how a file will be accessed.\n * The VFS implementation may use these to optimize performance,\n * react to external interference (such as concurrent writes),\n * or it may ignore them entirely.\n *\n * Hint flags do not change the behavior of each VFS function\n * unless otherwise noted.\n * @{\n */\n\n/** No particular hints are given. */\n#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)\n\n/**\n * Indicates that the file will be accessed frequently.\n *\n * The frontend should cache it or map it into memory.\n */\n#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 << 0)\n\n/** @} */\n\n/** @defgroup RETRO_VFS_SEEK_POSITION File Seek Positions\n * File access flags and hints.\n * @{\n */\n\n/**\n * Indicates a seek relative to the start of the file.\n */\n#define RETRO_VFS_SEEK_POSITION_START    0\n\n/**\n * Indicates a seek relative to the current stream position.\n */\n#define RETRO_VFS_SEEK_POSITION_CURRENT  1\n\n/**\n * Indicates a seek relative to the end of the file.\n * @note The offset passed to \\c retro_vfs_seek_t should be negative.\n */\n#define RETRO_VFS_SEEK_POSITION_END      2\n\n/** @} */\n\n/** @defgroup RETRO_VFS_STAT File Status Flags\n * File stat flags.\n * @see retro_vfs_stat_t\n * @since VFS API v3\n * @{\n */\n\n/** Indicates that the given path refers to a valid file. */\n#define RETRO_VFS_STAT_IS_VALID               (1 << 0)\n\n/** Indicates that the given path refers to a directory. */\n#define RETRO_VFS_STAT_IS_DIRECTORY           (1 << 1)\n\n/**\n * Indicates that the given path refers to a character special file,\n * such as \\c /dev/null.\n */\n#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 << 2)\n\n/** @} */\n\n/**\n * Returns the path that was used to open this file.\n *\n * @param stream The opened file handle to get the path of.\n * Behavior is undefined if \\c NULL or closed.\n * @return The path that was used to open \\c stream.\n * The string is owned by \\c stream and must not be modified.\n * @since VFS API v1\n * @see filestream_get_path\n */\ntypedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);\n\n/**\n * Open a file for reading or writing.\n *\n * @param path The path to open.\n * @param mode A bitwise combination of \\c RETRO_VFS_FILE_ACCESS flags.\n * At a minimum, one of \\c RETRO_VFS_FILE_ACCESS_READ or \\c RETRO_VFS_FILE_ACCESS_WRITE must be specified.\n * @param hints A bitwise combination of \\c RETRO_VFS_FILE_ACCESS_HINT flags.\n * @return A handle to the opened file,\n * or \\c NULL upon failure.\n * Note that this will return \\c NULL if \\c path names a directory.\n * The returned file handle must be closed with \\c retro_vfs_close_t.\n * @since VFS API v1\n * @see File Paths\n * @see RETRO_VFS_FILE_ACCESS\n * @see RETRO_VFS_FILE_ACCESS_HINT\n * @see retro_vfs_close_t\n * @see filestream_open\n */\ntypedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);\n\n/**\n * Close the file and release its resources.\n * All files returned by \\c retro_vfs_open_t must be closed with this function.\n *\n * @param stream The file handle to close.\n * Behavior is undefined if already closed.\n * Upon completion of this function, \\c stream is no longer valid\n * (even if it returns failure).\n * @return 0 on success, -1 on failure or if \\c stream is \\c NULL.\n * @see retro_vfs_open_t\n * @see filestream_close\n * @since VFS API v1\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);\n\n/**\n * Return the size of the file in bytes.\n *\n * @param stream The file to query the size of.\n * @return Size of the file in bytes, or -1 if there was an error.\n * @see filestream_get_size\n * @since VFS API v1\n */\ntypedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);\n\n/**\n * Set the file's length.\n *\n * @param stream The file whose length will be adjusted.\n * @param length The new length of the file, in bytes.\n * If shorter than the original length, the extra bytes will be discarded.\n * If longer, the file's padding is unspecified (and likely platform-dependent).\n * @return 0 on success,\n * -1 on failure.\n * @see filestream_truncate\n * @since VFS API v2\n */\ntypedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);\n\n/**\n * Gets the given file's current read/write position.\n * This position is advanced with each call to \\c retro_vfs_read_t or \\c retro_vfs_write_t.\n *\n * @param stream The file to query the position of.\n * @return The current stream position in bytes\n * or -1 if there was an error.\n * @see filestream_tell\n * @since VFS API v1\n */\ntypedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);\n\n/**\n * Sets the given file handle's current read/write position.\n *\n * @param stream The file to set the position of.\n * @param offset The new position, in bytes.\n * @param seek_position The position to seek from.\n * @return The new position,\n * or -1 if there was an error.\n * @since VFS API v1\n * @see File Seek Positions\n * @see filestream_seek\n */\ntypedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);\n\n/**\n * Read data from a file, if it was opened for reading.\n *\n * @param stream The file to read from.\n * @param s The buffer to read into.\n * @param len The number of bytes to read.\n * The buffer pointed to by \\c s must be this large.\n * @return The number of bytes read,\n * or -1 if there was an error.\n * @since VFS API v1\n * @see filestream_read\n */\ntypedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);\n\n/**\n * Write data to a file, if it was opened for writing.\n *\n * @param stream The file handle to write to.\n * @param s The buffer to write from.\n * @param len The number of bytes to write.\n * The buffer pointed to by \\c s must be this large.\n * @return The number of bytes written,\n * or -1 if there was an error.\n * @since VFS API v1\n * @see filestream_write\n */\ntypedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);\n\n/**\n * Flush pending writes to the file, if applicable.\n *\n * This does not mean that the changes will be immediately persisted to disk;\n * that may be scheduled for later, depending on the platform.\n *\n * @param stream The file handle to flush.\n * @return 0 on success, -1 on failure.\n * @since VFS API v1\n * @see filestream_flush\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);\n\n/**\n * Deletes the file at the given path.\n *\n * @param path The path to the file that will be deleted.\n * @return 0 on success, -1 on failure.\n * @see filestream_delete\n * @since VFS API v1\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);\n\n/**\n * Rename the specified file.\n *\n * @param old_path Path to an existing file.\n * @param new_path The destination path.\n * Must not name an existing file.\n * @return 0 on success, -1 on failure\n * @see filestream_rename\n * @since VFS API v1\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);\n\n/**\n * Gets information about the given file.\n *\n * @param path The path to the file to query.\n * @param[out] size The reported size of the file in bytes.\n * May be \\c NULL, in which case this value is ignored.\n * @return A bitmask of \\c RETRO_VFS_STAT flags,\n * or 0 if \\c path doesn't refer to a valid file.\n * @see path_stat\n * @see path_get_size\n * @see RETRO_VFS_STAT\n * @since VFS API v3\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);\n\n/**\n * Gets information about the given file (64-bit size).\n *\n * @param path The path to the file to query.\n * @param[out] size The reported size of the file in bytes.\n * May be \\c NULL, in which case this value is ignored.\n * @return A bitmask of \\c RETRO_VFS_STAT flags,\n * or 0 if \\c path doesn't refer to a valid file.\n * @see RETRO_VFS_STAT\n * @since VFS API v4\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_stat_64_t)(const char *path, int64_t *size);\n\n/**\n * Creates a directory at the given path.\n *\n * @param dir The desired location of the new directory.\n * @return 0 if the directory was created,\n * -2 if the directory already exists,\n * or -1 if some other error occurred.\n * @see path_mkdir\n * @since VFS API v3\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);\n\n/**\n * Opens a handle to a directory so its contents can be inspected.\n *\n * @param dir The path to the directory to open.\n * Must be an existing directory.\n * @param include_hidden Whether to include hidden files in the directory listing.\n * The exact semantics of this flag will depend on the platform.\n * @return A handle to the opened directory,\n * or \\c NULL if there was an error.\n * @see retro_opendir\n * @since VFS API v3\n */\ntypedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);\n\n/**\n * Gets the next dirent (\"directory entry\")\n * within the given directory.\n *\n * @param[in,out] dirstream The directory to read from.\n * Updated to point to the next file, directory, or other path.\n * @return \\c true when the next dirent was retrieved,\n * \\c false if there are no more dirents to read.\n * @note This API iterates over all files and directories within \\c dirstream.\n * Remember to check what the type of the current dirent is.\n * @note This function does not recurse,\n * i.e. it does not return the contents of subdirectories.\n * @note This may include \".\" and \"..\" on Unix-like platforms.\n * @see retro_readdir\n * @see retro_vfs_dirent_is_dir_t\n * @since VFS API v3\n */\ntypedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);\n\n/**\n * Gets the filename of the current dirent.\n *\n * The returned string pointer is valid\n * until the next call to \\c retro_vfs_readdir_t or \\c retro_vfs_closedir_t.\n *\n * @param dirstream The directory to read from.\n * @return The current dirent's name,\n * or \\c NULL if there was an error.\n * @note This function only returns the file's \\em name,\n * not a complete path to it.\n * @see retro_dirent_get_name\n * @since VFS API v3\n */\ntypedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);\n\n/**\n * Checks whether the current dirent names a directory.\n *\n * @param dirstream The directory to read from.\n * @return \\c true if \\c dirstream's current dirent points to a directory,\n * \\c false if not or if there was an error.\n * @see retro_dirent_is_dir\n * @since VFS API v3\n */\ntypedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);\n\n/**\n * Closes the given directory and release its resources.\n *\n * Must be called on any \\c retro_vfs_dir_handle returned by \\c retro_vfs_open_t.\n *\n * @param dirstream The directory to close.\n * When this function returns (even failure),\n * \\c dirstream will no longer be valid and must not be used.\n * @return 0 on success, -1 on failure.\n * @see retro_closedir\n * @since VFS API v3\n */\ntypedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);\n\n/**\n * File system interface exposed by the frontend.\n *\n * @see dirent_vfs_init\n * @see filestream_vfs_init\n * @see path_vfs_init\n * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE\n */\nstruct retro_vfs_interface\n{\n   /* VFS API v1 */\n   /** @copydoc retro_vfs_get_path_t */\n\tretro_vfs_get_path_t get_path;\n\n   /** @copydoc retro_vfs_open_t */\n\tretro_vfs_open_t open;\n\n   /** @copydoc retro_vfs_close_t */\n\tretro_vfs_close_t close;\n\n   /** @copydoc retro_vfs_size_t */\n\tretro_vfs_size_t size;\n\n   /** @copydoc retro_vfs_tell_t */\n\tretro_vfs_tell_t tell;\n\n   /** @copydoc retro_vfs_seek_t */\n\tretro_vfs_seek_t seek;\n\n   /** @copydoc retro_vfs_read_t */\n\tretro_vfs_read_t read;\n\n   /** @copydoc retro_vfs_write_t */\n\tretro_vfs_write_t write;\n\n   /** @copydoc retro_vfs_flush_t */\n\tretro_vfs_flush_t flush;\n\n   /** @copydoc retro_vfs_remove_t */\n\tretro_vfs_remove_t remove;\n\n   /** @copydoc retro_vfs_rename_t */\n\tretro_vfs_rename_t rename;\n   /* VFS API v2 */\n\n   /** @copydoc retro_vfs_truncate_t */\n   retro_vfs_truncate_t truncate;\n   /* VFS API v3 */\n\n   /** @copydoc retro_vfs_stat_t */\n   retro_vfs_stat_t stat;\n\n   /** @copydoc retro_vfs_mkdir_t */\n   retro_vfs_mkdir_t mkdir;\n\n   /** @copydoc retro_vfs_opendir_t */\n   retro_vfs_opendir_t opendir;\n\n   /** @copydoc retro_vfs_readdir_t */\n   retro_vfs_readdir_t readdir;\n\n   /** @copydoc retro_vfs_dirent_get_name_t */\n   retro_vfs_dirent_get_name_t dirent_get_name;\n\n   /** @copydoc retro_vfs_dirent_is_dir_t */\n   retro_vfs_dirent_is_dir_t dirent_is_dir;\n\n   /** @copydoc retro_vfs_closedir_t */\n   retro_vfs_closedir_t closedir;\n\n   /* VFS API v4 */\n   /** @copydoc retro_vfs_stat_64_t */\n   retro_vfs_stat_64_t stat_64;\n};\n\n/**\n * Represents a request by the core for the frontend's file system interface,\n * as well as the interface itself returned by the frontend.\n *\n * You do not need to use these functions directly;\n * you may pass this struct to \\c dirent_vfs_init,\n * \\c filestream_vfs_init, or \\c path_vfs_init\n * so that you can use the wrappers provided by these modules.\n *\n * @see dirent_vfs_init\n * @see filestream_vfs_init\n * @see path_vfs_init\n * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE\n */\nstruct retro_vfs_interface_info\n{\n   /**\n    * The minimum version of the VFS API that the core requires.\n    * libretro-common's wrapper API initializers will check this value as well.\n    *\n    * Set to the core's desired VFS version when requesting an interface,\n    * and set by the frontend to indicate its actual API version.\n    *\n    * If the core asks for a newer VFS API version than the frontend supports,\n    * the frontend must return \\c false within the \\c RETRO_ENVIRONMENT_GET_VFS_INTERFACE call.\n    * @since VFS API v1\n    */\n   uint32_t required_interface_version;\n\n   /**\n    * Set by the frontend.\n    * The frontend will set this to the VFS interface it provides.\n    *\n    * The interface is owned by the frontend\n    * and must not be modified or freed by the core.\n    * @since VFS API v1 */\n   struct retro_vfs_interface *iface;\n};\n\n/** @} */\n\n/** @defgroup GET_HW_RENDER_INTERFACE Hardware Rendering Interface\n * @{\n */\n\n/**\n * Describes the hardware rendering API supported by\n * a particular subtype of \\c retro_hw_render_interface.\n *\n * Not every rendering API supported by libretro has its own interface,\n * or even needs one.\n *\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE\n */\nenum retro_hw_render_interface_type\n{\n   /**\n    * Indicates a \\c retro_hw_render_interface for Vulkan.\n    * @see retro_hw_render_interface_vulkan\n    */\n   RETRO_HW_RENDER_INTERFACE_VULKAN     = 0,\n\n   /** Indicates a \\c retro_hw_render_interface for Direct3D 9. */\n   RETRO_HW_RENDER_INTERFACE_D3D9       = 1,\n\n   /** Indicates a \\c retro_hw_render_interface for Direct3D 10. */\n   RETRO_HW_RENDER_INTERFACE_D3D10      = 2,\n\n   /**\n    * Indicates a \\c retro_hw_render_interface for Direct3D 11.\n    * @see retro_hw_render_interface_d3d11\n    */\n   RETRO_HW_RENDER_INTERFACE_D3D11      = 3,\n\n   /**\n    * Indicates a \\c retro_hw_render_interface for Direct3D 12.\n    * @see retro_hw_render_interface_d3d12\n    */\n   RETRO_HW_RENDER_INTERFACE_D3D12      = 4,\n\n   /**\n    * Indicates a \\c retro_hw_render_interface for\n    * the PlayStation's 2 PSKit API.\n    * @see retro_hw_render_interface_gskit_ps2\n    */\n   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,\n\n   /** @private Defined to ensure <tt>sizeof(retro_hw_render_interface_type) == sizeof(int)</tt>.\n    * Do not use. */\n   RETRO_HW_RENDER_INTERFACE_DUMMY      = INT_MAX\n};\n\n/**\n * Base render interface type.\n * All \\c retro_hw_render_interface implementations\n * will start with these two fields set to particular values.\n *\n * @see retro_hw_render_interface_type\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE\n */\nstruct retro_hw_render_interface\n{\n   /**\n    * Denotes the particular rendering API that this interface is for.\n    * Each interface requires this field to be set to a particular value.\n    * Use it to cast this interface to the appropriate pointer.\n    */\n   enum retro_hw_render_interface_type interface_type;\n\n   /**\n    * The version of this rendering interface.\n    * @note This is not related to the version of the API itself.\n    */\n   unsigned interface_version;\n};\n\n/** @} */\n\n/**\n * @defgroup GET_LED_INTERFACE LED Interface\n * @{\n */\n\n/** @copydoc retro_led_interface::set_led_state */\ntypedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);\n\n/**\n * Interface that the core can use to set the state of available LEDs.\n * @see RETRO_ENVIRONMENT_GET_LED_INTERFACE\n */\nstruct retro_led_interface\n{\n   /**\n    * Sets the state of an LED.\n    *\n    * @param led The LED to set the state of.\n    * @param state The state to set the LED to.\n    * \\c true to enable, \\c false to disable.\n    */\n   retro_set_led_state_t set_led_state;\n};\n\n/** @} */\n\n/** @defgroup GET_AUDIO_VIDEO_ENABLE Skipped A/V Steps\n * @{\n */\n\n/**\n * Flags that define A/V steps that the core may skip for this frame.\n *\n * @see RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE\n */\nenum retro_av_enable_flags\n{\n   /**\n    * If set, the core should render video output with \\c retro_video_refresh_t as normal.\n    *\n    * Otherwise, the frontend will discard any video data received this frame,\n    * including frames presented via hardware acceleration.\n    * \\c retro_video_refresh_t will do nothing.\n    *\n    * @note After running the frame, the video output of the next frame\n    * should be no different than if video was enabled,\n    * and saving and loading state should have no issues.\n    * This implies that the emulated console's graphics pipeline state\n    * should not be affected by this flag.\n    *\n    * @note If emulating a platform that supports display capture\n    * (i.e. reading its own VRAM),\n    * the core may not be able to completely skip rendering,\n    * as the VRAM is part of the graphics pipeline's state.\n    */\n   RETRO_AV_ENABLE_VIDEO = (1 << 0),\n\n   /**\n    * If set, the core should render audio output\n    * with \\c retro_audio_sample_t or \\c retro_audio_sample_batch_t as normal.\n    *\n    * Otherwise, the frontend will discard any audio data received this frame.\n    * The core should skip audio rendering if possible.\n    *\n    * @note After running the frame, the audio output of the next frame\n    * should be no different than if audio was enabled,\n    * and saving and loading state should have no issues.\n    * This implies that the emulated console's audio pipeline state\n    * should not be affected by this flag.\n    */\n   RETRO_AV_ENABLE_AUDIO = (1 << 1),\n\n   /**\n    * If set, indicates that any savestates taken this frame\n    * are guaranteed to be created by the same binary that will load them,\n    * and will not be written to or read from the disk.\n    *\n    * The core may use these guarantees to:\n    *\n    * @li Assume that loading state will succeed.\n    * @li Update its memory buffers in-place if possible.\n    * @li Skip clearing memory.\n    * @li Skip resetting the system.\n    * @li Skip validation steps.\n    *\n    * @deprecated Use \\c RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT instead,\n    * except for compatibility purposes.\n    */\n   RETRO_AV_ENABLE_FAST_SAVESTATES = (1 << 2),\n\n   /**\n    * If set, indicates that the frontend will never need audio from the core.\n    * Used by a frontend for implementing runahead via a secondary core instance.\n    *\n    * The core may stop synthesizing audio if it can do so\n    * without compromising emulation accuracy.\n    *\n    * Audio output for the next frame does not matter,\n    * and the frontend will never need an accurate audio state in the future.\n    *\n    * State will never be saved while this flag is set.\n    */\n   RETRO_AV_ENABLE_HARD_DISABLE_AUDIO = (1 << 3),\n\n   /**\n    * @private Defined to ensure <tt>sizeof(retro_av_enable_flags) == sizeof(int)</tt>.\n    * Do not use.\n    */\n   RETRO_AV_ENABLE_DUMMY = INT_MAX\n};\n\n/** @} */\n\n/**\n * @defgroup GET_MIDI_INTERFACE MIDI Interface\n * @{\n */\n\n/** @copydoc retro_midi_interface::input_enabled */\ntypedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);\n\n/** @copydoc retro_midi_interface::output_enabled */\ntypedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);\n\n/** @copydoc retro_midi_interface::read */\ntypedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);\n\n/** @copydoc retro_midi_interface::write */\ntypedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);\n\n/** @copydoc retro_midi_interface::flush */\ntypedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);\n\n/**\n * Interface that the core can use for raw MIDI I/O.\n */\nstruct retro_midi_interface\n{\n   /**\n    * Retrieves the current state of MIDI input.\n    *\n    * @return \\c true if MIDI input is enabled.\n    */\n   retro_midi_input_enabled_t input_enabled;\n\n   /**\n    * Retrieves the current state of MIDI output.\n    * @return \\c true if MIDI output is enabled.\n    */\n   retro_midi_output_enabled_t output_enabled;\n\n   /**\n    * Reads a byte from the MIDI input stream.\n    *\n    * @param[out] byte The byte received from the input stream.\n    * @return \\c true if a byte was read,\n    * \\c false if MIDI input is disabled or \\c byte is \\c NULL.\n    */\n   retro_midi_read_t read;\n\n   /**\n    * Writes a byte to the output stream.\n    *\n    * @param byte The byte to write to the output stream.\n    * @param delta_time Time since the previous write, in microseconds.\n    * @return \\c true if c\\ byte was written, false otherwise.\n    */\n   retro_midi_write_t write;\n\n   /**\n    * Flushes previously-written data.\n    *\n    * @return \\c true if successful.\n    */\n   retro_midi_flush_t flush;\n};\n\n/** @} */\n\n/** @defgroup SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE Render Context Negotiation\n * @{\n */\n\n/**\n * Describes the hardware rendering API used by\n * a particular subtype of \\c retro_hw_render_context_negotiation_interface.\n *\n * Not every rendering API supported by libretro has a context negotiation interface,\n * or even needs one.\n *\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE\n */\nenum retro_hw_render_context_negotiation_interface_type\n{\n   /**\n    * Denotes a context negotiation interface for Vulkan.\n    * @see retro_hw_render_context_negotiation_interface_vulkan\n    */\n   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,\n\n   /**\n    * @private Defined to ensure <tt>sizeof(retro_hw_render_context_negotiation_interface_type) == sizeof(int)</tt>.\n    * Do not use.\n    */\n   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX\n};\n\n/**\n * Base context negotiation interface type.\n * All \\c retro_hw_render_context_negotiation_interface implementations\n * will start with these two fields set to particular values.\n *\n * @see retro_hw_render_interface_type\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER\n * @see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE\n * @see RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE\n */\nstruct retro_hw_render_context_negotiation_interface\n{\n   /**\n    * Denotes the particular rendering API that this interface is for.\n    * Each interface requires this field to be set to a particular value.\n    * Use it to cast this interface to the appropriate pointer.\n    */\n   enum retro_hw_render_context_negotiation_interface_type interface_type;\n\n   /**\n    * The version of this negotiation interface.\n    * @note This is not related to the version of the API itself.\n    */\n   unsigned interface_version;\n};\n\n/** @} */\n\n/** @defgroup RETRO_SERIALIZATION_QUIRK Serialization Quirks\n * @{\n */\n\n/**\n * Indicates that serialized state is incomplete in some way.\n *\n * Set if serialization is usable for the common case of saving and loading game state,\n * but should not be relied upon for frame-sensitive frontend features\n * such as netplay or rerecording.\n */\n#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0)\n\n/**\n * Indicates that core must spend some time initializing before serialization can be done.\n *\n * \\c retro_serialize(), \\c retro_unserialize(), and \\c retro_serialize_size() will initially fail.\n */\n#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1)\n\n/** Set by the core to indicate that serialization size may change within a session. */\n#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2)\n\n/** Set by the frontend to acknowledge that it supports variable-sized states. */\n#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3)\n\n/** Serialized state can only be loaded during the same session. */\n#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4)\n\n/**\n * Serialized state cannot be loaded on an architecture\n * with a different endianness from the one it was saved on.\n */\n#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5)\n\n/**\n * Serialized state cannot be loaded on a different platform\n * from the one it was saved on for reasons other than endianness,\n * such as word size dependence.\n */\n#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)\n\n/** @} */\n\n/** @defgroup SET_MEMORY_MAPS Memory Descriptors\n * @{\n */\n\n/** @defgroup RETRO_MEMDESC Memory Descriptor Flags\n * Information about how the emulated hardware uses this portion of its address space.\n * @{\n */\n\n/**\n * Indicates that this memory area won't be modified\n * once \\c retro_load_game has returned.\n */\n#define RETRO_MEMDESC_CONST      (1 << 0)\n\n/**\n * Indicates a memory area with big-endian byte ordering,\n * as opposed to the default of little-endian.\n */\n#define RETRO_MEMDESC_BIGENDIAN  (1 << 1)\n\n/**\n * Indicates a memory area that is used for the emulated system's main RAM.\n */\n#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2)\n\n/**\n * Indicates a memory area that is used for the emulated system's save RAM,\n * usually found on a game cartridge as battery-backed RAM or flash memory.\n */\n#define RETRO_MEMDESC_SAVE_RAM   (1 << 3)\n\n/**\n * Indicates a memory area that is used for the emulated system's video RAM,\n * usually found on a console's GPU (or local equivalent).\n */\n#define RETRO_MEMDESC_VIDEO_RAM  (1 << 4)\n\n/**\n * Indicates a memory area that requires all accesses\n * to be aligned to 2 bytes or their own size\n * (whichever is smaller).\n */\n#define RETRO_MEMDESC_ALIGN_2    (1 << 16)\n\n/**\n * Indicates a memory area that requires all accesses\n * to be aligned to 4 bytes or their own size\n * (whichever is smaller).\n */\n#define RETRO_MEMDESC_ALIGN_4    (2 << 16)\n\n/**\n * Indicates a memory area that requires all accesses\n * to be aligned to 8 bytes or their own size\n * (whichever is smaller).\n */\n#define RETRO_MEMDESC_ALIGN_8    (3 << 16)\n\n/**\n * Indicates a memory area that requires all accesses\n * to be at least 2 bytes long.\n */\n#define RETRO_MEMDESC_MINSIZE_2  (1 << 24)\n\n/**\n * Indicates a memory area that requires all accesses\n * to be at least 4 bytes long.\n */\n#define RETRO_MEMDESC_MINSIZE_4  (2 << 24)\n\n/**\n * Indicates a memory area that requires all accesses\n * to be at least 8 bytes long.\n */\n#define RETRO_MEMDESC_MINSIZE_8  (3 << 24)\n\n/** @} */\n\n/**\n * A mapping from a region of the emulated console's address space\n * to the host's address space.\n *\n * Can be used to map an address in the console's address space\n * to the host's address space, like so:\n *\n * @code\n * void* emu_to_host(void* addr, struct retro_memory_descriptor* descriptor)\n * {\n *     return descriptor->ptr + (addr & ~descriptor->disconnect) - descriptor->start;\n * }\n * @endcode\n *\n * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS\n */\nstruct retro_memory_descriptor\n{\n   /**\n    * A bitwise \\c OR of one or more \\ref RETRO_MEMDESC \"flags\"\n    * that describe how the emulated system uses this descriptor's address range.\n    *\n    * @note If \\c ptr is \\c NULL,\n    * then no flags should be set.\n    * @see RETRO_MEMDESC\n    */\n   uint64_t flags;\n\n   /**\n    * Pointer to the start of this memory region's buffer\n    * within the \\em host's address space.\n    * The address listed here must be valid for the duration of the session;\n    * it must not be freed or modified by the frontend\n    * and it must not be moved by the core.\n    *\n    * May be \\c NULL to indicate a lack of accessible memory\n    * at the emulated address given in \\c start.\n    *\n    * @note Overlapping descriptors that include the same byte\n    * must have the same \\c ptr value.\n    */\n   void *ptr;\n\n   /**\n    * The offset of this memory region,\n    * relative to the address given by \\c ptr.\n    *\n    * @note It is recommended to use this field for address calculations\n    * instead of performing arithmetic on \\c ptr.\n    */\n   size_t offset;\n\n   /**\n    * The starting address of this memory region\n    * <em>within the emulated hardware's address space</em>.\n    *\n    * @note Not represented as a pointer\n    * because it's unlikely to be valid on the host device.\n    */\n   size_t start;\n\n   /**\n    * A bitmask that specifies which bits of an address must match\n    * the bits of the \\ref start address.\n    *\n    * Combines with \\c disconnect to map an address to a memory block.\n    *\n    * If multiple memory descriptors can claim a particular byte,\n    * the first one defined in the \\ref retro_memory_descriptor array applies.\n    * A bit which is set in \\c start must also be set in this.\n    *\n    * Can be zero, in which case \\c start and \\c len represent\n    * the complete mapping for this region of memory\n    * (i.e. each byte is mapped exactly once).\n    * In this case, \\c len must be a power of two.\n    */\n   size_t select;\n\n   /**\n    * A bitmask of bits that are \\em not used for addressing.\n    *\n    * Any set bits are assumed to be disconnected from\n    * the emulated memory chip's address pins,\n    * and are therefore ignored when memory-mapping.\n    */\n   size_t disconnect;\n\n   /**\n    * The length of this memory region, in bytes.\n    *\n    * If applying \\ref start and \\ref disconnect to an address\n    * results in a value higher than this,\n    * the highest bit of the address is cleared.\n    *\n    * If the address is still too high, the next highest bit is cleared.\n    * Can be zero, in which case it's assumed to be\n    * bounded only by \\ref select and \\ref disconnect.\n    */\n   size_t len;\n\n   /**\n    * A short name for this address space.\n    *\n    * Names must meet the following requirements:\n    *\n    * \\li Characters must be in the set <tt>[a-zA-Z0-9_-]</tt>.\n    * \\li No more than 8 characters, plus a \\c NULL terminator.\n    * \\li Names are case-sensitive, but lowercase characters are discouraged.\n    * \\li A name must not be the same as another name plus a character in the set \\c [A-F0-9]\n    *     (i.e. if an address space named \"RAM\" exists,\n    *     then the names \"RAM0\", \"RAM1\", ..., \"RAMF\" are forbidden).\n    *     This is to allow addresses to be named by each descriptor unambiguously,\n    *     even if the areas overlap.\n    * \\li May be \\c NULL or empty (both are considered equivalent).\n    *\n    * Here are some examples of pairs of address space names:\n    *\n    * \\li \\em blank + \\em blank: valid (multiple things may be mapped in the same namespace)\n    * \\li \\c Sp + \\c Sp: valid (multiple things may be mapped in the same namespace)\n    * \\li \\c SRAM + \\c VRAM: valid (neither is a prefix of the other)\n    * \\li \\c V + \\em blank: valid (\\c V is not in \\c [A-F0-9])\n    * \\li \\c a + \\em blank: valid but discouraged (\\c a is not in \\c [A-F0-9])\n    * \\li \\c a + \\c A: valid but discouraged (neither is a prefix of the other)\n    * \\li \\c AR + \\em blank: valid (\\c R is not in \\c [A-F0-9])\n    * \\li \\c ARB + \\em blank: valid (there's no \\c AR namespace,\n    *     so the \\c B doesn't cause ambiguity).\n    * \\li \\em blank + \\c B: invalid, because it's ambiguous which address space \\c B1234 would refer to.\n    *\n    * The length of the address space's name can't be used to disambugiate,\n    * as extra information may be appended to it without a separator.\n    */\n   const char *addrspace;\n\n   /* TODO: When finalizing this one, add a description field, which should be\n    * \"WRAM\" or something roughly equally long. */\n\n   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells\n    * which bits can vary and still refer to the same address (limit = ~select).\n    * TODO: limit? range? vary? something else? */\n\n   /* TODO: When finalizing this one, if 'len' is above what 'select' (or\n    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'\n    * and 'select' != 0, and the mappings don't tell how the system switches the\n    * banks. */\n\n   /* TODO: When finalizing this one, fix the 'len' bit removal order.\n    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.\n    * Algorithm: Take bits highest to lowest, but if it goes above len, clear\n    * the most recent addition and continue on the next bit.\n    * TODO: Can the above be optimized? Is \"remove the lowest bit set in both\n    * pointer and 'len'\" equivalent? */\n\n   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing\n    * the emulated memory in 32-bit chunks, native endian. But that's nothing\n    * compared to Darek Mihocka <http://www.emulators.com/docs/nx07_vm101.htm>\n    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE\n    * RAM backwards! I'll want to represent both of those, via some flags.\n    *\n    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.\n    * Not sure which, nor do I really care. */\n\n   /* TODO: Some of those flags are unused and/or don't really make sense. Clean\n    * them up. */\n};\n\n/**\n * A list of regions within the emulated console's address space.\n *\n * The frontend may use the largest value of\n * \\ref retro_memory_descriptor::start + \\ref retro_memory_descriptor::select\n * in a certain namespace to infer the overall size of the address space.\n * If the address space is larger than that,\n * the last mapping in \\ref descriptors should have \\ref retro_memory_descriptor::ptr set to \\c NULL\n * and \\ref retro_memory_descriptor::select should have all bits used in the address space set to 1.\n *\n * Here's an example set of descriptors for the SNES.\n *\n * @code{.c}\n * struct retro_memory_map snes_descriptors = retro_memory_map\n * {\n *    .descriptors = (struct retro_memory_descriptor[])\n *    {\n *       // WRAM; must usually be mapped before the ROM,\n *       // as some SNES ROM mappers try to claim 0x7E0000\n *       { .addrspace=\"WRAM\", .start=0x7E0000, .len=0x20000 },\n *\n *       // SPC700 RAM\n *       { .addrspace=\"SPC700\", .len=0x10000 },\n *\n *       // WRAM mirrors\n *       { .addrspace=\"WRAM\", .start=0x000000, .select=0xC0E000, .len=0x2000 },\n *       { .addrspace=\"WRAM\", .start=0x800000, .select=0xC0E000, .len=0x2000 },\n *\n *       // WRAM mirror, alternate equivalent descriptor\n *       // (Various similar constructions can be created by combining parts of the above two.)\n *       { .addrspace=\"WRAM\", .select=0x40E000, .disconnect=~0x1FFF },\n *\n *       // LoROM (512KB, mirrored a couple of times)\n *       { .addrspace=\"LoROM\", .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },\n *       { .addrspace=\"LoROM\", .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024, .flags=RETRO_MEMDESC_CONST },\n *\n *       // HiROM (4MB)\n *       { .addrspace=\"HiROM\", .start=0x400000, .select=0x400000, .len=4*1024*1024, .flags=RETRO_MEMDESC_CONST },\n *       { .addrspace=\"HiROM\", .start=0x008000, .select=0x408000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },\n *\n *       // ExHiROM (8MB)\n *       { .addrspace=\"ExHiROM\", .start=0xC00000, .select=0xC00000, .len=4*1024*1024, .offset=0, .flags=RETRO_MEMDESC_CONST },\n *       { .addrspace=\"ExHiROM\", .start=0x400000, .select=0xC00000, .len=4*1024*1024, .offset=4*1024*1024, .flags=RETRO_MEMDESC_CONST },\n *       { .addrspace=\"ExHiROM\", .start=0x808000, .select=0xC08000, .len=4*1024*1024, .offset=0x8000, .flags=RETRO_MEMDESC_CONST },\n *       { .addrspace=\"ExHiROM\", .start=0x008000, .select=0xC08000, .len=4*1024*1024, .offset=4*1024*1024+0x8000, .flags=RETRO_MEMDESC_CONST },\n *\n *       // Clarifying the full size of the address space\n *       { .select=0xFFFFFF, .ptr=NULL },\n *    },\n *    .num_descriptors = 14,\n * };\n * @endcode\n *\n * @see RETRO_ENVIRONMENT_SET_MEMORY_MAPS\n */\nstruct retro_memory_map\n{\n   /**\n    * Pointer to an array of memory descriptors,\n    * each of which describes part of the emulated console's address space.\n    */\n   const struct retro_memory_descriptor *descriptors;\n\n   /** The number of descriptors in \\c descriptors. */\n   unsigned num_descriptors;\n};\n\n/** @} */\n\n/** @defgroup SET_CONTROLLER_INFO Controller Info\n * @{\n */\n\n/**\n * Details about a controller (or controller configuration)\n * supported by one of a core's emulated input ports.\n *\n * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO\n */\nstruct retro_controller_description\n{\n   /**\n    * A human-readable label for the controller or configuration\n    * represented by this device type.\n    * Most likely the device's original brand name.\n    */\n   const char *desc;\n\n   /**\n    * A unique identifier that will be passed to \\c retro_set_controller_port_device()'s \\c device parameter.\n    * May be the ID of one of \\ref RETRO_DEVICE \"the generic controller types\",\n    * or a subclass ID defined with \\c RETRO_DEVICE_SUBCLASS.\n    *\n    * @see RETRO_DEVICE_SUBCLASS\n    */\n   unsigned id;\n};\n\n/**\n * Lists the types of controllers supported by\n * one of core's emulated input ports.\n *\n * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO\n */\nstruct retro_controller_info\n{\n\n   /**\n    * A pointer to an array of device types supported by this controller port.\n    *\n    * @note Ports that support the same devices\n    * may share the same underlying array.\n    */\n   const struct retro_controller_description *types;\n\n   /** The number of elements in \\c types. */\n   unsigned num_types;\n};\n\n/** @} */\n\n/** @defgroup SET_SUBSYSTEM_INFO Subsystems\n * @{\n */\n\n/**\n * Information about a type of memory associated with a subsystem.\n * Usually used for SRAM (save RAM).\n *\n * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO\n * @see retro_get_memory_data\n * @see retro_get_memory_size\n */\nstruct retro_subsystem_memory_info\n{\n   /**\n    * The file extension the frontend should use\n    * to save this memory region to disk, e.g. \"srm\" or \"sav\".\n    */\n   const char *extension;\n\n   /**\n    * A constant that identifies this type of memory.\n    * Should be at least 0x100 (256) to avoid conflict\n    * with the standard libretro memory types,\n    * unless a subsystem uses the main platform's memory region.\n    * @see RETRO_MEMORY\n    */\n   unsigned type;\n};\n\n/**\n * Information about a type of ROM that a subsystem may use.\n * Subsystems may use one or more ROMs at once,\n * possibly of different types.\n *\n * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO\n * @see retro_subsystem_info\n */\nstruct retro_subsystem_rom_info\n{\n   /**\n    * Human-readable description of what the content represents,\n    * e.g. \"Game Boy ROM\".\n    */\n   const char *desc;\n\n   /** @copydoc retro_system_info::valid_extensions */\n   const char *valid_extensions;\n\n   /** @copydoc retro_system_info::need_fullpath */\n   bool need_fullpath;\n\n   /** @copydoc retro_system_info::block_extract */\n   bool block_extract;\n\n   /**\n    * Indicates whether this particular subsystem ROM is required.\n    * If \\c true and the user doesn't provide a ROM,\n    * the frontend should not load the core.\n    * If \\c false and the user doesn't provide a ROM,\n    * the frontend should pass a zeroed-out \\c retro_game_info\n    * to the corresponding entry in \\c retro_load_game_special().\n    */\n   bool required;\n\n   /**\n    * Pointer to an array of memory descriptors that this subsystem ROM type uses.\n    * Useful for secondary cartridges that have their own save data.\n    * May be \\c NULL, in which case this subsystem ROM's memory is not persisted by the frontend\n    * and \\c num_memory should be zero.\n    */\n   const struct retro_subsystem_memory_info *memory;\n\n   /** The number of elements in the array pointed to by \\c memory. */\n   unsigned num_memory;\n};\n\n/**\n * Information about a secondary platform that a core supports.\n * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO\n */\nstruct retro_subsystem_info\n{\n   /**\n    * A human-readable description of the subsystem type,\n    * usually the brand name of the original platform\n    * (e.g. \"Super Game Boy\").\n    */\n   const char *desc;\n\n   /**\n    * A short machine-friendly identifier for the subsystem,\n    * usually an abbreviation of the platform name.\n    * For example, a Super Game Boy subsystem for a SNES core\n    * might use an identifier of \"sgb\".\n    * This identifier can be used for command-line interfaces,\n    * configuration, or other purposes.\n    * Must use lower-case alphabetical characters only (i.e. from a-z).\n    */\n   const char *ident;\n\n   /**\n    * The list of ROM types that this subsystem may use.\n    *\n    * The first entry is considered to be the \"most significant\" content,\n    * for the purposes of the frontend's categorization.\n    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,\n    * as it is the most \"significant\" content to a user.\n    *\n    * If a frontend creates new files based on the content used (e.g. for savestates),\n    * it should derive the filenames from the name of the first ROM in this list.\n    *\n    * @note \\c roms can have a single element,\n    * but this is usually a sign that the core should broaden its\n    * primary system info instead.\n    *\n    * @see \\c retro_system_info\n    */\n   const struct retro_subsystem_rom_info *roms;\n\n   /** The length of the array given in \\c roms. */\n   unsigned num_roms;\n\n   /** A unique identifier passed to retro_load_game_special(). */\n   unsigned id;\n};\n\n/** @} */\n\n/** @defgroup SET_PROC_ADDRESS_CALLBACK Core Function Pointers\n * @{ */\n\n/**\n * The function pointer type that \\c retro_get_proc_address_t returns.\n *\n * Despite the signature shown here, the original function may include any parameters and return type\n * that respects the calling convention and C ABI.\n *\n * The frontend is expected to cast the function pointer to the correct type.\n */\ntypedef void (RETRO_CALLCONV *retro_proc_address_t)(void);\n\n/**\n * Get a symbol from a libretro core.\n *\n * Cores should only return symbols that serve as libretro extensions.\n * Frontends should not use this to obtain symbols to standard libretro entry points;\n * instead, they should link to the core statically or use \\c dlsym (or local equivalent).\n *\n * The symbol name must be equal to the function name.\n * e.g. if <tt>void retro_foo(void);</tt> exists, the symbol in the compiled library must be called \\c retro_foo.\n * The returned function pointer must be cast to the corresponding type.\n *\n * @param \\c sym The name of the symbol to look up.\n * @return Pointer to the exposed function with the name given in \\c sym,\n * or \\c NULL if one couldn't be found.\n * @note The frontend is expected to know the returned pointer's type in advance\n * so that it can be cast correctly.\n * @note The core doesn't need to expose every possible function through this interface.\n * It's enough to only expose the ones that it expects the frontend to use.\n * @note The functions exposed through this interface\n * don't need to be publicly exposed in the compiled library\n * (e.g. via \\c __declspec(dllexport)).\n * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK\n */\ntypedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);\n\n/**\n * An interface that the frontend can use to get function pointers from the core.\n *\n * @note The returned function pointer will be invalidated once the core is unloaded.\n * How and when that happens is up to the frontend.\n *\n * @see retro_get_proc_address_t\n * @see RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK\n */\nstruct retro_get_proc_address_interface\n{\n   /** Set by the core. */\n   retro_get_proc_address_t get_proc_address;\n};\n\n/** @} */\n\n/** @defgroup GET_LOG_INTERFACE Logging\n * @{\n */\n\n/**\n * The severity of a given message.\n * The frontend may log messages differently depending on the level.\n * It may also ignore log messages of a certain level.\n * @see retro_log_callback\n */\nenum retro_log_level\n{\n   /** The logged message is most likely not interesting to the user. */\n   RETRO_LOG_DEBUG = 0,\n\n   /** Information about the core operating normally. */\n   RETRO_LOG_INFO,\n\n   /** Indicates a potential problem, possibly one that the core can recover from. */\n   RETRO_LOG_WARN,\n\n   /** Indicates a degraded experience, if not failure. */\n   RETRO_LOG_ERROR,\n\n   /** Defined to ensure that sizeof(enum retro_log_level) == sizeof(int). Do not use. */\n   RETRO_LOG_DUMMY = INT_MAX\n};\n\n/**\n * Logs a message to the frontend.\n *\n * @param level The log level of the message.\n * @param fmt The format string to log.\n * Same format as \\c printf.\n * Behavior is undefined if this is \\c NULL.\n * @param ... Zero or more arguments used by the format string.\n * Behavior is undefined if these don't match the ones expected by \\c fmt.\n * @see retro_log_level\n * @see retro_log_callback\n * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE\n * @see printf\n */\ntypedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,\n      const char *fmt, ...);\n\n/**\n * Details about how to make log messages.\n *\n * @see retro_log_printf_t\n * @see RETRO_ENVIRONMENT_GET_LOG_INTERFACE\n */\nstruct retro_log_callback\n{\n   /**\n    * Called when logging a message.\n    *\n    * @note Set by the frontend.\n    */\n   retro_log_printf_t log;\n};\n\n/** @} */\n\n/** @defgroup GET_PERF_INTERFACE Performance Interface\n * @{\n */\n\n/** @defgroup RETRO_SIMD CPU Features\n * @{\n */\n\n/**\n * Indicates CPU support for the SSE instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE\n */\n#define RETRO_SIMD_SSE      (1 << 0)\n\n/**\n * Indicates CPU support for the SSE2 instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE2\n */\n#define RETRO_SIMD_SSE2     (1 << 1)\n\n/** Indicates CPU support for the AltiVec (aka VMX or Velocity Engine) instruction set. */\n#define RETRO_SIMD_VMX      (1 << 2)\n\n/** Indicates CPU support for the VMX128 instruction set. Xbox 360 only. */\n#define RETRO_SIMD_VMX128   (1 << 3)\n\n/**\n * Indicates CPU support for the AVX instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX\n */\n#define RETRO_SIMD_AVX      (1 << 4)\n\n/**\n * Indicates CPU support for the NEON instruction set.\n * @see https://developer.arm.com/architectures/instruction-sets/intrinsics/#f:@navigationhierarchiessimdisa=[Neon]\n */\n#define RETRO_SIMD_NEON     (1 << 5)\n\n/**\n * Indicates CPU support for the SSE3 instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE3\n */\n#define RETRO_SIMD_SSE3     (1 << 6)\n\n/**\n * Indicates CPU support for the SSSE3 instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSSE3\n */\n#define RETRO_SIMD_SSSE3    (1 << 7)\n\n/**\n * Indicates CPU support for the MMX instruction set.\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#techs=MMX\n */\n#define RETRO_SIMD_MMX      (1 << 8)\n\n/** Indicates CPU support for the MMXEXT instruction set. */\n#define RETRO_SIMD_MMXEXT   (1 << 9)\n\n/**\n * Indicates CPU support for the SSE4 instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_1\n */\n#define RETRO_SIMD_SSE4     (1 << 10)\n\n/**\n * Indicates CPU support for the SSE4.2 instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ssetechs=SSE4_2\n */\n#define RETRO_SIMD_SSE42    (1 << 11)\n\n/**\n * Indicates CPU support for the AVX2 instruction set.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#avxnewtechs=AVX2\n */\n#define RETRO_SIMD_AVX2     (1 << 12)\n\n/** Indicates CPU support for the VFPU instruction set. PS2 and PSP only.\n *\n * @see https://pspdev.github.io/vfpu-docs\n */\n#define RETRO_SIMD_VFPU     (1 << 13)\n\n/**\n * Indicates CPU support for Gekko SIMD extensions. GameCube only.\n */\n#define RETRO_SIMD_PS       (1 << 14)\n\n/**\n * Indicates CPU support for AES instructions.\n *\n * @see https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#aestechs=AES&othertechs=AES\n */\n#define RETRO_SIMD_AES      (1 << 15)\n\n/**\n * Indicates CPU support for the VFPv3 instruction set.\n */\n#define RETRO_SIMD_VFPV3    (1 << 16)\n\n/**\n * Indicates CPU support for the VFPv4 instruction set.\n */\n#define RETRO_SIMD_VFPV4    (1 << 17)\n\n/** Indicates CPU support for the POPCNT instruction. */\n#define RETRO_SIMD_POPCNT   (1 << 18)\n\n/** Indicates CPU support for the MOVBE instruction. */\n#define RETRO_SIMD_MOVBE    (1 << 19)\n\n/** Indicates CPU support for the CMOV instruction. */\n#define RETRO_SIMD_CMOV     (1 << 20)\n\n/** Indicates CPU support for the ASIMD instruction set. */\n#define RETRO_SIMD_ASIMD    (1 << 21)\n\n/** Indicates CPU support for the AVX512 instruction set. */\n#define RETRO_SIMD_AVX512   (1 << 22)\n\n/** @} */\n\n/**\n * An abstract unit of ticks.\n *\n * Usually nanoseconds or CPU cycles,\n * but it depends on the platform and the frontend.\n */\ntypedef uint64_t retro_perf_tick_t;\n\n/** Time in microseconds. */\ntypedef int64_t retro_time_t;\n\n/**\n * A performance counter.\n *\n * Use this to measure the execution time of a region of code.\n * @see retro_perf_callback\n */\nstruct retro_perf_counter\n{\n   /**\n    * A human-readable identifier for the counter.\n    *\n    * May be displayed by the frontend.\n    * Behavior is undefined if this is \\c NULL.\n    */\n   const char *ident;\n\n   /**\n    * The time of the most recent call to \\c retro_perf_callback::perf_start\n    * on this performance counter.\n    *\n    * @see retro_perf_start_t\n    */\n   retro_perf_tick_t start;\n\n   /**\n    * The total time spent within this performance counter's measured code,\n    * i.e. between calls to \\c retro_perf_callback::perf_start and \\c retro_perf_callback::perf_stop.\n    *\n    * Updated after each call to \\c retro_perf_callback::perf_stop.\n    * @see retro_perf_stop_t\n    */\n   retro_perf_tick_t total;\n\n   /**\n    * The number of times this performance counter has been started.\n    *\n    * Updated after each call to \\c retro_perf_callback::perf_start.\n    * @see retro_perf_start_t\n    */\n   retro_perf_tick_t call_cnt;\n\n   /**\n    * \\c true if this performance counter has been registered by the frontend.\n    * Must be initialized to \\c false by the core before registering it.\n    * @see retro_perf_register_t\n    */\n   bool registered;\n};\n\n/**\n * @returns The current system time in microseconds.\n * @note Accuracy may vary by platform.\n * The frontend should use the most accurate timer possible.\n * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE\n */\ntypedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);\n\n/**\n * @returns The number of ticks since some unspecified epoch.\n * The exact meaning of a \"tick\" depends on the platform,\n * but it usually refers to nanoseconds or CPU cycles.\n * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE\n */\ntypedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);\n\n/**\n * Returns a bitmask of detected CPU features.\n *\n * Use this for runtime dispatching of CPU-specific code.\n *\n * @returns A bitmask of detected CPU features.\n * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE\n * @see RETRO_SIMD\n */\ntypedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);\n\n/**\n * Asks the frontend to log or display the state of performance counters.\n * How this is done depends on the frontend.\n * Performance counters can be reviewed manually as well.\n *\n * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE\n * @see retro_perf_counter\n */\ntypedef void (RETRO_CALLCONV *retro_perf_log_t)(void);\n\n/**\n * Registers a new performance counter.\n *\n * If \\c counter has already been registered beforehand,\n * this function does nothing.\n *\n * @param counter The counter to register.\n * \\c counter::ident must be set to a unique identifier,\n * and all other values in \\c counter must be set to zero or \\c false.\n * Behavior is undefined if \\c NULL.\n * @post If \\c counter is successfully registered,\n * then \\c counter::registered will be set to \\c true.\n * Otherwise, it will be set to \\c false.\n * Registration may fail if the frontend's maximum number of counters (if any) has been reached.\n * @note The counter is owned by the core and must not be freed by the frontend.\n * The frontend must also clean up any references to a core's performance counters\n * before unloading it, otherwise undefined behavior may occur.\n * @see retro_perf_start_t\n * @see retro_perf_stop_t\n */\ntypedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);\n\n/**\n * Starts a registered performance counter.\n *\n * Call this just before the code you want to measure.\n *\n * @param counter The counter to start.\n * Behavior is undefined if \\c NULL.\n * @see retro_perf_stop_t\n */\ntypedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);\n\n/**\n * Stops a registered performance counter.\n *\n * Call this just after the code you want to measure.\n *\n * @param counter The counter to stop.\n * Behavior is undefined if \\c NULL.\n * @see retro_perf_start_t\n * @see retro_perf_stop_t\n */\ntypedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);\n\n/**\n * An interface that the core can use to get performance information.\n *\n * Here's a usage example:\n *\n * @code{.c}\n * #ifdef PROFILING\n * // Wrapper macros to simplify using performance counters.\n * // Optional; tailor these to your project's needs.\n * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))\n * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))\n * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))\n * #else\n * // Exclude the performance counters if profiling is disabled.\n * #define RETRO_PERFORMANCE_INIT(perf_cb, name) ((void)0)\n * #define RETRO_PERFORMANCE_START(perf_cb, name) ((void)0)\n * #define RETRO_PERFORMANCE_STOP(perf_cb, name) ((void)0)\n * #endif\n *\n * // Defined somewhere else in the core.\n * extern struct retro_perf_callback perf_cb;\n *\n * void retro_run(void)\n * {\n *    RETRO_PERFORMANCE_INIT(cb, interesting);\n *    RETRO_PERFORMANCE_START(cb, interesting);\n *    interesting_work();\n *    RETRO_PERFORMANCE_STOP(cb, interesting);\n *\n *    RETRO_PERFORMANCE_INIT(cb, maybe_slow);\n *    RETRO_PERFORMANCE_START(cb, maybe_slow);\n *    more_interesting_work();\n *    RETRO_PERFORMANCE_STOP(cb, maybe_slow);\n * }\n *\n * void retro_deinit(void)\n * {\n *    // Asks the frontend to log the results of all performance counters.\n *    perf_cb.perf_log();\n * }\n * @endcode\n *\n * All functions are set by the frontend.\n *\n * @see RETRO_ENVIRONMENT_GET_PERF_INTERFACE\n */\nstruct retro_perf_callback\n{\n   /** @copydoc retro_perf_get_time_usec_t */\n   retro_perf_get_time_usec_t    get_time_usec;\n\n   /** @copydoc retro_perf_get_counter_t */\n   retro_get_cpu_features_t      get_cpu_features;\n\n   /** @copydoc retro_perf_get_counter_t */\n   retro_perf_get_counter_t      get_perf_counter;\n\n   /** @copydoc retro_perf_register_t */\n   retro_perf_register_t         perf_register;\n\n   /** @copydoc retro_perf_start_t */\n   retro_perf_start_t            perf_start;\n\n   /** @copydoc retro_perf_stop_t */\n   retro_perf_stop_t             perf_stop;\n\n   /** @copydoc retro_perf_log_t */\n   retro_perf_log_t              perf_log;\n};\n\n/** @} */\n\n/**\n * @defgroup RETRO_SENSOR Sensor Interface\n * @{\n */\n\n/**\n * Defines actions that can be performed on sensors.\n * @note Cores should only enable sensors while they're actively being used;\n * depending on the frontend and platform,\n * enabling these sensors may impact battery life.\n *\n * @see RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE\n * @see retro_sensor_interface\n * @see retro_set_sensor_state_t\n */\nenum retro_sensor_action\n{\n   /** Enables accelerometer input, if one exists. */\n   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,\n\n   /** Disables accelerometer input, if one exists. */\n   RETRO_SENSOR_ACCELEROMETER_DISABLE,\n\n   /** Enables gyroscope input, if one exists. */\n   RETRO_SENSOR_GYROSCOPE_ENABLE,\n\n   /** Disables gyroscope input, if one exists. */\n   RETRO_SENSOR_GYROSCOPE_DISABLE,\n\n   /** Enables ambient light input, if a luminance sensor exists. */\n   RETRO_SENSOR_ILLUMINANCE_ENABLE,\n\n   /** Disables ambient light input, if a luminance sensor exists. */\n   RETRO_SENSOR_ILLUMINANCE_DISABLE,\n\n   /** @private Defined to ensure <tt>sizeof(enum retro_sensor_action) == sizeof(int)</tt>. Do not use. */\n   RETRO_SENSOR_DUMMY = INT_MAX\n};\n\n/** @defgroup RETRO_SENSOR_ID Sensor Value IDs\n * @{\n */\n/* Id values for SENSOR types. */\n\n/**\n * Returns the device's acceleration along its local X axis, in g (standard gravity, 9.80665 m/s^2).\n * Includes the effect of gravity;\n * a device at rest on a table will have values close to 0, 0, 1.\n *\n * Positive values mean that the device is accelerating to the right,\n * assuming the user is looking at it head-on.\n */\n#define RETRO_SENSOR_ACCELEROMETER_X 0\n\n/**\n * Returns the device's acceleration along its local Y axis, in g (standard gravity, 9.80665 m/s^2).\n * Includes the effect of gravity.\n *\n * Positive values mean that the device is accelerating upwards,\n * assuming the user is looking at it head-on.\n */\n#define RETRO_SENSOR_ACCELEROMETER_Y 1\n\n/**\n * Returns the device's acceleration along its local Z axis, in g (standard gravity, 9.80665 m/s^2).\n * Includes the effect of gravity.\n *\n * Positive values indicate forward acceleration towards the user,\n * assuming the user is looking at the device head-on.\n */\n#define RETRO_SENSOR_ACCELEROMETER_Z 2\n\n/**\n * Returns the angular velocity of the device around its local X axis, in radians per second.\n *\n * Positive values indicate counter-clockwise rotation.\n *\n * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.\n * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope\n * for guidance on using this value to derive a device's orientation.\n */\n#define RETRO_SENSOR_GYROSCOPE_X 3\n\n/**\n * Returns the angular velocity of the device around its local Z axis, in radians per second.\n *\n * Positive values indicate counter-clockwise rotation.\n *\n * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.\n * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope\n * for guidance on using this value to derive a device's orientation.\n */\n#define RETRO_SENSOR_GYROSCOPE_Y 4\n\n/**\n * Returns the angular velocity of the device around its local Z axis, in radians per second.\n *\n * Positive values indicate counter-clockwise rotation.\n *\n * @note A radian is about 57 degrees, and a full 360-degree rotation is 2*pi radians.\n * @see https://developer.android.com/reference/android/hardware/SensorEvent#sensor.type_gyroscope\n * for guidance on using this value to derive a device's orientation.\n */\n#define RETRO_SENSOR_GYROSCOPE_Z 5\n\n/**\n * Returns the ambient illuminance (light intensity) of the device's environment, in lux.\n *\n * @see https://en.wikipedia.org/wiki/Lux for a table of common lux values.\n */\n#define RETRO_SENSOR_ILLUMINANCE 6\n/** @} */\n\n/**\n * Adjusts the state of a sensor.\n *\n * @param port The device port of the controller that owns the sensor given in \\c action.\n * @param action The action to perform on the sensor.\n * Different devices support different sensors.\n * @param rate The rate at which the underlying sensor should be updated, in Hz.\n * This should be treated as a hint,\n * as some device sensors may not support the requested rate\n * (if it's configurable at all).\n * @returns \\c true if the sensor state was successfully adjusted, \\c false otherwise.\n * @note If one of the \\c RETRO_SENSOR_*_ENABLE actions fails,\n * this likely means that the given sensor is not available\n * on the provided \\c port.\n * @see retro_sensor_action\n */\ntypedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,\n      enum retro_sensor_action action, unsigned rate);\n\n/**\n * Retrieves the current value reported by sensor.\n * @param port The device port of the controller that owns the sensor given in \\c id.\n * @param id The sensor value to query.\n * @returns The current sensor value.\n * Exact semantics depend on the value given in \\c id,\n * but will return 0 for invalid arguments.\n *\n * @see RETRO_SENSOR_ID\n */\ntypedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);\n\n/**\n * An interface that cores can use to access device sensors.\n *\n * All function pointers are set by the frontend.\n */\nstruct retro_sensor_interface\n{\n   /** @copydoc retro_set_sensor_state_t */\n   retro_set_sensor_state_t set_sensor_state;\n\n   /** @copydoc retro_sensor_get_input_t */\n   retro_sensor_get_input_t get_sensor_input;\n};\n\n/** @} */\n\n/** @defgroup GET_CAMERA_INTERFACE Camera Interface\n * @{\n */\n\n/**\n * Denotes the type of buffer in which the camera will store its input.\n *\n * Different camera drivers may support different buffer types.\n *\n * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE\n * @see retro_camera_callback\n */\nenum retro_camera_buffer\n{\n   /**\n    * Indicates that camera frames should be delivered to the core as an OpenGL texture.\n    *\n    * Requires that the core is using an OpenGL context via \\c RETRO_ENVIRONMENT_SET_HW_RENDER.\n    *\n    * @see retro_camera_frame_opengl_texture_t\n    */\n   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,\n\n   /**\n    * Indicates that camera frames should be delivered to the core as a raw buffer in memory.\n    *\n    * @see retro_camera_frame_raw_framebuffer_t\n    */\n   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,\n\n   /**\n    * @private Defined to ensure <tt>sizeof(enum retro_camera_buffer) == sizeof(int)</tt>.\n    * Do not use.\n    */\n   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX\n};\n\n/**\n * Starts an initialized camera.\n * The camera is disabled by default,\n * and must be enabled with this function before being used.\n *\n * Set by the frontend.\n *\n * @returns \\c true if the camera was successfully started, \\c false otherwise.\n * Failure may occur if no actual camera is available,\n * or if the frontend doesn't have permission to access it.\n * @note Must be called in \\c retro_run().\n * @see retro_camera_callback\n */\ntypedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);\n\n/**\n * Stops the running camera.\n *\n * Set by the frontend.\n *\n * @note Must be called in \\c retro_run().\n * @warning The frontend may close the camera on its own when unloading the core,\n * but this behavior is not guaranteed.\n * Cores should clean up the camera before exiting.\n * @see retro_camera_callback\n */\ntypedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);\n\n/**\n * Called by the frontend to report the state of the camera driver.\n *\n * @see retro_camera_callback\n */\ntypedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);\n\n/**\n * Called by the frontend to report a new camera frame,\n * delivered as a raw buffer in memory.\n *\n * Set by the core.\n *\n * @param buffer Pointer to the camera's most recent video frame.\n * Each pixel is in XRGB8888 format.\n * The first pixel represents the top-left corner of the image\n * (i.e. the Y axis goes downward).\n * @param width The width of the frame given in \\c buffer, in pixels.\n * @param height The height of the frame given in \\c buffer, in pixels.\n * @param pitch The width of the frame given in \\c buffer, in bytes.\n * @warning \\c buffer may be invalidated when this function returns,\n * so the core should make its own copy of \\c buffer if necessary.\n * @see RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER\n */\ntypedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,\n      unsigned width, unsigned height, size_t pitch);\n\n/**\n * Called by the frontend to report a new camera frame,\n * delivered as an OpenGL texture.\n *\n * @param texture_id The ID of the OpenGL texture that represents the camera's most recent frame.\n * Owned by the frontend, and must not be modified by the core.\n * @param texture_target The type of the texture given in \\c texture_id.\n * Usually either \\c GL_TEXTURE_2D or \\c GL_TEXTURE_RECTANGLE,\n * but other types are allowed.\n * @param affine A pointer to a 3x3 column-major affine matrix\n * that can be used to transform pixel coordinates to texture coordinates.\n * After transformation, the bottom-left corner should have coordinates of <tt>(0, 0)</tt>\n * and the top-right corner should have coordinates of <tt>(1, 1)</tt>\n * (or <tt>(width, height)</tt> for \\c GL_TEXTURE_RECTANGLE).\n *\n * @note GL-specific typedefs (e.g. \\c GLfloat and \\c GLuint) are avoided here\n * so that the API doesn't rely on gl.h.\n * @warning \\c texture_id and \\c affine may be invalidated when this function returns,\n * so the core should make its own copy of them if necessary.\n */\ntypedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,\n      unsigned texture_target, const float *affine);\n\n/**\n * An interface that the core can use to access a device's camera.\n *\n * @see RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE\n */\nstruct retro_camera_callback\n{\n   /**\n    * Requested camera capabilities,\n    * given as a bitmask of \\c retro_camera_buffer values.\n    * Set by the core.\n    *\n    * Here's a usage example:\n    * @code\n    * // Requesting support for camera data delivered as both an OpenGL texture and a pixel buffer:\n    * struct retro_camera_callback callback;\n    * callback.caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER);\n    * @endcode\n    */\n   uint64_t caps;\n\n   /**\n    * The desired width of the camera frame, in pixels.\n    * This is only a hint; the frontend may provide a different size.\n    * Set by the core.\n    * Use zero to let the frontend decide.\n    */\n   unsigned width;\n\n   /**\n    * The desired height of the camera frame, in pixels.\n    * This is only a hint; the frontend may provide a different size.\n     * Set by the core.\n    * Use zero to let the frontend decide.\n    */\n   unsigned height;\n\n   /**\n    * @copydoc retro_camera_start_t\n    * @see retro_camera_callback\n    */\n   retro_camera_start_t start;\n\n   /**\n    * @copydoc retro_camera_stop_t\n    * @see retro_camera_callback\n    */\n   retro_camera_stop_t stop;\n\n   /**\n    * @copydoc retro_camera_frame_raw_framebuffer_t\n    * @note If \\c NULL, this function will not be called.\n    */\n   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;\n\n   /**\n    * @copydoc retro_camera_frame_opengl_texture_t\n    * @note If \\c NULL, this function will not be called.\n    */\n   retro_camera_frame_opengl_texture_t frame_opengl_texture;\n\n   /**\n    * Core-defined callback invoked by the frontend right after the camera driver is initialized\n    * (\\em not when calling \\c start).\n    * May be \\c NULL, in which case this function is skipped.\n    */\n   retro_camera_lifetime_status_t initialized;\n\n   /**\n    * Core-defined callback invoked by the frontend\n    * right before the video camera driver is deinitialized\n    * (\\em not when calling \\c stop).\n    * May be \\c NULL, in which case this function is skipped.\n    */\n   retro_camera_lifetime_status_t deinitialized;\n};\n\n/** @} */\n\n/** @defgroup GET_LOCATION_INTERFACE Location Interface\n * @{\n */\n\n/** @copydoc retro_location_callback::set_interval */\ntypedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,\n      unsigned interval_distance);\n\n/** @copydoc retro_location_callback::start */\ntypedef bool (RETRO_CALLCONV *retro_location_start_t)(void);\n\n/** @copydoc retro_location_callback::stop */\ntypedef void (RETRO_CALLCONV *retro_location_stop_t)(void);\n\n/** @copydoc retro_location_callback::get_position */\ntypedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,\n      double *horiz_accuracy, double *vert_accuracy);\n\n/** Function type that reports the status of the location service. */\ntypedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);\n\n/**\n * An interface that the core can use to access a device's location.\n *\n * @note It is the frontend's responsibility to request the necessary permissions\n * from the operating system.\n * @see RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE\n */\nstruct retro_location_callback\n{\n   /**\n    * Starts listening the device's location service.\n    *\n    * The frontend will report changes to the device's location\n    * at the interval defined by \\c set_interval.\n    * Set by the frontend.\n    *\n    * @return true if location services were successfully started, false otherwise.\n    * Note that this will return \\c false if location services are disabled\n    * or the frontend doesn't have permission to use them.\n    * @note The device's location service may or may not have been enabled\n    * before the core calls this function.\n    */\n   retro_location_start_t         start;\n\n   /**\n    * Stop listening to the device's location service.\n    *\n    * Set by the frontend.\n    *\n    * @note The location service itself may or may not\n    * be turned off by this function,\n    * depending on the platform and the frontend.\n    * @post The core will stop receiving location service updates.\n    */\n   retro_location_stop_t          stop;\n\n   /**\n    * Returns the device's current coordinates.\n    *\n    * Set by the frontend.\n    *\n    * @param[out] lat Pointer to latitude, in degrees.\n    * Will be set to 0 if no change has occurred since the last call.\n    * Behavior is undefined if \\c NULL.\n    * @param[out] lon Pointer to longitude, in degrees.\n    * Will be set to 0 if no change has occurred since the last call.\n    * Behavior is undefined if \\c NULL.\n    * @param[out] horiz_accuracy Pointer to horizontal accuracy.\n    * Will be set to 0 if no change has occurred since the last call.\n    * Behavior is undefined if \\c NULL.\n    * @param[out] vert_accuracy Pointer to vertical accuracy.\n    * Will be set to 0 if no change has occurred since the last call.\n    * Behavior is undefined if \\c NULL.\n    */\n   retro_location_get_position_t  get_position;\n\n   /**\n    * Sets the rate at which the location service should report updates.\n    *\n    * This is only a hint; the actual rate may differ.\n    * Sets the interval of time and/or distance at which to update/poll\n    * location-based data.\n    *\n    * Some platforms may only support one of the two parameters;\n    * cores should provide both to ensure compatibility.\n    *\n    * Set by the frontend.\n    *\n    * @param interval_ms The desired period of time between location updates, in milliseconds.\n    * @param interval_distance The desired distance between location updates, in meters.\n    */\n   retro_location_set_interval_t  set_interval;\n\n   /** Called when the location service is initialized. Set by the core. Optional. */\n   retro_location_lifetime_status_t initialized;\n\n   /** Called when the location service is deinitialized. Set by the core. Optional. */\n   retro_location_lifetime_status_t deinitialized;\n};\n\n/** @} */\n\n/** @addtogroup GET_RUMBLE_INTERFACE\n * @{ */\n\n/**\n * The type of rumble motor in a controller.\n *\n * Both motors can be controlled independently,\n * and the strong motor does not override the weak motor.\n * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE\n */\nenum retro_rumble_effect\n{\n   RETRO_RUMBLE_STRONG = 0,\n   RETRO_RUMBLE_WEAK = 1,\n\n   /** @private Defined to ensure <tt>sizeof(enum retro_rumble_effect) == sizeof(int)</tt>. Do not use. */\n   RETRO_RUMBLE_DUMMY = INT_MAX\n};\n\n/**\n * Requests a rumble state change for a controller.\n * Set by the frontend.\n *\n * @param port The controller port to set the rumble state for.\n * @param effect The rumble motor to set the strength of.\n * @param strength The desired intensity of the rumble motor, ranging from \\c 0 to \\c 0xffff (inclusive).\n * @return \\c true if the requested rumble state was honored.\n * If the controller doesn't support rumble, will return \\c false.\n * @note Calling this before the first \\c retro_run() may return \\c false.\n * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE\n */\ntypedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,\n      enum retro_rumble_effect effect, uint16_t strength);\n\n/**\n * An interface that the core can use to set the rumble state of a controller.\n * @see RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE\n */\nstruct retro_rumble_interface\n{\n   /** @copydoc retro_set_rumble_state_t */\n   retro_set_rumble_state_t set_rumble_state;\n};\n\n/** @} */\n\n/**\n * Called by the frontend to request audio samples.\n * The core should render audio within this function\n * using the callback provided by \\c retro_set_audio_sample or \\c retro_set_audio_sample_batch.\n *\n * @warning This function may be called by any thread,\n * therefore it must be thread-safe.\n * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK\n * @see retro_audio_callback\n * @see retro_audio_sample_batch_t\n * @see retro_audio_sample_t\n */\ntypedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);\n\n/**\n * Called by the frontend to notify the core that it should pause or resume audio rendering.\n * The initial state of the audio driver after registering this callback is \\c false (inactive).\n *\n * @param enabled \\c true if the frontend's audio driver is active.\n * If so, the registered audio callback will be called regularly.\n * If not, the audio callback will not be invoked until the next time\n * the frontend calls this function with \\c true.\n * @warning This function may be called by any thread,\n * therefore it must be thread-safe.\n * @note Even if no audio samples are rendered,\n * the core should continue to update its emulated platform's audio engine if necessary.\n * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK\n * @see retro_audio_callback\n * @see retro_audio_callback_t\n */\ntypedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);\n\n/**\n * An interface that the frontend uses to request audio samples from the core.\n * @note To unregister a callback, pass a \\c retro_audio_callback_t\n * with both fields set to <tt>NULL</tt>.\n * @see RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK\n */\nstruct retro_audio_callback\n{\n   /** @see retro_audio_callback_t */\n   retro_audio_callback_t callback;\n\n   /** @see retro_audio_set_state_callback_t */\n   retro_audio_set_state_callback_t set_state;\n};\n\ntypedef int64_t retro_usec_t;\n\n/**\n * Called right before each iteration of \\c retro_run\n * if registered via <tt>RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK</tt>.\n *\n * @param usec Time since the last call to <tt>retro_run</tt>, in microseconds.\n * If the frontend is manipulating the frame time\n * (e.g. via fast-forward or slow motion),\n * this value will be the reference value initially provided to the environment call.\n * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK\n * @see retro_frame_time_callback\n */\ntypedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);\n\n/**\n * @see RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK\n */\nstruct retro_frame_time_callback\n{\n   /**\n    * Called to notify the core of the current frame time.\n    * If <tt>NULL</tt>, the frontend will clear its registered callback.\n    */\n   retro_frame_time_callback_t callback;\n\n   /**\n    * The ideal duration of one frame, in microseconds.\n    * Compute it as <tt>1000000 / fps</tt>.\n    * The frontend will resolve rounding to ensure that framestepping, etc is exact.\n    */\n   retro_usec_t reference;\n};\n\n/** @defgroup SET_AUDIO_BUFFER_STATUS_CALLBACK Audio Buffer Occupancy\n * @{\n */\n\n/**\n * Notifies a libretro core of how full the frontend's audio buffer is.\n * Set by the core, called by the frontend.\n * It will be called right before \\c retro_run() every frame.\n *\n * @param active \\c true if the frontend's audio buffer is currently in use,\n * \\c false if audio is disabled in the frontend.\n * @param occupancy A value between 0 and 100 (inclusive),\n * corresponding to the frontend's audio buffer occupancy percentage.\n * @param underrun_likely \\c true if the frontend expects an audio buffer underrun\n * during the next frame, which indicates that a core should attempt frame-skipping.\n */\ntypedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(\n      bool active, unsigned occupancy, bool underrun_likely);\n\n/**\n * A callback to register with the frontend to receive audio buffer occupancy information.\n */\nstruct retro_audio_buffer_status_callback\n{\n   /** @copydoc retro_audio_buffer_status_callback_t */\n   retro_audio_buffer_status_callback_t callback;\n};\n\n/** @} */\n\n/* Pass this to retro_video_refresh_t if rendering to hardware.\n * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.\n * */\n#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)\n\n/* Invalidates the current HW context.\n * Any GL state is lost, and must not be deinitialized explicitly.\n * If explicit deinitialization is desired by the libretro core,\n * it should implement context_destroy callback.\n * If called, all GPU resources must be reinitialized.\n * Usually called when frontend reinits video driver.\n * Also called first time video driver is initialized,\n * allowing libretro core to initialize resources.\n */\ntypedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);\n\n/* Gets current framebuffer which is to be rendered to.\n * Could change every frame potentially.\n */\ntypedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);\n\n/* Get a symbol from HW context. */\ntypedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);\n\nenum retro_hw_context_type\n{\n   RETRO_HW_CONTEXT_NONE             = 0,\n   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */\n   RETRO_HW_CONTEXT_OPENGL           = 1,\n   /* OpenGL ES 2.0. */\n   RETRO_HW_CONTEXT_OPENGLES2        = 2,\n   /* Modern desktop core GL context. Use version_major/\n    * version_minor fields to set GL version. */\n   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,\n   /* OpenGL ES 3.0 */\n   RETRO_HW_CONTEXT_OPENGLES3        = 4,\n   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,\n    * use the corresponding enums directly. */\n   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,\n\n   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */\n   RETRO_HW_CONTEXT_VULKAN           = 6,\n\n   /* Direct3D11, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */\n   RETRO_HW_CONTEXT_D3D11            = 7,\n\n   /* Direct3D10, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */\n   RETRO_HW_CONTEXT_D3D10            = 8,\n\n   /* Direct3D12, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */\n   RETRO_HW_CONTEXT_D3D12            = 9,\n\n   /* Direct3D9, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */\n   RETRO_HW_CONTEXT_D3D9             = 10,\n\n   /** Dummy value to ensure sizeof(enum retro_hw_context_type) == sizeof(int). Do not use. */\n   RETRO_HW_CONTEXT_DUMMY = INT_MAX\n};\n\nstruct retro_hw_render_callback\n{\n   /* Which API to use. Set by libretro core. */\n   enum retro_hw_context_type context_type;\n\n   /* Called when a context has been created or when it has been reset.\n    * An OpenGL context is only valid after context_reset() has been called.\n    *\n    * When context_reset is called, OpenGL resources in the libretro\n    * implementation are guaranteed to be invalid.\n    *\n    * It is possible that context_reset is called multiple times during an\n    * application lifecycle.\n    * If context_reset is called without any notification (context_destroy),\n    * the OpenGL context was lost and resources should just be recreated\n    * without any attempt to \"free\" old resources.\n    */\n   retro_hw_context_reset_t context_reset;\n\n   /* Set by frontend.\n    * TODO: This is rather obsolete. The frontend should not\n    * be providing preallocated framebuffers. */\n   retro_hw_get_current_framebuffer_t get_current_framebuffer;\n\n   /* Set by frontend.\n    * Can return all relevant functions, including glClear on Windows. */\n   retro_hw_get_proc_address_t get_proc_address;\n\n   /* Set if render buffers should have depth component attached.\n    * TODO: Obsolete. */\n   bool depth;\n\n   /* Set if stencil buffers should be attached.\n    * TODO: Obsolete. */\n   bool stencil;\n\n   /* If depth and stencil are true, a packed 24/8 buffer will be added.\n    * Only attaching stencil is invalid and will be ignored. */\n\n   /* Use conventional bottom-left origin convention. If false,\n    * standard libretro top-left origin semantics are used.\n    * TODO: Move to GL specific interface. */\n   bool bottom_left_origin;\n\n   /* Major version number for core GL context or GLES 3.1+. */\n   unsigned version_major;\n\n   /* Minor version number for core GL context or GLES 3.1+. */\n   unsigned version_minor;\n\n   /* If this is true, the frontend will go very far to avoid\n    * resetting context in scenarios like toggling fullscreen, etc.\n    * TODO: Obsolete? Maybe frontend should just always assume this ...\n    */\n   bool cache_context;\n\n   /* The reset callback might still be called in extreme situations\n    * such as if the context is lost beyond recovery.\n    *\n    * For optimal stability, set this to false, and allow context to be\n    * reset at any time.\n    */\n\n   /* A callback to be called before the context is destroyed in a\n    * controlled way by the frontend. */\n   retro_hw_context_reset_t context_destroy;\n\n   /* OpenGL resources can be deinitialized cleanly at this step.\n    * context_destroy can be set to NULL, in which resources will\n    * just be destroyed without any notification.\n    *\n    * Even when context_destroy is non-NULL, it is possible that\n    * context_reset is called without any destroy notification.\n    * This happens if context is lost by external factors (such as\n    * notified by GL_ARB_robustness).\n    *\n    * In this case, the context is assumed to be already dead,\n    * and the libretro implementation must not try to free any OpenGL\n    * resources in the subsequent context_reset.\n    */\n\n   /* Creates a debug context. */\n   bool debug_context;\n};\n\n/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.\n * Called by the frontend in response to keyboard events.\n * down is set if the key is being pressed, or false if it is being released.\n * keycode is the RETROK value of the char.\n * character is the text character of the pressed key. (UTF-32).\n * key_modifiers is a set of RETROKMOD values or'ed together.\n *\n * The pressed/keycode state can be independent of the character.\n * It is also possible that multiple characters are generated from a\n * single keypress.\n * Keycode events should be treated separately from character events.\n * However, when possible, the frontend should try to synchronize these.\n * If only a character is posted, keycode should be RETROK_UNKNOWN.\n *\n * Similarly if only a keycode event is generated with no corresponding\n * character, character should be 0.\n */\ntypedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,\n      uint32_t character, uint16_t key_modifiers);\n\nstruct retro_keyboard_callback\n{\n   retro_keyboard_event_t callback;\n};\n\n/** @defgroup SET_DISK_CONTROL_INTERFACE Disk Control\n *\n * Callbacks for inserting and removing disks from the emulated console at runtime.\n * Should be provided by cores that support doing so.\n * Cores should automate this process if possible,\n * but some cases require the player's manual input.\n *\n * The steps for swapping disk images are generally as follows:\n *\n * \\li Eject the emulated console's disk drive with \\c set_eject_state(true).\n * \\li Insert the new disk image with \\c set_image_index(index).\n * \\li Close the virtual disk tray with \\c set_eject_state(false).\n *\n * @{\n */\n\n/**\n * Called by the frontend to open or close the emulated console's virtual disk tray.\n *\n * The frontend may only set the disk image index\n * while the emulated tray is opened.\n *\n * If the emulated console's disk tray is already in the state given by \\c ejected,\n * then this function should return \\c true without doing anything.\n * The core should return \\c false if it couldn't change the disk tray's state;\n * this may happen if the console itself limits when the disk tray can be open or closed\n * (e.g. to wait for the disc to stop spinning).\n *\n * @param ejected \\c true if the virtual disk tray should be \"ejected\",\n * \\c false if it should be \"closed\".\n * @return \\c true if the virtual disk tray's state has been set to the given state,\n * false if there was an error.\n * @see retro_get_eject_state_t\n */\ntypedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);\n\n/**\n * Gets the current ejected state of the disk drive.\n * The initial state is closed, i.e. \\c false.\n *\n * @return \\c true if the virtual disk tray is \"ejected\",\n * i.e. it's open and a disk can be inserted.\n * @see retro_set_eject_state_t\n */\ntypedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);\n\n/**\n * Gets the index of the current disk image,\n * as determined by however the frontend orders disk images\n * (such as m3u-formatted playlists or special directories).\n *\n * @return The index of the current disk image\n * (starting with 0 for the first disk),\n * or a value greater than or equal to \\c get_num_images() if no disk is inserted.\n * @see retro_get_num_images_t\n */\ntypedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);\n\n/**\n * Inserts the disk image at the given index into the emulated console's drive.\n * Can only be called while the disk tray is ejected\n * (i.e. \\c retro_get_eject_state_t returns \\c true).\n *\n * If the emulated disk tray is ejected\n * and already contains the disk image named by \\c index,\n * then this function should do nothing and return \\c true.\n *\n * @param index The index of the disk image to insert,\n * starting from 0 for the first disk.\n * A value greater than or equal to \\c get_num_images()\n * represents the frontend removing the disk without inserting a new one.\n * @return \\c true if the disk image was successfully set.\n * \\c false if the disk tray isn't ejected or there was another error\n * inserting a new disk image.\n */\ntypedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);\n\n/**\n * @return The number of disk images which are available to use.\n * These are most likely defined in a playlist file.\n */\ntypedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);\n\nstruct retro_game_info;\n\n/**\n * Replaces the disk image at the given index with a new disk.\n *\n * Replaces the disk image associated with index.\n * Arguments to pass in info have same requirements as retro_load_game().\n * Virtual disk tray must be ejected when calling this.\n *\n * Passing \\c NULL to this function indicates\n * that the frontend has removed this disk image from its internal list.\n * As a result, calls to this function can change the number of available disk indexes.\n *\n * For example, calling <tt>replace_image_index(1, NULL)</tt>\n * will remove the disk image at index 1,\n * and the disk image at index 2 (if any)\n * will be moved to the newly-available index 1.\n *\n * @param index The index of the disk image to replace.\n * @param info Details about the new disk image,\n * or \\c NULL if the disk image at the given index should be discarded.\n * The semantics of each field are the same as in \\c retro_load_game.\n * @return \\c true if the disk image was successfully replaced\n * or removed from the playlist,\n * \\c false if the tray is not ejected\n * or if there was an error.\n */\ntypedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,\n      const struct retro_game_info *info);\n\n/**\n * Adds a new index to the core's internal disk list.\n * This will increment the return value from \\c get_num_images() by 1.\n * This image index cannot be used until a disk image has been set\n * with \\c replace_image_index.\n *\n * @return \\c true if the core has added space for a new disk image\n * and is ready to receive one.\n */\ntypedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);\n\n/**\n * Sets the disk image that will be inserted into the emulated disk drive\n * before \\c retro_load_game is called.\n *\n * \\c retro_load_game does not provide a way to ensure\n * that a particular disk image in a playlist is inserted into the console;\n * this function makes up for that.\n * Frontends should call it immediately before \\c retro_load_game,\n * and the core should use the arguments\n * to validate the disk image in \\c retro_load_game.\n *\n * When content is loaded, the core should verify that the\n * disk specified by \\c index can be found at \\c path.\n * This is to guard against auto-selecting the wrong image\n * if (for example) the user should modify an existing M3U playlist.\n * We have to let the core handle this because\n * \\c set_initial_image() must be called before loading content,\n * i.e. the frontend cannot access image paths in advance\n * and thus cannot perform the error check itself.\n * If \\c index is invalid (i.e. <tt>index >= get_num_images()</tt>)\n * or the disk image doesn't match the value given in \\c path,\n * the core should ignore the arguments\n * and insert the disk at index 0 into the virtual disk tray.\n *\n * @warning If \\c RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE is called within \\c retro_load_game,\n * then this function may not be executed.\n * Set the disk control interface in \\c retro_init if possible.\n *\n * @param index The index of the disk image within the playlist to set.\n * @param path The path of the disk image to set as the first.\n * The core should not load this path immediately;\n * instead, it should use it within \\c retro_load_game\n * to verify that the correct disk image was loaded.\n * @return \\c true if the initial disk index was set,\n * \\c false if the arguments are invalid\n * or the core doesn't support this function.\n */\ntypedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);\n\n/**\n * Returns the path of the disk image at the given index\n * on the host's file system.\n *\n * @param index The index of the disk image to get the path of.\n * @param s A buffer to store the path in.\n * @param len The size of \\c s, in bytes.\n * @return \\c true if the disk image's location was successfully\n * queried and copied into \\c s,\n * \\c false if the index is invalid\n * or the core couldn't locate the disk image.\n */\ntypedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *s, size_t len);\n\n/**\n * Returns a friendly label for the given disk image.\n *\n * In the simplest case, this may be the disk image's file name\n * with the extension omitted.\n * For cores or games with more complex content requirements,\n * the label can be used to provide information to help the player\n * select a disk image to insert;\n * for example, a core may label different kinds of disks\n * (save data, level disk, installation disk, bonus content, etc.).\n * with names that correspond to in-game prompts,\n * so that the frontend can provide better guidance to the player.\n *\n * @param index The index of the disk image to return a label for.\n * @param s A buffer to store the resulting label in.\n * @param len The length of \\c s, in bytes.\n * @return \\c true if the disk image at \\c index is valid\n * and a label was copied into \\c s.\n */\ntypedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *s, size_t len);\n\n/**\n * An interface that the frontend can use to exchange disks\n * within the emulated console's disk drive.\n *\n * All function pointers are required.\n *\n * @deprecated This struct is superseded by \\ref retro_disk_control_ext_callback.\n * Only use this one to maintain compatibility\n * with older cores and frontends.\n *\n * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE\n * @see retro_disk_control_ext_callback\n */\nstruct retro_disk_control_callback\n{\n   /** @copydoc retro_set_eject_state_t */\n   retro_set_eject_state_t set_eject_state;\n\n   /** @copydoc retro_get_eject_state_t */\n   retro_get_eject_state_t get_eject_state;\n\n   /** @copydoc retro_get_image_index_t */\n   retro_get_image_index_t get_image_index;\n\n   /** @copydoc retro_set_image_index_t */\n   retro_set_image_index_t set_image_index;\n\n   /** @copydoc retro_get_num_images_t */\n   retro_get_num_images_t  get_num_images;\n\n   /** @copydoc retro_replace_image_index_t */\n   retro_replace_image_index_t replace_image_index;\n\n   /** @copydoc retro_add_image_index_t */\n   retro_add_image_index_t add_image_index;\n};\n\n/**\n * @copybrief retro_disk_control_callback\n *\n * All function pointers are required unless otherwise noted.\n *\n * @see RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE\n */\nstruct retro_disk_control_ext_callback\n{\n   /** @copydoc retro_set_eject_state_t */\n   retro_set_eject_state_t set_eject_state;\n\n   /** @copydoc retro_get_eject_state_t */\n   retro_get_eject_state_t get_eject_state;\n\n   /** @copydoc retro_get_image_index_t */\n   retro_get_image_index_t get_image_index;\n\n   /** @copydoc retro_set_image_index_t */\n   retro_set_image_index_t set_image_index;\n\n   /** @copydoc retro_get_num_images_t */\n   retro_get_num_images_t  get_num_images;\n\n   /** @copydoc retro_replace_image_index_t */\n   retro_replace_image_index_t replace_image_index;\n\n   /** @copydoc retro_add_image_index_t */\n   retro_add_image_index_t add_image_index;\n\n   /** @copydoc retro_set_initial_image_t\n    *\n    * Optional; not called if \\c NULL.\n    *\n    * @note The frontend will only try to record/restore the last-used disk index\n    * if both \\c set_initial_image and \\c get_image_path are implemented.\n    */\n   retro_set_initial_image_t set_initial_image;\n\n   /**\n    * @copydoc retro_get_image_path_t\n    *\n    * Optional; not called if \\c NULL.\n    */\n   retro_get_image_path_t get_image_path;\n\n   /**\n    * @copydoc retro_get_image_label_t\n    *\n    * Optional; not called if \\c NULL.\n    */\n   retro_get_image_label_t get_image_label;\n};\n\n/** @} */\n\n/* Definitions for RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE.\n * A core can set it if sending and receiving custom network packets\n * during a multiplayer session is desired.\n */\n\n/* Netpacket flags for retro_netpacket_send_t */\n#define RETRO_NETPACKET_UNRELIABLE  0        /* Packet to be sent unreliable, depending on network quality it might not arrive. */\n#define RETRO_NETPACKET_RELIABLE    (1 << 0) /* Reliable packets are guaranteed to arrive at the target in the order they were sent. */\n#define RETRO_NETPACKET_UNSEQUENCED (1 << 1) /* Packet will not be sequenced with other packets and may arrive out of order. Cannot be set on reliable packets. */\n#define RETRO_NETPACKET_FLUSH_HINT  (1 << 2) /* Request the packet and any previously buffered ones to be sent immediately */\n\n/* Broadcast client_id for retro_netpacket_send_t */\n#define RETRO_NETPACKET_BROADCAST 0xFFFF\n\n/* Used by the core to send a packet to one or all connected players.\n * A single packet sent via this interface can contain up to 64 KB of data.\n *\n * The client_id RETRO_NETPACKET_BROADCAST sends the packet as a broadcast to\n * all connected players. This is supported from the host as well as clients.\n*  Otherwise, the argument indicates the player to send the packet to.\n *\n * A frontend must support sending reliable packets (RETRO_NETPACKET_RELIABLE).\n * Unreliable packets might not be supported by the frontend, but the flags can\n * still be specified. Reliable transmission will be used instead.\n *\n * Calling this with the flag RETRO_NETPACKET_FLUSH_HINT will send off the\n * packet and any previously buffered ones immediately and without blocking.\n * To only flush previously queued packets, buf or len can be passed as NULL/0.\n *\n * This function is not guaranteed to be thread-safe and must be called during\n * retro_run or any of the netpacket callbacks passed with this interface.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_send_t)(int flags, const void* buf, size_t len, uint16_t client_id);\n\n/* Optionally read any incoming packets without waiting for the end of the\n * frame. While polling, retro_netpacket_receive_t and retro_netpacket_stop_t\n * can be called. The core can perform this in a loop to do a blocking read,\n * i.e., wait for incoming data, but needs to handle stop getting called and\n * also give up after a short while to avoid freezing on a connection problem.\n * It is a good idea to manually flush outgoing packets before calling this.\n *\n * This function is not guaranteed to be thread-safe and must be called during\n * retro_run or any of the netpacket callbacks passed with this interface.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_poll_receive_t)(void);\n\n/* Called by the frontend to signify that a multiplayer session has started.\n * If client_id is 0 the local player is the host of the session and at this\n * point no other player has connected yet.\n *\n * If client_id is > 0 the local player is a client connected to a host and\n * at this point is already fully connected to the host.\n *\n * The core must store the function pointer send_fn and use it whenever it\n * wants to send a packet. Optionally poll_receive_fn can be stored and used\n * when regular receiving between frames is not enough. These function pointers\n * remain valid until the frontend calls retro_netpacket_stop_t.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_start_t)(uint16_t client_id, retro_netpacket_send_t send_fn, retro_netpacket_poll_receive_t poll_receive_fn);\n\n/* Called by the frontend when a new packet arrives which has been sent from\n * another player with retro_netpacket_send_t. The client_id argument indicates\n * who has sent the packet.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_receive_t)(const void* buf, size_t len, uint16_t client_id);\n\n/* Called by the frontend when the multiplayer session has ended.\n * Once this gets called the function pointers passed to\n * retro_netpacket_start_t will not be valid anymore.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_stop_t)(void);\n\n/* Called by the frontend every frame (between calls to retro_run while\n * updating the state of the multiplayer session.\n * This is a good place for the core to call retro_netpacket_send_t from.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_poll_t)(void);\n\n/* Called by the frontend when a new player connects to the hosted session.\n * This is only called on the host side, not for clients connected to the host.\n * If this function returns false, the newly connected player gets dropped.\n * This can be used for example to limit the number of players.\n */\ntypedef bool (RETRO_CALLCONV *retro_netpacket_connected_t)(uint16_t client_id);\n\n/* Called by the frontend when a player leaves or disconnects from the hosted session.\n * This is only called on the host side, not for clients connected to the host.\n */\ntypedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id);\n\n/**\n * A callback interface for giving a core the ability to send and receive custom\n * network packets during a multiplayer session between two or more instances\n * of a libretro frontend.\n *\n * Normally during connection handshake the frontend will compare library_version\n * used by both parties and show a warning if there is a difference. When the core\n * supplies protocol_version, the frontend will check against this instead.\n *\n * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE\n */\nstruct retro_netpacket_callback\n{\n   retro_netpacket_start_t        start;\n   retro_netpacket_receive_t      receive;\n   retro_netpacket_stop_t         stop;         /* Optional - may be NULL */\n   retro_netpacket_poll_t         poll;         /* Optional - may be NULL */\n   retro_netpacket_connected_t    connected;    /* Optional - may be NULL */\n   retro_netpacket_disconnected_t disconnected; /* Optional - may be NULL */\n   const char* protocol_version; /* Optional - if not NULL will be used instead of core version to decide if communication is compatible */\n};\n\n/**\n * The pixel format used for rendering.\n * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT\n */\nenum retro_pixel_format\n{\n   /**\n    * 0RGB1555, native endian.\n    * Used as the default if \\c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT is not called.\n    * The most significant bit must be set to 0.\n    * @deprecated This format remains supported to maintain compatibility.\n    * New code should use <tt>RETRO_PIXEL_FORMAT_RGB565</tt> instead.\n    * @see RETRO_PIXEL_FORMAT_RGB565\n    */\n   RETRO_PIXEL_FORMAT_0RGB1555 = 0,\n\n   /**\n    * XRGB8888, native endian.\n    * The most significant byte (the <tt>X</tt>) is ignored.\n    */\n   RETRO_PIXEL_FORMAT_XRGB8888 = 1,\n\n   /**\n    * RGB565, native endian.\n    * This format is recommended if 16-bit pixels are desired,\n    * as it is available on a variety of devices and APIs.\n    */\n   RETRO_PIXEL_FORMAT_RGB565   = 2,\n\n   /** Defined to ensure that <tt>sizeof(retro_pixel_format) == sizeof(int)</tt>. Do not use. */\n   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX\n};\n\n/** @defgroup GET_SAVESTATE_CONTEXT Savestate Context\n * @{\n */\n\n/**\n * Details about how the frontend will use savestates.\n *\n * @see RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT\n * @see retro_serialize\n */\nenum retro_savestate_context\n{\n   /**\n    * Standard savestate written to disk.\n    * May be loaded at any time,\n    * even in a separate session or on another device.\n    *\n    * Should not contain any pointers to code or data.\n    */\n   RETRO_SAVESTATE_CONTEXT_NORMAL                 = 0,\n\n   /**\n    * The savestate is guaranteed to be loaded\n    * within the same session, address space, and binary.\n    * Will not be written to disk or sent over the network;\n    * therefore, internal pointers to code or data are acceptable.\n    * May still be loaded or saved at any time.\n    *\n    * @note This context generally implies the use of runahead or rewinding,\n    * which may work by taking savestates multiple times per second.\n    * Savestate code that runs in this context should be fast.\n    */\n   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE = 1,\n\n   /**\n    * The savestate is guaranteed to be loaded\n    * in the same session and by the same binary,\n    * but possibly by a different address space\n    * (e.g. for \"second instance\" runahead)\n    *\n    * Will not be written to disk or sent over the network,\n    * but may be loaded in a different address space.\n    * Therefore, the savestate <em>must not</em> contain pointers.\n    */\n   RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY   = 2,\n\n   /**\n    * The savestate will not be written to disk,\n    * but no other guarantees are made.\n    * The savestate will almost certainly be loaded\n    * by a separate binary, device, and address space.\n    *\n    * This context is intended for use with frontends that support rollback netplay.\n    * Serialized state should omit any data that would unnecessarily increase bandwidth usage.\n    * Must not contain pointers, and integers must be saved in big-endian format.\n    * @see retro_endianness.h\n    * @see network_stream\n    */\n   RETRO_SAVESTATE_CONTEXT_ROLLBACK_NETPLAY       = 3,\n\n   /**\n    * @private Defined to ensure <tt>sizeof(retro_savestate_context) == sizeof(int)</tt>.\n    * Do not use.\n    */\n   RETRO_SAVESTATE_CONTEXT_UNKNOWN                = INT_MAX\n};\n\n/** @} */\n\n/** @defgroup SET_MESSAGE User-Visible Messages\n *\n * @{\n */\n\n/**\n * Defines a message that the frontend will display to the user,\n * as determined by <tt>RETRO_ENVIRONMENT_SET_MESSAGE</tt>.\n *\n * @deprecated This struct is superseded by \\ref retro_message_ext,\n * which provides more control over how a message is presented.\n * Only use it for compatibility with older cores and frontends.\n *\n * @see RETRO_ENVIRONMENT_SET_MESSAGE\n * @see retro_message_ext\n */\nstruct retro_message\n{\n   /**\n    * Null-terminated message to be displayed.\n    * If \\c NULL or empty, the message will be ignored.\n    */\n   const char *msg;\n\n   /** Duration to display \\c msg in frames. */\n   unsigned    frames;\n};\n\n/**\n * The method that the frontend will use to display a message to the player.\n * @see retro_message_ext\n */\nenum retro_message_target\n{\n   /**\n    * Indicates that the frontend should display the given message\n    * using all other targets defined by \\c retro_message_target at once.\n    */\n   RETRO_MESSAGE_TARGET_ALL = 0,\n\n   /**\n    * Indicates that the frontend should display the given message\n    * using the frontend's on-screen display, if available.\n    *\n    * @attention If the frontend allows players to customize or disable notifications,\n    * then they may not see messages sent to this target.\n    */\n   RETRO_MESSAGE_TARGET_OSD,\n\n   /**\n    * Indicates that the frontend should log the message\n    * via its usual logging mechanism, if available.\n    *\n    * This is not intended to be a substitute for \\c RETRO_ENVIRONMENT_SET_LOG_INTERFACE.\n    * It is intended for the common use case of\n    * logging a player-facing message.\n    *\n    * This target should not be used for messages\n    * of type \\c RETRO_MESSAGE_TYPE_STATUS or \\c RETRO_MESSAGE_TYPE_PROGRESS,\n    * as it may add unnecessary noise to a log file.\n    *\n    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE\n    */\n   RETRO_MESSAGE_TARGET_LOG\n};\n\n/**\n * A broad category for the type of message that the frontend will display.\n *\n * Each message type has its own use case,\n * therefore the frontend should present each one differently.\n *\n * @note This is a hint that the frontend may ignore.\n * The frontend should fall back to \\c RETRO_MESSAGE_TYPE_NOTIFICATION\n * for message types that it doesn't support.\n */\nenum retro_message_type\n{\n   /**\n    * A standard on-screen message.\n    *\n    * Suitable for a variety of use cases,\n    * such as messages about errors\n    * or other important events.\n    *\n    * Frontends that display their own messages\n    * should display this type of core-generated message the same way.\n    */\n   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,\n\n   /**\n    * An on-screen message that should be visually distinct\n    * from \\c RETRO_MESSAGE_TYPE_NOTIFICATION messages.\n    *\n    * The exact meaning of \"visually distinct\" is left to the frontend,\n    * but this usually implies that the frontend shows the message\n    * in a way that it doesn't typically use for its own notices.\n    */\n   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,\n\n   /**\n    * Indicates a frequently-updated status display,\n    * rather than a standard notification.\n    * Status messages are intended to be displayed permanently while a core is running\n    * in a way that doesn't suggest user action is required.\n    *\n    * Here are some possible use cases for status messages:\n    *\n    * @li An internal framerate counter.\n    * @li Debugging information.\n    *     Remember to let the player disable it in the core options.\n    * @li Core-specific state, such as when a microphone is active.\n    *\n    * The status message is displayed for the given duration,\n    * unless another status message of equal or greater priority is shown.\n    */\n   RETRO_MESSAGE_TYPE_STATUS,\n\n   /**\n    * Denotes a message that reports the progress\n    * of a long-running asynchronous task,\n    * such as when a core loads large files from disk or the network.\n    *\n    * The frontend should display messages of this type as a progress bar\n    * (or a progress spinner for indefinite tasks),\n    * where \\c retro_message_ext::msg is the progress bar's title\n    * and \\c retro_message_ext::progress sets the progress bar's length.\n    *\n    * This message type shouldn't be used for tasks that are expected to complete quickly.\n    */\n   RETRO_MESSAGE_TYPE_PROGRESS\n};\n\n/**\n * A core-provided message that the frontend will display to the player.\n *\n * @note The frontend is encouraged store these messages in a queue.\n * However, it should not empty the queue of core-submitted messages upon exit;\n * if a core exits with an error, it may want to use this API\n * to show an error message to the player.\n *\n * The frontend should maintain its own copy of the submitted message\n * and all subobjects, including strings.\n *\n * @see RETRO_ENVIRONMENT_SET_MESSAGE_EXT\n */\nstruct retro_message_ext\n{\n   /**\n    * The \\c NULL-terminated text of a message to show to the player.\n    * Must not be \\c NULL.\n    *\n    * @note The frontend must honor newlines in this string\n    * when rendering text to \\c RETRO_MESSAGE_TARGET_OSD.\n    */\n   const char *msg;\n\n   /**\n    * The duration that \\c msg will be displayed on-screen, in milliseconds.\n    *\n    * Ignored for \\c RETRO_MESSAGE_TARGET_LOG.\n    */\n   unsigned duration;\n\n   /**\n    * The relative importance of this message\n    * when targeting \\c RETRO_MESSAGE_TARGET_OSD.\n    * Higher values indicate higher priority.\n    *\n    * The frontend should use this to prioritize messages\n    * when it can't show all active messages at once,\n    * or to remove messages from its queue if it's full.\n    *\n    * The relative display order of messages with the same priority\n    * is left to the frontend's discretion,\n    * although we suggest breaking ties\n    * in favor of the most recently-submitted message.\n    *\n    * Frontends may handle deprioritized messages at their discretion;\n    * such messages may have their \\c duration altered,\n    * be hidden without being delayed,\n    * or even be discarded entirely.\n    *\n    * @note In the reference frontend (RetroArch),\n    * the same priority values are used for frontend-generated notifications,\n    * which are typically between 0 and 3 depending upon importance.\n    *\n    * Ignored for \\c RETRO_MESSAGE_TARGET_LOG.\n    */\n   unsigned priority;\n\n   /**\n    * The severity level of this message.\n    *\n    * The frontend may use this to filter or customize messages\n    * depending on the player's preferences.\n    * Here are some ideas:\n    *\n    * @li Use this to prioritize errors and warnings\n    *     over higher-ranking info and debug messages.\n    * @li Render warnings or errors with extra visual feedback,\n    *     e.g. with brighter colors or accompanying sound effects.\n    *\n    * @see RETRO_ENVIRONMENT_SET_LOG_INTERFACE\n    */\n   enum retro_log_level level;\n\n   /**\n    * The intended destination of this message.\n    *\n    * @see retro_message_target\n    */\n   enum retro_message_target target;\n\n   /**\n    * The intended semantics of this message.\n    *\n    * Ignored for \\c RETRO_MESSAGE_TARGET_LOG.\n    *\n    * @see retro_message_type\n    */\n   enum retro_message_type type;\n\n   /**\n    * The progress of an asynchronous task.\n    *\n    * A value between 0 and 100 (inclusive) indicates the task's percentage,\n    * and a value of -1 indicates a task of unknown completion.\n    *\n    * @note Since message type is a hint, a frontend may ignore progress values.\n    * Where relevant, a core should include progress percentage within the message string,\n    * such that the message intent remains clear when displayed\n    * as a standard frontend-generated notification.\n    *\n    * Ignored for \\c RETRO_MESSAGE_TARGET_LOG and for\n    * message types other than \\c RETRO_MESSAGE_TYPE_PROGRESS.\n    */\n   int8_t progress;\n};\n\n/** @} */\n\n/* Describes how the libretro implementation maps a libretro input bind\n * to its internal input system through a human readable string.\n * This string can be used to better let a user configure input. */\nstruct retro_input_descriptor\n{\n   /* Associates given parameters with a description. */\n   unsigned port;\n   unsigned device;\n   unsigned index;\n   unsigned id;\n\n   /* Human readable description for parameters.\n    * The pointer must remain valid until\n    * retro_unload_game() is called. */\n   const char *description;\n};\n\n/**\n * Contains basic information about the core.\n *\n * @see retro_get_system_info\n * @warning All pointers are owned by the core\n * and must remain valid throughout its lifetime.\n */\nstruct retro_system_info\n{\n   /**\n    * Descriptive name of the library.\n    *\n    * @note Should not contain any version numbers, etc.\n    */\n   const char *library_name;\n\n   /**\n    * Descriptive version of the core.\n    */\n   const char *library_version;\n\n   /**\n    * A pipe-delimited string list of file extensions that this core can load, e.g. \"bin|rom|iso\".\n    * Typically used by a frontend for filtering or core selection.\n    */\n   const char *valid_extensions;\n\n   /* Libretro cores that need to have direct access to their content\n    * files, including cores which use the path of the content files to\n    * determine the paths of other files, should set need_fullpath to true.\n    *\n    * Cores should strive for setting need_fullpath to false,\n    * as it allows the frontend to perform patching, etc.\n    *\n    * If need_fullpath is true and retro_load_game() is called:\n    *    - retro_game_info::path is guaranteed to have a valid path\n    *    - retro_game_info::data and retro_game_info::size are invalid\n    *\n    * If need_fullpath is false and retro_load_game() is called:\n    *    - retro_game_info::path may be NULL\n    *    - retro_game_info::data and retro_game_info::size are guaranteed\n    *      to be valid\n    *\n    * See also:\n    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY\n    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY\n    */\n   bool        need_fullpath;\n\n   /* If true, the frontend is not allowed to extract any archives before\n    * loading the real content.\n    * Necessary for certain libretro implementations that load games\n    * from zipped archives. */\n   bool        block_extract;\n};\n\n/* Defines overrides which modify frontend handling of\n * specific content file types.\n * An array of retro_system_content_info_override is\n * passed to RETRO_ENVIRONMENT_SET_CONTENT_INFO_OVERRIDE\n * NOTE: In the following descriptions, references to\n *       retro_load_game() may be replaced with\n *       retro_load_game_special() */\nstruct retro_system_content_info_override\n{\n   /* A list of file extensions for which the override\n    * should apply, delimited by a 'pipe' character\n    * (e.g. \"md|sms|gg\")\n    * Permitted file extensions are limited to those\n    * included in retro_system_info::valid_extensions\n    * and/or retro_subsystem_rom_info::valid_extensions */\n   const char *extensions;\n\n   /* Overrides the need_fullpath value set in\n    * retro_system_info and/or retro_subsystem_rom_info.\n    * To reiterate:\n    *\n    * If need_fullpath is true and retro_load_game() is called:\n    *    - retro_game_info::path is guaranteed to contain a valid\n    *      path to an existent file\n    *    - retro_game_info::data and retro_game_info::size are invalid\n    *\n    * If need_fullpath is false and retro_load_game() is called:\n    *    - retro_game_info::path may be NULL\n    *    - retro_game_info::data and retro_game_info::size are guaranteed\n    *      to be valid\n    *\n    * In addition:\n    *\n    * If need_fullpath is true and retro_load_game() is called:\n    *    - retro_game_info_ext::full_path is guaranteed to contain a valid\n    *      path to an existent file\n    *    - retro_game_info_ext::archive_path may be NULL\n    *    - retro_game_info_ext::archive_file may be NULL\n    *    - retro_game_info_ext::dir is guaranteed to contain a valid path\n    *      to the directory in which the content file exists\n    *    - retro_game_info_ext::name is guaranteed to contain the\n    *      basename of the content file, without extension\n    *    - retro_game_info_ext::ext is guaranteed to contain the\n    *      extension of the content file in lower case format\n    *    - retro_game_info_ext::data and retro_game_info_ext::size\n    *      are invalid\n    *\n    * If need_fullpath is false and retro_load_game() is called:\n    *    - If retro_game_info_ext::file_in_archive is false:\n    *       - retro_game_info_ext::full_path is guaranteed to contain\n    *         a valid path to an existent file\n    *       - retro_game_info_ext::archive_path may be NULL\n    *       - retro_game_info_ext::archive_file may be NULL\n    *       - retro_game_info_ext::dir is guaranteed to contain a\n    *         valid path to the directory in which the content file exists\n    *       - retro_game_info_ext::name is guaranteed to contain the\n    *         basename of the content file, without extension\n    *       - retro_game_info_ext::ext is guaranteed to contain the\n    *         extension of the content file in lower case format\n    *    - If retro_game_info_ext::file_in_archive is true:\n    *       - retro_game_info_ext::full_path may be NULL\n    *       - retro_game_info_ext::archive_path is guaranteed to\n    *         contain a valid path to an existent compressed file\n    *         inside which the content file is located\n    *       - retro_game_info_ext::archive_file is guaranteed to\n    *         contain a valid path to an existent content file\n    *         inside the compressed file referred to by\n    *         retro_game_info_ext::archive_path\n    *            e.g. for a compressed file '/path/to/foo.zip'\n    *            containing 'bar.sfc'\n    *             > retro_game_info_ext::archive_path will be '/path/to/foo.zip'\n    *             > retro_game_info_ext::archive_file will be 'bar.sfc'\n    *       - retro_game_info_ext::dir is guaranteed to contain a\n    *         valid path to the directory in which the compressed file\n    *         (containing the content file) exists\n    *       - retro_game_info_ext::name is guaranteed to contain\n    *         EITHER\n    *         1) the basename of the compressed file (containing\n    *            the content file), without extension\n    *         OR\n    *         2) the basename of the content file inside the\n    *            compressed file, without extension\n    *         In either case, a core should consider 'name' to\n    *         be the canonical name/ID of the the content file\n    *       - retro_game_info_ext::ext is guaranteed to contain the\n    *         extension of the content file inside the compressed file,\n    *         in lower case format\n    *    - retro_game_info_ext::data and retro_game_info_ext::size are\n    *      guaranteed to be valid */\n   bool need_fullpath;\n\n   /* If need_fullpath is false, specifies whether the content\n    * data buffer available in retro_load_game() is 'persistent'\n    *\n    * If persistent_data is false and retro_load_game() is called:\n    *    - retro_game_info::data and retro_game_info::size\n    *      are valid only until retro_load_game() returns\n    *    - retro_game_info_ext::data and retro_game_info_ext::size\n    *      are valid only until retro_load_game() returns\n    *\n    * If persistent_data is true and retro_load_game() is called:\n    *    - retro_game_info::data and retro_game_info::size\n    *      are valid until retro_deinit() returns\n    *    - retro_game_info_ext::data and retro_game_info_ext::size\n    *      are valid until retro_deinit() returns */\n   bool persistent_data;\n};\n\n/* Similar to retro_game_info, but provides extended\n * information about the source content file and\n * game memory buffer status.\n * And array of retro_game_info_ext is returned by\n * RETRO_ENVIRONMENT_GET_GAME_INFO_EXT\n * NOTE: In the following descriptions, references to\n *       retro_load_game() may be replaced with\n *       retro_load_game_special() */\nstruct retro_game_info_ext\n{\n   /* - If file_in_archive is false, contains a valid\n    *   path to an existent content file (UTF-8 encoded)\n    * - If file_in_archive is true, may be NULL */\n   const char *full_path;\n\n   /* - If file_in_archive is false, may be NULL\n    * - If file_in_archive is true, contains a valid path\n    *   to an existent compressed file inside which the\n    *   content file is located (UTF-8 encoded) */\n   const char *archive_path;\n\n   /* - If file_in_archive is false, may be NULL\n    * - If file_in_archive is true, contain a valid path\n    *   to an existent content file inside the compressed\n    *   file referred to by archive_path (UTF-8 encoded)\n    *      e.g. for a compressed file '/path/to/foo.zip'\n    *      containing 'bar.sfc'\n    *      > archive_path will be '/path/to/foo.zip'\n    *      > archive_file will be 'bar.sfc' */\n   const char *archive_file;\n\n   /* - If file_in_archive is false, contains a valid path\n    *   to the directory in which the content file exists\n    *   (UTF-8 encoded)\n    * - If file_in_archive is true, contains a valid path\n    *   to the directory in which the compressed file\n    *   (containing the content file) exists (UTF-8 encoded) */\n   const char *dir;\n\n   /* Contains the canonical name/ID of the content file\n    * (UTF-8 encoded). Intended for use when identifying\n    * 'complementary' content named after the loaded file -\n    * i.e. companion data of a different format (a CD image\n    * required by a ROM), texture packs, internally handled\n    * save files, etc.\n    * - If file_in_archive is false, contains the basename\n    *   of the content file, without extension\n    * - If file_in_archive is true, then string is\n    *   implementation specific. A frontend may choose to\n    *   set a name value of:\n    *   EITHER\n    *   1) the basename of the compressed file (containing\n    *      the content file), without extension\n    *   OR\n    *   2) the basename of the content file inside the\n    *      compressed file, without extension\n    *   RetroArch sets the 'name' value according to (1).\n    *   A frontend that supports routine loading of\n    *   content from archives containing multiple unrelated\n    *   content files may set the 'name' value according\n    *   to (2). */\n   const char *name;\n\n   /* - If file_in_archive is false, contains the extension\n    *   of the content file in lower case format\n    * - If file_in_archive is true, contains the extension\n    *   of the content file inside the compressed file,\n    *   in lower case format */\n   const char *ext;\n\n   /* String of implementation specific meta-data. */\n   const char *meta;\n\n   /* Memory buffer of loaded game content. Will be NULL:\n    * IF\n    * - retro_system_info::need_fullpath is true and\n    *   retro_system_content_info_override::need_fullpath\n    *   is unset\n    * OR\n    * - retro_system_content_info_override::need_fullpath\n    *   is true */\n   const void *data;\n\n   /* Size of game content memory buffer, in bytes */\n   size_t size;\n\n   /* True if loaded content file is inside a compressed\n    * archive */\n   bool file_in_archive;\n\n   /* - If data is NULL, value is unset/ignored\n    * - If data is non-NULL:\n    *   - If persistent_data is false, data and size are\n    *     valid only until retro_load_game() returns\n    *   - If persistent_data is true, data and size are\n    *     are valid until retro_deinit() returns */\n   bool persistent_data;\n};\n\n/**\n * Parameters describing the size and shape of the video frame.\n * @see retro_system_av_info\n * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO\n * @see RETRO_ENVIRONMENT_SET_GEOMETRY\n * @see retro_get_system_av_info\n */\nstruct retro_game_geometry\n{\n   /**\n    * Nominal video width of game, in pixels.\n    * This will typically be the emulated platform's native video width\n    * (or its smallest, if the original hardware supports multiple resolutions).\n    */\n   unsigned base_width;\n\n   /**\n    * Nominal video height of game, in pixels.\n    * This will typically be the emulated platform's native video height\n    * (or its smallest, if the original hardware supports multiple resolutions).\n    */\n   unsigned base_height;\n\n   /**\n    * Maximum possible width of the game screen, in pixels.\n    * This will typically be the emulated platform's maximum video width.\n    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),\n    * this should assume the core's widest possible screen layout (e.g. side-by-side).\n    * For cores that support upscaling the resolution,\n    * this should assume the highest supported scale factor is active.\n    */\n   unsigned max_width;\n\n   /**\n    * Maximum possible height of the game screen, in pixels.\n    * This will typically be the emulated platform's maximum video height.\n    * For cores that emulate platforms with multiple screens (such as the Nintendo DS),\n    * this should assume the core's tallest possible screen layout (e.g. vertical).\n    * For cores that support upscaling the resolution,\n    * this should assume the highest supported scale factor is active.\n    */\n   unsigned max_height;    /* Maximum possible height of game. */\n\n   /**\n    * Nominal aspect ratio of game.\n    * If zero or less,\n    * an aspect ratio of <tt>base_width / base_height</tt> is assumed.\n    *\n    * @note A frontend may ignore this setting.\n    */\n   float    aspect_ratio;\n};\n\n/**\n * Parameters describing the timing of the video and audio.\n * @see retro_system_av_info\n * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO\n * @see retro_get_system_av_info\n */\nstruct retro_system_timing\n{\n   /** Video output refresh rate, in frames per second. */\n   double fps;\n\n   /** The audio output sample rate, in Hz. */\n   double sample_rate;\n};\n\n/**\n * Configures how the core's audio and video should be updated.\n * @see RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO\n * @see retro_get_system_av_info\n */\nstruct retro_system_av_info\n{\n   /** Parameters describing the size and shape of the video frame. */\n   struct retro_game_geometry geometry;\n\n   /** Parameters describing the timing of the video and audio. */\n   struct retro_system_timing timing;\n};\n\n/** @defgroup SET_CORE_OPTIONS Core Options\n *  @{\n */\n\n/**\n * Represents \\ref RETRO_ENVIRONMENT_GET_VARIABLE \"a core option query\".\n *\n * @note In \\ref RETRO_ENVIRONMENT_SET_VARIABLES\n * (which is a deprecated API),\n * this \\c struct serves as an option definition.\n *\n * @see RETRO_ENVIRONMENT_GET_VARIABLE\n */\nstruct retro_variable\n{\n   /**\n    * A unique key identifying this option.\n    *\n    * Should be a key for an option that was previously defined\n    * with \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 or similar.\n    *\n    * Should be prefixed with the core's name\n    * to minimize the risk of collisions with another core's options,\n    * as frontends are not required to use a namespacing scheme for storing options.\n    * For example, a core named \"foo\" might define an option named \"foo_option\".\n    *\n    * @note In \\ref RETRO_ENVIRONMENT_SET_VARIABLES\n    * (which is a deprecated API),\n    * this field is used to define an option\n    * named by this key.\n    */\n   const char *key;\n\n   /**\n    * Value to be obtained.\n    *\n    * Set by the frontend to \\c NULL if\n    * the option named by \\ref key does not exist.\n    *\n    * @note In \\ref RETRO_ENVIRONMENT_SET_VARIABLES\n    * (which is a deprecated API),\n    * this field is set by the core to define the possible values\n    * for an option named by \\ref key.\n    * When used this way, it must be formatted as follows:\n    * @li The text before the first ';' is the option's human-readable title.\n    * @li A single space follows the ';'.\n    * @li The rest of the string is a '|'-delimited list of possible values,\n    * with the first one being the default.\n    */\n   const char *value;\n};\n\n/**\n * An argument that's used to show or hide a core option in the frontend.\n *\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY\n */\nstruct retro_core_option_display\n{\n   /**\n    * The key for a core option that was defined with \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\n    * \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\n    * or their legacy equivalents.\n    */\n   const char *key;\n\n   /**\n    * Whether the option named by \\c key\n    * should be displayed to the player in the frontend's core options menu.\n    *\n    * @note This value is a hint, \\em not a requirement;\n    * the frontend is free to ignore this field.\n    */\n   bool visible;\n};\n\n/**\n * The maximum number of choices that can be defined for a given core option.\n *\n * This limit was chosen as a compromise between\n * a core's flexibility and a streamlined user experience.\n *\n * @note A guiding principle of libretro's API design is that\n * all common interactions (gameplay, menu navigation, etc.)\n * should be possible without a keyboard.\n *\n * If you need more than 128 choices for a core option,\n * consider simplifying your option structure.\n * Here are some ideas:\n *\n * \\li If a core option represents a numeric value,\n *     consider reducing the option's granularity\n *     (e.g. define time limits in increments of 5 seconds instead of 1 second).\n *     Providing a fixed set of values based on experimentation\n *     is also a good idea.\n * \\li If a core option represents a dynamically-built list of files,\n *     consider leaving out files that won't be useful.\n *     For example, if a core allows the player to choose a specific BIOS file,\n *     it can omit files of the wrong length or without a valid header.\n *\n * @see retro_core_option_definition\n * @see retro_core_option_v2_definition\n */\n#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128\n\n/**\n * A descriptor for a particular choice within a core option.\n *\n * @note All option values are represented as strings.\n * If you need to represent any other type,\n * parse the string in \\ref value.\n *\n * @see retro_core_option_v2_category\n */\nstruct retro_core_option_value\n{\n   /**\n    * The option value that the frontend will serialize.\n    *\n    * Must not be \\c NULL or empty.\n    * No other hard limits are placed on this value's contents,\n    * but here are some suggestions:\n    *\n    * \\li If the value represents a number,\n    *     don't include any non-digit characters (units, separators, etc.).\n    *     Instead, include that information in \\c label.\n    *     This will simplify parsing.\n    * \\li If the value represents a file path,\n    *     store it as a relative path with respect to one of the common libretro directories\n    *     (e.g. \\ref RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY \"the system directory\"\n    *     or \\ref RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY \"the save directory\"),\n    *     and use forward slashes (\\c \"/\") as directory separators.\n    *     This will simplify cloud storage if supported by the frontend,\n    *     as the same file may be used on multiple devices.\n    */\n   const char *value;\n\n   /**\n    * Human-readable name for \\c value that the frontend should show to players.\n    *\n    * May be \\c NULL, in which case the frontend\n    * should display \\c value itself.\n    *\n    * Here are some guidelines for writing a good label:\n    *\n    * \\li Make the option labels obvious\n    *     so that they don't need to be explained in the description.\n    * \\li Keep labels short, and don't use unnecessary words.\n    *     For example, \"OpenGL\" is a better label than \"OpenGL Mode\".\n    * \\li If the option represents a number,\n    *     consider adding units, separators, or other punctuation\n    *     into the label itself.\n    *     For example, \"5 seconds\" is a better label than \"5\".\n    * \\li If the option represents a number, use intuitive units\n    *     that don't take a lot of digits to express.\n    *     For example, prefer \"1 minute\" over \"60 seconds\" or \"60,000 milliseconds\".\n    */\n   const char *label;\n};\n\n/**\n * @copybrief retro_core_option_v2_definition\n *\n * @deprecated Use \\ref retro_core_option_v2_definition instead,\n * as it supports categorizing options into groups.\n * Only use this \\c struct to support older frontends or cores.\n *\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL\n */\nstruct retro_core_option_definition\n{\n   /** @copydoc retro_core_option_v2_definition::key */\n   const char *key;\n\n   /** @copydoc retro_core_option_v2_definition::desc */\n   const char *desc;\n\n   /** @copydoc retro_core_option_v2_definition::info */\n   const char *info;\n\n   /** @copydoc retro_core_option_v2_definition::values */\n   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];\n\n   /** @copydoc retro_core_option_v2_definition::default_value */\n   const char *default_value;\n};\n\n#ifdef __PS3__\n#undef local\n#endif\n\n/**\n * A variant of \\ref retro_core_options that supports internationalization.\n *\n * @deprecated Use \\ref retro_core_options_v2_intl instead,\n * as it supports categorizing options into groups.\n * Only use this \\c struct to support older frontends or cores.\n *\n * @see retro_core_options\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL\n * @see RETRO_ENVIRONMENT_GET_LANGUAGE\n * @see retro_language\n */\nstruct retro_core_options_intl\n{\n   /** @copydoc retro_core_options_v2_intl::us */\n   struct retro_core_option_definition *us;\n\n   /** @copydoc retro_core_options_v2_intl::local */\n   struct retro_core_option_definition *local;\n};\n\n/**\n * A descriptor for a group of related core options.\n *\n * Here's an example category:\n *\n * @code\n * {\n *     \"cpu\",\n *     \"CPU Emulation\",\n *     \"Settings for CPU quirks.\"\n * }\n * @endcode\n *\n * @see retro_core_options_v2\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL\n */\nstruct retro_core_option_v2_category\n{\n   /**\n    * A string that uniquely identifies this category within the core's options.\n    * Any \\c retro_core_option_v2_definition whose \\c category_key matches this\n    * is considered to be within this category.\n    * Different cores may use the same category keys,\n    * so namespacing them is not necessary.\n    * Valid characters are <tt>[a-zA-Z0-9_-]</tt>.\n    *\n    * Frontends should use this category to organize core options,\n    * but may customize this category's presentation in other ways.\n    * For example, a frontend may use common keys like \"audio\" or \"gfx\"\n    * to select an appropriate icon in its UI.\n    *\n    * Required; must not be \\c NULL.\n    */\n   const char *key;\n\n   /**\n    * A brief human-readable name for this category,\n    * intended for the frontend to display to the player.\n    * This should be a name that's concise and descriptive, such as \"Audio\" or \"Video\".\n    *\n    * Required; must not be \\c NULL.\n    */\n   const char *desc;\n\n   /**\n    * A human-readable description for this category,\n    * intended for the frontend to display to the player\n    * as secondary help text (e.g. a sublabel or a tooltip).\n    * Optional; may be \\c NULL or an empty string.\n    */\n   const char *info;\n};\n\n/**\n * A descriptor for a particular core option and the values it may take.\n *\n * Supports categorizing options into groups,\n * so as not to overwhelm the player.\n *\n * @see retro_core_option_v2_category\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL\n */\nstruct retro_core_option_v2_definition\n{\n   /**\n    * A unique identifier for this option that cores may use\n    * \\ref RETRO_ENVIRONMENT_GET_VARIABLE \"to query its value from the frontend\".\n    * Must be unique within this core.\n    *\n    * Should be unique globally;\n    * the recommended method for doing so\n    * is to prefix each option with the core's name.\n    * For example, an option that controls the resolution for a core named \"foo\"\n    * should be named \\c \"foo_resolution\".\n    *\n    * Valid key characters are in the set <tt>[a-zA-Z0-9_-]</tt>.\n    */\n   const char *key;\n\n   /**\n    * A human-readable name for this option,\n    * intended to be displayed by frontends that don't support\n    * categorizing core options.\n    *\n    * Required; must not be \\c NULL or empty.\n    */\n   const char *desc;\n\n   /**\n    * A human-readable name for this option,\n    * intended to be displayed by frontends that support\n    * categorizing core options.\n    *\n    * This version may be slightly more concise than \\ref desc,\n    * as it can rely on the structure of the options menu.\n    * For example, \"Interface\" is a good \\c desc_categorized,\n    * as it can be displayed as a sublabel for a \"Network\" category.\n    * For \\c desc, \"Network Interface\" would be more suitable.\n    *\n    * Optional; if this field or \\c category_key is empty or \\c NULL,\n    * \\c desc will be used instead.\n    */\n   const char *desc_categorized;\n\n   /**\n    * A human-readable description of this option and its effects,\n    * intended to be displayed by frontends that don't support\n    * categorizing core options.\n    *\n    * @details Intended to be displayed as secondary help text,\n    * such as a tooltip or a sublabel.\n    *\n    * Here are some suggestions for writing a good description:\n    *\n    * \\li Avoid technical jargon unless this option is meant for advanced users.\n    *     If unavoidable, suggest one of the default options for those unsure.\n    * \\li Don't repeat the option name in the description;\n    *     instead, describe what the option name means.\n    * \\li If an option requires a core restart or game reset to take effect,\n    *     be sure to say so.\n    * \\li Try to make the option labels obvious\n    *     so that they don't need to be explained in the description.\n    *\n    * Optional; may be \\c NULL.\n    */\n   const char *info;\n\n   /**\n    * @brief A human-readable description of this option and its effects,\n    * intended to be displayed by frontends that support\n    * categorizing core options.\n    *\n    * This version is provided to accommodate descriptions\n    * that reference other options by name,\n    * as options may have different user-facing names\n    * depending on whether the frontend supports categorization.\n    *\n    * @copydetails info\n    *\n    * If empty or \\c NULL, \\c info will be used instead.\n    * Will be ignored if \\c category_key is empty or \\c NULL.\n    */\n   const char *info_categorized;\n\n   /**\n    * The key of the category that this option belongs to.\n    *\n    * Optional; if equal to \\ref retro_core_option_v2_category::key \"a defined category\",\n    * then this option shall be displayed by the frontend\n    * next to other options in this same category,\n    * assuming it supports doing so.\n    * Option categories are intended to be displayed in a submenu,\n    * but this isn't a hard requirement.\n    *\n    * If \\c NULL, empty, or not equal to a defined category,\n    * then this option is considered uncategorized\n    * and the frontend shall display it outside of any category\n    * (most likely at a top-level menu).\n    *\n    * @see retro_core_option_v2_category\n    */\n   const char *category_key;\n\n   /**\n    * One or more possible values for this option,\n    * up to the limit of \\ref RETRO_NUM_CORE_OPTION_VALUES_MAX.\n    *\n    * Terminated by a \\c { NULL, NULL } element,\n    * although frontends should work even if all elements are used.\n    */\n   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];\n\n   /**\n    * The default value for this core option.\n    * Used if it hasn't been set, e.g. for new cores.\n    * Must equal one of the \\ref value members in the \\c values array,\n    * or else this option will be ignored.\n    */\n   const char *default_value;\n};\n\n/**\n * A set of core option descriptors and the categories that group them,\n * suitable for enabling a core to be customized.\n *\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2\n */\nstruct retro_core_options_v2\n{\n   /**\n    * An array of \\ref retro_core_option_v2_category \"option categories\",\n    * terminated by a zeroed-out category \\c struct.\n    *\n    * Will be ignored if the frontend doesn't support core option categories.\n    *\n    * If \\c NULL or ignored, all options will be treated as uncategorized.\n    * This most likely means that a frontend will display them at a top-level menu\n    * without any kind of hierarchy or grouping.\n    */\n   struct retro_core_option_v2_category *categories;\n\n   /**\n    * An array of \\ref retro_core_option_v2_definition \"core option descriptors\",\n    * terminated by a zeroed-out definition \\c struct.\n    *\n    * Required; must not be \\c NULL.\n    */\n   struct retro_core_option_v2_definition *definitions;\n};\n\n/**\n * A variant of \\ref retro_core_options_v2 that supports internationalization.\n *\n * @see retro_core_options_v2\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL\n * @see RETRO_ENVIRONMENT_GET_LANGUAGE\n * @see retro_language\n */\nstruct retro_core_options_v2_intl\n{\n   /**\n    * Pointer to a core options set\n    * whose text is written in American English.\n    *\n    * This may be passed to \\c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2 as-is\n    * if not using \\c RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL.\n    *\n    * Required; must not be \\c NULL.\n    */\n   struct retro_core_options_v2 *us;\n\n   /**\n    * Pointer to a core options set\n    * whose text is written in one of libretro's \\ref retro_language \"supported languages\",\n    * most likely the one returned by \\ref RETRO_ENVIRONMENT_GET_LANGUAGE.\n    *\n    * Structure is the same, but usage is slightly different:\n    *\n    * \\li All text (except for keys and option values)\n    *     should be written in whichever language\n    *     is returned by \\c RETRO_ENVIRONMENT_GET_LANGUAGE.\n    * \\li All fields besides keys and option values may be \\c NULL,\n    *     in which case the corresponding string in \\c us\n    *     is used instead.\n    * \\li All \\ref retro_core_option_v2_definition::default_value \"default option values\"\n    *     are taken from \\c us.\n    *     The defaults in this field are ignored.\n    *\n    * May be \\c NULL, in which case \\c us is used instead.\n    */\n   struct retro_core_options_v2 *local;\n};\n\n/**\n * Called by the frontend to determine if any core option's visibility has changed.\n *\n * Each time a frontend sets a core option,\n * it should call this function to see if\n * any core option should be made visible or invisible.\n *\n * May also be called after \\ref retro_load_game \"loading a game\",\n * to determine what the initial visibility of each option should be.\n *\n * Within this function, the core must update the visibility\n * of any dynamically-hidden options\n * using \\ref RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY.\n *\n * @note All core options are visible by default,\n * even during this function's first call.\n *\n * @return \\c true if any core option's visibility was adjusted\n * since the last call to this function.\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY\n * @see retro_core_option_display\n */\ntypedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void);\n\n/**\n * Callback registered by the core for the frontend to use\n * when setting the visibility of each core option.\n *\n * @see RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY\n * @see retro_core_option_display\n */\nstruct retro_core_options_update_display_callback\n{\n   /**\n    * @copydoc retro_core_options_update_display_callback_t\n    *\n    * Set by the core.\n    */\n   retro_core_options_update_display_callback_t callback;\n};\n\n/** @} */\n\nstruct retro_game_info\n{\n   const char *path;       /* Path to game, UTF-8 encoded.\n                            * Sometimes used as a reference for building other paths.\n                            * May be NULL if game was loaded from stdin or similar,\n                            * but in this case some cores will be unable to load `data`.\n                            * So, it is preferable to fabricate something here instead\n                            * of passing NULL, which will help more cores to succeed.\n                            * retro_system_info::need_fullpath requires\n                            * that this path is valid. */\n   const void *data;       /* Memory buffer of loaded game. Will be NULL\n                            * if need_fullpath was set. */\n   size_t      size;       /* Size of memory buffer. */\n   const char *meta;       /* String of implementation specific meta-data. */\n};\n\n/** @defgroup GET_CURRENT_SOFTWARE_FRAMEBUFFER Frontend-Owned Framebuffers\n * @{\n */\n\n/** @defgroup RETRO_MEMORY_ACCESS Framebuffer Memory Access Types\n * @{\n */\n\n/** Indicates that core will write to the framebuffer returned by the frontend. */\n#define RETRO_MEMORY_ACCESS_WRITE (1 << 0)\n\n/** Indicates that the core will read from the framebuffer returned by the frontend. */\n#define RETRO_MEMORY_ACCESS_READ (1 << 1)\n\n/** @} */\n\n/** @defgroup RETRO_MEMORY_TYPE Framebuffer Memory Types\n * @{\n */\n\n/**\n * Indicates that the returned framebuffer's memory is cached.\n * If not set, random access to the buffer may be very slow.\n */\n#define RETRO_MEMORY_TYPE_CACHED (1 << 0)\n\n/** @} */\n\n/**\n * A frame buffer owned by the frontend that a core may use for rendering.\n *\n * @see GET_CURRENT_SOFTWARE_FRAMEBUFFER\n * @see retro_video_refresh_t\n */\nstruct retro_framebuffer\n{\n   /**\n    * Pointer to the beginning of the framebuffer provided by the frontend.\n    * The initial contents of this buffer are unspecified,\n    * as is the means used to map the memory;\n    * this may be defined in software,\n    * or it may be GPU memory mapped to RAM.\n    *\n    * If the framebuffer is used,\n    * this pointer must be passed to \\c retro_video_refresh_t as-is.\n    * It is undefined behavior to pass an offset to this pointer.\n    *\n    * @warning This pointer is only guaranteed to be valid\n    * for the duration of the same \\c retro_run iteration\n    * \\ref GET_CURRENT_SOFTWARE_FRAMEBUFFER \"that requested the framebuffer\".\n    * Reuse of this pointer is undefined.\n    */\n   void *data;\n\n   /**\n    * The width of the framebuffer given in \\c data, in pixels.\n    * Set by the core.\n    *\n    * @warning If the framebuffer is used,\n    * this value must be passed to \\c retro_video_refresh_t as-is.\n    * It is undefined behavior to try to render \\c data with any other width.\n    */\n   unsigned width;\n\n   /**\n    * The height of the framebuffer given in \\c data, in pixels.\n    * Set by the core.\n    *\n    * @warning If the framebuffer is used,\n    * this value must be passed to \\c retro_video_refresh_t as-is.\n    * It is undefined behavior to try to render \\c data with any other height.\n    */\n   unsigned height;\n\n   /**\n    * The distance between the start of one scanline and the beginning of the next, in bytes.\n    * In practice this is usually equal to \\c width times the pixel size,\n    * but that's not guaranteed.\n    * Sometimes called the \"stride\".\n    *\n    * @setby{frontend}\n    * @warning If the framebuffer is used,\n    * this value must be passed to \\c retro_video_refresh_t as-is.\n    * It is undefined to try to render \\c data with any other pitch.\n    */\n   size_t pitch;\n\n   /**\n    * The pixel format of the returned framebuffer.\n    * May be different than the format specified by the core in \\c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT,\n    * e.g. due to conversions.\n    * Set by the frontend.\n    *\n    * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT\n    */\n   enum retro_pixel_format format;\n\n   /**\n    * One or more \\ref RETRO_MEMORY_ACCESS \"memory access flags\"\n    * that specify how the core will access the memory in \\c data.\n    *\n    * @setby{core}\n    */\n   unsigned access_flags;\n\n   /**\n    * Zero or more \\ref RETRO_MEMORY_TYPE \"memory type flags\"\n    * that describe how the framebuffer's memory has been mapped.\n    *\n    * @setby{frontend}\n    */\n   unsigned memory_flags;\n};\n\n/** @} */\n\n/** @defgroup SET_FASTFORWARDING_OVERRIDE Fast-Forward Override\n * @{\n */\n\n/**\n * Parameters that govern when and how the core takes control\n * of fast-forwarding mode.\n */\nstruct retro_fastforwarding_override\n{\n   /**\n    * The factor by which the core will be sped up\n    * when \\c fastforward is \\c true.\n    * This value is used as follows:\n    *\n    * @li A value greater than 1.0 will run the core at\n    *     the specified multiple of normal speed.\n    *     For example, a value of 5.0\n    *     combined with a normal target rate of 60 FPS\n    *     will result in a target rate of 300 FPS.\n    *     The actual rate may be lower if the host's hardware can't keep up.\n    * @li A value of 1.0 will run the core at normal speed.\n    * @li A value between 0.0 (inclusive) and 1.0 (exclusive)\n    *     will run the core as fast as the host system can manage.\n    * @li A negative value will let the frontend choose a factor.\n    * @li An infinite value or \\c NaN results in undefined behavior.\n    *\n    * @attention Setting this value to less than 1.0 will \\em not\n    * slow down the core.\n    */\n   float ratio;\n\n   /**\n    * If \\c true, the frontend should activate fast-forwarding\n    * until this field is set to \\c false or the core is unloaded.\n    */\n   bool fastforward;\n\n   /**\n    * If \\c true, the frontend should display an on-screen notification or icon\n    * while \\c fastforward is \\c true (where supported).\n    * Otherwise, the frontend should not display any such notification.\n    */\n   bool notification;\n\n   /**\n    * If \\c true, the core has exclusive control\n    * over enabling and disabling fast-forwarding\n    * via the \\c fastforward field.\n    * The frontend will not be able to start or stop fast-forwarding\n    * until this field is set to \\c false or the core is unloaded.\n    */\n   bool inhibit_toggle;\n};\n\n/** @} */\n\n/**\n * During normal operation.\n *\n * @note Rate will be equal to the core's internal FPS.\n */\n#define RETRO_THROTTLE_NONE              0\n\n/**\n * While paused or stepping single frames.\n *\n * @note Rate will be 0.\n */\n#define RETRO_THROTTLE_FRAME_STEPPING    1\n\n/**\n * During fast forwarding.\n *\n * @note Rate will be 0 if not specifically limited to a maximum speed.\n */\n#define RETRO_THROTTLE_FAST_FORWARD      2\n\n/**\n * During slow motion.\n *\n * @note Rate will be less than the core's internal FPS.\n */\n#define RETRO_THROTTLE_SLOW_MOTION       3\n\n/**\n * While rewinding recorded save states.\n *\n * @note Rate can vary depending on the rewind speed or be 0 if the frontend\n * is not aiming for a specific rate.\n */\n#define RETRO_THROTTLE_REWINDING         4\n\n/**\n * While vsync is active in the video driver, and the target refresh rate is lower than the core's internal FPS.\n *\n * @note Rate is the target refresh rate.\n */\n#define RETRO_THROTTLE_VSYNC             5\n\n/**\n * When the frontend does not throttle in any way.\n *\n * @note Rate will be 0. An example could be if no vsync or audio output is active.\n */\n#define RETRO_THROTTLE_UNBLOCKED         6\n\n/**\n * Details about the actual rate an implementation is calling \\c retro_run() at.\n *\n * @see RETRO_ENVIRONMENT_GET_THROTTLE_STATE\n */\nstruct retro_throttle_state\n{\n   /**\n    * The current throttling mode.\n    *\n    * @note Should be one of the \\c RETRO_THROTTLE_* values.\n    * @see RETRO_THROTTLE_NONE\n    * @see RETRO_THROTTLE_FRAME_STEPPING\n    * @see RETRO_THROTTLE_FAST_FORWARD\n    * @see RETRO_THROTTLE_SLOW_MOTION\n    * @see RETRO_THROTTLE_REWINDING\n    * @see RETRO_THROTTLE_VSYNC\n    * @see RETRO_THROTTLE_UNBLOCKED\n    */\n   unsigned mode;\n\n   /**\n    * How many times per second the frontend aims to call retro_run.\n    *\n    * @note Depending on the mode, it can be 0 if there is no known fixed rate.\n    * This won't be accurate if the total processing time of the core and\n    * the frontend is longer than what is available for one frame.\n    */\n   float rate;\n};\n\n/** @defgroup GET_MICROPHONE_INTERFACE Microphone Interface\n * @{\n */\n\n/**\n * Opaque handle to a microphone that's been opened for use.\n * The underlying object is accessed or created with \\c retro_microphone_interface_t.\n */\ntypedef struct retro_microphone retro_microphone_t;\n\n/**\n * Parameters for configuring a microphone.\n * Some of these might not be honored,\n * depending on the available hardware and driver configuration.\n */\ntypedef struct retro_microphone_params\n{\n   /**\n    * The desired sample rate of the microphone's input, in Hz.\n    * The microphone's input will be resampled,\n    * so cores can ask for whichever frequency they need.\n    *\n    * If zero, some reasonable default will be provided by the frontend\n    * (usually from its config file).\n    *\n    * @see retro_get_mic_rate_t\n    */\n   unsigned rate;\n} retro_microphone_params_t;\n\n/**\n * @copydoc retro_microphone_interface::open_mic\n */\ntypedef retro_microphone_t *(RETRO_CALLCONV *retro_open_mic_t)(const retro_microphone_params_t *params);\n\n/**\n * @copydoc retro_microphone_interface::close_mic\n */\ntypedef void (RETRO_CALLCONV *retro_close_mic_t)(retro_microphone_t *microphone);\n\n/**\n * @copydoc retro_microphone_interface::get_params\n */\ntypedef bool (RETRO_CALLCONV *retro_get_mic_params_t)(const retro_microphone_t *microphone, retro_microphone_params_t *params);\n\n/**\n * @copydoc retro_microphone_interface::set_mic_state\n */\ntypedef bool (RETRO_CALLCONV *retro_set_mic_state_t)(retro_microphone_t *microphone, bool state);\n\n/**\n * @copydoc retro_microphone_interface::get_mic_state\n */\ntypedef bool (RETRO_CALLCONV *retro_get_mic_state_t)(const retro_microphone_t *microphone);\n\n/**\n * @copydoc retro_microphone_interface::read_mic\n */\ntypedef int (RETRO_CALLCONV *retro_read_mic_t)(retro_microphone_t *microphone, int16_t* samples, size_t num_samples);\n\n/**\n * The current version of the microphone interface.\n * Will be incremented whenever \\c retro_microphone_interface or \\c retro_microphone_params_t\n * receive new fields.\n *\n * Frontends using cores built against older mic interface versions\n * should not access fields introduced in newer versions.\n */\n#define RETRO_MICROPHONE_INTERFACE_VERSION 1\n\n/**\n * An interface for querying the microphone and accessing data read from it.\n *\n * @see RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE\n */\nstruct retro_microphone_interface\n{\n   /**\n    * The version of this microphone interface.\n    * Set by the core to request a particular version,\n    * and set by the frontend to indicate the returned version.\n    * 0 indicates that the interface is invalid or uninitialized.\n    */\n   unsigned interface_version;\n\n   /**\n    * Initializes a new microphone.\n    * Assuming that microphone support is enabled and provided by the frontend,\n    * cores may call this function whenever necessary.\n    * A microphone could be opened throughout a core's lifetime,\n    * or it could wait until a microphone is plugged in to the emulated device.\n    *\n    * The returned handle will be valid until it's freed,\n    * even if the audio driver is reinitialized.\n    *\n    * This function is not guaranteed to be thread-safe.\n    *\n    * @param[in] args Parameters used to create the microphone.\n    * May be \\c NULL, in which case the default value of each parameter will be used.\n    *\n    * @returns Pointer to the newly-opened microphone,\n    * or \\c NULL if one couldn't be opened.\n    * This likely means that no microphone is plugged in and recognized,\n    * or the maximum number of supported microphones has been reached.\n    *\n    * @note Microphones are \\em inactive by default;\n    * to begin capturing audio, call \\c set_mic_state.\n    * @see retro_microphone_params_t\n    */\n   retro_open_mic_t open_mic;\n\n   /**\n    * Closes a microphone that was initialized with \\c open_mic.\n    * Calling this function will stop all microphone activity\n    * and free up the resources that it allocated.\n    * Afterwards, the handle is invalid and must not be used.\n    *\n    * A frontend may close opened microphones when unloading content,\n    * but this behavior is not guaranteed.\n    * Cores should close their microphones when exiting, just to be safe.\n    *\n    * @param microphone Pointer to the microphone that was allocated by \\c open_mic.\n    * If \\c NULL, this function does nothing.\n    *\n    * @note The handle might be reused if another microphone is opened later.\n    */\n   retro_close_mic_t close_mic;\n\n   /**\n    * Returns the configured parameters of this microphone.\n    * These may differ from what was requested depending on\n    * the driver and device configuration.\n    *\n    * Cores should check these values before they start fetching samples.\n    *\n    * Will not change after the mic was opened.\n    *\n    * @param[in] microphone Opaque handle to the microphone\n    * whose parameters will be retrieved.\n    * @param[out] params The parameters object that the\n    * microphone's parameters will be copied to.\n    *\n    * @return \\c true if the parameters were retrieved,\n    * \\c false if there was an error.\n    */\n   retro_get_mic_params_t get_params;\n\n   /**\n    * Enables or disables the given microphone.\n    * Microphones are disabled by default\n    * and must be explicitly enabled before they can be used.\n    * Disabled microphones will not process incoming audio samples,\n    * and will therefore have minimal impact on overall performance.\n    * Cores may enable microphones throughout their lifetime,\n    * or only for periods where they're needed.\n    *\n    * Cores that accept microphone input should be able to operate without it;\n    * we suggest substituting silence in this case.\n    *\n    * @param microphone Opaque handle to the microphone\n    * whose state will be adjusted.\n    * This will have been provided by \\c open_mic.\n    * @param state \\c true if the microphone should receive audio input,\n    * \\c false if it should be idle.\n    * @returns \\c true if the microphone's state was successfully set,\n    * \\c false if \\c microphone is invalid\n    * or if there was an error.\n    */\n   retro_set_mic_state_t set_mic_state;\n\n   /**\n    * Queries the active state of a microphone at the given index.\n    * Will return whether the microphone is enabled,\n    * even if the driver is paused.\n    *\n    * @param microphone Opaque handle to the microphone\n    * whose state will be queried.\n    * @return \\c true if the provided \\c microphone is valid and active,\n    * \\c false if not or if there was an error.\n    */\n   retro_get_mic_state_t get_mic_state;\n\n   /**\n    * Retrieves the input processed by the microphone since the last call.\n    * \\em Must be called every frame unless \\c microphone is disabled,\n    * similar to how \\c retro_audio_sample_batch_t works.\n    *\n    * @param[in] microphone Opaque handle to the microphone\n    * whose recent input will be retrieved.\n    * @param[out] samples The buffer that will be used to store the microphone's data.\n    * Microphone input is in mono (i.e. one number per sample).\n    * Should be large enough to accommodate the expected number of samples per frame;\n    * for example, a 44.1kHz sample rate at 60 FPS would require space for 735 samples.\n    * @param[in] num_samples The size of the data buffer in samples (\\em not bytes).\n    * Microphone input is in mono, so a \"frame\" and a \"sample\" are equivalent in length here.\n    *\n    * @return The number of samples that were copied into \\c samples.\n    * If \\c microphone is pending driver initialization,\n    * this function will copy silence of the requested length into \\c samples.\n    *\n    * Will return -1 if the microphone is disabled,\n    * the audio driver is paused,\n    * or there was an error.\n    */\n   retro_read_mic_t read_mic;\n};\n\n/** @} */\n\n/** @defgroup GET_DEVICE_POWER Device Power\n * @{\n */\n\n/**\n * Describes how a device is being powered.\n * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER\n */\nenum retro_power_state\n{\n   /**\n    * Indicates that the frontend cannot report its power state at this time,\n    * most likely due to a lack of support.\n    *\n    * \\c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value;\n    * instead, the environment callback will return \\c false.\n    */\n   RETRO_POWERSTATE_UNKNOWN = 0,\n\n   /**\n    * Indicates that the device is running on its battery.\n    * Usually applies to portable devices such as handhelds, laptops, and smartphones.\n    */\n   RETRO_POWERSTATE_DISCHARGING,\n\n   /**\n    * Indicates that the device's battery is currently charging.\n    */\n   RETRO_POWERSTATE_CHARGING,\n\n   /**\n    * Indicates that the device is connected to a power source\n    * and that its battery has finished charging.\n    */\n   RETRO_POWERSTATE_CHARGED,\n\n   /**\n    * Indicates that the device is connected to a power source\n    * and that it does not have a battery.\n    * This usually suggests a desktop computer or a non-portable game console.\n    */\n   RETRO_POWERSTATE_PLUGGED_IN\n};\n\n/**\n * Indicates that an estimate is not available for the battery level or time remaining,\n * even if the actual power state is known.\n */\n#define RETRO_POWERSTATE_NO_ESTIMATE (-1)\n\n/**\n * Describes the power state of the device running the frontend.\n * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER\n */\nstruct retro_device_power\n{\n   /**\n    * The current state of the frontend's power usage.\n    */\n   enum retro_power_state state;\n\n   /**\n    * A rough estimate of the amount of time remaining (in seconds)\n    * before the device powers off.\n    * This value depends on a variety of factors,\n    * so it is not guaranteed to be accurate.\n    *\n    * Will be set to \\c RETRO_POWERSTATE_NO_ESTIMATE if \\c state does not equal \\c RETRO_POWERSTATE_DISCHARGING.\n    * May still be set to \\c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate.\n    */\n   int seconds;\n\n   /**\n    * The approximate percentage of battery charge,\n    * ranging from 0 to 100 (inclusive).\n    * The device may power off before this reaches 0.\n    *\n    * The user might have configured their device\n    * to stop charging before the battery is full,\n    * so do not assume that this will be 100 in the \\c RETRO_POWERSTATE_CHARGED state.\n    */\n   int8_t percent;\n};\n\n/** @} */\n\n/**\n * @defgroup Callbacks\n * @{\n */\n\n/**\n * Environment callback to give implementations a way of performing uncommon tasks.\n *\n * @note Extensible.\n *\n * @param cmd The command to run.\n * @param data A pointer to the data associated with the command.\n *\n * @return Varies by callback,\n * but will always return \\c false if the command is not recognized.\n *\n * @see RETRO_ENVIRONMENT_SET_ROTATION\n * @see retro_set_environment()\n */\ntypedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);\n\n/**\n * Render a frame.\n *\n * @note For performance reasons, it is highly recommended to have a frame\n * that is packed in memory, i.e. pitch == width * byte_per_pixel.\n * Certain graphic APIs, such as OpenGL ES, do not like textures\n * that are not packed in memory.\n *\n * @param data A pointer to the frame buffer data with a pixel format of 15-bit \\c 0RGB1555 native endian, unless changed with \\c RETRO_ENVIRONMENT_SET_PIXEL_FORMAT.\n * @param width The width of the frame buffer, in pixels.\n * @param height The height frame buffer, in pixels.\n * @param pitch The width of the frame buffer, in bytes.\n *\n * @see retro_set_video_refresh()\n * @see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT\n * @see retro_pixel_format\n */\ntypedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,\n      unsigned height, size_t pitch);\n\n/**\n * Renders a single audio frame. Should only be used if implementation generates a single sample at a time.\n *\n * @param left The left audio sample represented as a signed 16-bit native endian.\n * @param right The right audio sample represented as a signed 16-bit native endian.\n *\n * @see retro_set_audio_sample()\n * @see retro_set_audio_sample_batch()\n */\ntypedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);\n\n/**\n * Renders multiple audio frames in one go.\n *\n * @note Only one of the audio callbacks must ever be used.\n *\n * @param data A pointer to the audio sample data pairs to render.\n * @param frames The number of frames that are represented in the data. One frame\n *     is defined as a sample of left and right channels, interleaved.\n *     For example: <tt>int16_t buf[4] = { l, r, l, r };</tt> would be 2 frames.\n *\n * @return The number of frames that were processed.\n *\n * @see retro_set_audio_sample_batch()\n * @see retro_set_audio_sample()\n */\ntypedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,\n      size_t frames);\n\n/**\n * Polls input.\n *\n * @see retro_set_input_poll()\n */\ntypedef void (RETRO_CALLCONV *retro_input_poll_t)(void);\n\n/**\n * Queries for input for player 'port'.\n *\n * @param port Which player 'port' to query.\n * @param device Which device to query for. Will be masked with \\c RETRO_DEVICE_MASK.\n * @param index The input index to retrieve.\n * The exact semantics depend on the device type given in \\c device.\n * @param id The ID of which value to query, like \\c RETRO_DEVICE_ID_JOYPAD_B.\n * @returns Depends on the provided arguments,\n * but will return 0 if their values are unsupported\n * by the frontend or the backing physical device.\n * @note Specialization of devices such as \\c RETRO_DEVICE_JOYPAD_MULTITAP that\n * have been set with \\c retro_set_controller_port_device() will still use the\n * higher level \\c RETRO_DEVICE_JOYPAD to request input.\n *\n * @see retro_set_input_state()\n * @see RETRO_DEVICE_NONE\n * @see RETRO_DEVICE_JOYPAD\n * @see RETRO_DEVICE_MOUSE\n * @see RETRO_DEVICE_KEYBOARD\n * @see RETRO_DEVICE_LIGHTGUN\n * @see RETRO_DEVICE_ANALOG\n * @see RETRO_DEVICE_POINTER\n */\ntypedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,\n      unsigned index, unsigned id);\n\n/**\n * Sets the environment callback.\n *\n * @param cb The function which is used when making environment calls.\n *\n * @note Guaranteed to be called before \\c retro_init().\n *\n * @see RETRO_ENVIRONMENT\n */\nRETRO_API void retro_set_environment(retro_environment_t cb);\n\n/**\n * Sets the video refresh callback.\n *\n * @param cb The function which is used when rendering a frame.\n *\n * @note Guaranteed to have been called before the first call to \\c retro_run() is made.\n */\nRETRO_API void retro_set_video_refresh(retro_video_refresh_t cb);\n\n/**\n * Sets the audio sample callback.\n *\n * @param cb The function which is used when rendering a single audio frame.\n *\n * @note Guaranteed to have been called before the first call to \\c retro_run() is made.\n */\nRETRO_API void retro_set_audio_sample(retro_audio_sample_t cb);\n\n/**\n * Sets the audio sample batch callback.\n *\n * @param cb The function which is used when rendering multiple audio frames in one go.\n *\n * @note Guaranteed to have been called before the first call to \\c retro_run() is made.\n */\nRETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb);\n\n/**\n * Sets the input poll callback.\n *\n * @param cb The function which is used to poll the active input.\n *\n * @note Guaranteed to have been called before the first call to \\c retro_run() is made.\n */\nRETRO_API void retro_set_input_poll(retro_input_poll_t cb);\n\n/**\n * Sets the input state callback.\n *\n * @param cb The function which is used to query the input state.\n *\n *@note Guaranteed to have been called before the first call to \\c retro_run() is made.\n */\nRETRO_API void retro_set_input_state(retro_input_state_t cb);\n\n/**\n * @}\n */\n\n/**\n * Called by the frontend when initializing a libretro core.\n *\n * @warning There are many possible \"gotchas\" with global state in dynamic libraries.\n * Here are some to keep in mind:\n * <ul>\n * <li>Do not assume that the core was loaded by the operating system\n * for the first time within this call.\n * It may have been statically linked or retained from a previous session.\n * Consequently, cores must not rely on global variables being initialized\n * to their default values before this function is called;\n * this also goes for object constructors in C++.\n * <li>Although C++ requires that constructors be called for global variables,\n * it does not require that their destructors be called\n * if stored within a dynamic library's global scope.\n * <li>If the core is statically linked to the frontend,\n * global variables may be initialized when the frontend itself is initially executed.\n * </ul>\n * @see retro_deinit\n */\nRETRO_API void retro_init(void);\n\n/**\n * Called by the frontend when deinitializing a libretro core.\n * The core must release all of its allocated resources before this function returns.\n *\n * @warning There are many possible \"gotchas\" with global state in dynamic libraries.\n * Here are some to keep in mind:\n * <ul>\n * <li>Do not assume that the operating system will unload the core after this function returns,\n * as the core may be linked statically or retained in memory.\n * Cores should use this function to clean up all allocated resources\n * and reset all global variables to their default states.\n * <li>Do not assume that this core won't be loaded again after this function returns.\n * It may be kept in memory by the frontend for later use,\n * or it may be statically linked.\n * Therefore, all global variables should be reset to their default states within this function.\n * <li>C++ does not require that destructors be called\n * for variables within a dynamic library's global scope.\n * Therefore, global objects that own dynamically-managed resources\n * (such as \\c std::string or <tt>std::vector</tt>)\n * should be kept behind pointers that are explicitly deallocated within this function.\n * </ul>\n * @see retro_init\n */\nRETRO_API void retro_deinit(void);\n\n/**\n * Retrieves which version of the libretro API is being used.\n *\n * @note This is used to validate ABI compatibility when the API is revised.\n *\n * @return Must return \\c RETRO_API_VERSION.\n *\n * @see RETRO_API_VERSION\n */\nRETRO_API unsigned retro_api_version(void);\n\n/**\n * Gets statically known system info.\n *\n * @note Can be called at any time, even before retro_init().\n *\n * @param info A pointer to a \\c retro_system_info where the info is to be loaded into. This must be statically allocated.\n */\nRETRO_API void retro_get_system_info(struct retro_system_info *info);\n\n/**\n * Gets information about system audio/video timings and geometry.\n *\n * @note Can be called only after \\c retro_load_game() has successfully completed.\n *\n * @note The implementation of this function might not initialize every variable\n * if needed. For example, \\c geom.aspect_ratio might not be initialized if\n * the core doesn't desire a particular aspect ratio.\n *\n * @param info A pointer to a \\c retro_system_av_info where the audio/video information should be loaded into.\n *\n * @see retro_system_av_info\n */\nRETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);\n\n/**\n * Sets device to be used for player 'port'.\n *\n * By default, \\c RETRO_DEVICE_JOYPAD is assumed to be plugged into all\n * available ports.\n *\n * @note Setting a particular device type is not a guarantee that libretro cores\n * will only poll input based on that particular device type. It is only a\n * hint to the libretro core when a core cannot automatically detect the\n * appropriate input device type on its own. It is also relevant when a\n * core can change its behavior depending on device type.\n *\n * @note As part of the core's implementation of retro_set_controller_port_device,\n * the core should call \\c RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the\n * frontend if the descriptions for any controls have changed as a\n * result of changing the device type.\n *\n * @param port Which port to set the device for, usually indicates the player number.\n * @param device Which device the given port is using. By default, \\c RETRO_DEVICE_JOYPAD is assumed for all ports.\n *\n * @see RETRO_DEVICE_NONE\n * @see RETRO_DEVICE_JOYPAD\n * @see RETRO_DEVICE_MOUSE\n * @see RETRO_DEVICE_KEYBOARD\n * @see RETRO_DEVICE_LIGHTGUN\n * @see RETRO_DEVICE_ANALOG\n * @see RETRO_DEVICE_POINTER\n * @see RETRO_ENVIRONMENT_SET_CONTROLLER_INFO\n */\nRETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);\n\n/**\n * Resets the currently-loaded game.\n * Cores should treat this as a soft reset (i.e. an emulated reset button) if possible,\n * but hard resets are acceptable.\n */\nRETRO_API void retro_reset(void);\n\n/**\n * Runs the game for one video frame.\n *\n * During \\c retro_run(), the \\c retro_input_poll_t callback must be called at least once.\n *\n * @note If a frame is not rendered for reasons where a game \"dropped\" a frame,\n * this still counts as a frame, and \\c retro_run() should explicitly dupe\n * a frame if \\c RETRO_ENVIRONMENT_GET_CAN_DUPE returns true. In this case,\n * the video callback can take a NULL argument for data.\n *\n * @see retro_input_poll_t\n */\nRETRO_API void retro_run(void);\n\n/**\n * Returns the amount of data the implementation requires to serialize internal state (save states).\n *\n * @note Between calls to \\c retro_load_game() and \\c retro_unload_game(), the\n * returned size is never allowed to be larger than a previous returned\n * value, to ensure that the frontend can allocate a save state buffer once.\n *\n * @return The amount of data the implementation requires to serialize the internal state.\n *\n * @see retro_serialize()\n */\nRETRO_API size_t retro_serialize_size(void);\n\n/**\n * Serializes the internal state.\n *\n * @param data A pointer to where the serialized data should be saved to.\n * @param size The size of the memory.\n *\n * @return If failed, or size is lower than \\c retro_serialize_size(), it\n * should return false. On success, it will return true.\n *\n * @see retro_serialize_size()\n * @see retro_unserialize()\n */\nRETRO_API bool retro_serialize(void *data, size_t len);\n\n/**\n * Unserialize the given state data, and load it into the internal state.\n *\n * @return Returns true if loading the state was successful, false otherwise.\n *\n * @see retro_serialize()\n */\nRETRO_API bool retro_unserialize(const void *data, size_t len);\n\n/**\n * Reset all the active cheats to their default disabled state.\n *\n * @see retro_cheat_set()\n */\nRETRO_API void retro_cheat_reset(void);\n\n/**\n * Enable or disable a cheat.\n *\n * @param index The index of the cheat to act upon.\n * @param enabled Whether to enable or disable the cheat.\n * @param code A string of the code used for the cheat.\n *\n * @see retro_cheat_reset()\n */\nRETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);\n\n/**\n * Loads a game.\n *\n * @param game A pointer to a \\c retro_game_info detailing information about the game to load.\n * May be \\c NULL if the core is loaded without content.\n *\n * @return Will return true when the game was loaded successfully, or false otherwise.\n *\n * @see retro_game_info\n * @see RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME\n */\nRETRO_API bool retro_load_game(const struct retro_game_info *game);\n\n/**\n * Called when the frontend has loaded one or more \"special\" content files,\n * typically through subsystems.\n *\n * @note Only necessary for cores that support subsystems.\n * Others may return \\c false or delegate to <tt>retro_load_game</tt>.\n *\n * @param game_type The type of game to load,\n * as determined by \\c retro_subsystem_info.\n * @param info A pointer to an array of \\c retro_game_info objects\n * providing information about the loaded content.\n * @param num_info The number of \\c retro_game_info objects passed into the info parameter.\n * @return \\c true if loading is successful, false otherwise.\n * If the core returns \\c false,\n * the frontend should abort the core\n * and return to its main menu (if applicable).\n *\n * @see RETRO_ENVIRONMENT_GET_GAME_INFO_EXT\n * @see RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO\n * @see retro_load_game()\n * @see retro_subsystem_info\n */\nRETRO_API bool retro_load_game_special(\n  unsigned game_type,\n  const struct retro_game_info *info, size_t num_info\n);\n\n/**\n * Unloads the currently loaded game.\n *\n * @note This is called before \\c retro_deinit(void).\n *\n * @see retro_load_game()\n * @see retro_deinit()\n */\nRETRO_API void retro_unload_game(void);\n\n/**\n * Gets the region of the actively loaded content as either \\c RETRO_REGION_NTSC or \\c RETRO_REGION_PAL.\n * @note This refers to the region of the content's intended television standard,\n * not necessarily the region of the content's origin.\n * For emulated consoles that don't use either standard\n * (e.g. handhelds or post-HD platforms),\n * the core should return \\c RETRO_REGION_NTSC.\n * @return The region of the actively loaded content.\n *\n * @see RETRO_REGION_NTSC\n * @see RETRO_REGION_PAL\n */\nRETRO_API unsigned retro_get_region(void);\n\n/**\n * Get a region of memory.\n *\n * @param id The ID for the memory block that's desired to retrieve. Can be \\c RETRO_MEMORY_SAVE_RAM, \\c RETRO_MEMORY_RTC, \\c RETRO_MEMORY_SYSTEM_RAM, or \\c RETRO_MEMORY_VIDEO_RAM.\n *\n * @return A pointer to the desired region of memory, or NULL when not available.\n *\n * @see RETRO_MEMORY_SAVE_RAM\n * @see RETRO_MEMORY_RTC\n * @see RETRO_MEMORY_SYSTEM_RAM\n * @see RETRO_MEMORY_VIDEO_RAM\n */\nRETRO_API void *retro_get_memory_data(unsigned id);\n\n/**\n * Gets the size of the given region of memory.\n *\n * @param id The ID for the memory block to check the size of. Can be RETRO_MEMORY_SAVE_RAM, RETRO_MEMORY_RTC, RETRO_MEMORY_SYSTEM_RAM, or RETRO_MEMORY_VIDEO_RAM.\n *\n * @return The size of the region in memory, or 0 when not available.\n *\n * @see RETRO_MEMORY_SAVE_RAM\n * @see RETRO_MEMORY_RTC\n * @see RETRO_MEMORY_SYSTEM_RAM\n * @see RETRO_MEMORY_VIDEO_RAM\n */\nRETRO_API size_t retro_get_memory_size(unsigned id);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/libretro_d3d.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro API header (libretro_d3d.h)\n * ---------------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the\n * \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_DIRECT3D_H__\n#define LIBRETRO_DIRECT3D_H__\n\n#include \"libretro.h\"\n\n#ifdef HAVE_D3D11\n#include \"libretro_d3d11.h\"\n#endif\n\n#ifdef HAVE_D3D12\n#include \"libretro_d3d12.h\"\n#endif\n\n#endif /* LIBRETRO_DIRECT3D_H__ */\n"
  },
  {
    "path": "include/libretro_d3d11.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro API header (libretro_d3d.h)\n * ---------------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the\n * \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_DIRECT3D11_H__\n#define LIBRETRO_DIRECT3D11_H__\n\n#include <d3d11.h>\n#include <d3dcompiler.h>\n\n#define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1\n\nstruct retro_hw_render_interface_d3d11\n{\n  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11. */\n  enum retro_hw_render_interface_type interface_type;\n  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11_VERSION. */\n  unsigned interface_version;\n\n  /* Opaque handle to the d3d11 backend in the frontend\n   * which must be passed along to all function pointers\n   * in this interface.\n   */\n  void* handle;\n  ID3D11Device *device;\n  ID3D11DeviceContext *context;\n  D3D_FEATURE_LEVEL featureLevel;\n  pD3DCompile D3DCompile;\n};\n\n#endif /* LIBRETRO_DIRECT3D11_H__ */\n"
  },
  {
    "path": "include/libretro_d3d12.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro API header (libretro_d3d.h)\n * ---------------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the\n * \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_DIRECT3D12_H__\n#define LIBRETRO_DIRECT3D12_H__\n\n#include <d3d12.h>\n#include <d3dcompiler.h>\n\n#define RETRO_HW_RENDER_INTERFACE_D3D12_VERSION 1\n\nstruct retro_hw_render_interface_d3d12\n{\n  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12. */\n  enum retro_hw_render_interface_type interface_type;\n  /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D12_VERSION. */\n  unsigned interface_version;\n\n  /* Opaque handle to the d3d12 backend in the frontend\n   * which must be passed along to all function pointers\n   * in this interface.\n   */\n  void* handle;\n  ID3D12Device *device;\n  ID3D12CommandQueue *queue;\n  pD3DCompile D3DCompile;\n  D3D12_RESOURCE_STATES required_state;\n  void (*set_texture)(void* handle, ID3D12Resource* texture, DXGI_FORMAT format);\n};\n\n#endif /* LIBRETRO_DIRECT3D12_H__ */\n"
  },
  {
    "path": "include/libretro_dspfilter.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro API header (libretro_dspfilter.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_DSPFILTER_API_H__\n#define LIBRETRO_DSPFILTER_API_H__\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#define DSPFILTER_SIMD_SSE      (1 << 0)\n#define DSPFILTER_SIMD_SSE2     (1 << 1)\n#define DSPFILTER_SIMD_VMX      (1 << 2)\n#define DSPFILTER_SIMD_VMX128   (1 << 3)\n#define DSPFILTER_SIMD_AVX      (1 << 4)\n#define DSPFILTER_SIMD_NEON     (1 << 5)\n#define DSPFILTER_SIMD_SSE3     (1 << 6)\n#define DSPFILTER_SIMD_SSSE3    (1 << 7)\n#define DSPFILTER_SIMD_MMX      (1 << 8)\n#define DSPFILTER_SIMD_MMXEXT   (1 << 9)\n#define DSPFILTER_SIMD_SSE4     (1 << 10)\n#define DSPFILTER_SIMD_SSE42    (1 << 11)\n#define DSPFILTER_SIMD_AVX2     (1 << 12)\n#define DSPFILTER_SIMD_VFPU     (1 << 13)\n#define DSPFILTER_SIMD_PS       (1 << 14)\n\n/* A bit-mask of all supported SIMD instruction sets.\n * Allows an implementation to pick different\n * dspfilter_implementation structs.\n */\ntypedef unsigned dspfilter_simd_mask_t;\n\n/* Dynamic library endpoint. */\ntypedef const struct dspfilter_implementation *(\n      *dspfilter_get_implementation_t)(dspfilter_simd_mask_t mask);\n\n/* The same SIMD mask argument is forwarded to create() callback\n * as well to avoid having to keep lots of state around. */\nconst struct dspfilter_implementation *dspfilter_get_implementation(\n      dspfilter_simd_mask_t mask);\n\n#define DSPFILTER_API_VERSION 1\n\nstruct dspfilter_info\n{\n   /* Input sample rate that the DSP plugin receives. */\n   float input_rate;\n};\n\nstruct dspfilter_output\n{\n   /* The DSP plugin has to provide the buffering for the\n    * output samples or reuse the input buffer directly.\n    *\n    * The samples are laid out in interleaving order: LRLRLRLR\n    * The range of the samples are [-1.0, 1.0].\n    *\n    * It is not necessary to manually clip values. */\n   float *samples;\n\n   /* Frames which the DSP plugin outputted for the current process.\n    *\n    * One frame is here defined as a combined sample of\n    * left and right channels.\n    *\n    * (I.e. 44.1kHz, 16bit stereo will have\n    * 88.2k samples/sec and 44.1k frames/sec.)\n    */\n   unsigned frames;\n};\n\nstruct dspfilter_input\n{\n   /* Input data for the DSP. The samples are interleaved in order: LRLRLRLR\n    *\n    * It is valid for a DSP plug to use this buffer for output as long as\n    * the output size is less or equal to the input.\n    *\n    * This is useful for filters which can output one sample for each\n    * input sample and do not need to maintain its own buffers.\n    *\n    * Block based filters must provide their own buffering scheme.\n    *\n    * The input size is not bound, but it can be safely assumed that it\n    * will not exceed ~100ms worth of audio at a time. */\n   float *samples;\n\n   /* Number of frames for input data.\n    * One frame is here defined as a combined sample of\n    * left and right channels.\n    *\n    * (I.e. 44.1kHz, 16bit stereo will have\n    * 88.2k samples/sec and 44.1k frames/sec.)\n    */\n   unsigned frames;\n};\n\n/* Returns true if config key was found. Otherwise,\n * returns false, and sets value to default value.\n */\ntypedef int (*dspfilter_config_get_float_t)(void *userdata,\n      const char *key, float *value, float default_value);\n\ntypedef int (*dspfilter_config_get_int_t)(void *userdata,\n      const char *key, int *value, int default_value);\n\n/* Allocates an array with values. free() with dspfilter_config_free_t. */\ntypedef int (*dspfilter_config_get_float_array_t)(void *userdata,\n      const char *key, float **values, unsigned *out_num_values,\n      const float *default_values, unsigned num_default_values);\n\ntypedef int (*dspfilter_config_get_int_array_t)(void *userdata,\n      const char *key, int **values, unsigned *out_num_values,\n      const int *default_values, unsigned num_default_values);\n\ntypedef int (*dspfilter_config_get_string_t)(void *userdata,\n      const char *key, char **output, const char *default_output);\n\n/* Calls free() in host runtime. Sometimes needed on Windows.\n * free() on NULL is fine. */\ntypedef void (*dspfilter_config_free_t)(void *ptr);\n\nstruct dspfilter_config\n{\n   dspfilter_config_get_float_t get_float;\n   dspfilter_config_get_int_t get_int;\n\n   dspfilter_config_get_float_array_t get_float_array;\n   dspfilter_config_get_int_array_t get_int_array;\n\n   dspfilter_config_get_string_t get_string;\n   /* Avoid problems where DSP plug and host are\n    * linked against different C runtimes. */\n   dspfilter_config_free_t free;\n};\n\n/* Creates a handle of the plugin. Returns NULL if failed. */\ntypedef void *(*dspfilter_init_t)(const struct dspfilter_info *info,\n      const struct dspfilter_config *config, void *userdata);\n\n/* Frees the handle. */\ntypedef void (*dspfilter_free_t)(void *data);\n\n/* Processes input data.\n * The plugin is allowed to return variable sizes for output data. */\ntypedef void (*dspfilter_process_t)(void *data,\n      struct dspfilter_output *output, const struct dspfilter_input *input);\n\nstruct dspfilter_implementation\n{\n   dspfilter_init_t     init;\n   dspfilter_process_t  process;\n   dspfilter_free_t     free;\n\n   /* Must be DSPFILTER_API_VERSION */\n   unsigned api_version;\n\n   /* Human readable identifier of implementation. */\n   const char *ident;\n\n   /* Computer-friendly short version of ident.\n    * Lower case, no spaces and special characters, etc. */\n   const char *short_ident;\n};\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/libretro_gskit_ps2.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro API header (libretro_d3d.h)\n * ---------------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the\n * \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or\n * substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_GSKIT_PS2_H_\n#define LIBRETRO_GSKIT_PS2_H_\n\n#include \"libretro.h\"\n\n#if defined(PS2)\n\n#include <gsKit.h>\n\n#define RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION 2\n\nstruct retro_hw_ps2_insets\n{\n  float top;\n  float left;\n  float bottom;\n  float right;\n};\n\n#define empty_ps2_insets (struct retro_hw_ps2_insets){0.f, 0.f, 0.f, 0.f}\n\nstruct retro_hw_render_interface_gskit_ps2\n{\n  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2. */\n  enum retro_hw_render_interface_type interface_type;\n  /* Must be set to RETRO_HW_RENDER_INTERFACE_GSKIT_PS2_VERSION. */\n  unsigned interface_version;\n\n  /* Opaque handle to the GSKit_PS2 backend in the frontend\n   * which must be passed along to all function pointers\n   * in this interface.\n   */\n   GSTEXTURE *coreTexture;\n   struct retro_hw_ps2_insets padding;\n};\ntypedef struct retro_hw_render_interface_gskit_ps2 RETRO_HW_RENDER_INTEFACE_GSKIT_PS2;\n\n#endif\n\n#endif /* LIBRETRO_GSKIT_PS2_H_ */\n"
  },
  {
    "path": "include/libretro_vulkan.h",
    "content": "/* Copyright (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------------\n * The following license statement only applies to this libretro API header (libretro_vulkan.h)\n * ---------------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_VULKAN_H__\n#define LIBRETRO_VULKAN_H__\n\n#include <libretro.h>\n#include <vulkan/vulkan.h>\n\n#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5\n#define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 2\n\nstruct retro_vulkan_image\n{\n   VkImageView image_view;\n   VkImageLayout image_layout;\n   VkImageViewCreateInfo create_info;\n};\n\ntypedef void (*retro_vulkan_set_image_t)(void *handle,\n      const struct retro_vulkan_image *image,\n      uint32_t num_semaphores,\n      const VkSemaphore *semaphores,\n      uint32_t src_queue_family);\n\ntypedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle);\ntypedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle);\ntypedef void (*retro_vulkan_set_command_buffers_t)(void *handle,\n      uint32_t num_cmd,\n      const VkCommandBuffer *cmd);\ntypedef void (*retro_vulkan_wait_sync_index_t)(void *handle);\ntypedef void (*retro_vulkan_lock_queue_t)(void *handle);\ntypedef void (*retro_vulkan_unlock_queue_t)(void *handle);\ntypedef void (*retro_vulkan_set_signal_semaphore_t)(void *handle, VkSemaphore semaphore);\n\ntypedef const VkApplicationInfo *(*retro_vulkan_get_application_info_t)(void);\n\nstruct retro_vulkan_context\n{\n   VkPhysicalDevice gpu;\n   VkDevice device;\n   VkQueue queue;\n   uint32_t queue_family_index;\n   VkQueue presentation_queue;\n   uint32_t presentation_queue_family_index;\n};\n\n/* This is only used in v1 of the negotiation interface.\n * It is deprecated since it cannot express PDF2 features or optional extensions. */\ntypedef bool (*retro_vulkan_create_device_t)(\n      struct retro_vulkan_context *context,\n      VkInstance instance,\n      VkPhysicalDevice gpu,\n      VkSurfaceKHR surface,\n      PFN_vkGetInstanceProcAddr get_instance_proc_addr,\n      const char **required_device_extensions,\n      unsigned num_required_device_extensions,\n      const char **required_device_layers,\n      unsigned num_required_device_layers,\n      const VkPhysicalDeviceFeatures *required_features);\n\ntypedef void (*retro_vulkan_destroy_device_t)(void);\n\n/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */\ntypedef VkInstance (*retro_vulkan_create_instance_wrapper_t)(\n      void *opaque, const VkInstanceCreateInfo *create_info);\n\n/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */\ntypedef VkInstance (*retro_vulkan_create_instance_t)(\n      PFN_vkGetInstanceProcAddr get_instance_proc_addr,\n      const VkApplicationInfo *app,\n      retro_vulkan_create_instance_wrapper_t create_instance_wrapper,\n      void *opaque);\n\n/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */\ntypedef VkDevice (*retro_vulkan_create_device_wrapper_t)(\n      VkPhysicalDevice gpu, void *opaque,\n      const VkDeviceCreateInfo *create_info);\n\n/* v2 CONTEXT_NEGOTIATION_INTERFACE only. */\ntypedef bool (*retro_vulkan_create_device2_t)(\n      struct retro_vulkan_context *context,\n      VkInstance instance,\n      VkPhysicalDevice gpu,\n      VkSurfaceKHR surface,\n      PFN_vkGetInstanceProcAddr get_instance_proc_addr,\n      retro_vulkan_create_device_wrapper_t create_device_wrapper,\n      void *opaque);\n\n/* Note on thread safety:\n * The Vulkan API is heavily designed around multi-threading, and\n * the libretro interface for it should also be threading friendly.\n * A core should be able to build command buffers and submit\n * command buffers to the GPU from any thread.\n */\n\nstruct retro_hw_render_context_negotiation_interface_vulkan\n{\n   /* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */\n   enum retro_hw_render_context_negotiation_interface_type interface_type;\n   /* Usually set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION,\n    * but can be lower depending on GET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_SUPPORT. */\n   unsigned interface_version;\n\n   /* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of\n    * its \"default\" application info.\n    * VkApplicationInfo::apiVersion also controls the target core Vulkan version for instance level functionality.\n    * Lifetime of the returned pointer must remain until the retro_vulkan_context is initialized.\n    *\n    * NOTE: For optimal compatibility with e.g. Android which is very slow to update its loader,\n    * a core version of 1.1 should be requested. Features beyond that can be requested with extensions.\n    * Vulkan 1.0 is only appropriate for legacy cores, but is still supported.\n    * A frontend is free to bump the instance creation apiVersion as necessary if the frontend requires more advanced core features.\n    *\n    * v2: This function must not be NULL, and must not return NULL.\n    * v1: It was not clearly defined if this function could return NULL.\n    *     Frontends should be defensive and provide a default VkApplicationInfo\n    *     if this function returns NULL or if this function is NULL.\n    */\n   retro_vulkan_get_application_info_t get_application_info;\n\n   /* If non-NULL, the libretro core will choose one or more physical devices,\n    * create one or more logical devices and create one or more queues.\n    * The core must prepare a designated PhysicalDevice, Device, Queue and queue family index\n    * which the frontend will use for its internal operation.\n    *\n    * If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this PhysicalDevice if the call succeeds.\n    * The core is still free to use other physical devices for other purposes that are private to the core.\n    *\n    * The frontend will request certain extensions and layers for a device which is created.\n    * The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE.\n    *\n    * If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues.\n    * If presentation to \"surface\" is supported on the queue, presentation_queue must be equal to queue.\n    * If not, a second queue must be provided in presentation_queue and presentation_queue_index.\n    * If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with supported for\n    * VK_KHR_surface extension.\n    *\n    * The core is free to set its own queue priorities.\n    * Device provided to frontend is owned by the frontend, but any additional device resources must be freed by core\n    * in destroy_device callback.\n    *\n    * If this function returns true, a PhysicalDevice, Device and Queues are initialized.\n    * If false, none of the above have been initialized and the frontend will attempt\n    * to fallback to \"default\" device creation, as if this function was never called.\n    */\n   retro_vulkan_create_device_t create_device;\n\n   /* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE.\n    * However, it will be called even if context_reset was not called.\n    * This can happen if the context never succeeds in being created.\n    * destroy_device will always be called before the VkInstance\n    * of the frontend is destroyed if create_device was called successfully so that the core has a chance of\n    * tearing down its own device resources.\n    *\n    * Only auxiliary resources should be freed here, i.e. resources which are not part of retro_vulkan_context.\n    * v2: Auxiliary instance resources created during create_instance can also be freed here.\n    */\n   retro_vulkan_destroy_device_t destroy_device;\n\n   /* v2 API: If interface_version is < 2, fields below must be ignored.\n    * If the frontend does not support interface version 2, the v1 entry points will be used instead. */\n\n   /* If non-NULL, this is called to create an instance, otherwise a VkInstance is created by the frontend.\n    * v1 interface bug: The only way to enable instance features is through core versions signalled in VkApplicationInfo.\n    * The frontend may request that certain extensions and layers\n    * are enabled on the VkInstance. Application may add additional features.\n    * If app is non-NULL, apiVersion controls the minimum core version required by the application.\n    * Return a VkInstance or VK_NULL_HANDLE. The VkInstance is owned by the frontend.\n    *\n    * Rather than call vkCreateInstance directly, a core must call the CreateInstance wrapper provided with:\n    * VkInstance instance = create_instance_wrapper(opaque, &create_info);\n    * If the core wishes to create a private instance for whatever reason (relying on shared memory for example),\n    * it may call vkCreateInstance directly. */\n   retro_vulkan_create_instance_t create_instance;\n\n   /* If non-NULL and frontend recognizes negotiation interface >= 2, create_device2 takes precedence over create_device.\n    * Similar to create_device, but is extended to better understand new core versions and PDF2 feature enablement.\n    * Requirements for create_device2 are the same as create_device unless a difference is mentioned.\n    *\n    * v2 consideration:\n    * If the chosen gpu by frontend cannot be supported, a core must return false.\n    *\n    * NOTE: \"Cannot be supported\" is intentionally vaguely defined.\n    * Refusing to run on an iGPU for a very intensive core with desktop GPU as a minimum spec may be in the gray area.\n    * Not supporting optional features is not a good reason to reject a physical device, however.\n    *\n    * On device creation feature with explicit gpu, a frontend should fall back create_device2 with gpu == VK_NULL_HANDLE and let core\n    * decide on a supported device if possible.\n    *\n    * A core must assume that the explicitly provided GPU is the only guaranteed attempt it has to create a device.\n    * A fallback may not be attempted if there are particular reasons why only a specific physical device can work,\n    * but these situations should be esoteric and rare in nature, e.g. a libretro frontend is implemented with external memory\n    * and only LUID matching would work.\n    * Cores and frontends should ensure \"best effort\" when negotiating like this and appropriate logging is encouraged.\n    *\n    * v1 note: In the v1 version of create_device, it was never expected that create_device would fail like this,\n    * and frontends are not expected to attempt fall backs.\n    *\n    * Rather than call vkCreateDevice directly, a core must call the CreateDevice wrapper provided with:\n    * VkDevice device = create_device_wrapper(gpu, opaque, &create_info);\n    * If the core wishes to create a private device for whatever reason (relying on shared memory for example),\n    * it may call vkCreateDevice directly.\n    *\n    * This allows the frontend to add additional extensions that it requires as well as adjust the PDF2 pNext as required.\n    * It is also possible adjust the queue create infos in case the frontend desires to allocate some private queues.\n    *\n    * The get_instance_proc_addr provided in create_device2 must be the same as create_instance.\n    *\n    * NOTE: The frontend must not disable features requested by application.\n    * NOTE: The frontend must not add any robustness features as some API behavior may change (VK_EXT_descriptor_buffer comes to mind).\n    * I.e. robustBufferAccess and the like. (nullDescriptor from robustness2 is allowed to be enabled).\n    */\n   retro_vulkan_create_device2_t create_device2;\n};\n\nstruct retro_hw_render_interface_vulkan\n{\n   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */\n   enum retro_hw_render_interface_type interface_type;\n   /* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */\n   unsigned interface_version;\n\n   /* Opaque handle to the Vulkan backend in the frontend\n    * which must be passed along to all function pointers\n    * in this interface.\n    *\n    * The rationale for including a handle here (which libretro v1\n    * doesn't currently do in general) is:\n    *\n    * - Vulkan cores should be able to be freely threaded without lots of fuzz.\n    *   This would break frontends which currently rely on TLS\n    *   to deal with multiple cores loaded at the same time.\n    * - Fixing this in general is TODO for an eventual libretro v2.\n    */\n   void *handle;\n\n   /* The Vulkan instance the context is using. */\n   VkInstance instance;\n   /* The physical device used. */\n   VkPhysicalDevice gpu;\n   /* The logical device used. */\n   VkDevice device;\n\n   /* Allows a core to fetch all its needed symbols without having to link\n    * against the loader itself. */\n   PFN_vkGetDeviceProcAddr get_device_proc_addr;\n   PFN_vkGetInstanceProcAddr get_instance_proc_addr;\n\n   /* The queue the core must use to submit data.\n    * This queue and index must remain constant throughout the lifetime\n    * of the context.\n    *\n    * This queue will be the queue that supports graphics and compute\n    * if the device supports compute.\n    */\n   VkQueue queue;\n   unsigned queue_index;\n\n   /* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,\n    * set which image to use for this frame.\n    *\n    * If num_semaphores is non-zero, the frontend will wait for the\n    * semaphores provided to be signaled before using the results further\n    * in the pipeline.\n    *\n    * Semaphores provided by a single call to set_image will only be\n    * waited for once (waiting for a semaphore resets it).\n    * E.g. set_image, video_refresh, and then another\n    * video_refresh without set_image,\n    * but same image will only wait for semaphores once.\n    *\n    * For this reason, ownership transfer will only occur if semaphores\n    * are waited on for a particular frame in the frontend.\n    *\n    * Using semaphores is optional for synchronization purposes,\n    * but if not using\n    * semaphores, an image memory barrier in vkCmdPipelineBarrier\n    * should be used in the graphics_queue.\n    * Example:\n    *\n    * vkCmdPipelineBarrier(cmd,\n    *    srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,\n    *    dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n    *    image_memory_barrier = {\n    *       srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,\n    *       dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n    *    });\n    *\n    * The use of pipeline barriers instead of semaphores is encouraged\n    * as it is simpler and more fine-grained. A layout transition\n    * must generally happen anyways which requires a\n    * pipeline barrier.\n    *\n    * The image passed to set_image must have imageUsage flags set to at least\n    * VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.\n    * The core will naturally want to use flags such as\n    * VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or\n    * VK_IMAGE_USAGE_TRANSFER_DST_BIT depending\n    * on how the final image is created.\n    *\n    * The image must also have been created with MUTABLE_FORMAT bit set if\n    * 8-bit formats are used, so that the frontend can reinterpret sRGB\n    * formats as it sees fit.\n    *\n    * Images passed to set_image should be created with TILING_OPTIMAL.\n    * The image layout should be transitioned to either\n    * VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.\n    * The actual image layout used must be set in image_layout.\n    *\n    * The image must be a 2D texture which may or not be layered\n    * and/or mipmapped.\n    *\n    * The image must be suitable for linear sampling.\n    * While the image_view is typically the only field used,\n    * the frontend may want to reinterpret the texture as sRGB vs.\n    * non-sRGB for example so the VkImageViewCreateInfo used to\n    * create the image view must also be passed in.\n    *\n    * The data in the pointer to the image struct will not be copied\n    * as the pNext field in create_info cannot be reliably deep-copied.\n    * The image pointer passed to set_image must be valid until\n    * retro_video_refresh_t has returned.\n    *\n    * If frame duping is used when passing NULL to retro_video_refresh_t,\n    * the frontend is free to either use the latest image passed to\n    * set_image or reuse the older pointer passed to set_image the\n    * frame RETRO_HW_FRAME_BUFFER_VALID was last used.\n    *\n    * Essentially, the lifetime of the pointer passed to\n    * retro_video_refresh_t should be extended if frame duping is used\n    * so that the frontend can reuse the older pointer.\n    *\n    * The image itself however, must not be touched by the core until\n    * wait_sync_index has been completed later. The frontend may perform\n    * layout transitions on the image, so even read-only access is not defined.\n    * The exception to read-only rule is if GENERAL layout is used for the image.\n    * In this case, the frontend is not allowed to perform any layout transitions,\n    * so concurrent reads from core and frontend are allowed.\n    *\n    * If frame duping is used, or if set_command_buffers is used,\n    * the frontend will not wait for any semaphores.\n    *\n    * The src_queue_family is used to specify which queue family\n    * the image is currently owned by. If using multiple queue families\n    * (e.g. async compute), the frontend will need to acquire ownership of the\n    * image before rendering with it and release the image afterwards.\n    *\n    * If src_queue_family is equal to the queue family (queue_index),\n    * no ownership transfer will occur.\n    * Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED,\n    * no ownership transfer will occur.\n    *\n    * The frontend will always release ownership back to src_queue_family.\n    * Waiting for frontend to complete with wait_sync_index() ensures that\n    * the frontend has released ownership back to the application.\n    * Note that in Vulkan, transferring ownership is a two-part process.\n    *\n    * Example frame:\n    *  - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier.\n    *  - core calls set_image with src_queue_index.\n    *  - Frontend will acquire the image with src_queue_index -> queue_index as well, completing the ownership transfer.\n    *  - Frontend renders the frame.\n    *  - Frontend releases ownership with queue_index -> src_queue_index.\n    *  - Next time image is used, core must acquire ownership from queue_index ...\n    *\n    * Since the frontend releases ownership, we cannot necessarily dupe the frame because\n    * the core needs to make the roundtrip of ownership transfer.\n    */\n   retro_vulkan_set_image_t set_image;\n\n   /* Get the current sync index for this frame which is obtained in\n    * frontend by calling e.g. vkAcquireNextImageKHR before calling\n    * retro_run().\n    *\n    * This index will correspond to which swapchain buffer is currently\n    * the active one.\n    *\n    * Knowing this index is very useful for maintaining safe asynchronous CPU\n    * and GPU operation without stalling.\n    *\n    * The common pattern for synchronization is to receive fences when\n    * submitting command buffers to Vulkan (vkQueueSubmit) and add this fence\n    * to a list of fences for frame number get_sync_index().\n    *\n    * Next time we receive the same get_sync_index(), we can wait for the\n    * fences from before, which will usually return immediately as the\n    * frontend will generally also avoid letting the GPU run ahead too much.\n    *\n    * After the fence has signaled, we know that the GPU has completed all\n    * GPU work related to work submitted in the frame we last saw get_sync_index().\n    *\n    * This means we can safely reuse or free resources allocated in this frame.\n    *\n    * In theory, even if we wait for the fences correctly, it is not technically\n    * safe to write to the image we earlier passed to the frontend since we're\n    * not waiting for the frontend GPU jobs to complete.\n    *\n    * The frontend will guarantee that the appropriate pipeline barrier\n    * in graphics_queue has been used such that\n    * VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot\n    * start until the frontend is done with the image.\n    */\n   retro_vulkan_get_sync_index_t get_sync_index;\n\n   /* Returns a bitmask of how many swapchain images we currently have\n    * in the frontend.\n    *\n    * If bit #N is set in the return value, get_sync_index can return N.\n    * Knowing this value is useful for preallocating per-frame management\n    * structures ahead of time.\n    *\n    * While this value will typically remain constant throughout the\n    * applications lifecycle, it may for example change if the frontend\n    * suddenly changes fullscreen state and/or latency.\n    *\n    * If this value ever changes, it is safe to assume that the device\n    * is completely idle and all synchronization objects can be deleted\n    * right away as desired.\n    */\n   retro_vulkan_get_sync_index_mask_t get_sync_index_mask;\n\n   /* Instead of submitting the command buffer to the queue first, the core\n    * can pass along its command buffer to the frontend, and the frontend\n    * will submit the command buffer together with the frontends command buffers.\n    *\n    * This has the advantage that the overhead of vkQueueSubmit can be\n    * amortized into a single call. For this mode, semaphores in set_image\n    * will be ignored, so vkCmdPipelineBarrier must be used to synchronize\n    * the core and frontend.\n    *\n    * The command buffers in set_command_buffers are only executed once,\n    * even if frame duping is used.\n    *\n    * If frame duping is used, set_image should be used for the frames\n    * which should be duped instead.\n    *\n    * Command buffers passed to the frontend with set_command_buffers\n    * must not actually be submitted to the GPU until retro_video_refresh_t\n    * is called.\n    *\n    * The frontend must submit the command buffer before submitting any\n    * other command buffers provided by set_command_buffers. */\n   retro_vulkan_set_command_buffers_t set_command_buffers;\n\n   /* Waits on CPU for device activity for the current sync index to complete.\n    * This is useful since the core will not have a relevant fence to sync with\n    * when the frontend is submitting the command buffers. */\n   retro_vulkan_wait_sync_index_t wait_sync_index;\n\n   /* If the core submits command buffers itself to any of the queues provided\n    * in this interface, the core must lock and unlock the frontend from\n    * racing on the VkQueue.\n    *\n    * Queue submission can happen on any thread.\n    * Even if queue submission happens on the same thread as retro_run(),\n    * the lock/unlock functions must still be called.\n    *\n    * NOTE: Queue submissions are heavy-weight. */\n   retro_vulkan_lock_queue_t lock_queue;\n   retro_vulkan_unlock_queue_t unlock_queue;\n\n   /* Sets a semaphore which is signaled when the image in set_image can safely be reused.\n    * The semaphore is consumed next call to retro_video_refresh_t.\n    * The semaphore will be signalled even for duped frames.\n    * The semaphore will be signalled only once, so set_signal_semaphore should be called every frame.\n    * The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to retro_video_refresh_t.\n    *\n    * This is mostly useful to support use cases where you're rendering to a single image that\n    * is recycled in a ping-pong fashion with the frontend to save memory (but potentially less throughput).\n    */\n   retro_vulkan_set_signal_semaphore_t set_signal_semaphore;\n};\n\n#endif\n"
  },
  {
    "path": "include/lists/dir_list.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (dir_list.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_DIR_LIST_H\n#define __LIBRETRO_SDK_DIR_LIST_H\n\n#include <retro_common_api.h>\n#include <boolean.h>\n\n#include <lists/string_list.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * dir_list_append:\n * @list               : existing list to append to.\n * @dir                : directory path.\n * @ext                : allowed extensions of file directory entries to include.\n * @include_dirs       : include directories as part of the finished directory listing?\n * @include_hidden     : include hidden files and directories as part of the finished directory listing?\n * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.\n * @recursive          : list directory contents recursively\n *\n * Create a directory listing, appending to an existing list\n *\n * @return Returns true on success, otherwise false.\n **/\nbool dir_list_append(struct string_list *list, const char *dir, const char *ext,\n      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);\n\n/**\n * dir_list_new:\n * @dir                : directory path.\n * @ext                : allowed extensions of file directory entries to include.\n * @include_dirs       : include directories as part of the finished directory listing?\n * @include_hidden     : include hidden files and directories as part of the finished directory listing?\n * @include_compressed : include compressed files, even when not part of ext.\n * @recursive          : list directory contents recursively\n *\n * Create a directory listing.\n *\n * @return pointer to a directory listing of type 'struct string_list *' on success,\n * NULL in case of error. Has to be freed manually.\n **/\nstruct string_list *dir_list_new(const char *dir, const char *ext,\n      bool include_dirs, bool include_hidden, bool include_compressed, bool recursive);\n\n/**\n * dir_list_initialize:\n *\n * NOTE: @list must zero initialised before\n * calling this function, otherwise UB.\n **/\nbool dir_list_initialize(struct string_list *list,\n      const char *dir,\n      const char *ext, bool include_dirs,\n      bool include_hidden, bool include_compressed,\n      bool recursive);\n\n/**\n * dir_list_sort:\n * @list      : pointer to the directory listing.\n * @dir_first : move the directories in the listing to the top?\n *\n * Sorts a directory listing.\n **/\nvoid dir_list_sort(struct string_list *list, bool dir_first);\n\n/**\n * dir_list_sort_ignore_ext:\n * @list      : pointer to the directory listing.\n * @dir_first : move the directories in the listing to the top?\n *\n * Sorts a directory listing. File extensions are ignored.\n **/\nvoid dir_list_sort_ignore_ext(struct string_list *list, bool dir_first);\n\n/**\n * dir_list_free:\n * @list : pointer to the directory listing\n *\n * Frees a directory listing.\n **/\nvoid dir_list_free(struct string_list *list);\n\nbool dir_list_deinitialize(struct string_list *list);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/lists/file_list.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_list.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FILE_LIST_H__\n#define __LIBRETRO_SDK_FILE_LIST_H__\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n#include <stddef.h>\n#include <stdlib.h>\n\n#include <boolean.h>\n\nstruct item_file\n{\n   void *userdata;\n   void *actiondata;\n   char *path;\n   char *label;\n   char *alt;\n   size_t directory_ptr;\n   size_t entry_idx;\n   unsigned type;\n};\n\ntypedef struct file_list\n{\n   struct item_file *list;\n\n   size_t capacity;\n   size_t size;\n} file_list_t;\n\nvoid *file_list_get_userdata_at_offset(const file_list_t *list,\n      size_t index);\n\nvoid *file_list_get_actiondata_at_offset(const file_list_t *list,\n      size_t index);\n\n/**\n * @brief frees the list\n *\n * NOTE: This function will also free() the entries actiondata\n * and userdata fields if they are non-null. If you store complex\n * or non-contiguous data there, make sure you free it's fields\n * before calling this function or you might get a memory leak.\n *\n * @param list List to be freed\n */\nvoid file_list_free(file_list_t *list);\n\nbool file_list_deinitialize(file_list_t *list);\n\n/**\n * @brief makes the list big enough to contain at least nitems\n *\n * This function will not change the capacity if nitems is smaller\n * than the current capacity.\n *\n * @param list The list to open for input\n * @param nitems Number of items to reserve space for\n * @return whether or not the operation succeeded\n */\nbool file_list_reserve(file_list_t *list, size_t nitems);\n\nbool file_list_append(file_list_t *userdata, const char *path,\n      const char *label, unsigned type, size_t current_directory_ptr,\n      size_t entry_index);\n\nbool file_list_insert(file_list_t *list,\n      const char *path, const char *label,\n      unsigned type, size_t directory_ptr,\n      size_t entry_idx,\n      size_t idx);\n\nvoid file_list_pop(file_list_t *list, size_t *directory_ptr);\n\nvoid file_list_clear(file_list_t *list);\n\nvoid file_list_free_userdata(const file_list_t *list, size_t index);\n\nvoid file_list_free_actiondata(const file_list_t *list, size_t idx);\n\nvoid file_list_set_alt_at_offset(file_list_t *list, size_t index,\n      const char *alt);\n\nvoid file_list_sort_on_alt(file_list_t *list);\n\nvoid file_list_sort_on_type(file_list_t *list);\n\nbool file_list_search(const file_list_t *list, const char *needle,\n      size_t *index);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/lists/linked_list.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (linked_list.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_LINKED_LIST_H\n#define __LIBRETRO_SDK_LINKED_LIST_H\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n#include <stddef.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Represents a linked list. Contains any number of elements.\n */\ntypedef struct linked_list linked_list_t;\n\n/**\n * Represents an iterator for iterating over a linked list. The iterator can\n * go through the linked list forwards or backwards.\n */\ntypedef struct linked_list_iterator linked_list_iterator_t;\n\n/**\n * Creates a new linked list with no elements.\n *\n * @return New linked list\n */\nlinked_list_t *linked_list_new(void);\n\n/**\n * @brief frees the memory used by the linked list\n *\n * Frees all of the memory used by this linked list. The values of all\n * remaining elements are freed using the \"free_value\" function. Does\n * nothing if \"list\" is NULL.\n *\n * @param list linked list to free\n * @param free_value function to use to free remaining values\n */\nvoid linked_list_free(linked_list_t *list, void (*free_value)(void *value));\n\n/**\n * @brief adds an element to the linked list\n *\n * Add a new element to the end of this linked list. Does nothing if\n * \"list\" is NULL.\n *\n * @param list list to add the element to\n * @param value new value to add to the linked list\n */\nvoid linked_list_add(linked_list_t *list, void *value);\n\n/**\n * @brief inserts a value into the linked list\n *\n * Inserts a value into the linked list at the specified index. Does\n * nothing if \"list\" is NULL.\n *\n * @param list list to insert the value into\n * @param index index where the value should be inserted at (can be equal to list size)\n * @param value value to insert into the linked list\n */\nvoid linked_list_insert(linked_list_t *list, size_t index, void *value);\n\n/**\n * @brief Get the value in the linked list at the provided index.\n *\n * Return the value vstored in the linked list at the provided index. Does\n * nothing if \"list\" is NULL.\n *\n * @param list list to get the value from\n * @param index index of the value to return\n * @return value in the list at the provided index\n */\nvoid *linked_list_get(linked_list_t *list, size_t index);\n\n/**\n * @brief Get the first value that is matched by the provided function\n *\n * Return the first value that the function matches. The matches function\n * parameters are value from the linked list and the provided state.\n *\n * @param list list to get the value from\n * @param matches function to test the values with\n * @param usrptr user data to pass to the matches function\n * @return first value that matches otherwise NULL\n */\nvoid *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);\n\n/**\n * @brief Get the last value that is matched by the provided function\n *\n * Return the last value that the function matches. The matches function\n * parameters are value from the linked list and the provided state.\n *\n * @param list list to get the value from\n * @param matches function to test the values with\n * @param usrptr user data to pass to the matches function\n * @return last value that matches otherwise NULL\n */\nvoid *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr);\n\n/**\n * @brief Remove the element at the provided index\n *\n * Removes the element of the linked list at the provided index.\n *\n * @param list linked list to remove the element from\n * @param index index of the element to remove\n * @return value of the element that was removed, NULL if list is NULL or\n *         index is invalid\n */\nvoid *linked_list_remove_at(linked_list_t *list, size_t index);\n\n/**\n * @brief Remove the first element with the provided value\n *\n * Removes the first element with a value equal to the provided value.\n * Does nothing if \"list\" is NULL.\n *\n * @param list linked list to remove the element from\n * @param value value of the element to remove\n * @return value if a matching element was removed\n */\nvoid *linked_list_remove_first(linked_list_t *list, void *value);\n\n/**\n * @brief Remove the last element with the provided value\n *\n * Removes the last element with a value equal to the provided value.\n * Does nothing if \"list\" is NULL.\n *\n * @param list linked list to remove the element from\n * @param value value of the element to remove\n * @return value if a matching element was removed\n */\nvoid *linked_list_remove_last(linked_list_t *list, void *value);\n\n/**\n * @brief Remove all elements with the provided value\n *\n * Removes all elements with a value equal to the provided value.\n * Does nothing if \"list\" is NULL.\n *\n * @param list linked list to remove the elements from\n * @param value value of the elements to remove\n * @return value if any matching element(s) where removed\n */\nvoid *linked_list_remove_all(linked_list_t *list, void *value);\n\n/**\n * @brief Remove the first matching element\n *\n * Removes the first matching element from the linked list. The \"matches\" function\n * is used to test for matching element values. Does nothing if \"list\" is NULL.\n *\n * @param list linked list to remove the element from\n * @param matches function to use for testing element values for a match\n * @return value if a matching element was removed\n */\nvoid *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value));\n\n/**\n * @brief Remove the last matching element\n *\n * Removes the last matching element from the linked list. The \"matches\" function\n * is used to test for matching element values.\n *\n * @param list linked list to remove the element from\n * @param matches function to use for testing element value for a match\n * @return value if a matching element was removed\n */\nvoid *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value));\n\n/**\n * @brief Remove all matching elements\n *\n * Removes all matching elements from the linked list. The \"matches\" function\n * is used to test for matching element values. Does nothing if \"list\" is NULL.\n *\n * @param list linked list to remove the elements from\n * @param matches function to use for testing element values for a match\n */\nvoid linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value));\n\n/**\n * @brief Replace the value of the element at the provided index\n *\n * Replaces the value of the element at the provided index. The linked list must\n * contain an element at the index.\n *\n * @param list linked list to replace the value in\n * @param index index of the element to replace the value of\n * @param value new value for the selected element\n * @return whether an element was updated\n */\nbool linked_list_set_at(linked_list_t *list, size_t index, void *value);\n\n/**\n * @brief Get the size of the linked list\n *\n * Returns the number of elements in the linked list.\n *\n * @param linked list to get the size of\n * @return number of elements in the linked list, 0 if linked list is NULL\n */\nsize_t linked_list_size(linked_list_t *list);\n\n/**\n * @brief Get an iterator for the linked list\n *\n * Returns a new iterator for the linked list. Can be either a forward or backward\n * iterator.\n *\n * @param list linked list to iterate over\n * @param forward true for a forward iterator, false for backwards\n * @return new iterator for the linked list in the specified direction, NULL if\n *         \"list\" is NULL\n */\nlinked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward);\n\n/**\n * @brief Move to the next element in the linked list\n *\n * Moves the iterator to the next element in the linked list. The direction is\n * specified when retrieving a new iterator.\n *\n * @param iterator iterator for the current element\n * @return iterator for the next element, NULL if iterator is NULL or \"iterator\"\n *         is at the last element\n */\nlinked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator);\n\n/**\n * @brief Get the value of the element for the iterator\n *\n * Returns the value of the element that the iterator is at.\n *\n * @param iterator iterator for the current element\n * @return value of the element for the iterator\n */\nvoid *linked_list_iterator_value(linked_list_iterator_t *iterator);\n\n/**\n * @brief Remove the element that the iterator is at\n *\n * Removes the element that the iterator is at. The iterator is updated to the\n * next element.\n *\n * @param iterator iterator for the current element\n * @return updated iterator or NULL if the last element was removed\n */\nlinked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator);\n\n/**\n * @brief Release the memory for the iterator\n *\n * Frees the memory for the provided iterator. Does nothing if \"iterator\" is NULL.\n *\n * @param iterator iterator to free\n */\nvoid linked_list_iterator_free(linked_list_iterator_t *iterator);\n\n/**\n * @brief Apply the provided function to all values in the linked list\n *\n * Apply the provided function to all values in the linked list. The values are applied\n * in the forward direction. Does nothing if \"list\" is NULL.\n *\n * @param list linked list to apply the function to\n * @param fn function to apply to all elements\n */\nvoid linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value));\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/lists/nested_list.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nested_list.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_NESTED_LIST_H__\n#define __LIBRETRO_SDK_NESTED_LIST_H__\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n#include <stdlib.h>\n#include <stddef.h>\n\nRETRO_BEGIN_DECLS\n\n/* Prevent direct access to nested_list_* members */\ntypedef struct nested_list_item nested_list_item_t;\ntypedef struct nested_list nested_list_t;\n\n/**************************************/\n/* Initialisation / De-Initialisation */\n/**************************************/\n\n/**\n * nested_list_init:\n *\n * Creates a new empty nested list. Returned pointer\n * must be freed using nested_list_free.\n *\n * Returns: Valid nested_list_t pointer if successful,\n * otherwise NULL.\n */\nnested_list_t *nested_list_init(void);\n\n/**\n * nested_list_free:\n *\n * @list : pointer to nested_list_t object\n *\n * Frees specified nested list.\n */\nvoid nested_list_free(nested_list_t *list);\n\n/***********/\n/* Setters */\n/***********/\n\n/**\n * nested_list_add_item:\n *\n * @list    : pointer to nested_list_t object\n * @address : a delimited list of item identifiers,\n *            corresponding to item 'levels'\n * @delim   : delimiter to use when splitting @address\n *            into individual ids\n * @value   : optional value (user data) associated with\n *            new list item. This is added to the last\n *            item specified by @address\n *\n * Appends a new item to the specified nested list.\n * If @delim is NULL, item is added to the top level\n * list (@list itself) with id equal to @address.\n * Otherwise, @address is split by @delim and each\n * id is added as new 'layer'. For example:\n *\n * > @address = \"one:two:three\", @delim = \":\" will\n *   produce:\n *      top_level_list:one\n *                     `- \"one\" list:two\n *                                   `- \"two\" list:three\n *   where @value is assigned to the \"two\" list:three\n *   item.\n *\n * Returns: true if successful, otherwise false. Will\n * always return false if item specified by @address\n * already exists in the nested list.\n */\nbool nested_list_add_item(nested_list_t *list,\n      const char *address, const char *delim, const void *value);\n\n/***********/\n/* Getters */\n/***********/\n\n/**\n * nested_list_get_size:\n *\n * @list : pointer to nested_list_t object\n *\n * Fetches the current size (number of items) in\n * the specified list.\n *\n * Returns: list size.\n */\nsize_t nested_list_get_size(nested_list_t *list);\n\n/**\n * nested_list_get_item:\n *\n * @list    : pointer to nested_list_t object\n * @address : a delimited list of item identifiers,\n *            corresponding to item 'levels'\n * @delim   : delimiter to use when splitting @address\n *            into individual ids\n *\n * Searches for (and returns) the list item corresponding\n * to @address. If @delim is NULL, the top level list\n * (@list itself) is searched for an item with an id\n * equal to @address. Otherwise, @address is split by\n * @delim and each id is searched for in a subsequent\n * list level.\n *\n * Returns: valid nested_list_item_t pointer if item\n * is found, otherwise NULL.\n */\nnested_list_item_t *nested_list_get_item(nested_list_t *list,\n      const char *address, const char *delim);\n\n/**\n * nested_list_get_item_idx:\n *\n * @list : pointer to nested_list_t object\n * @idx  : item index\n *\n * Fetches the item corresponding to index @idx in\n * the top level list (@list itself) of the specified\n * nested list.\n *\n * Returns: valid nested_list_item_t pointer if item\n * exists, otherwise NULL.\n */\nnested_list_item_t *nested_list_get_item_idx(nested_list_t *list,\n      size_t idx);\n\n/**\n * nested_list_item_get_parent:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches the parent item of the specified nested\n * list item. If returned value is NULL, specified\n * nested list item belongs to a top level list.\n *\n * Returns: valid nested_list_item_t pointer if item\n * has a parent, otherwise NULL.\n */\nnested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item);\n\n/**\n * nested_list_item_get_parent_list:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches a pointer to the nested list of which the\n * specified list item is a direct member.\n *\n * Returns: valid nested_list_t pointer if successful,\n * otherwise NULL.\n */\nnested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item);\n\n/**\n * nested_list_item_get_children:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches a pointer to the nested list of child items\n * belonging to the specified list item.\n *\n * Returns: valid nested_list_t pointer if item has\n * children, otherwise NULL.\n */\nnested_list_t *nested_list_item_get_children(nested_list_item_t *list_item);\n\n/**\n * nested_list_item_get_id:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches the id string of the specified list item,\n * as set by nested_list_add_item().\n *\n * Returns: item id if successful, otherwise NULL.\n */\nconst char *nested_list_item_get_id(nested_list_item_t *list_item);\n\n/**\n * nested_list_item_get_address:\n *\n * @list_item : pointer to nested_list_item_t object\n * @delim     : delimiter to use when concatenating\n *              individual item ids into a an @address\n *              string\n * @address   : a delimited list of item identifiers,\n *              corresponding to item 'levels'\n * @len       : length of supplied @address char array\n \n * Fetches a compound @address string corresponding to\n * the specified item's 'position' in the top level\n * nested list of which it is a member. The resultant\n * @address may be used to find the item when calling\n * nested_list_get_item() on the top level nested list.\n *\n * Returns: true if successful, otherwise false.\n */\nbool nested_list_item_get_address(nested_list_item_t *list_item,\n      const char *delim, char *address, size_t len);\n\n/**\n * nested_list_item_get_value:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches the value (user data) associated with the\n * specified list item.\n *\n * Returns: pointer to user data if set, otherwise\n * NULL.\n */\nconst void *nested_list_item_get_value(nested_list_item_t *list_item);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/lists/string_list.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (string_list.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_STRING_LIST_H\n#define __LIBRETRO_SDK_STRING_LIST_H\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n#include <stdlib.h>\n#include <stddef.h>\n\nRETRO_BEGIN_DECLS\n\nunion string_list_elem_attr\n{\n   bool  b;\n   int   i;\n   void *p;\n};\n\nstruct string_list_elem\n{\n   char *data;\n   void *userdata;\n   union string_list_elem_attr attr;\n};\n\nstruct string_list\n{\n   struct string_list_elem *elems;\n   size_t size;\n   size_t cap;\n};\n\n/**\n * string_list_find_elem:\n * @list             : pointer to string list\n * @elem             : element to find inside the string list.\n *\n * Searches for an element (@elem) inside the string list.\n *\n * @return 1-based index if element could be found, otherwise 0.\n */\nint string_list_find_elem(const struct string_list *list, const char *elem);\n\n/**\n * string_list_find_elem_prefix:\n * @list             : pointer to string list\n * @prefix           : prefix to append to @elem\n * @elem             : element to find inside the string list.\n *\n * Searches for an element (@elem) inside the string list. Will\n * also search for the same element prefixed by @prefix.\n *\n * Returns: true (1) if element could be found, otherwise false (0).\n */\nbool string_list_find_elem_prefix(const struct string_list *list,\n      const char *prefix, const char *elem);\n\n/**\n * string_split:\n * @str              : string to turn into a string list\n * @delim            : delimiter character to use for splitting the string.\n *\n * Creates a new string list based on string @str, delimited by @delim.\n *\n * Returns: new string list if successful, otherwise NULL.\n */\nstruct string_list *string_split(const char *str, const char *delim);\n\nbool string_split_noalloc(struct string_list *list,\n      const char *str, const char *delim);\n\nbool string_list_deinitialize(struct string_list *list);\n\nbool string_list_initialize(struct string_list *list);\n\n/**\n * string_list_new:\n *\n * Creates a new string list. Has to be freed manually.\n *\n * @return New string list if successful, otherwise NULL.\n **/\nstruct string_list *string_list_new(void);\n\n/**\n * string_list_append:\n * @list             : pointer to string list\n * @elem             : element to add to the string list\n * @attr             : attributes of new element.\n *\n * Appends a new element to the string list.\n *\n * Hidden non-leaf function cost:\n * - Calls string_list_capacity()\n * - Calls strdup\n *\n * @return true if successful, otherwise false.\n **/\nbool string_list_append(struct string_list *list, const char *elem,\n      union string_list_elem_attr attr);\n\n/**\n * string_list_append_n:\n * @list             : pointer to string list\n * @elem             : element to add to the string list\n * @len              : length of @elem (caller already knows it)\n * @attr             : attributes of new element.\n *\n * Appends a new element when the caller already has its length,\n * avoiding a redundant strlen inside strdup.\n *\n * @return true if successful, otherwise false.\n **/\nbool string_list_append_n(struct string_list *list, const char *elem,\n      size_t len, union string_list_elem_attr attr);\n\n/**\n * string_list_free\n * @list             : pointer to string list object\n *\n * Frees a string list.\n **/\nvoid string_list_free(struct string_list *list);\n\n/**\n * string_list_join_concat:\n * @s                : buffer that @list will be joined to.\n * @len              : length of @s.\n * @list             : pointer to string list.\n * @delim            : delimiter character for @list.\n *\n * A string list will be joined/concatenated as a\n * string to @s, delimited by @delim.\n *\n * NOTE: @s must be NULL-terminated.\n *\n * Hidden non-leaf function cost:\n * - Calls strlen()\n * - Calls strlcpy x times in a loop\n **/\nvoid string_list_join_concat(char *s, size_t len,\n      const struct string_list *list, const char *sep);\n\n/**\n * string_list_join_concat_special:\n * @s                : buffer that @list will be joined to.\n * @len              : length of @s.\n * @list             : pointer to string list.\n * @delim            : delimiter character for @list.\n *\n * Specialized version of string_list_join_concat\n * without the bounds check.\n *\n * A string list will be joined/concatenated as a\n * string to @s, delimited by @delim.\n **/\nvoid string_list_join_concat_special(char *s, size_t len,\n      const struct string_list *list, const char *delim);\n\n/**\n * string_list_capacity:\n * @list             : pointer to string list\n * @cap              : new capacity for string list.\n *\n * Change maximum capacity of string list's size.\n *\n * @return true if successful, otherwise false.\n **/\nbool string_list_capacity(struct string_list *list, size_t cap);\n\nstruct string_list *string_list_clone(const struct string_list *src);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/lrc_hash.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (lrc_hash.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_HASH_H\n#define __LIBRETRO_SDK_HASH_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <compat/msvc.h>\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include <retro_inline.h>\n\n#include <retro_common_api.h>\n\n#ifdef __APPLE__\n#include <CommonCrypto/CommonDigest.h>\n#endif\n\nRETRO_BEGIN_DECLS\n\n/**\n * sha256_hash:\n * @s                 : Output.\n * @in                : Input.\n * @len               : Size of @out.\n *\n * Hashes SHA256 and outputs a human readable string.\n **/\nvoid sha256_hash(char *s, const uint8_t *in, size_t len);\n\n/**\n * SHA1Digest:\n * @data              : Input.\n * @len               : Size of @data.\n * @digest            : Output.\n *\n * Hashes SHA1\n **/\nvoid SHA1Digest(const uint8_t* data, size_t len, uint8_t digest[20]);\n\nint sha1_calculate(const char *path, char *result);\n\nuint32_t djb2_calculate(const char *str);\n\n#ifdef __APPLE__\ntypedef CC_MD5_CTX MD5_CTX;\n#define MD5_Init CC_MD5_Init\n#define MD5_Update CC_MD5_Update\n#define MD5_Final CC_MD5_Final\n#else\n\ntypedef struct {\n\tuint32_t lo, hi;\n\tuint32_t a, b, c, d;\n\tunsigned char buffer[64];\n\tuint32_t block[16];\n} MD5_CTX;\n\n/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * See md5.c for more information.\n */\n\nvoid MD5_Init(MD5_CTX *ctx);\nvoid MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);\nvoid MD5_Final(unsigned char *result, MD5_CTX *ctx);\n\n#endif\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/math/complex.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (complex.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#ifndef __LIBRETRO_SDK_MATH_COMPLEX_H__\n#define __LIBRETRO_SDK_MATH_COMPLEX_H__\n\n#include <stdint.h>\n\n#include <retro_inline.h>\n\ntypedef struct\n{\n   float real;\n   float imag;\n} fft_complex_t;\n\nstatic INLINE fft_complex_t fft_complex_mul(fft_complex_t a,\n      fft_complex_t b)\n{\n   fft_complex_t out;\n   out.real = a.real * b.real - a.imag * b.imag;\n   out.imag = a.imag * b.real + a.real * b.imag;\n\n   return out;\n\n}\n\nstatic INLINE fft_complex_t fft_complex_add(fft_complex_t a,\n      fft_complex_t b)\n{\n   fft_complex_t out;\n   out.real = a.real + b.real;\n   out.imag = a.imag + b.imag;\n\n   return out;\n\n}\n\nstatic INLINE fft_complex_t fft_complex_sub(fft_complex_t a,\n      fft_complex_t b)\n{\n   fft_complex_t out;\n   out.real = a.real - b.real;\n   out.imag = a.imag - b.imag;\n\n   return out;\n\n}\n\nstatic INLINE fft_complex_t fft_complex_conj(fft_complex_t a)\n{\n   fft_complex_t out;\n   out.real = a.real;\n   out.imag = -a.imag;\n\n   return out;\n}\n\n#endif\n"
  },
  {
    "path": "include/math/float_minmax.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (float_minmax.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#ifndef __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__\n#define __LIBRETRO_SDK_MATH_FLOAT_MINMAX_H__\n\n#include <stdint.h>\n#include <math.h>\n\n#include <retro_inline.h>\n#include <retro_miscellaneous.h>\n#include <retro_environment.h>\n\n#ifdef __SSE2__\n#include <emmintrin.h>\n#include <mmintrin.h>\n#endif\n\nstatic INLINE float float_min(float a, float b)\n{\n#ifdef __SSE2__\n   _mm_store_ss( &a, _mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)) );\n   return a;\n#elif !defined(DJGPP) && (defined(__STDC_C99__) || defined(__STDC_C11__))\n   return fminf(a, b);\n#else\n   return MIN(a, b);\n#endif\n}\n\nstatic INLINE float float_max(float a, float b)\n{\n#ifdef __SSE2__\n   _mm_store_ss( &a, _mm_max_ss(_mm_set_ss(a),_mm_set_ss(b)) );\n   return a;\n#elif !defined(DJGPP) && (defined(__STDC_C99__) || defined(__STDC_C11__))\n   return fmaxf(a, b);\n#else\n   return MAX(a, b);\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "include/math/fxp.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fxp.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_MATH_FXP_H__\n#define __LIBRETRO_SDK_MATH_FXP_H__\n\n#include <stdint.h>\n\n#ifdef _MSC_VER\n#include <intrin.h>\n#endif\n\n#include <retro_inline.h>\n\nstatic INLINE int64_t fx32_mul(const int32_t a, const int32_t b)\n{\n#ifdef _MSC_VER\n   return __emul(a, b);\n#else\n   return ((int64_t)a) * ((int64_t)b);\n#endif\n}\n\nstatic INLINE int32_t fx32_shiftdown(const int64_t a)\n{\n#ifdef _MSC_VER\n\treturn (int32_t)__ll_rshift(a, 12);\n#else\n\treturn (int32_t)(a >> 12);\n#endif\n}\n\nstatic INLINE int64_t fx32_shiftup(const int32_t a)\n{\n#ifdef _MSC_VER\n\treturn __ll_lshift(a, 12);\n#else\n\treturn ((int64_t)a) << 12;\n#endif\n}\n\n#endif\n"
  },
  {
    "path": "include/media/media_detect_cd.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (media_detect_cd.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_MEDIA_DETECT_CD_H\n#define __LIBRETRO_SDK_MEDIA_DETECT_CD_H\n\n#include <retro_common_api.h>\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\nenum media_detect_cd_system\n{\n   MEDIA_CD_SYSTEM_MEGA_CD,\n   MEDIA_CD_SYSTEM_SATURN,\n   MEDIA_CD_SYSTEM_DREAMCAST,\n   MEDIA_CD_SYSTEM_PSX,\n   MEDIA_CD_SYSTEM_3DO,\n   MEDIA_CD_SYSTEM_PC_ENGINE_CD\n};\n\ntypedef struct\n{\n   char title[256];\n   char system[128];\n   char region[128];\n   char serial[64];\n   char maker[64];\n   char version[32];\n   char release_date[32];\n   enum media_detect_cd_system system_id;\n} media_detect_cd_info_t;\n\n/* Fill in \"info\" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */\nbool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info);\n\n/* 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. */\nbool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/memalign.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (memalign.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_MEMALIGN_H\n#define _LIBRETRO_MEMALIGN_H\n\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nvoid *memalign_alloc(size_t boundary, size_t len);\n\nvoid *memalign_alloc_aligned(size_t len);\n\nvoid memalign_free(void *ptr);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/memmap.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (memmap.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_MEMMAP_H\n#define _LIBRETRO_MEMMAP_H\n\n#include <stdio.h>\n#include <stdint.h>\n\n#if defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX) || defined(__PS3__) || defined(__PSL1GHT__)\n/* No mman available */\n#elif defined(_WIN32) && !defined(_XBOX)\n#include <windows.h>\n#include <errno.h>\n#include <io.h>\n#else\n#define HAVE_MMAN\n#include <sys/mman.h>\n#endif\n\n#if !defined(HAVE_MMAN) || defined(_WIN32)\nvoid* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off);\n\nint munmap(void *addr, size_t len);\n\nint mprotect(void *addr, size_t len, int prot);\n#endif\n\nint memsync(void *start, void *end);\n\nint memprotect(void *addr, size_t len);\n\n#endif\n"
  },
  {
    "path": "include/net/net_compat.h",
    "content": "/* Copyright  (C) 2010-2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_compat.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NET_COMPAT_H\n#define _LIBRETRO_SDK_NET_COMPAT_H\n\n#include <stdint.h>\n#include <boolean.h>\n#include <retro_inline.h>\n\n#include <errno.h>\n\n#ifndef _WIN32\n#include <sys/time.h>\n#include <unistd.h>\n#endif\n\n#include <retro_common_api.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#define WIN32_LEAN_AND_MEAN\n\n#include <winsock2.h>\n#include <windows.h>\n#include <ws2tcpip.h>\n\n#if _MSC_VER && _MSC_VER <= 1600\n/* If we are using MSVC2010 or lower, disable WSAPoll support \n * to ensure Windows XP and earlier backwards compatibility */\n#else\n#ifndef WIN32_SUPPORTS_POLL\n#define WIN32_SUPPORTS_POLL 1\n#endif\n#endif\n\n#if defined(WIN32_SUPPORTS_POLL) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600\n#define NETWORK_HAVE_POLL 1\n#endif\n\n#elif defined(_XBOX)\n#define NOD3D\n\n#include <xtl.h>\n#include <io.h>\n\n#ifndef SO_KEEPALIVE\n#define SO_KEEPALIVE 0 /* verify if correct */\n#endif\n\n#define socklen_t unsigned int\n\n#elif defined(VITA)\n#include <psp2/net/net.h>\n#include <psp2/net/netctl.h>\n\n#define NETWORK_HAVE_POLL 1\n\n#define AF_UNSPEC 0\n#define AF_INET SCE_NET_AF_INET\n\n#define SOCK_STREAM SCE_NET_SOCK_STREAM\n#define SOCK_DGRAM SCE_NET_SOCK_DGRAM\n\n#define INADDR_ANY SCE_NET_INADDR_ANY\n#define INADDR_NONE 0xFFFFFFFF\n\n#define SOL_SOCKET SCE_NET_SOL_SOCKET\n#define SO_REUSEADDR SCE_NET_SO_REUSEADDR\n#define SO_KEEPALIVE SCE_NET_SO_KEEPALIVE\n#define SO_BROADCAST SCE_NET_SO_BROADCAST\n#define SO_SNDBUF SCE_NET_SO_SNDBUF\n#define SO_RCVBUF SCE_NET_SO_RCVBUF\n#define SO_SNDTIMEO SCE_NET_SO_SNDTIMEO\n#define SO_RCVTIMEO SCE_NET_SO_RCVTIMEO\n#define SO_ERROR SCE_NET_SO_ERROR\n#define SO_NBIO SCE_NET_SO_NBIO\n\n#define IPPROTO_IP SCE_NET_IPPROTO_IP\n#define IP_MULTICAST_TTL SCE_NET_IP_MULTICAST_TTL\n\n#define IPPROTO_TCP SCE_NET_IPPROTO_TCP\n#define TCP_NODELAY SCE_NET_TCP_NODELAY\n\n#define IPPROTO_UDP SCE_NET_IPPROTO_UDP\n\n#define MSG_DONTWAIT SCE_NET_MSG_DONTWAIT\n\n#define POLLIN   SCE_NET_EPOLLIN\n#define POLLOUT  SCE_NET_EPOLLOUT\n#define POLLERR  SCE_NET_EPOLLERR\n#define POLLHUP  SCE_NET_EPOLLHUP\n#define POLLNVAL 0\n\n#define sockaddr SceNetSockaddr\n#define sockaddr_in SceNetSockaddrIn\n#define in_addr SceNetInAddr\n#define socklen_t unsigned int\n\n#define socket(a,b,c) sceNetSocket(\"unknown\",a,b,c)\n#define getsockname sceNetGetsockname\n#define getsockopt sceNetGetsockopt\n#define setsockopt sceNetSetsockopt\n#define bind sceNetBind\n#define listen sceNetListen\n#define accept sceNetAccept\n#define connect sceNetConnect\n#define send sceNetSend\n#define sendto sceNetSendto\n#define recv sceNetRecv\n#define recvfrom sceNetRecvfrom\n#define htonl sceNetHtonl\n#define ntohl sceNetNtohl\n#define htons sceNetHtons\n#define ntohs sceNetNtohs\n#define inet_ntop sceNetInetNtop\n#define inet_pton sceNetInetPton\n\n#elif defined(GEKKO)\n#include <network.h>\n\n#define NETWORK_HAVE_POLL 1\n\n#define pollfd pollsd\n\n#define socket(a,b,c) net_socket(a,b,c)\n#define getsockopt(a,b,c,d,e) net_getsockopt(a,b,c,d,e)\n#define setsockopt(a,b,c,d,e) net_setsockopt(a,b,c,d,e)\n#define bind(a,b,c) net_bind(a,b,c)\n#define listen(a,b) net_listen(a,b)\n#define accept(a,b,c) net_accept(a,b,c)\n#define connect(a,b,c) net_connect(a,b,c)\n#define send(a,b,c,d) net_send(a,b,c,d)\n#define sendto(a,b,c,d,e,f) net_sendto(a,b,c,d,e,f)\n#define recv(a,b,c,d) net_recv(a,b,c,d)\n#define recvfrom(a,b,c,d,e,f) net_recvfrom(a,b,c,d,e,f)\n#define select(a,b,c,d,e) net_select(a,b,c,d,e)\n#define gethostbyname(a) net_gethostbyname(a)\n\n#else\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/select.h>\n\n#include <netinet/in.h>\n#ifndef __PSL1GHT__\n#include <netinet/tcp.h>\n#endif\n\n#include <arpa/inet.h>\n#include <netdb.h>\n#include <fcntl.h>\n\n#if !defined(__PSL1GHT__) && defined(__PS3__)\n#include <netex/libnetctl.h>\n#include <netex/errno.h>\n#else\n#include <signal.h>\n#endif\n\n#if defined(__PSL1GHT__)\n#include <net/poll.h>\n\n#define NETWORK_HAVE_POLL 1\n\n#elif defined(WIIU)\n#define WIIU_RCVBUF 0x40000\n#define WIIU_SNDBUF 0x40000\n\n#elif !defined(__PS3__)\n#include <poll.h>\n\n#define NETWORK_HAVE_POLL 1\n\n#endif\n#endif\n\n#ifndef MSG_NOSIGNAL\n#define MSG_NOSIGNAL 0\n#endif\n\n#if defined(AF_INET6) && !defined(HAVE_SOCKET_LEGACY) && !defined(_3DS)\n#define HAVE_INET6 1\n#endif\n\n#ifdef NETWORK_HAVE_POLL\n#ifdef GEKKO\n#define NET_POLL_FD(sockfd, sockfds)    (sockfds)->socket  = (sockfd)\n#else\n#define NET_POLL_FD(sockfd, sockfds)    (sockfds)->fd      = (sockfd)\n#endif\n#define NET_POLL_EVENT(sockev, sockfds) (sockfds)->events |= (sockev)\n#define NET_POLL_HAS_EVENT(sockev, sockfds) ((sockfds)->revents & (sockev))\n#endif\n\nRETRO_BEGIN_DECLS\n\n/* Compatibility layer for legacy or incomplete BSD socket implementations.\n * Only for IPv4. Mostly useful for the consoles which do not support\n * anything reasonably modern on the socket API side of things. */\n#ifdef HAVE_SOCKET_LEGACY\n#define sockaddr_storage sockaddr_in\n\n#ifdef AI_PASSIVE\n#undef AI_PASSIVE\n#endif\n#ifdef AI_CANONNAME\n#undef AI_CANONNAME\n#endif\n#ifdef AI_NUMERICHOST\n#undef AI_NUMERICHOST\n#endif\n#ifdef AI_NUMERICSERV\n#undef AI_NUMERICSERV\n#endif\n\n#ifdef NI_NUMERICHOST\n#undef NI_NUMERICHOST\n#endif\n#ifdef NI_NUMERICSERV\n#undef NI_NUMERICSERV\n#endif\n#ifdef NI_NOFQDN\n#undef NI_NOFQDN\n#endif\n#ifdef NI_NAMEREQD\n#undef NI_NAMEREQD\n#endif\n#ifdef NI_DGRAM\n#undef NI_DGRAM\n#endif\n\n#define AI_PASSIVE     1\n#define AI_CANONNAME   2\n#define AI_NUMERICHOST 4\n#define AI_NUMERICSERV 8\n\n#define NI_NUMERICHOST 1\n#define NI_NUMERICSERV 2\n#define NI_NOFQDN      4\n#define NI_NAMEREQD    8\n#define NI_DGRAM       16\n\n#ifndef __PS3__\nstruct addrinfo\n{\n   int ai_flags;\n   int ai_family;\n   int ai_socktype;\n   int ai_protocol;\n   socklen_t ai_addrlen;\n   struct sockaddr *ai_addr;\n   char *ai_canonname;\n   struct addrinfo *ai_next;\n};\n#endif\n\n/* gai_strerror() not used, so we skip that. */\n\n#else\n/* Ensure that getaddrinfo and getnameinfo flags are always defined. */\n#ifndef AI_PASSIVE\n#define AI_PASSIVE 0\n#endif\n#ifndef AI_CANONNAME\n#define AI_CANONNAME 0\n#endif\n#ifndef AI_NUMERICHOST\n#define AI_NUMERICHOST 0\n#endif\n#ifndef AI_NUMERICSERV\n#define AI_NUMERICSERV 0\n#endif\n\n#ifndef NI_NUMERICHOST\n#define NI_NUMERICHOST 0\n#endif\n#ifndef NI_NUMERICSERV\n#define NI_NUMERICSERV 0\n#endif\n#ifndef NI_NOFQDN\n#define NI_NOFQDN 0\n#endif\n#ifndef NI_NAMEREQD\n#define NI_NAMEREQD 0\n#endif\n#ifndef NI_DGRAM\n#define NI_DGRAM 0\n#endif\n\n#endif\n\n#if defined(_XBOX)\nstruct hostent\n{\n   char *h_name;\n   char **h_aliases;\n   int  h_addrtype;\n   int  h_length;\n   char **h_addr_list;\n   char *h_addr;\n   char *h_end;\n};\n\n#elif defined(VITA)\nstruct pollfd\n{\n   int fd;\n   unsigned events;\n   unsigned revents;\n   unsigned __pad; /* Align to 64-bits boundary */\n};\n\nstruct hostent\n{\n   char *h_name;\n   char **h_aliases;\n   int  h_addrtype;\n   int  h_length;\n   char **h_addr_list;\n   char *h_addr;\n   char *h_end;\n};\n\n#endif\n\nstatic INLINE bool isagain(int val)\n{\n#if defined(_WIN32)\n   return (val == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK);\n#elif !defined(__PSL1GHT__) && defined(__PS3__)\n   return (sys_net_errno == SYS_NET_EAGAIN) || (sys_net_errno == SYS_NET_EWOULDBLOCK);\n#elif defined(VITA)\n   return (val == SCE_NET_ERROR_EAGAIN) || (val == SCE_NET_ERROR_EWOULDBLOCK);\n#elif defined(WIIU)\n   return (val == -1) && (socketlasterr() == SO_SUCCESS || socketlasterr() == SO_EWOULDBLOCK);\n#elif defined(GEKKO)\n   return (-val == EAGAIN);\n#else\n   return (val < 0) && (errno == EAGAIN || errno == EWOULDBLOCK);\n#endif\n}\n\nstatic INLINE bool isinprogress(int val)\n{\n#if defined(_WIN32)\n   return (val == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK);\n#elif !defined(__PSL1GHT__) && defined(__PS3__)\n   return (sys_net_errno == SYS_NET_EINPROGRESS);\n#elif defined(VITA)\n   return (val == SCE_NET_ERROR_EINPROGRESS);\n#elif defined(WIIU)\n   return (val == -1) && (socketlasterr() == SO_EINPROGRESS);\n#elif defined(GEKKO)\n   return (-val == EINPROGRESS);\n#else\n   return (val < 0) && (errno == EINPROGRESS);\n#endif\n}\n\n#if defined(_WIN32) && !defined(_XBOX)\n#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600\nconst char *inet_ntop(int af, const void *src, char *dst, socklen_t size);\nint inet_pton(int af, const char *src, void *dst);\n#endif\n\n#elif defined(_XBOX)\nstruct hostent *gethostbyname(const char *name);\n\n#elif defined(VITA)\nchar *inet_ntoa(struct in_addr in);\nint inet_aton(const char *cp, struct in_addr *inp);\nuint32_t inet_addr(const char *cp);\n\nstruct hostent *gethostbyname(const char *name);\n\n#elif defined(GEKKO)\nconst char *inet_ntop(int af, const void *src, char *dst, socklen_t size);\nint inet_pton(int af, const char *src, void *dst);\n\n#endif\n\nint getaddrinfo_retro(const char *node, const char *service,\n      struct addrinfo *hints, struct addrinfo **res);\n\nvoid freeaddrinfo_retro(struct addrinfo *res);\n\nint getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,\n      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);\n\nbool addr_6to4(struct sockaddr_storage *addr);\n\nbool ipv4_is_lan_address(const struct sockaddr_in *addr);\nbool ipv4_is_cgnat_address(const struct sockaddr_in *addr);\n\n/**\n * network_init:\n *\n * Platform specific socket library initialization.\n *\n * @return true if successful, otherwise false.\n **/\nbool network_init(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/net/net_http.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_http.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NET_HTTP_H\n#define _LIBRETRO_SDK_NET_HTTP_H\n\n#include <stdint.h>\n#include <boolean.h>\n#include <string.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nstruct http_t;\nstruct http_connection_t;\n\nstruct http_connection_t *net_http_connection_new(const char *url, const char *method, const char *data);\n\n/**\n * net_http_connection_iterate:\n *\n * Leaf function.\n **/\nbool net_http_connection_iterate(struct http_connection_t *conn);\n\nbool net_http_connection_done(struct http_connection_t *conn);\n\nvoid net_http_connection_free(struct http_connection_t *conn);\n\nvoid net_http_connection_set_user_agent(struct http_connection_t *conn, const char *user_agent);\n\nvoid net_http_connection_set_headers(struct http_connection_t *conn, const char *headers);\n\nvoid net_http_connection_set_content(struct http_connection_t *conn, const char *content_type,\n      size_t content_length, const void *content);\n\nconst char *net_http_connection_url(struct http_connection_t *conn);\n\nconst char* net_http_connection_method(struct http_connection_t* conn);\n\nstruct http_t *net_http_new(struct http_connection_t *conn);\n\n/**\n * net_http_fd:\n *\n * Leaf function.\n *\n * You can use this to call net_http_update\n * only when something will happen; select() it for reading.\n **/\nint net_http_fd(struct http_t *state);\n\n/**\n * net_http_update:\n *\n * @return true if it's done, or if something broke.\n * @total will be 0 if it's not known.\n **/\nbool net_http_update(struct http_t *state, size_t* progress, size_t* total);\n\n/**\n * net_http_status:\n *\n * Report HTTP status. 200, 404, or whatever.\n *\n * Leaf function.\n *\n * @return HTTP status code.\n **/\nint net_http_status(struct http_t *state);\n\n/**\n * net_http_error:\n *\n * Leaf function\n **/\nbool net_http_error(struct http_t *state);\n\n/**\n * net_http_headers:\n *\n * Leaf function.\n *\n * @return the response headers. The returned buffer is owned by the\n * caller of net_http_new; it is not freed by net_http_delete.\n * On a transport error, NULL is returned unless accept_error is true.\n * Headers are returned for any response that was parsed successfully,\n * including HTTP error statuses such as 401 (needed for auth challenges).\n **/\nstruct string_list *net_http_headers(struct http_t *state);\nstruct string_list *net_http_headers_ex(struct http_t *state, bool accept_error);\n\n/**\n * net_http_data:\n *\n * Leaf function.\n *\n * @return the downloaded data. The returned buffer is owned by the\n * HTTP handler; it's freed by net_http_delete.\n * If the status is not 20x and accept_error is false, it returns NULL.\n **/\nuint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error);\n\n/**\n * net_http_delete:\n *\n * Cleans up all memory.\n **/\nvoid net_http_delete(struct http_t *state);\n\n/**\n * net_http_urlencode:\n *\n * URL Encode a string\n * caller is responsible for deleting the destination buffer\n **/\nvoid net_http_urlencode(char **dest, const char *source);\n\n/**\n * net_http_urlencode_full:\n *\n * Re-encode a full URL\n **/\nvoid net_http_urlencode_full(char *s, const char *source, size_t len);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/net/net_http_parse.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_http.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NET_HTTP_PARSE_H\n#define _LIBRETRO_SDK_NET_HTTP_PARSE_H\n\n#include <stdint.h>\n#include <boolean.h>\n#include <string.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * string_parse_html_anchor:\n * @line               : Buffer where the <a> tag is stored\n * @link               : Buffer to store the link URL in\n * @name               : Buffer to store the link URL in\n * @link_size          : Size of the link buffer including the NUL-terminator\n * @name_size          : Size of the name buffer including the NUL-terminator\n *\n * Parses an HTML anchor link stored in @line in the form of: <a href=\"/path/to/url\">Title</a>\n * The buffer pointed to by @link is filled with the URL path the link points to,\n * and @name is filled with the title portion of the link.\n *\n * @return 0 if URL was parsed completely, otherwise 1.\n **/\nint string_parse_html_anchor(const char *line, char *link, char *name,\n      size_t link_size, size_t name_size);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/net/net_ifinfo.h",
    "content": "/* Copyright  (C) 2010-2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_ifinfo.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NET_IFINFO_H\n#define _LIBRETRO_SDK_NET_IFINFO_H\n\n#include <stddef.h>\n\n#include <boolean.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nstruct net_ifinfo_entry\n{\n   char name[256];\n   char host[256];\n};\n\ntypedef struct net_ifinfo\n{\n   struct net_ifinfo_entry *entries;\n   size_t size;\n} net_ifinfo_t;\n\nbool net_ifinfo_new(net_ifinfo_t *list);\n\nvoid net_ifinfo_free(net_ifinfo_t *list);\n\nbool net_ifinfo_best(const char *dst, void *src, bool ipv6);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/net/net_socket.h",
    "content": "/* Copyright  (C) 2010-2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_socket.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NET_SOCKET_H\n#define _LIBRETRO_SDK_NET_SOCKET_H\n\n#include <stddef.h>\n#include <stdint.h>\n#include <boolean.h>\n\n#include <net/net_compat.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nenum socket_domain\n{\n   SOCKET_DOMAIN_INET = 0\n};\n\nenum socket_type\n{\n   SOCKET_TYPE_DATAGRAM = 0,\n   SOCKET_TYPE_STREAM,\n   SOCKET_TYPE_SEQPACKET\n};\n\nenum socket_protocol\n{\n   SOCKET_PROTOCOL_NONE = 0,\n   SOCKET_PROTOCOL_TCP,\n   SOCKET_PROTOCOL_UDP\n};\n\ntypedef struct socket_target\n{\n   unsigned port;\n   const char *server;\n   enum socket_domain domain;\n   enum socket_protocol prot;\n} socket_target_t;\n\nint socket_init(void **address, uint16_t port, const char *server,\n      enum socket_type type, int family);\n\nint socket_next(void **address);\n\nint socket_close(int fd);\n\nbool socket_set_block(int fd, bool block);\n\n/* TODO: all callers should be converted to socket_set_block() */\nbool socket_nonblock(int fd);\n\nint socket_select(int nfds, fd_set *readfds, fd_set *writefds,\n      fd_set *errorfds, struct timeval *timeout);\n\n#ifdef NETWORK_HAVE_POLL\nint socket_poll(struct pollfd *fds, unsigned nfds, int timeout);\n#endif\n\nbool socket_wait(int fd, bool *rd, bool *wr, int timeout);\n\nbool socket_send_all_blocking(int fd, const void *data_, size_t len, bool no_signal);\n\nbool socket_send_all_blocking_with_timeout(int fd,\n      const void *data_, size_t len, int timeout, bool no_signal);\n\nssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t len,\n      bool no_signal);\n\nbool socket_receive_all_blocking(int fd, void *data_, size_t len);\n\nbool socket_receive_all_blocking_with_timeout(int fd,\n      void *data_, size_t len, int timeout);\n\nssize_t socket_receive_all_nonblocking(int fd, bool *error,\n      void *data_, size_t len);\n\nbool socket_bind(int fd, void *data);\n\nint socket_connect(int fd, void *data);\n\nbool socket_connect_with_timeout(int fd, void *data, int timeout);\n\nint socket_create(\n      const char *name,\n      enum socket_domain domain_type,\n      enum socket_type socket_type,\n      enum socket_protocol protocol_type);\n\nvoid socket_set_target(void *data, socket_target_t *in_addr);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/net/net_socket_ssl.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_socket.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NET_SOCKET_SSL_H\n#define _LIBRETRO_SDK_NET_SOCKET_SSL_H\n\n#include <stdlib.h>\n#include <boolean.h>\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nvoid* ssl_socket_init(int fd, const char *domain);\n\nint ssl_socket_connect(void *state_data, void *data, bool timeout_enable, bool nonblock);\n\nint ssl_socket_send_all_blocking(void *state_data, const void *data_, size_t len, bool no_signal);\n\nssize_t ssl_socket_send_all_nonblocking(void *state_data, const void *data_, size_t len, bool no_signal);\n\nint ssl_socket_receive_all_blocking(void *state_data, void *data_, size_t len);\n\nssize_t ssl_socket_receive_all_nonblocking(void *state_data, bool *error, void *data_, size_t len);\n\nvoid ssl_socket_close(void *state_data);\n\nvoid ssl_socket_free(void *state_data);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/playlists/label_sanitization.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (label_sanitization.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <stddef.h>\n#include <boolean.h>\n\n/**\n * label_sanitize:\n *\n * NOTE: Does not work with nested blocks.\n **/\nvoid label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*));\n\nvoid label_remove_parens(char *label);\n\nvoid label_remove_brackets(char *label);\n\nvoid label_remove_parens_and_brackets(char *label);\n\nvoid label_keep_region(char *label);\n\nvoid label_keep_disc(char *label);\n\nvoid label_keep_region_and_disc(char *label);\n"
  },
  {
    "path": "include/queues/fifo_queue.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fifo_queue.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FIFO_BUFFER_H\n#define __LIBRETRO_SDK_FIFO_BUFFER_H\n\n#include <stdint.h>\n#include <stddef.h>\n#include <stdlib.h>\n\n#include <retro_common_api.h>\n#include <retro_inline.h>\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Returns the available data in \\c buffer for reading.\n *\n * @param buffer <tt>fifo_buffer_t *</tt>. The FIFO queue to check.\n * @return The number of bytes available for reading from \\c buffer.\n */\n#define FIFO_READ_AVAIL(buffer) (((buffer)->end + (((buffer)->end < (buffer)->first) ? (buffer)->size : 0)) - (buffer)->first)\n\n/**\n * Returns the available space in \\c buffer for writing.\n *\n * @param buffer <tt>fifo_buffer_t *</tt>. The FIFO queue to check.\n * @return The number of bytes that \\c buffer can accept.\n */\n#define FIFO_WRITE_AVAIL(buffer) (((buffer)->size - 1) - (((buffer)->end + (((buffer)->end < (buffer)->first) ? (buffer)->size : 0)) - (buffer)->first))\n\n/**\n * Returns the available data in \\c buffer for reading.\n *\n * @param buffer \\c fifo_buffer_t. The FIFO queue to check.\n * @return The number of bytes available for reading from \\c buffer.\n */\n#define FIFO_READ_AVAIL_NONPTR(buffer) (((buffer).end + (((buffer).end < (buffer).first) ? (buffer).size : 0)) - (buffer).first)\n\n/**\n * Returns the available space in \\c buffer for writing.\n *\n * @param buffer \\c fifo_buffer_t. The FIFO queue to check.\n * @return The number of bytes that \\c buffer can accept.\n */\n#define FIFO_WRITE_AVAIL_NONPTR(buffer) (((buffer).size - 1) - (((buffer).end + (((buffer).end < (buffer).first) ? (buffer).size : 0)) - (buffer).first))\n\n/** @copydoc fifo_buffer_t */\nstruct fifo_buffer\n{\n   uint8_t *buffer;\n   size_t size;\n   size_t first;\n   size_t end;\n};\n\n/**\n * A bounded FIFO byte queue implemented as a ring buffer.\n *\n * Useful for communication between threads,\n * although the caller is responsible for synchronization.\n */\ntypedef struct fifo_buffer fifo_buffer_t;\n\n/**\n * Creates a new FIFO queue with \\c size bytes of memory.\n * Must be freed with \\c fifo_free.\n *\n * @param size The size of the FIFO queue, in bytes.\n * @return The new queue if successful, \\c NULL otherwise.\n * @see fifo_initialize\n */\nfifo_buffer_t *fifo_new(size_t len);\n\n/**\n * Initializes an existing FIFO queue with \\c size bytes of memory.\n *\n * Suitable for use with \\c fifo_buffer_t instances\n * of static or automatic lifetime.\n * Must be freed with \\c fifo_deinitialize.\n *\n * @param buf Pointer to the FIFO queue to initialize.\n * May be static or automatic.\n * @param size The size of the FIFO queue, in bytes.\n * @return \\c true if \\c buf was initialized with the requested memory,\n * \\c false if \\c buf is \\c NULL or there was an error.\n */\nbool fifo_initialize(fifo_buffer_t *buf, size_t len);\n\n/**\n * Resets the bounds of \\c buffer,\n * effectively clearing it.\n *\n * No memory will actually be freed,\n * but the contents of \\c buffer will be overwritten\n * with the next call to \\c fifo_write.\n * @param buffer The FIFO queue to clear.\n * Behavior is undefined if \\c NULL.\n */\nstatic INLINE void fifo_clear(fifo_buffer_t *buffer)\n{\n   buffer->first = 0;\n   buffer->end   = 0;\n}\n\n/**\n * Writes \\c size bytes to the given queue.\n *\n * @param buffer The FIFO queue to write to.\n * @param in_buf The buffer to read bytes from.\n * @param size The length of \\c in_buf, in bytes.\n */\nvoid fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len);\n\n/**\n * Reads \\c size bytes from the given queue.\n *\n * @param buffer The FIFO queue to read from.\n * @param in_buf The buffer to store the read bytes in.\n * @param size The length of \\c in_buf, in bytes.\n * @post Upon return, \\c buffer will have up to \\c size more bytes of space available for writing.\n */\nvoid fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len);\n\n/**\n * Releases \\c buffer and its contents.\n *\n * @param buffer The FIFO queue to free.\n * If \\c NULL, this function will do nothing.\n * Behavior is undefined if \\c buffer was previously freed.\n * @see fifo_deinitialize\n */\nvoid fifo_free(fifo_buffer_t *buffer);\n\n/**\n * Deallocates the contents of \\c buffer,\n * but not \\c buffer itself.\n *\n * Suitable for use with static or automatic \\c fifo_buffer_t instances.\n *\n * @param buffer The buffer to deinitialize.\n * @return \\c false if \\c buffer is \\c NULL, \\c true otherwise.\n * @see fifo_free\n */\nbool fifo_deinitialize(fifo_buffer_t *buffer);\n\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/queues/generic_queue.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (generic_queue.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_GENERIC_QUEUE_H\n#define __LIBRETRO_SDK_GENERIC_QUEUE_H\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n#include <stddef.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Represents a generic queue. Can contain any number of elements. Each element contains\n * a value of type \"void *\". Can be used as a FIFO or LIFO queue.\n */\ntypedef struct generic_queue generic_queue_t;\n\n/**\n * Represents an iterator for iterating over a queue.\n */\ntypedef struct generic_queue_iterator generic_queue_iterator_t;\n\n/**\n * Creates a new queue with no elements.\n *\n * @return New queue\n */\ngeneric_queue_t *generic_queue_new(void);\n\n/**\n * @brief frees the memory used by the queue\n * \n * Frees all of the memory used by this queue. The values of all\n * remaining elements are freed using the \"free_value\" function. Does\n * nothing if \"queue\" is NULL.\n *\n * @param queue queue to free\n * @param free_value function to use to free remaining values\n */\nvoid generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value));\n\n/**\n * @brief Push a new value onto the queue\n *\n * Pushes a new value onto the end of the queue. Does nothing if \"queue\"\n * is NULL.\n *\n * @param queue queue to the push the value onto\n * @param value value to push onto the queue\n */\nvoid generic_queue_push(generic_queue_t *queue, void *value);\n\n/**\n * @brief Remove the last value from the queue\n *\n * Removes the last element from the queue. Does nothing if the queue is\n * NULL.\n *\n * @param queue queue to get the value from\n * @return value of the last element, NULL if queue is empty or NULL\n */\nvoid *generic_queue_pop(generic_queue_t *queue);\n\n/**\n * @brief Get the last value from the queue\n *\n * Returns the value of the last element in the queue. Returns NULL if the\n * queue is NULL or empty.\n *\n * @param queue queue to get the last value from\n * @return value of the last element or NULL\n */\nvoid *generic_queue_peek(generic_queue_t *queue);\n\n/**\n * @brief Get the first value from the queue\n *\n * Returns the value of the first element in the queue. Returns NULL if the\n * queue is NULL or empty.\n *\n * @param queue queue to get the first value from\n * @return value of the first element or NULL\n */\nvoid *generic_queue_peek_first(generic_queue_t *queue);\n\n/**\n * @brief Push a new value onto the front of the queue\n *\n * Pushes a new value onto the front of the queue. Does nothing if \"queue\"\n * is NULL.\n *\n * @param queue queue to the push the value onto\n * @param value value to push onto the queue\n */\nvoid generic_queue_shift(generic_queue_t *queue, void *value);\n\n/**\n * @brief Remove the first value from the queue\n *\n * Removes the first element from the queue. Does nothing if the queue is\n * NULL.\n *\n * @param queue queue to get the value from\n * @return value of the last element, NULL if queue is empty or NULL\n */\nvoid *generic_queue_unshift(generic_queue_t *queue);\n\n/**\n * @brief Get the size of the queue\n *\n * Returns the number of elements in the queue.\n *\n * @param queue queue to get the size of\n * @return number of elements in the queue, 0 if queue is NULL\n */\nsize_t generic_queue_length(generic_queue_t *queue);\n\n/**\n * @brief Remove the first element in the queue with the provided value\n *\n * Removes the first element with a value matching the provided value. Does\n * nothing if queue is NULL.\n *\n * @param queue queue to remove the element from\n * @param value value to look for in the queue\n * @return the value of the element removed, NULL if no element was removed\n */\nvoid *generic_queue_remove(generic_queue_t *queue, void *value);\n\n/**\n * @brief Get an iterator for the queue\n *\n * Returns a new iterator for the queue. Can be either a forward or backward\n * iterator.\n *\n * @param queue queue to iterate over\n * @param forward true for a forward iterator, false for backwards\n * @return new iterator for the queue in the specified direction, NULL if\n *         \"queue\" is NULL\n */\ngeneric_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward);\n\n/**\n * @brief Move to the next element in the queue\n *\n * Moves the iterator to the next element in the queue. The direction is\n * specified when retrieving a new iterator.\n *\n * @param iterator iterator for the current element\n * @return iterator for the next element, NULL if iterator is NULL or \"iterator\"\n *         is at the last element\n */\ngeneric_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator);\n\n/**\n * @brief Get the value of the element for the iterator\n *\n * Returns the value of the element that the iterator is at.\n *\n * @param iterator iterator for the current element\n * @return value of the element for the iterator\n */\nvoid *generic_queue_iterator_value(generic_queue_iterator_t *iterator);\n\n/**\n * @brief Remove the element that the iterator is at\n *\n * Removes the element that the iterator is at. The iterator is updated to the\n * next element.\n *\n * @param iterator iterator for the current element\n * @return updated iterator or NULL if the last element was removed\n */\ngeneric_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator);\n\n/**\n * @brief Release the memory for the iterator\n *\n * Frees the memory for the provided iterator. Does nothing if \"iterator\" is NULL.\n *\n * @param iterator iterator to free\n */\nvoid generic_queue_iterator_free(generic_queue_iterator_t *iterator);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/queues/message_queue.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (message_queue.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_MSG_QUEUE_H\n#define __LIBRETRO_SDK_MSG_QUEUE_H\n\n#include <stddef.h>\n\n#include <retro_common_api.h>\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\nenum message_queue_icon\n{\n   MESSAGE_QUEUE_ICON_DEFAULT = 0 /* default icon is tied to category */\n};\n\nenum message_queue_category\n{\n   MESSAGE_QUEUE_CATEGORY_INFO = 0,\n   MESSAGE_QUEUE_CATEGORY_ERROR,\n   MESSAGE_QUEUE_CATEGORY_WARNING,\n   MESSAGE_QUEUE_CATEGORY_SUCCESS\n};\n\ntypedef struct queue_elem\n{\n   char *msg;\n   char *title;\n   unsigned duration;\n   unsigned prio;\n   enum message_queue_icon icon;\n   enum message_queue_category category;\n} queue_elem_t;\n\ntypedef struct msg_queue\n{\n   char *tmp_msg;\n   queue_elem_t **elems;\n   size_t ptr;\n   size_t size;\n} msg_queue_t;\n\ntypedef struct\n{\n   unsigned duration;\n   unsigned prio;\n   enum message_queue_icon icon;\n   enum message_queue_category category;\n   char msg[1024];\n   char title[1024];\n} msg_queue_entry_t;\n\n/**\n * msg_queue_new:\n * @len               : maximum size of message\n *\n * Creates a message queue with maximum size different messages.\n *\n * Returns: NULL if allocation error, pointer to a message queue\n * if successful. Has to be freed manually.\n **/\nmsg_queue_t *msg_queue_new(size_t len);\n\nbool msg_queue_initialize(msg_queue_t *queue, size_t len);\n\n/**\n * msg_queue_push:\n * @queue             : pointer to queue object\n * @msg               : message to add to the queue\n * @prio              : priority level of the message\n * @duration          : how many times the message can be pulled\n *                      before it vanishes (E.g. show a message for\n *                      3 seconds @ 60fps = 180 duration).\n *\n * Push a new message onto the queue.\n **/\nvoid msg_queue_push(msg_queue_t *queue, const char *msg,\n      unsigned prio, unsigned duration,\n      char *title,\n      enum message_queue_icon icon, enum message_queue_category category);\n\n/**\n * msg_queue_pull:\n * @queue             : pointer to queue object\n *\n * Pulls highest priority message in queue.\n *\n * Returns: NULL if no message in queue, otherwise a string\n * containing the message.\n **/\nconst char *msg_queue_pull(msg_queue_t *queue);\n\n/**\n * msg_queue_extract:\n * @queue             : pointer to queue object\n * @queue_entry       : pointer to external queue entry struct\n *\n * Removes highest priority message from queue, copying\n * contents into queue_entry struct.\n *\n * Returns: false if no messages in queue, otherwise true\n **/\nbool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry);\n\n/**\n * msg_queue_size:\n * @queue             : pointer to queue object\n *\n * Fetches number of messages in queue.\n *\n * Returns: Number of messages in queue.\n **/\nsize_t msg_queue_size(msg_queue_t *queue);\n\n/**\n * msg_queue_clear:\n * @queue             : pointer to queue object\n *\n * Clears out everything in the queue.\n **/\nvoid msg_queue_clear(msg_queue_t *queue);\n\n/**\n * msg_queue_free:\n * @queue             : pointer to queue object\n *\n * Frees message queue..\n **/\nvoid msg_queue_free(msg_queue_t *queue);\n\nbool msg_queue_deinitialize(msg_queue_t *queue);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/queues/task_queue.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (task_queue.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_TASK_QUEUE_H__\n#define __LIBRETRO_SDK_TASK_QUEUE_H__\n\n#include <stdint.h>\n#include <stddef.h>\n#include <boolean.h>\n\n#include <retro_common.h>\n#include <retro_common_api.h>\n\n#include <libretro.h>\n\nRETRO_BEGIN_DECLS\n\nenum task_type\n{\n   /** A regular task. The vast majority of tasks will use this type. */\n   TASK_TYPE_NONE,\n\n   /**\n    * Only one blocking task can exist in the queue at a time.\n    * Attempts to add a new one while another is running will fail.\n    */\n   TASK_TYPE_BLOCKING\n};\n\nenum task_style\n{\n   TASK_STYLE_NONE,\n   TASK_STYLE_POSITIVE,\n   TASK_STYLE_NEGATIVE\n};\n\ntypedef struct retro_task retro_task_t;\n\n/** @copydoc retro_task::callback */\ntypedef void (*retro_task_callback_t)(retro_task_t *task,\n      void *task_data,\n      void *user_data, const char *error);\n\n/** @copydoc retro_task::handler */\ntypedef void (*retro_task_handler_t)(retro_task_t *task);\n\n/** @copydoc task_finder_data::func */\ntypedef bool (*retro_task_finder_t)(retro_task_t *task,\n      void *userdata);\n\n/**\n * Displays a message output by a task.\n */\ntypedef void (*retro_task_queue_msg_t)(retro_task_t *task,\n      const char *msg,\n      unsigned prio, unsigned duration, bool flush);\n\n/** @copydoc task_retriever_data::func */\ntypedef bool (*retro_task_retriever_t)(retro_task_t *task, void *data);\n\n/**\n * Called by \\c task_queue_wait after each task executes\n * (i.e. once per pass over the queue).\n * @param data Arbitrary data.\n * The function should cast this to a known type.\n * @return \\c true if \\c task_queue_wait should continue waiting,\n * \\c false if it should return early.\n * @see task_queue_wait\n */\ntypedef bool (*retro_task_condition_fn_t)(void *data);\n\ntypedef struct\n{\n   char *source_file;\n} decompress_task_data_t;\n\nenum retro_task_flags\n{\n   /**\n    * If \\c true, the frontend should use some alternative means\n    * of displaying this task's progress or messages.\n    * Not used within cores.\n    */\n   RETRO_TASK_FLG_ALTERNATIVE_LOOK = (1 << 0),\n   /**\n    * Set to \\c true by \\c handler to indicate that this task has finished.\n    * At this point the task queue will call \\c callback and \\c cleanup,\n    * then deallocate the task.\n    */\n   RETRO_TASK_FLG_FINISHED         = (1 << 1),\n   /**\n    * Set to true by the task queue to signal that this task \\em must end.\n    * \\c handler should check to see if this is set,\n    * aborting or completing its work as soon as possible afterward.\n    * \\c callback and \\c cleanup will still be called as normal.\n    *\n    * @see task_queue_reset\n    */\n   RETRO_TASK_FLG_CANCELLED        = (1 << 2),\n   /**\n    * If set, the task queue will not call \\c progress_cb\n    * and will not display any messages from this task.\n    */\n   RETRO_TASK_FLG_MUTE             = (1 << 3)\n};\n\n/**\n * A unit of work executed by the task system,\n * spread across one or more frames.\n *\n * Some fields are set by the caller,\n * others are set by the task system.\n */\nstruct retro_task\n{\n   /**\n    * The time (in microseconds) when the task should start running,\n    * or 0 if it should start as soon as possible.\n    * The exact time this task starts will depend on when the queue is next updated.\n    * Set by the caller.\n    * @note This is a point in time, not a duration.\n    * It is not affected by a frontend's time manipulation (pausing, fast-forward, etc.).\n    * @see cpu_features_get_time_usec\n    */\n   retro_time_t when;\n\n   /**\n    * The main body of work for a task.\n    * Should be as fast as possible,\n    * as it will be called with each task queue update\n    * (usually once per frame).\n    * Must not be \\c NULL.\n    *\n    * @param task The task that this handler is associated with.\n    * Can be used to configure or query the task.\n    * Will never be \\c NULL.\n    * @see task_queue_check\n    */\n   retro_task_handler_t  handler;\n\n   /**\n    * Called when this task finishes;\n    * executed during the next task queue update\n    * after \\c finished is set to \\c true.\n    * May be \\c NULL, in which case this function is skipped.\n    *\n    * @param task The task that is being cleaned up.\n    * Will never be \\c NULL.\n    * @param task_data \\c task's \\c task_data field.\n    * @param user_data \\c task's \\c user_data field.\n    * @param error \\c task's \\c error field.\n    * @see task_queue_check\n    * @see retro_task_callback_t\n    */\n   retro_task_callback_t callback;\n\n   /**\n    * Called when this task finishes immediately after \\c callback is run.\n    * Used to clean up any resources or state owned by the task.\n    * May be \\c NULL, in which case this function is skipped.\n    *\n    * @param task The task that is being cleaned up.\n    * Will never be \\c NULL.\n    */\n   retro_task_handler_t cleanup;\n\n   /**\n    * Pointer to arbitrary data, intended for \"returning\" an object from the task\n    * (although it can be used for any purpose).\n    * If owned by the task, it should be cleaned up within \\c cleanup.\n    * Not modified or freed by the task queue.\n    */\n   void *task_data;\n\n   /**\n    * Pointer to arbitrary data, intended for passing parameters to the task.\n    * If owned by the task, it should be cleaned up within \\c cleanup.\n    * Not modified or freed by the task queue.\n    */\n   void *user_data;\n\n   /**\n    * Pointer to arbitrary data, intended for state that exists for the task's lifetime.\n    * If owned by the task, it should be cleaned up within \\c cleanup.\n    * Not modified or freed by the task queue.\n    */\n   void *state;\n\n   /**\n    * Human-readable details about an error that occurred while running the task.\n    * Should be created and assigned within \\c handler if there was an error.\n    * Will be cleaned up by the task queue with \\c free() upon this task's completion.\n    *\n    * If \\c handler may set this more than once on the same task,\n    * call \\c task_free_error before the subsequent \\c task_set_error\n    * to avoid leaking the previous string.\n    *\n    * @see task_set_error\n    * @see task_free_error\n    */\n   char *error;\n\n   /**\n    * Called to update a task's \\c progress,\n    * or to update some view layer (e.g. an on-screen display)\n    * about the task's progress.\n    *\n    * Skipped if \\c NULL or if \\c mute is set.\n    *\n    * @param task The task whose progress is being updated or reported.\n    * @see progress\n    */\n   void (*progress_cb)(retro_task_t*);\n\n   /**\n    * Human-readable description of this task.\n    * May be \\c NULL,\n    * but if not then it will be disposed of by the task system with \\c free()\n    * upon this task's completion.\n    *\n    * Can be modified or replaced at any time, but \\c task_set_title\n    * does \\em not free the previous value: callers must call\n    * \\c task_free_title first to avoid leaking the prior title.\n    *\n    * @see strdup\n    * @see task_set_title\n    * @see task_free_title\n    */\n   char *title;\n\n   /**\n    * Pointer to arbitrary data, intended for use by a frontend\n    * (for example, to associate a sticky notification with a task).\n    *\n    * This should be cleaned up within \\c cleanup if necessary.\n    * Cores may use this for any purpose.\n    */\n   void *frontend_userdata;\n\n   /**\n    * @private Pointer to the next task in the queue.\n    * Do not touch this; it is managed by the task system.\n    */\n   retro_task_t *next;\n\n   /**\n    * Indicates the current progress of the task.\n    *\n    * -1 means the task is indefinite or not measured,\n    * 0-100 is a percentage of the task's completion.\n    *\n    * Set by the caller.\n    *\n    * @see progress_cb\n    */\n   int8_t progress;\n\n   /**\n    * A unique identifier assigned to a task when it's created.\n    * Set by the task system.\n    */\n   uint32_t ident;\n\n   /**\n    * The type of task this is.\n    * Set by the caller.\n    */\n   enum task_type type;\n   enum task_style style;\n\n   uint8_t flags;\n};\n\n/**\n * Parameters for \\c task_queue_find.\n *\n * @see task_queue_find\n */\ntypedef struct task_finder_data\n{\n   /**\n    * Predicate to call for each task.\n    * Must not be \\c NULL.\n    *\n    * @param task The task to query.\n    * @param userdata \\c userdata from this struct.\n    * @return \\c true if this task matches the search criteria,\n    * at which point \\c task_queue_find will stop searching and return \\c true.\n    */\n   retro_task_finder_t func;\n\n   /**\n    * Pointer to arbitrary data.\n    * Passed directly to \\c func.\n    * May be \\c NULL.\n    */\n   void *userdata;\n} task_finder_data_t;\n\n/**\n * Contains the result of a call to \\c task_retriever_data::func.\n * Implemented as an intrusive singly-linked list.\n */\ntypedef struct task_retriever_info\n{\n   /**\n    * The next item in the result list,\n    * or \\c NULL if this is the last one.\n    */\n   struct task_retriever_info *next;\n\n   /**\n    * Arbitrary data returned by \\c func.\n    * Can be anything, but should be a simple \\c struct\n    * so that it can be freed by \\c task_queue_retriever_info_free.\n    */\n   void *data;\n} task_retriever_info_t;\n\n/**\n * Parameters for \\c task_queue_retrieve.\n *\n * @see task_queue_retrieve\n */\ntypedef struct task_retriever_data\n{\n   /**\n    * Contains the result of each call to \\c func that returned \\c true.\n    * Should be initialized to \\c NULL.\n    * Will remain \\c NULL after \\c task_queue_retrieve if no tasks matched.\n    * Must be freed by \\c task_queue_retriever_info_free.\n    * @see task_queue_retriever_info_free\n    */\n   task_retriever_info_t *list;\n\n   /**\n    * The handler to compare against.\n    * Only tasks with this handler will be considered for retrieval.\n    * Must not be \\c NULL.\n    */\n   retro_task_handler_t handler;\n\n   /**\n    * The predicate that determines if the given task will be retrieved.\n    * Must not be \\c NULL.\n    *\n    * @param task[in] The task to query.\n    * @param data[out] Arbitrary data that the retriever should return.\n    * Allocated by the task queue based on \\c element_size.\n    * @return \\c true if \\c data should be appended to \\c list.\n    */\n   retro_task_retriever_t func;\n\n   /**\n    * The size of the output that \\c func may write to.\n    * Must not be zero.\n    */\n   size_t element_size;\n} task_retriever_data_t;\n\n/**\n * Returns the next item in the result list.\n * Here's a usage example, assuming that \\c results is used to store strings:\n *\n * @code{.c}\n * void print_results(task_retriever_info_t *results)\n * {\n *    char* text = NULL;\n *    task_retriever_info_t *current = results;\n *    while (text = task_queue_retriever_info_next(&current))\n *    {\n *       printf(\"%s\\n\", text);\n *    }\n * }\n * @endcode\n *\n * @param link Pointer to the first element in the result list.\n * Must not be \\c NULL.\n * @return The next item in the result list.\n */\nvoid *task_queue_retriever_info_next(task_retriever_info_t **link);\n\n/**\n * Frees the result of a call to \\c task_queue_retrieve.\n * @param list The result list to free.\n * May be \\c NULL, in which case this function does nothing.\n * The list, its nodes, and its elements will all be freed.\n *\n * If the list's elements must be cleaned up with anything besides \\c free,\n * then the caller must do that itself before invoking this function.\n */\nvoid task_queue_retriever_info_free(task_retriever_info_t *list);\n\n/**\n * Cancels the provided task.\n * The task should finish its work as soon as possible afterward.\n *\n * @param task The task to cancel.\n * @see task_set_cancelled\n */\nvoid task_queue_cancel_task(void *task);\n\nvoid task_set_flags(retro_task_t *task, uint8_t flags, bool set);\n\n/**\n * Sets \\c task::error to the given value.\n * Thread-safe if the task queue is threaded.\n *\n * Ownership of \\c error transfers to the task; the task system\n * will \\c free() it when the task completes (or via\n * \\c task_free_error).  \\c error must therefore point to memory\n * obtained via \\c malloc / \\c strdup / similar -- string\n * literals or stack buffers will cause an invalid free later.\n *\n * @warning This does \\em not free the previous error message.\n * When replacing an already-set error, callers \\em must call\n * \\c task_free_error first to avoid a leak:\n * @code\n *    task_free_error(task);\n *    task_set_error(task, strdup(\"New error\"));\n * @endcode\n * Alternatively, guard with \\c task_get_error so the second\n * \\c task_set_error is skipped when an error is already set.\n *\n * @param task The task to modify.\n * Behavior is undefined if \\c NULL.\n * @param error The error message to set.\n * @see retro_task::error\n * @see task_free_error\n */\nvoid task_set_error(retro_task_t *task, char *error);\n\n/**\n * Sets \\c task::progress to the given value.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to modify.\n * Behavior is undefined if \\c NULL.\n * @param progress The progress value to set.\n * @see retro_task::progress\n */\nvoid task_set_progress(retro_task_t *task, int8_t progress);\n\n/**\n * Sets \\c task::title to the given value.\n * Thread-safe if the task queue is threaded.\n *\n * Ownership of \\c title transfers to the task; the task system\n * will \\c free() it when the task completes (or via\n * \\c task_free_title).  \\c title must therefore point to memory\n * obtained via \\c malloc / \\c strdup / similar -- string\n * literals or stack buffers will cause an invalid free later.\n *\n * @warning This does \\em not free the previous title.  When\n * replacing an already-set title, callers \\em must call\n * \\c task_free_title first to avoid a leak:\n * @code\n *    task_free_title(task);\n *    task_set_title(task, strdup(\"New title\"));\n * @endcode\n *\n * @param task The task to modify.\n * Behavior is undefined if \\c NULL.\n * @param title The title to set.\n * @see retro_task::title\n * @see task_free_title\n */\nvoid task_set_title(retro_task_t *task, char *title);\n\n/**\n * Sets \\c task::data to the given value.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to modify.\n * Behavior is undefined if \\c NULL.\n * @param data The data to set.\n * @see retro_task::data\n */\nvoid task_set_data(retro_task_t *task, void *data);\n\n/**\n * Frees the \\c task's title, if any.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to modify.\n * @see task_set_title\n */\nvoid task_free_title(retro_task_t *task);\n\n/**\n * Frees the \\c task's error message, if any.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to modify.\n * @see task_set_error\n */\nvoid task_free_error(retro_task_t *task);\n\n/**\n * Returns \\c task::error.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to query.\n * Behavior is undefined if \\c NULL.\n * @return The value of \\c task::error.\n * @see retro_task::error\n */\nchar* task_get_error(retro_task_t *task);\n\n/**\n * Returns \\c task::progress.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to query.\n * Behavior is undefined if \\c NULL.\n * @return The value of \\c task::progress.\n * @see retro_task::progress\n */\nint8_t task_get_progress(retro_task_t *task);\n\n/**\n * Returns \\c task::title.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to query.\n * Behavior is undefined if \\c NULL.\n * @return The value of \\c task::title.\n * @see retro_task::title\n */\nchar* task_get_title(retro_task_t *task);\n\n/**\n * Returns \\c task::data.\n * Thread-safe if the task queue is threaded.\n *\n * @param task The task to query.\n * Behavior is undefined if \\c NULL.\n * @return The value of \\c task::data.\n * @see retro_task::data\n */\nvoid* task_get_data(retro_task_t *task);\n\n/**\n * Returns whether the task queue is running\n * on the same thread that called \\c task_queue_init.\n *\n * @return \\c true if the caller is running\n * on the same thread that called \\c task_queue_init.\n */\nbool task_is_on_main_thread(void);\n\n/**\n * Ensures that the task queue is in threaded mode.\n *\n * Next time \\c retro_task_queue_check is called,\n * the task queue will be recreated with threading enabled.\n * Existing tasks will continue to run on the new thread.\n */\nvoid task_queue_set_threaded(void);\n\n/**\n * Ensures that the task queue is not in threaded mode.\n *\n * Next time \\c retro_task_queue_check is called,\n * the task queue will be recreated with threading disabled.\n * Existing tasks will continue to run on whichever thread updates the queue.\n *\n * @see task_queue_set_threaded\n * @see task_queue_is_threaded\n */\nvoid task_queue_unset_threaded(void);\n\n/**\n * Returns whether the task queue is running in threaded mode.\n *\n * @return \\c true if the task queue is running its tasks on a separate thread.\n */\nbool task_queue_is_threaded(void);\n\n/**\n * Calls the function given in \\c find_data for each task\n * until it returns \\c true for one of them,\n * or until all tasks have been searched.\n *\n * @param find_data Parameters for the search.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if \\c find_data::func returned \\c true for any task.\n * @see task_finder_data_t\n */\nbool task_queue_find(task_finder_data_t *find_data);\n\n/**\n * Retrieves arbitrary data from every task\n * whose handler matches \\c data::handler.\n *\n * @param data[in, out] Parameters for retrieving data from the task queue,\n * including the results themselves.\n * Behavior is undefined if \\c NULL.\n * @see task_retriever_data_t\n */\nvoid task_queue_retrieve(task_retriever_data_t *data);\n\n /**\n  * Runs each task.\n  * If a task is finished or cancelled,\n  * its callback and cleanup handler will be called.\n  * Afterwards, the task will be deallocated.\n  * If used in a core, generally called in \\c retro_run\n  * and just before \\c task_queue_deinit.\n  * @warning This must only be called from the main thread.\n  */\nvoid task_queue_check(void);\n\nuint8_t task_get_flags(retro_task_t *task);\n\n/**\n * Schedules a task to start running.\n * If \\c task::when is 0, it will start as soon as possible.\n *\n * Tasks with the same \\c task::when value\n * will be executed in the order they were scheduled.\n *\n * @param task The task to schedule.\n * @return \\c true unless \\c task's type is \\c TASK_TYPE_BLOCKING\n * and there's already a blocking task in the queue.\n */\nbool task_queue_push(retro_task_t *task);\n\n/**\n * Block until all active (i.e. current time > \\c task::when) tasks have finished,\n * or until the given function returns \\c false.\n * If a scheduled task's \\c when is passed while within this function,\n * it will start executing.\n *\n * Must only be called from the main thread.\n *\n * @param cond Function to call after all tasks in the queue have executed\n * (i.e. once per pass over the task queue).\n * May be \\c NULL, in which case the task queue will wait unconditionally.\n * @param data Pointer to arbitrary data, passed directly into \\c cond.\n * May be \\c NULL.\n * @see retro_task_condition_fn_t\n * @see task_queue_deinit\n * @see task_queue_reset\n * @warning Passing \\c NULL to \\c cond is strongly discouraged.\n * If you use tasks that run indefinitely\n * (e.g. for the lifetime of the core),\n * you will need a way to stop these tasks externally;\n * otherwise, you risk the frontend and core freezing.\n */\nvoid task_queue_wait(retro_task_condition_fn_t cond, void* data);\n\n/**\n * Marks all tasks in the queue as cancelled.\n *\n * The tasks won't immediately be terminated;\n * each task may finish its work,\n * but must do so as quickly as possible.\n *\n * Must only be called from the main thread.\n *\n * @see task_queue_wait\n * @see task_queue_deinit\n * @see task_set_finished\n * @see task_get_cancelled\n */\nvoid task_queue_reset(void);\n\n/**\n * Deinitializes the task system.\n *\n * Outstanding tasks will not be cleaned up;\n * if the intent is to finish the core or frontend's work,\n * then all tasks must be finished before calling this function.\n * May be safely called multiple times in a row,\n * but only from the main thread.\n * @see task_queue_wait\n * @see task_queue_reset\n */\nvoid task_queue_deinit(void);\n\n/**\n * Initializes the task system with the provided parameters.\n * Must be called before any other task_queue_* function,\n * and must only be called from the main thread.\n *\n * @param threaded \\c true if tasks should run on a separate thread,\n * \\c false if they should remain on the calling thread.\n * All tasks run in sequence on a single thread.\n * If you want to scale a task to multiple threads,\n * you must do so within the task itself.\n * @param msg_push The task system will call this function to output messages.\n * If \\c NULL, no messages will be output.\n * @note Calling this function while the task system is already initialized\n * will reinitialize it with the new parameters,\n * but it will not reset the task queue;\n * all existing tasks will continue to run\n * when the queue is updated.\n * @see task_queue_deinit\n * @see retro_task_queue_msg_t\n */\nvoid task_queue_init(bool threaded, retro_task_queue_msg_t msg_push);\n\n/**\n * Allocates and initializes a new task.\n * Deallocated by the task queue after it finishes executing.\n *\n * @returns Pointer to a newly allocated task,\n * or \\c NULL if allocation fails.\n */\nretro_task_t *task_init(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/retro_assert.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_assert.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __RETRO_ASSERT_H\n#define __RETRO_ASSERT_H\n\n#include <assert.h>\n\n#ifdef RARCH_INTERNAL\n#include <stdio.h>\n#define retro_assert(cond) ((void)( (cond) || (printf(\"Assertion failed at %s:%d.\\n\", __FILE__, __LINE__), abort(), 0) ))\n#else\n#define retro_assert(cond) assert(cond)\n#endif\n\n#endif\n"
  },
  {
    "path": "include/retro_atomic.h",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_atomic.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_ATOMIC_H\n#define __LIBRETRO_SDK_ATOMIC_H\n\n#include <retro_common_api.h>\n\n/* Minimal portable atomic operations for SPSC patterns.\n *\n * This header consolidates the ad-hoc atomic shims previously duplicated\n * in audio/drivers/{coreaudio,coreaudio3,xaudio,opensl}.c, audio/common/\n * mmdevice_common.c and gfx/gfx_thumbnail.c.  The surface is intentionally\n * narrow: load, store, fetch_add, fetch_sub, plus inc/dec convenience\n * wrappers.  Everything is on plain machine words (int and size_t); no\n * compare-exchange, no double-word ops, no thread-fences.  Add only when\n * a real caller needs it.\n *\n * Memory ordering is fixed per-operation rather than parameterised, to\n * keep the call sites readable and to avoid having to invent ordering\n * tags for every backend:\n *\n *   retro_atomic_load_acquire   - acquire load   (pairs with release store)\n *   retro_atomic_store_release  - release store  (pairs with acquire load)\n *   retro_atomic_fetch_add      - acq_rel RMW\n *   retro_atomic_fetch_sub      - acq_rel RMW\n *   retro_atomic_inc / dec      - acq_rel RMW, return void\n *\n * Backend selection (in order):\n *   1. C11 <stdatomic.h>            (modern GCC/Clang/MSVC with /std:c11)\n *   2. C++11 <atomic>               (any C++ TU with __cplusplus >= 201103L\n *                                    or _MSVC_LANG >= 201103L; the natural\n *                                    peer of C11 stdatomic for C++ callers)\n *   3. GCC __atomic_*               (GCC 4.7+ / Clang 3.1+)\n *   4. MSVC Interlocked* (Win32)    (every MSVC since VS2003, OG Xbox,\n *                                    Xbox 360 XDK, modern Win32/x64)\n *   5. Mach OSAtomic*               (Apple PPC / pre-10.7)\n *   6. GCC __sync_*                 (very old GCC, GCC 4.1-4.6)\n *   7. volatile fallback            (single-core, x86 TSO, or last resort)\n *\n * Capability macros (defined after backend selection):\n *\n *   HAVE_RETRO_ATOMIC          -> always 1 if the header included\n *                                 successfully.  Use for compile-time gating\n *                                 of any code that uses the API at all.\n *   RETRO_ATOMIC_LOCK_FREE     -> 1 if a real lock-free backend was\n *                                 selected (1, 2, 3, 4, 5, or 6).  NOT\n *                                 defined if the volatile fallback (7)\n *                                 was selected.  SPSC fifos and other\n *                                 lock-free data structures should gate\n *                                 on this.\n *\n *                                 Strictly speaking, the C and C++\n *                                 standards do not guarantee that\n *                                 atomic_int / std::atomic<int> are\n *                                 lock-free on all conforming\n *                                 implementations.  In practice, on\n *                                 every architecture and toolchain\n *                                 RetroArch supports (x86/x64, ARM,\n *                                 AArch64, PowerPC, MIPS, all with\n *                                 32-bit aligned word atomics), int and\n *                                 size_t are always lock-free, so this\n *                                 macro is defined unconditionally for\n *                                 every named backend.  If a future\n *                                 port lands on a target where this is\n *                                 not the case, this comment is the\n *                                 right place to add an\n *                                 ATOMIC_INT_LOCK_FREE / atomic\n *                                 _is_always_lock_free gate.\n *   RETRO_ATOMIC_BACKEND_NAME  -> string literal naming the active backend\n *                                 (e.g. \"C11 stdatomic\", \"volatile fallback\").\n *                                 Useful for diagnostics and CI logs.\n *\n * Caller-side opt-in for stricter selection:\n *\n *   RETRO_ATOMIC_REQUIRE_LOCK_FREE\n *     If defined by the caller before including this header, an\n *     #error is raised when only the volatile fallback would be\n *     available.  Use in code paths whose correctness depends on\n *     real hardware barriers (e.g. SPSC ring buffers used across\n *     SMP threads on weakly-ordered targets).\n *\n * Caller patterns\n * ---------------\n * There are three idiomatic ways to consume this header, picked\n * according to how the caller copes with no-atomics:\n *\n * Pattern 1 -- \"lock-free fast path with a portable fallback\"\n *   Use when you have a working alternative (mutex-based, locked,\n *   slock_t / scond_t, fifo_queue with a lock around it) that you\n *   would happily fall back to on a target without real atomics.\n *   This is the same shape as audio/drivers/coreaudio.c's\n *   RARCH_COREAUDIO_LEGACY split.\n *\n *     #include <retro_atomic.h>\n *     #if defined(RETRO_ATOMIC_LOCK_FREE)\n *        // SPSC fast path -- producer/consumer split with\n *        // load_acquire / store_release / fetch_add.\n *        static retro_atomic_size_t fill;\n *        ...\n *     #else\n *        // Locked fallback -- regular fifo_queue + slock_t.\n *        static fifo_buffer_t *fifo;\n *        static slock_t       *lock;\n *        ...\n *     #endif\n *\n * Pattern 2 -- \"atomics required, refuse to compile otherwise\"\n *   Use when the calling code has no sensible non-atomic\n *   implementation -- the fast path *is* the only path, and a\n *   silent volatile fallback would be worse than a build break.\n *   Define RETRO_ATOMIC_REQUIRE_LOCK_FREE before the include and\n *   the header will #error out if no real backend is available.\n *\n *     #define RETRO_ATOMIC_REQUIRE_LOCK_FREE\n *     #include <retro_atomic.h>\n *\n *     // From here on, RETRO_ATOMIC_LOCK_FREE is guaranteed.\n *\n * Pattern 3 -- \"atomics if useful, harmless if not\"\n *   Use when the calling code is correct without atomics (e.g.\n *   relaxed counters used only for diagnostics or rate-limiting\n *   that can tolerate a torn read).  Just use the macros\n *   unconditionally; the volatile fallback gives you the loosest\n *   semantics that still compiles, and that's enough.\n *\n *     #include <retro_atomic.h>\n *     // No #if needed -- counters work either way.\n *     retro_atomic_int_t debug_counter;\n *     retro_atomic_inc_int(&debug_counter);\n *\n * The choice between Pattern 1 and Pattern 2 is mostly about how\n * forgiving the calling code can be: a reusable library primitive\n * (fifo_spsc_t for instance) is better off with Pattern 1, because\n * a dependent that doesn't care about SMP correctness on the rare\n * volatile-fallback target shouldn't be forced to provide an\n * alternative.  Application code that hard-relies on real barriers\n * to be correct is better off with Pattern 2 -- it makes the\n * portability requirement loud at build time on the platform that\n * needs to fix it, instead of silently miscompiling.\n *\n * The fallback is intentionally weak.  It is correct on:\n *   - true single-core hardware (PSP, original NDS-class)\n *   - x86/x64 (TSO masks the missing release/acquire fences for naturally\n *     aligned word-sized loads/stores; the missing piece is a compiler\n *     barrier, supplied by `volatile`)\n * It is NOT correct on weakly-ordered SMP without barriers (ARMv7+ SMP,\n * PowerPC SMP, MIPS SMP).  No RetroArch target lands in that gap today\n * without also having one of the higher-priority backends available, but\n * compiling there raises a #warning so it's loud.\n *\n * PowerPC coverage:\n *   - Xbox 360 XDK (MSVC + Xenon PPC) -> MSVC backend, *Acquire variants\n *     emit lwsync. Correct on the 3-core console.\n *   - libxenon Xbox 360 (xenon-gcc)   -> GCC __atomic_* backend.\n *   - GameCube (single-core Gekko)    -> GCC __atomic_* backend; SMP\n *     concerns moot anyway.\n *   - Wii (single-core Broadway)      -> GCC __atomic_* backend; SMP\n *     concerns moot anyway.\n *   - Wii U (3-core Espresso)         -> GCC __atomic_* backend.\n *   - PS3 (Cell PPU, plus SPEs the\n *     host code does not run on)      -> GCC __atomic_* backend.\n *   - Apple PPC G3/G4 (single-core)   -> Apple OSAtomic backend.\n *   - Apple PPC G5 (SMP)              -> Apple OSAtomic backend.\n *\n * ARM / AArch64 coverage:\n *   - Switch / libnx (Cortex-A57 SMP) -> GCC __atomic_* backend; emits\n *     real ldar/stlr/ldadd*_acq_rel.  Verified by aarch64-linux-gnu\n *     cross-compile + qemu user-mode.\n *   - PSVita (Cortex-A9 SMP, ARMv7)   -> GCC __atomic_* backend; emits\n *     dmb ish around exclusive monitor pairs.  Verified by qemu-arm.\n *   - 3DS (ARM11 ARMv6, single-core\n *     OldOld 3DS, dual-core New 3DS)  -> GCC __atomic_* backend.\n *   - webOS / Miyoo / OpenPandora     -> GCC __atomic_* backend.\n *   - Raspberry Pi / generic Linux    -> GCC __atomic_* or C11 stdatomic.\n *   - Android (NDK Clang)             -> C11 stdatomic.\n *   - Apple iOS / tvOS / Apple Silicon\n *     Mac (ARM64, multi-core SMP)     -> C11 stdatomic.\n *   - Windows on ARM64 (MSVC)         -> MSVC backend.  *Acquire variants\n *     for load and store emit dmb per MSVC docs; fetch_add/fetch_sub\n *     are bracketed with explicit __dmb(_ARM64_BARRIER_ISH) since plain\n *     Interlocked* RMW lacks barriers on ARM64 (PostgreSQL hit this on\n *     Win11/ARM64 in 2025).\n *\n * Clang notes:\n *   Clang impersonates GCC 4.2 in its __GNUC__ / __GNUC_MINOR__\n *   defines (a long-standing legacy compatibility setting), so a naive\n *   \"GCC >= 4.7\" gate would fall through to __sync_* on Clang even\n *   though Clang has supported __atomic_* since 3.1.  The GCC backend\n *   gate above keys on `defined(__clang__) || (GCC version check)` to\n *   short-circuit this trap.\n *\n *   Selection on Clang in practice:\n *     -std=c89/c99/gnu99   -> GCC __atomic_*\n *     -std=c11/c17/gnu17   -> C11 stdatomic\n *     -std=c++98           -> GCC __atomic_*\n *     -std=c++11 and later -> C++11 std::atomic\n *\n *   On AArch64, Clang and GCC emit the same family of instructions\n *   (ldar / stlr / ldadd*_acq_rel), so the hardware contract is\n *   honoured identically.  Clang on Apple platforms (macOS, iOS,\n *   tvOS), Android NDK r18+, Emscripten, and PS4-ORBIS all flow\n *   through one of the gcc / C11 / C++11 paths above; the CI lane\n *   exercises Clang with ThreadSanitizer, which would flag any\n *   missing-barrier regression in the SPSC stress.\n */\n\n/* No external libretro-common includes are needed: the header is all\n * macros and integer typedefs.  Each backend block pulls in the\n * platform headers it needs (<stdatomic.h>, <atomic>, <windows.h>,\n * <libkern/OSAtomic.h>) inside its own #if guard. */\n\n/* ---- Backend detection ------------------------------------------------- */\n\n/* Build-time overrides.  Define one of:\n *   RETRO_ATOMIC_FORCE_C11\n *   RETRO_ATOMIC_FORCE_CXX11\n *   RETRO_ATOMIC_FORCE_GCC_NEW\n *   RETRO_ATOMIC_FORCE_MSVC\n *   RETRO_ATOMIC_FORCE_APPLE\n *   RETRO_ATOMIC_FORCE_SYNC\n *   RETRO_ATOMIC_FORCE_VOLATILE\n * to bypass auto-detection.  Useful for porting and for testing.       */\n#if defined(RETRO_ATOMIC_FORCE_C11)\n#define RETRO_ATOMIC_BACKEND_C11 1\n#elif defined(RETRO_ATOMIC_FORCE_CXX11)\n#define RETRO_ATOMIC_BACKEND_CXX11 1\n#elif defined(RETRO_ATOMIC_FORCE_GCC_NEW)\n#define RETRO_ATOMIC_BACKEND_GCC_NEW 1\n#elif defined(RETRO_ATOMIC_FORCE_MSVC)\n#define RETRO_ATOMIC_BACKEND_MSVC 1\n#elif defined(RETRO_ATOMIC_FORCE_APPLE)\n#define RETRO_ATOMIC_BACKEND_APPLE 1\n#elif defined(RETRO_ATOMIC_FORCE_SYNC)\n#define RETRO_ATOMIC_BACKEND_SYNC 1\n#elif defined(RETRO_ATOMIC_FORCE_VOLATILE)\n#define RETRO_ATOMIC_BACKEND_VOLATILE 1\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \\\n    !defined(__STDC_NO_ATOMICS__)\n#define RETRO_ATOMIC_BACKEND_C11 1\n/* C++11 <atomic> is the natural peer of C11 <stdatomic.h> for any\n * C++ TU that includes this header.  Note: MSVC keeps __cplusplus\n * pinned at 199711L unless /Zc:__cplusplus is passed; _MSVC_LANG\n * carries the actual language level, so we test both.  RetroArch\n * builds Makefile.win and a few legacy paths with -std=c++98, so\n * the gate must be exact -- defined(__cplusplus) alone is not\n * enough. */\n#elif (defined(__cplusplus) && __cplusplus >= 201103L) || \\\n      (defined(_MSVC_LANG)  && _MSVC_LANG  >= 201103L)\n#define RETRO_ATOMIC_BACKEND_CXX11 1\n#elif defined(__clang__) || (defined(__GNUC__) && \\\n    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))\n#define RETRO_ATOMIC_BACKEND_GCC_NEW 1\n#elif defined(_MSC_VER)\n#define RETRO_ATOMIC_BACKEND_MSVC 1\n#elif defined(__APPLE__) && defined(__MACH__)\n/* Old Apple toolchains (PPC / pre-10.7) without modern GCC builtins.\n * OSAtomic is deprecated but functional through 10.x. */\n#define RETRO_ATOMIC_BACKEND_APPLE 1\n#elif defined(__GNUC__) && \\\n    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))\n#define RETRO_ATOMIC_BACKEND_SYNC 1\n#else\n#define RETRO_ATOMIC_BACKEND_VOLATILE 1\n#if !defined(RETRO_ATOMIC_SUPPRESS_WARNING)\n#warning \"retro_atomic.h: no atomic backend matched, falling back to volatile. Safe only on single-core or x86 TSO.\"\n#endif\n#endif\n\n/* ---- Capability flags -------------------------------------------------- */\n\n/* The header is always usable in the sense that the macros expand to\n * working C; HAVE_RETRO_ATOMIC just signals that the API surface exists.\n * Callers that want to know whether the backend is actually lock-free\n * on SMP must additionally test RETRO_ATOMIC_LOCK_FREE. */\n#define HAVE_RETRO_ATOMIC 1\n\n#if defined(RETRO_ATOMIC_BACKEND_C11)\n#define RETRO_ATOMIC_LOCK_FREE 1\n#define RETRO_ATOMIC_BACKEND_NAME \"C11 stdatomic\"\n#elif defined(RETRO_ATOMIC_BACKEND_CXX11)\n#define RETRO_ATOMIC_LOCK_FREE 1\n#define RETRO_ATOMIC_BACKEND_NAME \"C++11 std::atomic\"\n#elif defined(RETRO_ATOMIC_BACKEND_GCC_NEW)\n#define RETRO_ATOMIC_LOCK_FREE 1\n#define RETRO_ATOMIC_BACKEND_NAME \"GCC __atomic_*\"\n#elif defined(RETRO_ATOMIC_BACKEND_MSVC)\n#define RETRO_ATOMIC_LOCK_FREE 1\n#define RETRO_ATOMIC_BACKEND_NAME \"MSVC Interlocked*\"\n#elif defined(RETRO_ATOMIC_BACKEND_APPLE)\n#define RETRO_ATOMIC_LOCK_FREE 1\n#define RETRO_ATOMIC_BACKEND_NAME \"Apple OSAtomic*\"\n#elif defined(RETRO_ATOMIC_BACKEND_SYNC)\n#define RETRO_ATOMIC_LOCK_FREE 1\n#define RETRO_ATOMIC_BACKEND_NAME \"GCC __sync_*\"\n#else /* RETRO_ATOMIC_BACKEND_VOLATILE */\n/* RETRO_ATOMIC_LOCK_FREE intentionally NOT defined for the volatile\n * fallback; callers that gate on it will compile without the\n * lock-free fast path on this target. */\n#define RETRO_ATOMIC_BACKEND_NAME \"volatile fallback (best-effort)\"\n#if defined(RETRO_ATOMIC_REQUIRE_LOCK_FREE)\n#error \"retro_atomic.h: RETRO_ATOMIC_REQUIRE_LOCK_FREE was set, but only the volatile fallback is available on this target. The caller's correctness depends on hardware barriers that this backend does not provide. Either provide a real atomic backend (C11 stdatomic, C++11 std::atomic, GCC __atomic_*, MSVC Interlocked*, Apple OSAtomic*, or GCC __sync_*) or fall back to a locked implementation in the calling code.\"\n#endif\n#endif\n\n/* The header contains only macros and integer typedefs; there are no\n * function declarations and therefore no need for RETRO_BEGIN_DECLS\n * around the file.  The C++11 backend below #includes <atomic>, whose\n * templates cannot be declared with C linkage; if a caller wraps its\n * #include of this header in extern \"C\" { ... } (e.g. ui_qt.cpp under\n * !CXX_BUILD), libstdc++ <atomic> emits dozens of \"template with C\n * linkage\" errors.  RETRO_BEGIN_DECLS_CXX below escapes that. */\n\n/* ---- C11 <stdatomic.h> ------------------------------------------------- */\n#if defined(RETRO_ATOMIC_BACKEND_C11)\n\n#include <stdatomic.h>\n#include <stddef.h>\n\ntypedef atomic_int    retro_atomic_int_t;\ntypedef atomic_size_t retro_atomic_size_t;\n\n#define retro_atomic_int_init(p, v)    atomic_init((p), (v))\n#define retro_atomic_size_init(p, v)   atomic_init((p), (v))\n\n#define retro_atomic_load_acquire_int(p) \\\n   atomic_load_explicit((p), memory_order_acquire)\n#define retro_atomic_store_release_int(p, v) \\\n   atomic_store_explicit((p), (v), memory_order_release)\n#define retro_atomic_fetch_add_int(p, v) \\\n   atomic_fetch_add_explicit((p), (v), memory_order_acq_rel)\n#define retro_atomic_fetch_sub_int(p, v) \\\n   atomic_fetch_sub_explicit((p), (v), memory_order_acq_rel)\n\n#define retro_atomic_load_acquire_size(p) \\\n   atomic_load_explicit((p), memory_order_acquire)\n#define retro_atomic_store_release_size(p, v) \\\n   atomic_store_explicit((p), (v), memory_order_release)\n#define retro_atomic_fetch_add_size(p, v) \\\n   atomic_fetch_add_explicit((p), (v), memory_order_acq_rel)\n#define retro_atomic_fetch_sub_size(p, v) \\\n   atomic_fetch_sub_explicit((p), (v), memory_order_acq_rel)\n\n/* ---- C++11 <atomic> --------------------------------------------------- */\n#elif defined(RETRO_ATOMIC_BACKEND_CXX11)\n\nRETRO_BEGIN_DECLS_CXX\n#include <atomic>\n#include <cstddef>\nRETRO_END_DECLS_CXX\n/* This header is included by C++ TUs in C++11+ mode (gated on\n * __cplusplus >= 201103L or _MSVC_LANG >= 201103L).  We use the\n * std::atomic_* free-function forms rather than the member-function\n * forms because they are syntactically closest to the C11 macros\n * above and keep the macro expansions identical in shape across\n * the two languages.\n *\n * The std::atomic<T> types are required by the standard to be\n * standard-layout for our integer instantiations and lock-free on\n * every RetroArch-supported target (every architecture has a\n * lock-free 32-bit and pointer-width atomic).  Size equality with\n * the underlying T is not promised by the standard but holds in\n * practice on every libstdc++/libc++/MSVC STL implementation we\n * care about; we do not rely on it. */\n\ntypedef std::atomic<int>         retro_atomic_int_t;\ntypedef std::atomic<std::size_t> retro_atomic_size_t;\n\n#define retro_atomic_int_init(p, v)    std::atomic_init((p), (v))\n#define retro_atomic_size_init(p, v)   std::atomic_init((p), (std::size_t)(v))\n\n#define retro_atomic_load_acquire_int(p) \\\n   std::atomic_load_explicit((p), std::memory_order_acquire)\n#define retro_atomic_store_release_int(p, v) \\\n   std::atomic_store_explicit((p), (v), std::memory_order_release)\n#define retro_atomic_fetch_add_int(p, v) \\\n   std::atomic_fetch_add_explicit((p), (v), std::memory_order_acq_rel)\n#define retro_atomic_fetch_sub_int(p, v) \\\n   std::atomic_fetch_sub_explicit((p), (v), std::memory_order_acq_rel)\n\n#define retro_atomic_load_acquire_size(p) \\\n   std::atomic_load_explicit((p), std::memory_order_acquire)\n#define retro_atomic_store_release_size(p, v) \\\n   std::atomic_store_explicit((p), (std::size_t)(v), std::memory_order_release)\n#define retro_atomic_fetch_add_size(p, v) \\\n   std::atomic_fetch_add_explicit((p), (std::size_t)(v), std::memory_order_acq_rel)\n#define retro_atomic_fetch_sub_size(p, v) \\\n   std::atomic_fetch_sub_explicit((p), (std::size_t)(v), std::memory_order_acq_rel)\n\n/* ---- GCC __atomic_* (4.7+) / Clang ------------------------------------ */\n#elif defined(RETRO_ATOMIC_BACKEND_GCC_NEW)\n\n#include <stddef.h>\n\ntypedef int    retro_atomic_int_t;\ntypedef size_t retro_atomic_size_t;\n\n#define retro_atomic_int_init(p, v)    (*(p) = (v))\n#define retro_atomic_size_init(p, v)   (*(p) = (v))\n\n#define retro_atomic_load_acquire_int(p) \\\n   __atomic_load_n((p), __ATOMIC_ACQUIRE)\n#define retro_atomic_store_release_int(p, v) \\\n   __atomic_store_n((p), (v), __ATOMIC_RELEASE)\n#define retro_atomic_fetch_add_int(p, v) \\\n   __atomic_fetch_add((p), (v), __ATOMIC_ACQ_REL)\n#define retro_atomic_fetch_sub_int(p, v) \\\n   __atomic_fetch_sub((p), (v), __ATOMIC_ACQ_REL)\n\n#define retro_atomic_load_acquire_size(p) \\\n   __atomic_load_n((p), __ATOMIC_ACQUIRE)\n#define retro_atomic_store_release_size(p, v) \\\n   __atomic_store_n((p), (v), __ATOMIC_RELEASE)\n#define retro_atomic_fetch_add_size(p, v) \\\n   __atomic_fetch_add((p), (v), __ATOMIC_ACQ_REL)\n#define retro_atomic_fetch_sub_size(p, v) \\\n   __atomic_fetch_sub((p), (v), __ATOMIC_ACQ_REL)\n\n/* ---- MSVC Interlocked* (Win32 API, works back to VS2003 / Xbox 360) ---- */\n#elif defined(RETRO_ATOMIC_BACKEND_MSVC)\n\n#include <stddef.h>\n/* Use the Win32 API forms (capital I, declared in <windows.h>) rather\n * than the compiler intrinsics (_InterlockedFoo, declared in <intrin.h>).\n * The intrinsics require <intrin.h> which doesn't exist before VS2005.\n * The Win32 API forms are available on every MSVC since Windows NT and\n * on the Xbox 360 / OG Xbox XDKs.\n *\n * Memory ordering is non-trivial on this backend because Microsoft's\n * Win32 plain Interlocked* functions have inconsistent ordering across\n * architectures:\n *   - x86/x64: full barrier (LOCK prefix), every form, always.\n *   - Itanium / Xbox 360 PowerPC: full barrier, but historically the\n *     docs warned to pair with __lwsync; the *Acquire / *Release\n *     forms (which fold the barrier in) are recommended.\n *   - ARM / ARM64: NO barrier on the plain forms; you must either\n *     use the *Acquire / *Release forms or pair the plain form with\n *     an explicit __dmb.\n *\n * To get correct semantics on every supported architecture without an\n * x86 perf cost, we:\n *   - Use InterlockedCompareExchangeAcquire for atomic loads.\n *   - Use InterlockedExchange*Release* (the Release variant) for\n *     atomic stores.\n *   - Use the plain InterlockedExchangeAdd for fetch_add / fetch_sub,\n *     bracketed by __dmb(_ARM64_BARRIER_ISH) on ARM64 to provide the\n *     acq_rel ordering.  On every other MSVC target the bracketing\n *     compiles out and the plain form's full-barrier semantics are\n *     used directly.\n *\n * The __dmb intrinsic is declared in <intrin.h> and is available from\n * VS2008 (the same release that introduced ARM as a target).  Since\n * MSVC ARM/ARM64 builds are themselves a VS2008+ feature, the\n * <intrin.h> include is gated on _M_ARM / _M_ARM64 and remains absent\n * on the legacy x86 / Xbox 360 / Itanium paths.\n */\n\n#include <windows.h>\n\n#if defined(_M_ARM) || defined(_M_ARM64)\n#include <intrin.h>\n#define RETRO_ATOMIC_MSVC_ARM_FENCE() __dmb(_ARM64_BARRIER_ISH)\n#else\n#define RETRO_ATOMIC_MSVC_ARM_FENCE() ((void)0)\n#endif\n\ntypedef volatile LONG     retro_atomic_int_t;\ntypedef volatile LONG_PTR retro_atomic_size_t;\n/* LONG_PTR is 32-bit on Win32, 64-bit on Win64 -- matches size_t width\n * on every Windows ABI. */\n\n#define retro_atomic_int_init(p, v)    (*(p) = (LONG)(v))\n#define retro_atomic_size_init(p, v)   (*(p) = (LONG_PTR)(v))\n\n#define retro_atomic_load_acquire_int(p) \\\n   InterlockedCompareExchangeAcquire((LONG volatile*)(p), 0, 0)\n#define retro_atomic_store_release_int(p, v)                              \\\n   do {                                                                   \\\n      RETRO_ATOMIC_MSVC_ARM_FENCE();                                      \\\n      (void)InterlockedExchange((LONG volatile*)(p), (LONG)(v));          \\\n   } while (0)\n/* fetch_add / fetch_sub: plain Interlocked* on x86/x64/Itanium/PPC\n * is full-barrier; on ARM we surround with __dmb to get acq_rel. */\n#define retro_atomic_fetch_add_int(p, v) (                                \\\n   RETRO_ATOMIC_MSVC_ARM_FENCE(),                                         \\\n   InterlockedExchangeAdd((LONG volatile*)(p), (LONG)(v)) )\n#define retro_atomic_fetch_sub_int(p, v) (                                \\\n   RETRO_ATOMIC_MSVC_ARM_FENCE(),                                         \\\n   InterlockedExchangeAdd((LONG volatile*)(p), -(LONG)(v)) )\n/* Note: on ARM we'd ideally want a __dmb both before AND after the\n * RMW for full sequential consistency (PostgreSQL's recent fix does\n * exactly that).  acq_rel needs only one barrier on most use cases;\n * the C11 contract says acq_rel = release-before, acquire-after,\n * which on ARMv8 is satisfied by a single dmb ish.  If a caller\n * needs seq_cst, they can pair this with an additional load_acquire\n * on the same variable. */\n\n#if defined(_WIN64)\n#define retro_atomic_load_acquire_size(p) \\\n   ((size_t)InterlockedCompareExchangeAcquire64((LONGLONG volatile*)(p), 0, 0))\n#define retro_atomic_store_release_size(p, v)                             \\\n   do {                                                                   \\\n      RETRO_ATOMIC_MSVC_ARM_FENCE();                                      \\\n      (void)InterlockedExchange64((LONGLONG volatile*)(p), (LONGLONG)(v));\\\n   } while (0)\n#define retro_atomic_fetch_add_size(p, v) (                               \\\n   RETRO_ATOMIC_MSVC_ARM_FENCE(),                                         \\\n   (size_t)InterlockedExchangeAdd64((LONGLONG volatile*)(p), (LONGLONG)(v)) )\n#define retro_atomic_fetch_sub_size(p, v) (                               \\\n   RETRO_ATOMIC_MSVC_ARM_FENCE(),                                         \\\n   (size_t)InterlockedExchangeAdd64((LONGLONG volatile*)(p), -(LONGLONG)(v)) )\n#else\n#define retro_atomic_load_acquire_size(p) \\\n   ((size_t)InterlockedCompareExchangeAcquire((LONG volatile*)(p), 0, 0))\n#define retro_atomic_store_release_size(p, v)                             \\\n   do {                                                                   \\\n      RETRO_ATOMIC_MSVC_ARM_FENCE();                                      \\\n      (void)InterlockedExchange((LONG volatile*)(p), (LONG)(v));          \\\n   } while (0)\n#define retro_atomic_fetch_add_size(p, v) (                               \\\n   RETRO_ATOMIC_MSVC_ARM_FENCE(),                                         \\\n   (size_t)InterlockedExchangeAdd((LONG volatile*)(p), (LONG)(v)) )\n#define retro_atomic_fetch_sub_size(p, v) (                               \\\n   RETRO_ATOMIC_MSVC_ARM_FENCE(),                                         \\\n   (size_t)InterlockedExchangeAdd((LONG volatile*)(p), -(LONG)(v)) )\n#endif\n\n/* ---- Apple OSAtomic (deprecated but available pre-10.7) --------------- */\n#elif defined(RETRO_ATOMIC_BACKEND_APPLE)\n\n#include <libkern/OSAtomic.h>\n#include <stddef.h>\n\ntypedef volatile int32_t  retro_atomic_int_t;\ntypedef volatile intptr_t retro_atomic_size_t;\n/* OSAtomic uses int32 / int64; we pun size_t to intptr_t and assume\n * size_t == intptr_t in width.  Holds on every Apple ABI. */\n\n#define retro_atomic_int_init(p, v)    (*(p) = (v))\n#define retro_atomic_size_init(p, v)   (*(p) = (intptr_t)(v))\n\n#define retro_atomic_load_acquire_int(p)  OSAtomicAdd32Barrier(0, (p))\n#define retro_atomic_store_release_int(p, v) \\\n   do { OSMemoryBarrier(); *(p) = (v); } while (0)\n#define retro_atomic_fetch_add_int(p, v) \\\n   (OSAtomicAdd32Barrier((v), (p)) - (v))\n#define retro_atomic_fetch_sub_int(p, v) \\\n   (OSAtomicAdd32Barrier(-(v), (p)) + (v))\n\n#if defined(__LP64__)\n#define retro_atomic_load_acquire_size(p) \\\n   ((size_t)OSAtomicAdd64Barrier(0, (volatile int64_t*)(p)))\n#define retro_atomic_store_release_size(p, v) \\\n   do { OSMemoryBarrier(); *(p) = (intptr_t)(v); } while (0)\n#define retro_atomic_fetch_add_size(p, v) \\\n   ((size_t)(OSAtomicAdd64Barrier((int64_t)(v), (volatile int64_t*)(p)) - (int64_t)(v)))\n#define retro_atomic_fetch_sub_size(p, v) \\\n   ((size_t)(OSAtomicAdd64Barrier(-(int64_t)(v), (volatile int64_t*)(p)) + (int64_t)(v)))\n#else\n#define retro_atomic_load_acquire_size(p) \\\n   ((size_t)OSAtomicAdd32Barrier(0, (volatile int32_t*)(p)))\n#define retro_atomic_store_release_size(p, v) \\\n   do { OSMemoryBarrier(); *(p) = (intptr_t)(v); } while (0)\n#define retro_atomic_fetch_add_size(p, v) \\\n   ((size_t)(OSAtomicAdd32Barrier((int32_t)(v), (volatile int32_t*)(p)) - (int32_t)(v)))\n#define retro_atomic_fetch_sub_size(p, v) \\\n   ((size_t)(OSAtomicAdd32Barrier(-(int32_t)(v), (volatile int32_t*)(p)) + (int32_t)(v)))\n#endif\n\n/* ---- GCC __sync_* (legacy, 4.1-4.6) ----------------------------------- */\n#elif defined(RETRO_ATOMIC_BACKEND_SYNC)\n\n#include <stddef.h>\n\ntypedef volatile int    retro_atomic_int_t;\ntypedef volatile size_t retro_atomic_size_t;\n\n#define retro_atomic_int_init(p, v)    (*(p) = (v))\n#define retro_atomic_size_init(p, v)   (*(p) = (v))\n\n/* __sync builtins are full sequential-consistency; over-strong but correct.\n * The \"load via fetch_and_add 0\" / \"store via lock+swap\" idioms are the\n * canonical way to get an atomic load/store out of __sync. */\n#define retro_atomic_load_acquire_int(p) \\\n   __sync_fetch_and_add((p), 0)\n#define retro_atomic_store_release_int(p, v) \\\n   do { __sync_synchronize(); *(p) = (v); __sync_synchronize(); } while (0)\n#define retro_atomic_fetch_add_int(p, v) \\\n   __sync_fetch_and_add((p), (v))\n#define retro_atomic_fetch_sub_int(p, v) \\\n   __sync_fetch_and_sub((p), (v))\n\n#define retro_atomic_load_acquire_size(p) \\\n   __sync_fetch_and_add((p), (size_t)0)\n#define retro_atomic_store_release_size(p, v) \\\n   do { __sync_synchronize(); *(p) = (v); __sync_synchronize(); } while (0)\n#define retro_atomic_fetch_add_size(p, v) \\\n   __sync_fetch_and_add((p), (v))\n#define retro_atomic_fetch_sub_size(p, v) \\\n   __sync_fetch_and_sub((p), (v))\n\n/* ---- Volatile fallback ------------------------------------------------- */\n#else /* RETRO_ATOMIC_BACKEND_VOLATILE */\n\n#include <stddef.h>\n\ntypedef volatile int    retro_atomic_int_t;\ntypedef volatile size_t retro_atomic_size_t;\n\n#define retro_atomic_int_init(p, v)    (*(p) = (v))\n#define retro_atomic_size_init(p, v)   (*(p) = (v))\n\n/* No barriers.  Correct only on single-core or x86 TSO. */\n#define retro_atomic_load_acquire_int(p)         (*(p))\n#define retro_atomic_store_release_int(p, v)     do { *(p) = (v); } while (0)\n#define retro_atomic_fetch_add_int(p, v)         ((*(p) += (v)) - (v))\n#define retro_atomic_fetch_sub_int(p, v)         ((*(p) -= (v)) + (v))\n\n#define retro_atomic_load_acquire_size(p)        (*(p))\n#define retro_atomic_store_release_size(p, v)    do { *(p) = (v); } while (0)\n#define retro_atomic_fetch_add_size(p, v)        ((*(p) += (v)) - (v))\n#define retro_atomic_fetch_sub_size(p, v)        ((*(p) -= (v)) + (v))\n\n#endif /* backend selection */\n\n/* ---- Convenience wrappers (backend-agnostic) -------------------------- */\n\n#define retro_atomic_inc_int(p)    ((void)retro_atomic_fetch_add_int((p), 1))\n#define retro_atomic_dec_int(p)    ((void)retro_atomic_fetch_sub_int((p), 1))\n#define retro_atomic_inc_size(p)   ((void)retro_atomic_fetch_add_size((p), 1))\n#define retro_atomic_dec_size(p)   ((void)retro_atomic_fetch_sub_size((p), 1))\n\n#endif /* __LIBRETRO_SDK_ATOMIC_H */\n"
  },
  {
    "path": "include/retro_common.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_common.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_COMMON_RETRO_COMMON_H\n#define _LIBRETRO_COMMON_RETRO_COMMON_H\n\n/*!\n * @internal This file is designed to normalize the libretro-common compiling environment.\n * It is not to be used in public API headers, as they should be designed as leanly as possible.\n * Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,\n * in a public API, you may need this.\n */\n\n/* conditional compilation is handled inside here */\n#include <compat/msvc.h>\n\n#endif\n"
  },
  {
    "path": "include/retro_common_api.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_common_api.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H\n#define _LIBRETRO_COMMON_RETRO_COMMON_API_H\n\n/*\nThis file is designed to normalize the libretro-common compiling environment\nfor public API headers. This should be leaner than a normal compiling environment,\nsince it gets #included into other project's sources.\n*/\n\n/* ------------------------------------ */\n\n/*\nOrdinarily we want to put #ifdef __cplusplus extern \"C\" in C library\nheaders to enable them to get used by c++ sources.\nHowever, we want to support building this library as C++ as well, so a\nspecial technique is called for.\n*/\n\n#define RETRO_BEGIN_DECLS\n#define RETRO_END_DECLS\n#define RETRO_BEGIN_DECLS_CXX\n#define RETRO_END_DECLS_CXX\n\n#ifdef __cplusplus\n\n#ifdef CXX_BUILD\n/* build wants everything to be built as c++, so no extern \"C\" */\n#else\n#undef RETRO_BEGIN_DECLS\n#undef RETRO_END_DECLS\n#define RETRO_BEGIN_DECLS extern \"C\" {\n#define RETRO_END_DECLS }\n/* Force C++ linkage for a region inside a header that may be included\n * from within a caller's extern \"C\" { ... } block -- needed when the\n * region pulls in a C++ standard library header (e.g. <atomic>). */\n#undef RETRO_BEGIN_DECLS_CXX\n#undef RETRO_END_DECLS_CXX\n#define RETRO_BEGIN_DECLS_CXX extern \"C++\" {\n#define RETRO_END_DECLS_CXX }\n#endif\n\n#else\n\n/* header is included by a C source file, so no extern \"C\" */\n\n#endif\n\n/*\nIMO, this non-standard ssize_t should not be used.\nHowever, it's a good example of how to handle something like this.\n*/\n#ifdef _MSC_VER\n#ifndef HAVE_SSIZE_T\n#define HAVE_SSIZE_T\n#if defined(_WIN64)\ntypedef __int64 ssize_t;\n#elif defined(_WIN32)\ntypedef int ssize_t;\n#endif\n#endif\n#elif defined(__MACH__) && defined(__APPLE__)\n#include <sys/types.h>\n#endif\n\n#ifdef _MSC_VER\n#if _MSC_VER >= 1800\n#include <inttypes.h>\n#else\n#ifndef PRId64\n#define PRId64 \"I64d\"\n#define PRIu64 \"I64u\"\n#define PRIuPTR \"Iu\"\n#endif\n#endif\n#else\n/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */\n/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */\n/* https://github.com/libretro/RetroArch/issues/6009 */\n#ifndef __STDC_FORMAT_MACROS\n#define __STDC_FORMAT_MACROS 1\n#endif\n#include <inttypes.h>\n#endif\n#ifndef PRId64\n#error \"inttypes.h is being screwy\"\n#endif\n#define STRING_REP_INT64 \"%\" PRId64\n#define STRING_REP_UINT64 \"%\" PRIu64\n#define STRING_REP_USIZE \"%\" PRIuPTR\n\n/* Wrap a declaration in RETRO_DEPRECATED() to produce a compiler warning when\nit's used. This is intended for developer machines, so it won't work on ancient\nor obscure compilers */\n#if defined(_MSC_VER)\n#if _MSC_VER >= 1400 /* Visual C 2005 or later */\n#define RETRO_DEPRECATED(decl) __declspec(deprecated) decl\n#endif\n#elif defined(__GNUC__)\n#if __GNUC__ >= 3 /* GCC 3 or later */\n#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))\n#endif\n#elif defined(__clang__)\n#if __clang_major__ >= 3 /* clang 3 or later */\n#define RETRO_DEPRECATED(decl) decl __attribute__((deprecated))\n#endif\n#endif\n#ifndef RETRO_DEPRECATED /* Unsupported compilers */\n#define RETRO_DEPRECATED(decl) decl\n#endif\n\n/*\nI would like to see retro_inline.h moved in here; possibly boolean too.\n\nrationale: these are used in public APIs, and it is easier to find problems\nand write code that works the first time portably when they are included uniformly\nthan to do the analysis from scratch each time you think you need it, for each feature.\n\nMoreover it helps force you to make hard decisions: if you EVER bring in boolean.h,\nthen you should pay the price everywhere, so you can see how much grief it will cause.\n\nOf course, another school of thought is that you should do as little damage as possible\nin as few places as possible...\n*/\n\n/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */\n#endif\n"
  },
  {
    "path": "include/retro_dirent.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_dirent.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __RETRO_DIRENT_H\n#define __RETRO_DIRENT_H\n\n#include <libretro.h>\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\n/** @defgroup dirent Directory Entries\n * @{\n */\n\nRETRO_BEGIN_DECLS\n\n/**\n * The minimum VFS version (as defined in \\c retro_vfs_interface_info::required_interface_version)\n * required by the \\c dirent functions.\n * If no acceptable VFS interface is provided,\n * all dirent functions will fall back to libretro-common's implementations.\n * @see retro_vfs_interface_info\n */\n#define DIRENT_REQUIRED_VFS_VERSION 3\n\n/**\n * Installs a frontend-provided VFS interface for the dirent functions to use\n * instead of libretro-common's built-in implementations.\n *\n * @param vfs_info The VFS interface returned by the frontend.\n * The dirent functions will fall back to libretro-common's implementations\n * if \\c vfs_info::required_interface_version is too low.\n * @see retro_vfs_interface_info\n * @see RETRO_ENVIRONMENT_GET_VFS_INTERFACE\n */\nvoid dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info);\n\n/**\n * Opaque handle to a directory entry (aka \"dirent\").\n * It may name a file, directory, or other filesystem object.\n * @see retro_opendir\n */\ntypedef struct RDIR RDIR;\n\n/**\n * Opens a directory for reading.\n *\n * @param name Path to a directory to open.\n * @return An \\c RDIR representing the given directory if successful.\n * Returns \\c NULL if \\c name is \\c NULL, the empty string, or does not name a directory.\n * @note The returned \\c RDIR must be closed with \\c retro_closedir.\n * @see retro_opendir_include_hidden\n * @see retro_closedir\n */\nstruct RDIR *retro_opendir(const char *name);\n\n/**\n * @copybrief retro_opendir\n *\n * @param name Path to the directory to open.\n * @param include_hidden Whether to include hidden files and directories\n * when iterating over this directory with \\c retro_readdir.\n * Platforms and filesystems have different notions of \"hidden\" files.\n * Setting this to \\c false will not prevent this function from opening \\c name.\n * @return An \\c RDIR representing the given directory if successful.\n * Returns \\c NULL if \\c name is \\c NULL, the empty string, or does not name a directory.\n * @note The returned \\c RDIR must be closed with \\c retro_closedir.\n * @see retro_opendir\n * @see retro_closedir\n */\nstruct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden);\n\n/**\n * Reads the next entry in the given directory.\n *\n * Here's a usage example that prints the names of all files in the current directory:\n * @code\n * struct RDIR *rdir = retro_opendir(\".\");\n * if (rdir)\n * {\n *    while (retro_readdir(rdir))\n *    {\n *       const char *name = retro_dirent_get_name(rdir);\n *       printf(\"%s\\n\", name);\n *    }\n *    retro_closedir(rdir);\n *    rdir = NULL;\n * }\n * @endcode\n *\n * @param rdir The directory to iterate over.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if the next entry was read successfully,\n * \\c false if there are no more entries to read or if there was an error.\n * @note This may include \".\" and \"..\" on Unix-like platforms.\n * @see retro_dirent_get_name\n * @see retro_dirent_is_dir\n */\nint retro_readdir(struct RDIR *rdir);\n\n/**\n * @deprecated Left for compatibility.\n * @param rdir Ignored.\n * @return \\c false.\n */\nbool retro_dirent_error(struct RDIR *rdir);\n\n/**\n * Gets the name of the dirent's current file or directory.\n *\n * @param rdir The dirent to get the name of.\n * Behavior is undefined if \\c NULL.\n * @return The name of the directory entry (file, directory, etc.) that the dirent points to.\n * Will return \\c NULL if there was an error,\n * \\c retro_readdir has not been called on \\c rdir,\n * or if there are no more entries to read.\n * @note This returns only a name, not a full path.\n * @warning The returned string is managed by the VFS implementation\n * and must not be modified or freed by the caller.\n * @warning The returned string is only valid until the next call to \\c retro_readdir.\n * @see retro_readdir\n */\nconst char *retro_dirent_get_name(struct RDIR *rdir);\n\n/**\n * Checks if the given \\c RDIR's current dirent names a directory.\n *\n * @param rdir The directory entry to check.\n * Behavior is undefined if \\c NULL.\n * @param unused Ignored for compatibility reasons. Pass \\c NULL.\n * @return \\c true if \\c rdir refers to a directory, otherwise \\c false.\n * @see retro_readdir\n */\nbool retro_dirent_is_dir(struct RDIR *rdir, const char *unused);\n\n/**\n * Closes an opened \\c RDIR that was returned by \\c retro_opendir.\n *\n * @param rdir The directory entry to close.\n * If \\c NULL, this function does nothing.\n * @see retro_vfs_closedir_t\n */\nvoid retro_closedir(struct RDIR *rdir);\n\nRETRO_END_DECLS\n\n/** @} */\n\n#endif\n"
  },
  {
    "path": "include/retro_endianness.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_endianness.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_ENDIANNESS_H\n#define __LIBRETRO_SDK_ENDIANNESS_H\n\n#include <retro_inline.h>\n#include <stdint.h>\n#include <stdlib.h>\n\n#if defined(_MSC_VER) && _MSC_VER > 1200\n#define SWAP16 _byteswap_ushort\n#define SWAP32 _byteswap_ulong\n#else\n/**\n * Swaps the byte order of a 16-bit unsigned integer.\n * @param x The integer to byteswap.\n * @return \\c with its two bytes swapped.\n */\nstatic INLINE uint16_t SWAP16(uint16_t x)\n{\n  return ((x & 0x00ff) << 8) |\n         ((x & 0xff00) >> 8);\n}\n\n/**\n * Swaps the byte order of a 32-bit unsigned integer.\n * @param x The integer to byteswap.\n * @return \\c with its bytes swapped.\n */\nstatic INLINE uint32_t SWAP32(uint32_t x)\n{\n  return ((x & 0x000000ff) << 24) |\n         ((x & 0x0000ff00) <<  8) |\n         ((x & 0x00ff0000) >>  8) |\n         ((x & 0xff000000) >> 24);\n}\n\n#endif\n\n#if defined(_MSC_VER) && _MSC_VER <= 1200\nstatic INLINE uint64_t SWAP64(uint64_t val)\n{\n  return\n      ((val & 0x00000000000000ff) << 56)\n    | ((val & 0x000000000000ff00) << 40)\n    | ((val & 0x0000000000ff0000) << 24)\n    | ((val & 0x00000000ff000000) << 8)\n    | ((val & 0x000000ff00000000) >> 8)\n    | ((val & 0x0000ff0000000000) >> 24)\n    | ((val & 0x00ff000000000000) >> 40)\n    | ((val & 0xff00000000000000) >> 56);\n}\n#else\n/**\n * Swaps the byte order of a 64-bit unsigned integer.\n * @param x The integer to byteswap.\n * @return \\c with its bytes swapped.\n */\nstatic INLINE uint64_t SWAP64(uint64_t val)\n{\n  return   ((val & 0x00000000000000ffULL) << 56)\n\t | ((val & 0x000000000000ff00ULL) << 40)\n\t | ((val & 0x0000000000ff0000ULL) << 24)\n\t | ((val & 0x00000000ff000000ULL) << 8)\n\t | ((val & 0x000000ff00000000ULL) >> 8)\n\t | ((val & 0x0000ff0000000000ULL) >> 24)\n\t | ((val & 0x00ff000000000000ULL) >> 40)\n         | ((val & 0xff00000000000000ULL) >> 56);\n}\n#endif\n\n#ifdef _MSC_VER\n/* MSVC pre-defines macros depending on target arch */\n#if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)\n#ifndef LSB_FIRST\n#define LSB_FIRST 1\n#endif\n#elif _M_PPC\n#ifndef MSB_FIRST\n#define MSB_FIRST 1\n#endif\n#else\n/* 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 */\n#error \"unknown platform, can't determine endianness\"\n#endif\n#else\n#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n#ifndef MSB_FIRST\n#define MSB_FIRST 1\n#endif\n#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#ifndef LSB_FIRST\n#define LSB_FIRST 1\n#endif\n#else\n#error \"Invalid endianness macros\"\n#endif\n#endif\n\n#if defined(MSB_FIRST) && defined(LSB_FIRST)\n#  error \"Bug in LSB_FIRST/MSB_FIRST definition\"\n#endif\n\n#if !defined(MSB_FIRST) && !defined(LSB_FIRST)\n#  error \"Bug in LSB_FIRST/MSB_FIRST definition\"\n#endif\n\n#ifdef MSB_FIRST\n#  define RETRO_IS_BIG_ENDIAN 1\n#  define RETRO_IS_LITTLE_ENDIAN 0\n/* For compatibility */\n#  define WORDS_BIGENDIAN 1\n#else\n#  define RETRO_IS_BIG_ENDIAN 0\n#  define RETRO_IS_LITTLE_ENDIAN 1\n/* For compatibility */\n#  undef WORDS_BIGENDIAN\n#endif\n\n\n/**\n * Checks if the current CPU is little-endian.\n *\n * @return \\c true on little-endian CPUs,\n * \\c false on big-endian CPUs.\n */\n#define is_little_endian() RETRO_IS_LITTLE_ENDIAN\n\n/**\n * Byte-swaps an unsigned 64-bit integer on big-endian CPUs.\n *\n * @param val The value to byteswap if necessary.\n * @return \\c val byteswapped on big-endian CPUs,\n * \\c val unchanged on little-endian CPUs.\n */\n#if RETRO_IS_BIG_ENDIAN\n#define swap_if_big64(val) (SWAP64(val))\n#elif RETRO_IS_LITTLE_ENDIAN\n#define swap_if_big64(val) (val)\n#endif\n\n/**\n * Byte-swaps an unsigned 32-bit integer on big-endian CPUs.\n *\n * @param val The value to byteswap if necessary.\n * @return \\c val byteswapped on big-endian CPUs,\n * \\c val unchanged on little-endian CPUs.\n */\n#if RETRO_IS_BIG_ENDIAN\n#define swap_if_big32(val) (SWAP32(val))\n#elif RETRO_IS_LITTLE_ENDIAN\n#define swap_if_big32(val) (val)\n#endif\n\n/**\n * Byte-swaps an unsigned 64-bit integer on little-endian CPUs.\n *\n * @param val The value to byteswap if necessary.\n * @return \\c val byteswapped on little-endian CPUs,\n * \\c val unchanged on big-endian CPUs.\n */\n#if RETRO_IS_BIG_ENDIAN\n#define swap_if_little64(val) (val)\n#elif RETRO_IS_LITTLE_ENDIAN\n#define swap_if_little64(val) (SWAP64(val))\n#endif\n\n/**\n * Byte-swaps an unsigned 32-bit integer on little-endian CPUs.\n *\n * @param val The value to byteswap if necessary.\n * @return \\c val byteswapped on little-endian CPUs,\n * \\c val unchanged on big-endian CPUs.\n */\n#if RETRO_IS_BIG_ENDIAN\n#define swap_if_little32(val) (val)\n#elif RETRO_IS_LITTLE_ENDIAN\n#define swap_if_little32(val) (SWAP32(val))\n#endif\n\n/**\n * Byte-swaps an unsigned 16-bit integer on big-endian systems.\n *\n * @param val The value to byteswap if necessary.\n * @return \\c val byteswapped on big-endian systems,\n * \\c val unchanged on little-endian systems.\n */\n#if RETRO_IS_BIG_ENDIAN\n#define swap_if_big16(val) (SWAP16(val))\n#elif RETRO_IS_LITTLE_ENDIAN\n#define swap_if_big16(val) (val)\n#endif\n\n/**\n * Byte-swaps an unsigned 16-bit integer on little-endian systems.\n *\n * @param val The value to byteswap if necessary.\n * @return \\c val byteswapped on little-endian systems,\n * \\c val unchanged on big-endian systems.\n */\n#if RETRO_IS_BIG_ENDIAN\n#define swap_if_little16(val) (val)\n#elif RETRO_IS_LITTLE_ENDIAN\n#define swap_if_little16(val) (SWAP16(val))\n#endif\n\n/**\n * Stores a 32-bit integer in at the given address, in big-endian order.\n *\n * @param addr The address to store the value at.\n * Behavior is undefined if \\c NULL or not aligned to a 32-bit boundary.\n * @param data The value to store in \\c addr.\n * Will be byteswapped if on a little-endian CPU.\n */\nstatic INLINE void store32be(uint32_t *addr, uint32_t data)\n{\n   *addr = swap_if_little32(data);\n}\n\n/**\n * Loads a 32-bit integer order from the given address, in big-endian order.\n *\n * @param addr The address to load the value from.\n * Behavior is undefined if \\c NULL or not aligned to a 32-bit boundary.\n * @return The value at \\c addr, byteswapped if on a little-endian CPU.\n */\nstatic INLINE uint32_t load32be(const uint32_t *addr)\n{\n   return swap_if_little32(*addr);\n}\n\n/**\n * Converts the given unsigned 16-bit integer to little-endian order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a big-endian CPU,\n * unchanged otherwise.\n */\n#define retro_cpu_to_le16(val) swap_if_big16(val)\n\n/**\n * Converts the given unsigned 32-bit integer to little-endian order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a big-endian CPU,\n * unchanged otherwise.\n */\n#define retro_cpu_to_le32(val) swap_if_big32(val)\n\n/**\n * Converts the given unsigned 64-bit integer to little-endian order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a big-endian CPU,\n * unchanged otherwise.\n */\n#define retro_cpu_to_le64(val) swap_if_big64(val)\n\n/**\n * Converts the given unsigned 16-bit integer to host-native order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a big-endian CPU,\n * unchanged otherwise.\n */\n#define retro_le_to_cpu16(val) swap_if_big16(val)\n\n/**\n * Converts the given unsigned 32-bit integer to host-native order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a big-endian CPU,\n * unchanged otherwise.\n */\n#define retro_le_to_cpu32(val) swap_if_big32(val)\n\n/**\n * Converts the given unsigned 64-bit integer to host-native order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a big-endian CPU,\n * unchanged otherwise.\n */\n#define retro_le_to_cpu64(val) swap_if_big64(val)\n\n/**\n * Converts the given unsigned 16-bit integer to big-endian order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a little-endian CPU,\n * unchanged otherwise.\n */\n#define retro_cpu_to_be16(val) swap_if_little16(val)\n\n/**\n * Converts the given unsigned 32-bit integer to big-endian order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a little-endian CPU,\n * unchanged otherwise.\n */\n#define retro_cpu_to_be32(val) swap_if_little32(val)\n\n/**\n * Converts the given unsigned 64-bit integer to big-endian order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a little-endian CPU,\n * unchanged otherwise.\n */\n#define retro_cpu_to_be64(val) swap_if_little64(val)\n\n/**\n * Converts the given unsigned 16-bit integer from big-endian to host-native order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a little-endian CPU,\n * unchanged otherwise.\n */\n#define retro_be_to_cpu16(val) swap_if_little16(val)\n\n/**\n * Converts the given unsigned 32-bit integer from big-endian to host-native order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a little-endian CPU,\n * unchanged otherwise.\n */\n#define retro_be_to_cpu32(val) swap_if_little32(val)\n\n/**\n * Converts the given unsigned 64-bit integer from big-endian to host-native order if necessary.\n *\n * @param val The value to convert if necessary.\n * @return \\c val byteswapped if on a little-endian CPU,\n * unchanged otherwise.\n */\n#define retro_be_to_cpu64(val) swap_if_little64(val)\n\n#ifdef  __GNUC__\n/**\n * This attribute indicates that pointers to this type may alias\n * to pointers of any other type, similar to \\c void* or \\c char*.\n */\n#define MAY_ALIAS  __attribute__((__may_alias__))\n#else\n#define MAY_ALIAS\n#endif\n\n#pragma pack(push, 1)\nstruct retro_unaligned_uint16_s\n{\n  uint16_t val;\n} MAY_ALIAS;\nstruct retro_unaligned_uint32_s\n{\n  uint32_t val;\n} MAY_ALIAS;\nstruct retro_unaligned_uint64_s\n{\n  uint64_t val;\n} MAY_ALIAS;\n#pragma pack(pop)\n\n/**\n * A wrapper around a \\c uint16_t that allows unaligned access\n * where supported by the compiler.\n */\ntypedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;\n\n/**\n * A wrapper around a \\c uint32_t that allows unaligned access\n * where supported by the compiler.\n */\ntypedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;\n\n/**\n * A wrapper around a \\c uint64_t that allows unaligned access\n * where supported by the compiler.\n */\ntypedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;\n\n/* L-value references to unaligned pointers.  */\n#define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)\n#define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)\n#define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)\n\n/**\n * Reads a 16-bit unsigned integer from the given address\n * and converts it from big-endian to host-native order (if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address of the integer to read.\n * Does not need to be divisible by 2\n * the way a \\c uint16_t* usually would be.\n * @return The first two bytes of \\c addr as a 16-bit unsigned integer,\n * byteswapped from big-endian to host-native order if necessary.\n */\nstatic INLINE uint16_t retro_get_unaligned_16be(void *addr)\n{\n   return retro_be_to_cpu16(retro_unaligned16(addr));\n}\n\n/**\n * Reads a 32-bit unsigned integer from the given address\n * and converts it from big-endian to host-native order (if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address of the integer to read.\n * Does not need to be divisible by 4\n * the way a \\c uint32_t* usually would be.\n * @return The first four bytes of \\c addr as a 32-bit unsigned integer,\n * byteswapped from big-endian to host-native order if necessary.\n */\nstatic INLINE uint32_t retro_get_unaligned_32be(void *addr)\n{\n   return retro_be_to_cpu32(retro_unaligned32(addr));\n}\n\n/**\n * Reads a 64-bit unsigned integer from the given address\n * and converts it from big-endian to host-native order (if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address of the integer to read.\n * Does not need to be divisible by 8\n * the way a \\c uint64_t* usually would be.\n * @return The first eight bytes of \\c addr as a 64-bit unsigned integer,\n * byteswapped from big-endian to host-native order if necessary.\n */\nstatic INLINE uint64_t retro_get_unaligned_64be(void *addr)\n{\n   return retro_be_to_cpu64(retro_unaligned64(addr));\n}\n\n/**\n * Reads a 16-bit unsigned integer from the given address\n * and converts it from little-endian to host-native order (if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address of the integer to read.\n * Does not need to be divisible by 2\n * the way a \\c uint16_t* usually would be.\n * @return The first two bytes of \\c addr as a 16-bit unsigned integer,\n * byteswapped from little-endian to host-native order if necessary.\n */\nstatic INLINE uint16_t retro_get_unaligned_16le(void *addr)\n{\n   return retro_le_to_cpu16(retro_unaligned16(addr));\n}\n\n/**\n * Reads a 32-bit unsigned integer from the given address\n * and converts it from little-endian to host-native order (if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address of the integer to read.\n * Does not need to be divisible by 4\n * the way a \\c uint32_t* usually would be.\n * @return The first four bytes of \\c addr as a 32-bit unsigned integer,\n * byteswapped from little-endian to host-native order if necessary.\n */\nstatic INLINE uint32_t retro_get_unaligned_32le(void *addr)\n{\n   return retro_le_to_cpu32(retro_unaligned32(addr));\n}\n\n/**\n * Reads a 64-bit unsigned integer from the given address\n * and converts it from little-endian to host-native order (if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address of the integer to read.\n * Does not need to be divisible by 8\n * the way a \\c uint64_t* usually would be.\n * @return The first eight bytes of \\c addr as a 64-bit unsigned integer,\n * byteswapped from little-endian to host-native order if necessary.\n */\nstatic INLINE uint64_t retro_get_unaligned_64le(void *addr)\n{\n   return retro_le_to_cpu64(retro_unaligned64(addr));\n}\n\n/**\n * Writes a 16-bit unsigned integer to the given address\n * (converted to little-endian order if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address to write the integer to.\n * Does not need to be divisible by 2\n * the way a \\c uint16_t* usually would be.\n * @param v The value to write.\n */\nstatic INLINE void retro_set_unaligned_16le(void *addr, uint16_t v)\n{\n   retro_unaligned16(addr) = retro_cpu_to_le16(v);\n}\n\n/**\n * Writes a 32-bit unsigned integer to the given address\n * (converted to little-endian order if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address to write the integer to.\n * Does not need to be divisible by 4\n * the way a \\c uint32_t* usually would be.\n * @param v The value to write.\n */\nstatic INLINE void retro_set_unaligned_32le(void *addr, uint32_t v)\n{\n   retro_unaligned32(addr) = retro_cpu_to_le32(v);\n}\n\n/**\n * Writes a 64-bit unsigned integer to the given address\n * (converted to little-endian order if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address to write the integer to.\n * Does not need to be divisible by 8\n * the way a \\c uint64_t* usually would be.\n * @param v The value to write.\n */\nstatic INLINE void retro_set_unaligned_64le(void *addr, uint64_t v)\n{\n   retro_unaligned64(addr) = retro_cpu_to_le64(v);\n}\n\n/**\n * Writes a 16-bit unsigned integer to the given address\n * (converted to big-endian order if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address to write the integer to.\n * Does not need to be divisible by 2\n * the way a \\c uint16_t* usually would be.\n * @param v The value to write.\n */\nstatic INLINE void retro_set_unaligned_16be(void *addr, uint16_t v)\n{\n   retro_unaligned16(addr) = retro_cpu_to_be16(v);\n}\n\n/**\n * Writes a 32-bit unsigned integer to the given address\n * (converted to big-endian order if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address to write the integer to.\n * Does not need to be divisible by 4\n * the way a \\c uint32_t* usually would be.\n * @param v The value to write.\n */\nstatic INLINE void retro_set_unaligned_32be(void *addr, uint32_t v)\n{\n   retro_unaligned32(addr) = retro_cpu_to_be32(v);\n}\n\n/**\n * Writes a 64-bit unsigned integer to the given address\n * (converted to big-endian order if necessary),\n * regardless of the CPU's alignment requirements.\n *\n * @param addr The address to write the integer to.\n * Does not need to be divisible by 8\n * the way a \\c uint64_t* usually would be.\n * @param v The value to write.\n */\nstatic INLINE void retro_set_unaligned_64be(void *addr, uint64_t v)\n{\n   retro_unaligned64(addr) = retro_cpu_to_be64(v);\n}\n\n\n#endif\n"
  },
  {
    "path": "include/retro_environment.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_environment.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_ENVIRONMENT_H\n#define __LIBRETRO_SDK_ENVIRONMENT_H\n\n/*\nThis file is designed to create a normalized environment for compiling\nlibretro-common's private implementations, or any other sources which might\nenjoy use of it's environment (RetroArch for instance).\nThis should be an elaborately crafted environment so that sources don't\nneed to be full of platform-specific workarounds.\n*/\n\n#if defined (__cplusplus)\n/* The expected values would be\n *   199711L, for ISO/IEC 14882:1998 or 14882:2003\n */\n\n#elif defined(__STDC__)\n/* This is standard C. */\n\n#if (__STDC__ == 1)\n/* The implementation is ISO-conforming. */\n#define __STDC_ISO__\n#else\n/* The implementation is not ISO-conforming. */\n#endif\n\n#if defined(__STDC_VERSION__)\n#if (__STDC_VERSION__ >= 201112L)\n/* This is C11. */\n#define __STDC_C11__\n#elif (__STDC_VERSION__ >= 199901L)\n/* This is C99. */\n#define __STDC_C99__\n#elif (__STDC_VERSION__ >= 199409L)\n/* This is C89 with amendment 1. */\n#define __STDC_C89__\n#define __STDC_C89_AMENDMENT_1__\n#else\n/* This is C89 without amendment 1. */\n#define __STDC_C89__\n#endif\n#else /* !defined(__STDC_VERSION__) */\n/* This is C89. __STDC_VERSION__ is not defined. */\n#define __STDC_C89__\n#endif\n\n#else   /* !defined(__STDC__) */\n/* This is not standard C. __STDC__ is not defined. */\n#endif\n\n#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)\n/* Try to find out if we're compiling for WinRT or non-WinRT */\n#if defined(_MSC_VER) && defined(__has_include)\n#if __has_include(<winapifamily.h>)\n#define HAVE_WINAPIFAMILY_H 1\n#else\n#define HAVE_WINAPIFAMILY_H 0\n#endif\n\n/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */\n#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */\n#define HAVE_WINAPIFAMILY_H 1\n#else\n#define HAVE_WINAPIFAMILY_H 0\n#endif\n\n#if HAVE_WINAPIFAMILY_H\n#include <winapifamily.h>\n#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))\n#else\n#define WINAPI_FAMILY_WINRT 0\n#endif /* HAVE_WINAPIFAMILY_H */\n\n#if WINAPI_FAMILY_WINRT\n#undef __WINRT__\n#define __WINRT__ 1\n#endif\n\n/* MSVC obviously has to have some non-standard constants... */\n#if _M_IX86_FP == 1\n#define __SSE__ 1\n#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))\n#define __SSE__ 1\n#define __SSE2__ 1\n#endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/retro_inline.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_inline.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_INLINE_H\n#define __LIBRETRO_SDK_INLINE_H\n\n#ifndef INLINE\n\n/**\n * Cross-platform inline specifier.\n *\n * Expands to something like \\c __inline or \\c inline,\n * depending on the compiler.\n */\n#if defined(_WIN32) || defined(__INTEL_COMPILER)\n#define INLINE __inline\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L\n#define INLINE inline\n#elif defined(__GNUC__)\n#define INLINE __inline__\n#else\n#define INLINE\n#endif\n\n#endif\n#endif\n"
  },
  {
    "path": "include/retro_math.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_math.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_COMMON_MATH_H\n#define _LIBRETRO_COMMON_MATH_H\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#elif defined(_WIN32) && defined(_XBOX)\n#include <Xtl.h>\n#endif\n\n#include <limits.h>\n\n#ifdef _MSC_VER\n#include <compat/msvc.h>\n#endif\n#include <retro_inline.h>\n\n#ifndef M_PI\n#if !defined(USE_MATH_DEFINES)\n#define M_PI 3.14159265358979323846264338327\n#endif\n#endif\n\n#ifndef MAX\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#endif\n\n#ifndef MIN\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n#endif\n\n/**\n * next_pow2:\n * @v         : initial value\n *\n * Get next power of 2 value based on  initial value.\n *\n * Returns: next power of 2 value (derived from @v).\n **/\nstatic INLINE uint32_t next_pow2(uint32_t v)\n{\n   v--;\n   v |= v >> 1;\n   v |= v >> 2;\n   v |= v >> 4;\n   v |= v >> 8;\n   v |= v >> 16;\n   v++;\n   return v;\n}\n\n/**\n * prev_pow2:\n * @v         : initial value\n *\n * Get previous power of 2 value based on initial value.\n *\n * Returns: previous power of 2 value (derived from @v).\n **/\nstatic INLINE uint32_t prev_pow2(uint32_t v)\n{\n   v |= v >> 1;\n   v |= v >> 2;\n   v |= v >> 4;\n   v |= v >> 8;\n   v |= v >> 16;\n   return v - (v >> 1);\n}\n\n/**\n * clamp:\n * @v         : initial value\n *\n * Get the clamped value based on initial value.\n *\n * Returns: clamped value (derived from @v).\n **/\nstatic INLINE float clamp_value(float v, float min, float max)\n{\n   return v <= min ? min : v >= max ? max : v;\n}\n\n/**\n * saturate_value:\n * @v         : initial value\n *\n * Get the clamped 0.0-1.0 value based on initial value.\n *\n * Returns: clamped 0.0-1.0 value (derived from @v).\n **/\nstatic INLINE float saturate_value(float v)\n{\n   return clamp_value(v, 0.0f, 1.0f);\n}\n\n/**\n * dot_product:\n * @a         : left hand vector value\n * @b         : right hand vector value\n *\n * Get the dot product of the two passed in vectors.\n *\n * Returns: dot product value (derived from @a and @b).\n **/\nstatic INLINE float dot_product(const float* a, const float* b)\n{\n   return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);\n}\n\n/**\n * convert_rgb_to_yxy:\n * @rgb         : in RGB colour space value\n * @Yxy         : out Yxy colour space value\n *\n * Convert from RGB colour space to Yxy colour space.\n *\n * Returns: Yxy colour space value (derived from @rgb).\n **/\nstatic INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)\n{\n   float inv;\n   float xyz[3];\n   float one[3]        = {1.0, 1.0, 1.0};\n   float rgb_xyz[3][3] = {\n      {0.4124564, 0.3575761, 0.1804375},\n      {0.2126729, 0.7151522, 0.0721750},\n      {0.0193339, 0.1191920, 0.9503041}\n   };\n\n   xyz[0]              = dot_product(rgb_xyz[0], rgb);\n   xyz[1]              = dot_product(rgb_xyz[1], rgb);\n   xyz[2]              = dot_product(rgb_xyz[2], rgb);\n\n   inv                 = 1.0f / dot_product(xyz, one);\n   Yxy[0]              = xyz[1];\n   Yxy[1]              = xyz[0] * inv;\n   Yxy[2]              = xyz[1] * inv;\n}\n\n/**\n * convert_yxy_to_rgb:\n * @rgb         : in Yxy colour space value\n * @Yxy         : out rgb colour space value\n *\n * Convert from Yxy colour space to rgb colour space.\n *\n * Returns: rgb colour space value (derived from @Yxy).\n **/\nstatic INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)\n{\n   float xyz[3];\n   float xyz_rgb[3][3] = {\n      {3.2404542, -1.5371385, -0.4985314},\n      {-0.9692660, 1.8760108,  0.0415560},\n      {0.0556434, -0.2040259, 1.0572252}\n   };\n   xyz[0]              = Yxy[0] * Yxy[1] / Yxy[2];\n   xyz[1]              = Yxy[0];\n   xyz[2]              = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];\n\n   rgb[0]              = dot_product(xyz_rgb[0], xyz);\n   rgb[1]              = dot_product(xyz_rgb[1], xyz);\n   rgb[2]              = dot_product(xyz_rgb[2], xyz);\n}\n\n/**\n * Picks a random value between a specified range.\n *\n * @param \\c min unsigned minimum possible value.\n * @param \\c max unsigned maximum possible value.\n *\n * @return unsigned random value between \\c min and \\c max (inclusive).\n */\nstatic INLINE size_t random_range(unsigned min, unsigned max)\n{\n   return (min == max) ? min : (size_t)((float)rand() / (float)RAND_MAX * (max + 1 - min) + min);\n}\n\n#endif\n"
  },
  {
    "path": "include/retro_miscellaneous.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_miscellaneous.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __RARCH_MISCELLANEOUS_H\n#define __RARCH_MISCELLANEOUS_H\n\n#define RARCH_MAX_SUBSYSTEMS 20\n#define RARCH_MAX_SUBSYSTEM_ROMS 10\n\n#include <stdint.h>\n#include <boolean.h>\n#include <retro_inline.h>\n\n#if defined(_WIN32)\n\n#if defined(_XBOX)\n#include <Xtl.h>\n#else\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <windows.h>\n#endif\n\n#endif\n\n#include <limits.h>\n\n#ifdef _MSC_VER\n#include <compat/msvc.h>\n#endif\n\n#ifdef IOS\n#include <sys/param.h>\n#endif\n\n/**\n * Computes the bitwise OR of two bit arrays.\n *\n * @param a[in,out] The first bit array, and the location of the result.\n * @param b[in] The second bit array.\n * @param count The length of each bit array, in 32-bit words.\n */\nstatic INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)\n{\n   uint32_t i;\n   for (i = 0; i < count;i++)\n      a[i] |= b[i];\n}\n\n/**\n * Clears every bit in \\c a that is set in \\c b.\n *\n * @param a[in,out] The bit array to modify.\n * @param b[in] The bit array to use for reference.\n * @param count The length of each bit array, in 32-bit words\n * (\\em not bits or bytes).\n */\nstatic INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)\n{\n   uint32_t i;\n   for (i = 0; i < count;i++)\n      a[i] &= ~b[i];\n}\n\n/**\n * Checks if any bits in \\c ptr are set.\n *\n * @param ptr The bit array to check.\n * @param count The length of the buffer pointed to by \\c ptr, in 32-bit words\n * (\\em not bits or bytes).\n * @return \\c true if any bit in \\c ptr is set,\n * \\c false if all bits are clear (zero).\n */\nstatic INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)\n{\n   uint32_t i;\n   for (i = 0; i < count; i++)\n   {\n      if (ptr[i] != 0)\n         return true;\n   }\n   return false;\n}\n\n/**\n * Checks if any bits in \\c a are different from those in \\c b.\n *\n * @param a The first bit array to compare.\n * @param b The second bit array to compare.\n * @param count The length of each bit array, in 32-bit words\n * (\\em not bits or bytes).\n * @return \\c true if \\c and \\c differ by at least one bit,\n * \\c false if they're both identical.\n */\nstatic INLINE bool bits_any_different(uint32_t *a, uint32_t *b, uint32_t count)\n{\n   uint32_t i;\n   for (i = 0; i < count; i++)\n   {\n      if (a[i] != b[i])\n         return true;\n   }\n   return false;\n}\n\n/**\n * An upper limit for the length of a path (including the filename).\n * If a path is longer than this, it may not work properly.\n * This value may vary by platform.\n */\n\n#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(__PSL1GHT__) || defined(__PS3__) || defined(HAVE_EMSCRIPTEN)\n\n#ifndef PATH_MAX_LENGTH\n#define PATH_MAX_LENGTH 512\n#endif\n\n#ifndef DIR_MAX_LENGTH\n#define DIR_MAX_LENGTH 256\n#endif\n\n/**\n * An upper limit for the length of a file or directory (excluding parent directories).\n * If a path has a component longer than this, it may not work properly.\n */\n#ifndef NAME_MAX_LENGTH\n#define NAME_MAX_LENGTH 128\n#endif\n\n#else\n\n#ifndef PATH_MAX_LENGTH\n#define PATH_MAX_LENGTH 2048\n#endif\n\n#ifndef DIR_MAX_LENGTH\n#define DIR_MAX_LENGTH 1024\n#endif\n\n/**\n * An upper limit for the length of a file or directory (excluding parent directories).\n * If a path has a component longer than this, it may not work properly.\n */\n#ifndef NAME_MAX_LENGTH\n#define NAME_MAX_LENGTH 256\n#endif\n\n#endif\n\n\n#ifndef MAX\n/**\n * @return \\c a or \\c b, whichever is larger.\n */\n#define MAX(a, b) ((a) > (b) ? (a) : (b))\n#endif\n\n#ifndef MIN\n/**\n * @return \\c a or \\c b, whichever is smaller.\n */\n#define MIN(a, b) ((a) < (b) ? (a) : (b))\n#endif\n\n/**\n * Gets the number of elements in an array whose size is known at compile time.\n * @param a An array of fixed length.\n * @return The number of elements in \\c a.\n */\n#define ARRAY_SIZE(a)              (sizeof(a) / sizeof((a)[0]))\n\n/** @defgroup BITS Bit Arrays\n *\n * @{\n */\n\n#define BITS_GET_ELEM(a, i)        ((a).data[i])\n#define BITS_GET_ELEM_PTR(a, i)    ((a)->data[i])\n\n/** @defgroup BIT_ Arbitrary-length Bit Arrays\n *\n * @{\n */\n\n/**\n * Sets a particular bit within a bit array to 1.\n *\n * @param a A \\c uint8_t array,\n * treated here as a bit vector.\n * @param bit Index of the bit to set, where 0 is the least significant.\n */\n#define BIT_SET(a, bit)   ((a)[(bit) >> 3] |=  (1 << ((bit) & 7)))\n\n/**\n * Clears a particular bit within a bit array.\n *\n * @param a A \\c uint8_t array,\n * treated here as a bit vector.\n * @param bit Index of the bit to clear, where 0 is the least significant.\n */\n#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))\n\n/**\n * Gets the value of a particular bit within a bit array.\n *\n * @param a A \\c uint8_t array,\n * treated here as a bit vector.\n * @param bit Index of the bit to get, where 0 is the least significant.\n * @return The value of the bit at the specified index.\n */\n#define BIT_GET(a, bit)   (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)\n\n/** @} */\n\n/** @defgroup BIT16 16-bit Bit Arrays\n *\n * @{\n */\n\n/**\n * Sets a particular bit within a 16-bit integer to 1.\n * @param a An unsigned 16-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to set, where 0 is the least significant and 15 is the most.\n */\n#define BIT16_SET(a, bit)    ((a) |=  (1 << ((bit) & 15)))\n\n/**\n * Clears a particular bit within a 16-bit integer.\n *\n * @param a An unsigned 16-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to clear, where 0 is the least significant and 15 is the most.\n */\n#define BIT16_CLEAR(a, bit)  ((a) &= ~(1 << ((bit) & 15)))\n\n/**\n * Gets the value of a particular bit within a 16-bit integer.\n *\n * @param a An unsigned 16-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to get, where 0 is the least significant and 15 is the most.\n * @return The value of the bit at the specified index.\n */\n#define BIT16_GET(a, bit)    (((a) >> ((bit) & 15)) & 1)\n\n/**\n * Clears all bits in a 16-bit bitmask.\n */\n#define BIT16_CLEAR_ALL(a)   ((a) = 0)\n\n/** @} */\n\n/** @defgroup BIT32 32-bit Bit Arrays\n *\n * @{\n */\n\n/**\n * Sets a particular bit within a 32-bit integer to 1.\n *\n * @param a An unsigned 32-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to set, where 0 is the least significant and 31 is the most.\n */\n#define BIT32_SET(a, bit)    ((a) |=  (UINT32_C(1) << ((bit) & 31)))\n\n/**\n * Clears a particular bit within a 32-bit integer.\n *\n * @param a An unsigned 32-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to clear, where 0 is the least significant and 31 is the most.\n */\n#define BIT32_CLEAR(a, bit)  ((a) &= ~(UINT32_C(1) << ((bit) & 31)))\n\n/**\n * Gets the value of a particular bit within a 32-bit integer.\n *\n * @param a An unsigned 32-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to get, where 0 is the least significant and 31 is the most.\n * @return The value of the bit at the specified index.\n */\n#define BIT32_GET(a, bit)    (((a) >> ((bit) & 31)) & 1)\n\n/**\n * Clears all bits in a 32-bit bitmask.\n *\n * @param a An unsigned 32-bit integer,\n * treated as a bit array.\n */\n#define BIT32_CLEAR_ALL(a)   ((a) = 0)\n\n/** @} */\n\n/**\n * @defgroup BIT64 64-bit Bit Arrays\n * @{\n */\n\n/**\n * Sets a particular bit within a 64-bit integer to 1.\n *\n * @param a An unsigned 64-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to set, where 0 is the least significant and 63 is the most.\n */\n#define BIT64_SET(a, bit)    ((a) |=  (UINT64_C(1) << ((bit) & 63)))\n\n/**\n * Clears a particular bit within a 64-bit integer.\n *\n * @param a An unsigned 64-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to clear, where 0 is the least significant and 63 is the most.\n */\n#define BIT64_CLEAR(a, bit)  ((a) &= ~(UINT64_C(1) << ((bit) & 63)))\n\n/**\n * Gets the value of a particular bit within a 64-bit integer.\n *\n * @param a An unsigned 64-bit integer,\n * treated as a bit array.\n * @param bit Index of the bit to get, where 0 is the least significant and 63 is the most.\n * @return The value of the bit at the specified index.\n */\n#define BIT64_GET(a, bit)    (((a) >> ((bit) & 63)) & 1)\n\n/**\n * Clears all bits in a 64-bit bitmask.\n *\n * @param a An unsigned 64-bit integer,\n * treated as a bit array.\n */\n#define BIT64_CLEAR_ALL(a)   ((a) = 0)\n\n/** @} */\n\n#define BIT128_SET(a, bit)   ((a).data[(bit) >> 5] |=  (UINT32_C(1) << ((bit) & 31)))\n#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))\n#define BIT128_GET(a, bit)   (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)\n#define BIT128_CLEAR_ALL(a)  memset(&(a), 0, sizeof(a))\n\n#define BIT128_SET_PTR(a, bit)   BIT128_SET(*a, bit)\n#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)\n#define BIT128_GET_PTR(a, bit)   BIT128_GET(*a, bit)\n#define BIT128_CLEAR_ALL_PTR(a)  BIT128_CLEAR_ALL(*a)\n\n/**\n * Sets a single bit from a 256-bit \\c retro_bits_t to 1.\n *\n * @param a A 256-bit \\c retro_bits_t.\n * @param bit Index of the bit to set,\n * where 0 is the least significant and 255 is the most.\n */\n#define BIT256_SET(a, bit)       BIT128_SET(a, bit)\n\n/**\n * Clears a single bit from a 256-bit \\c retro_bits_t.\n *\n * @param a A 256-bit \\c retro_bits_t.\n * @param bit Index of the bit to clear,\n * where 0 is the least significant and 255 is the most.\n */\n#define BIT256_CLEAR(a, bit)     BIT128_CLEAR(a, bit)\n\n/**\n * Gets the value of a single bit from a 256-bit \\c retro_bits_t.\n *\n * @param a A 256-bit \\c retro_bits_t.\n * @param bit Index of the bit to get,\n * where 0 is the least significant and 255 is the most.\n * @return The value of the bit at the specified index.\n */\n#define BIT256_GET(a, bit)       BIT128_GET(a, bit)\n\n/**\n * Clears all bits in a 256-bit \\c retro_bits_t.\n *\n * @param a A 256-bit \\c retro_bits_t.\n */\n#define BIT256_CLEAR_ALL(a)      BIT128_CLEAR_ALL(a)\n\n/** Variant of BIT256_SET() that takes a pointer to a \\c retro_bits_t. */\n#define BIT256_SET_PTR(a, bit)   BIT256_SET(*a, bit)\n\n/** Variant of BIT256_CLEAR() that takes a pointer to a \\c retro_bits_t. */\n#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)\n\n/** Variant of BIT256_GET() that takes a pointer to a \\c retro_bits_t. */\n#define BIT256_GET_PTR(a, bit)   BIT256_GET(*a, bit)\n\n/** Variant of BIT256_CLEAR_ALL() that takes a pointer to a \\c retro_bits_t. */\n#define BIT256_CLEAR_ALL_PTR(a)  BIT256_CLEAR_ALL(*a)\n\n/**\n * Sets a single bit from a 512-bit \\c retro_bits_512_t to 1.\n *\n * @param a A 512-bit \\c retro_bits_512_t.\n * @param bit Index of the bit to set,\n * where 0 is the least significant and 511 is the most.\n */\n#define BIT512_SET(a, bit)       BIT256_SET(a, bit)\n\n/**\n * Clears a single bit from a 512-bit \\c retro_bits_512_t.\n *\n * @param a A 512-bit \\c retro_bits_512_t.\n * @param bit Index of the bit to clear,\n * where 0 is the least significant and 511 is the most.\n */\n#define BIT512_CLEAR(a, bit)     BIT256_CLEAR(a, bit)\n\n/**\n * Gets the value of a single bit from a 512-bit \\c retro_bits_512_t.\n *\n * @param a A 512-bit \\c retro_bits_512_t.\n * @param bit Index of the bit to get,\n * where 0 is the least significant and 511 is the most.\n * @return The value of the bit at the specified index.\n */\n#define BIT512_GET(a, bit)       BIT256_GET(a, bit)\n\n/**\n * Clears all bits in a 512-bit \\c retro_bits_512_t.\n *\n * @param a A 512-bit \\c retro_bits_512_t.\n */\n#define BIT512_CLEAR_ALL(a)      BIT256_CLEAR_ALL(a)\n\n/** Variant of BIT512_SET() that takes a pointer to a \\c retro_bits_512_t. */\n#define BIT512_SET_PTR(a, bit)   BIT512_SET(*a, bit)\n\n/** Variant of BIT512_CLEAR() that takes a pointer to a \\c retro_bits_512_t. */\n#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)\n\n/** Variant of BIT512_GET() that takes a pointer to a \\c retro_bits_512_t. */\n#define BIT512_GET_PTR(a, bit)   BIT512_GET(*a, bit)\n\n/** Variant of BIT512_CLEAR_ALL() that takes a pointer to a \\c retro_bits_512_t. */\n#define BIT512_CLEAR_ALL_PTR(a)  BIT512_CLEAR_ALL(*a)\n\n#define BITS_COPY16_PTR(a,bits) \\\n{ \\\n   BIT128_CLEAR_ALL_PTR(a); \\\n   BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \\\n}\n\n#define BITS_COPY32_PTR(a,bits) \\\n{ \\\n   BIT128_CLEAR_ALL_PTR(a); \\\n   BITS_GET_ELEM_PTR(a, 0) = (bits); \\\n}\n\n#define BITS_COPY64_PTR(a,bits) \\\n{ \\\n   BIT128_CLEAR_ALL_PTR(a); \\\n   BITS_GET_ELEM_PTR(a, 0) = (bits); \\\n   BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \\\n}\n\n/* Helper macros and struct to keep track of many booleans. */\n\n/** A 256-bit boolean array. */\ntypedef struct\n{\n   /** @private 256 bits. Not intended for direct use. */\n   uint32_t data[8];\n} retro_bits_t;\n\n/** A 512-bit boolean array. */\ntypedef struct\n{\n   /** @private 512 bits. Not intended for direct use. */\n   uint32_t data[16];\n} retro_bits_512_t;\n\n/** @} */\n\n#ifdef _WIN32\n#  ifdef _WIN64\n#    define PRI_SIZET PRIu64\n#  else\n#    if _MSC_VER == 1800\n#      define PRI_SIZET PRIu32\n#    else\n#      define PRI_SIZET \"u\"\n#    endif\n#  endif\n#elif defined(PS2)\n#  define PRI_SIZET \"u\"\n#elif defined(__EMSCRIPTEN__)\n#  define PRI_SIZET \"zu\"\n#else\n#  if (SIZE_MAX == 0xFFFF)\n#    define PRI_SIZET \"hu\"\n#  elif (SIZE_MAX == 0xFFFFFFFF)\n#    define PRI_SIZET \"u\"\n#  elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)\n#    define PRI_SIZET \"lu\"\n#  else\n#    error PRI_SIZET: unknown SIZE_MAX\n#  endif\n#endif\n\n#endif\n"
  },
  {
    "path": "include/retro_spsc.h",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_spsc.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_SPSC_H\n#define __LIBRETRO_SDK_SPSC_H\n\n/*\n * retro_spsc.h - portable single-producer / single-consumer byte queue\n *\n * Lock-free byte-stream queue with one writer thread and one reader\n * thread.  Uses release-store / acquire-load on two cursors (the\n * Lamport / Disruptor design) rather than a single shared count, so\n * neither thread issues atomic RMW operations on the hot path.\n *\n * Constraints:\n *   - Exactly ONE producer and ONE consumer.  No locking is performed;\n *     two producers or two consumers will corrupt the queue.\n *   - Capacity must be power-of-2.  Init rounds up.\n *   - Maximum capacity is SIZE_MAX/2 (so head - tail never overflows\n *     the well-defined unsigned modular range).\n *   - The buffer is byte-addressed.  Callers pushing structured records\n *     are responsible for framing.\n *\n * Memory model:\n *   - Producer writes data into the buffer (non-atomic stores), then\n *     publishes the new head via release-store.\n *   - Consumer acquire-loads head (sees data writes that preceded the\n *     release), reads data (non-atomic loads), then publishes the new\n *     tail via release-store.\n *   - Producer acquire-loads tail to know how much space is free.\n *   - This pairing gives the SPSC invariant on every backend\n *     retro_atomic.h supports lock-freely.  On the volatile fallback\n *     (no real backend), correctness reduces to single-core or x86 TSO,\n *     same as every other retro_atomic.h caller.\n *\n * Cache behaviour:\n *   - head and tail are placed on separate cache lines via explicit\n *     padding to RETRO_SPSC_CACHE_LINE.  Without this, the producer's\n *     publish would invalidate the consumer's tail line and vice versa,\n *     halving throughput on contended SMP.  The padding is a\n *     performance hint; correctness does not depend on it.\n *\n * Lifetime:\n *   - retro_spsc_init allocates an internal buffer; retro_spsc_free\n *     releases it.  The caller owns the retro_spsc_t struct itself.\n *   - The struct is NOT itself thread-safe to construct or destroy\n *     while in use.  Build it on one thread, hand the producer pointer\n *     to one thread and the consumer pointer to another, then tear\n *     down on one thread after both producer and consumer have stopped.\n *\n * Example:\n *\n *   retro_spsc_t q;\n *   retro_spsc_init(&q, 4096);\n *\n *   // Producer thread:\n *   uint8_t msg[64] = ...;\n *   if (retro_spsc_write_avail(&q) >= sizeof(msg))\n *      retro_spsc_write(&q, msg, sizeof(msg));\n *\n *   // Consumer thread:\n *   uint8_t msg[64];\n *   if (retro_spsc_read_avail(&q) >= sizeof(msg))\n *      retro_spsc_read(&q, msg, sizeof(msg));\n *\n *   retro_spsc_free(&q);\n *\n * Comparison with libretro-common's existing fifo_queue_t:\n *   - fifo_queue uses a slock_t internally; safe with multiple producers\n *     and multiple consumers, but every push/pop takes a mutex.\n *   - retro_spsc is lock-free but limited to one producer and one\n *     consumer.  Use this when (a) the producer/consumer count is fixed\n *     at one each (audio driver -> backend, video -> task system, etc.)\n *     and (b) the lock contention in fifo_queue measurably matters.\n *   - For most code paths, fifo_queue is the better default.  This\n *     primitive is for hot paths where lock-free is a measured win.\n */\n\n#include <stddef.h>\n#include <stdint.h>\n#include <boolean.h>\n\n#include <retro_common_api.h>\n#include <retro_atomic.h>\n\nRETRO_BEGIN_DECLS\n\n/* Cache-line padding size.  64 covers x86-64, AArch64, most modern\n * ARMs, and modern PowerPC.  Apple Silicon's effective coherency line\n * is 128 due to its M-series cluster topology; over-padding to 64\n * still avoids false sharing, just slightly less efficiently.  Older\n * 32-bit ARMs (ARMv6, Cortex-A8) used 32-byte lines but tolerate the\n * larger pad without correctness impact. */\n#ifndef RETRO_SPSC_CACHE_LINE\n#define RETRO_SPSC_CACHE_LINE 64\n#endif\n\n/* Padding helper.  C89 has no _Static_assert; the array-size trick is\n * portable.  We pad to the next multiple of cache-line size after the\n * pointer-and-size_t prefix and after each cursor. */\n\n/* Effective cache line for padding.  We pad each cursor to a full\n * cache line.  If the pre-cursor fields exceed RETRO_SPSC_CACHE_LINE\n * on some hypothetical small-cache target, the underflow on the\n * subtraction would produce a giant array; guard with a max() so\n * the pad is always at least 1 byte and never underflows. */\n#define RETRO_SPSC_PAD0_BYTES \\\n   ((RETRO_SPSC_CACHE_LINE > (sizeof(uint8_t*) + sizeof(size_t))) \\\n      ? (RETRO_SPSC_CACHE_LINE - (sizeof(uint8_t*) + sizeof(size_t))) \\\n      : 1)\n#define RETRO_SPSC_PAD1_BYTES \\\n   ((RETRO_SPSC_CACHE_LINE > sizeof(retro_atomic_size_t)) \\\n      ? (RETRO_SPSC_CACHE_LINE - sizeof(retro_atomic_size_t)) \\\n      : 1)\n\ntypedef struct retro_spsc\n{\n   uint8_t            *buffer;\n   size_t              capacity;   /* power of 2; mask = capacity - 1 */\n   /* Pad so head sits on a fresh cache line, isolating it from\n    * the buffer/capacity fields that init may touch. */\n   uint8_t             _pad0[RETRO_SPSC_PAD0_BYTES];\n   retro_atomic_size_t head;       /* producer publishes; consumer reads */\n   /* Pad so tail sits on its own cache line, isolating it from head. */\n   uint8_t             _pad1[RETRO_SPSC_PAD1_BYTES];\n   retro_atomic_size_t tail;       /* consumer publishes; producer reads */\n} retro_spsc_t;\n\n/**\n * retro_spsc_init:\n * @q             : The queue.\n * @min_capacity  : Requested capacity in bytes.  Rounded up to the\n *                  next power of 2.  Must be > 0 and <= SIZE_MAX/2.\n *\n * Allocates the internal buffer and zero-initialises both cursors.\n * Both cursors begin at 0; the queue is empty.\n *\n * Returns: true on success, false on allocation failure or invalid\n * @min_capacity.\n *\n * After this returns true, the producer thread can call\n * retro_spsc_write / retro_spsc_write_avail and the consumer thread can\n * call retro_spsc_read / retro_spsc_read_avail.\n */\nbool retro_spsc_init(retro_spsc_t *q, size_t min_capacity);\n\n/**\n * retro_spsc_free:\n * @q : The queue.\n *\n * Releases the internal buffer.  Caller must ensure both producer\n * and consumer have stopped using @q before calling.  Safe to call\n * on a queue that retro_spsc_init failed on (no-op).\n */\nvoid retro_spsc_free(retro_spsc_t *q);\n\n/**\n * retro_spsc_clear:\n * @q : The queue.\n *\n * Resets head and tail to 0, discarding any unread data.  The\n * underlying buffer is preserved (no reallocation).\n *\n * SAFETY: callable only when both the producer and consumer are\n * quiesced -- e.g. before either has started, or after both have\n * stopped.  Concurrent calls with a live producer or consumer are\n * a data race.  This is the same lifetime constraint as\n * retro_spsc_init / retro_spsc_free.\n *\n * Typical use is when a stream is stopped and restarted (e.g. an\n * audio driver pausing and resuming, or switching device formats),\n * and stale buffered data should be discarded before the new\n * stream begins.\n */\nvoid retro_spsc_clear(retro_spsc_t *q);\n\n/**\n * retro_spsc_write_avail:\n * @q : The queue.\n *\n * Producer-side query: how many bytes can be written before the\n * queue is full.\n *\n * Returns: byte count, in [0, capacity].\n *\n * SAFETY: callable only from the producer thread.\n */\nsize_t retro_spsc_write_avail(const retro_spsc_t *q);\n\n/**\n * retro_spsc_read_avail:\n * @q : The queue.\n *\n * Consumer-side query: how many bytes are available to read.\n *\n * Returns: byte count, in [0, capacity].\n *\n * SAFETY: callable only from the consumer thread.\n */\nsize_t retro_spsc_read_avail(const retro_spsc_t *q);\n\n/**\n * retro_spsc_write:\n * @q     : The queue.\n * @data  : Source bytes.\n * @bytes : Number of bytes to attempt to write.\n *\n * Writes up to @bytes from @data into the queue.  If the queue has\n * less than @bytes free, writes only what fits.\n *\n * Returns: number of bytes actually written.\n *\n * SAFETY: callable only from the producer thread.  Concurrent calls\n * with another producer corrupt the queue.\n */\nsize_t retro_spsc_write(retro_spsc_t *q, const void *data, size_t bytes);\n\n/**\n * retro_spsc_read:\n * @q     : The queue.\n * @data  : Destination bytes.\n * @bytes : Number of bytes to attempt to read.\n *\n * Reads up to @bytes from the queue into @data.  If the queue has\n * less than @bytes available, reads only what is present.\n *\n * Returns: number of bytes actually read.\n *\n * SAFETY: callable only from the consumer thread.  Concurrent calls\n * with another consumer corrupt the queue.\n */\nsize_t retro_spsc_read(retro_spsc_t *q, void *data, size_t bytes);\n\n/**\n * retro_spsc_peek:\n * @q     : The queue.\n * @data  : Destination bytes.\n * @bytes : Number of bytes to peek.\n *\n * Like retro_spsc_read but does not advance the read cursor.  The\n * peeked bytes remain available for the next read.\n *\n * Returns: number of bytes peeked.\n *\n * SAFETY: callable only from the consumer thread.\n */\nsize_t retro_spsc_peek(const retro_spsc_t *q, void *data, size_t bytes);\n\nRETRO_END_DECLS\n\n#endif /* __LIBRETRO_SDK_SPSC_H */\n"
  },
  {
    "path": "include/retro_timers.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_timers.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_COMMON_TIMERS_H\n#define __LIBRETRO_COMMON_TIMERS_H\n\n#include <stdint.h>\n\n#if defined(XENON)\n#include <time/time.h>\n#elif !defined(__PSL1GHT__) && defined(__PS3__)\n#include <sys/timer.h>\n#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)\n#include <unistd.h>\n#elif defined(WIIU)\n#include <wiiu/os/thread.h>\n#elif defined(PSP)\n#include <pspthreadman.h>\n#elif defined(VITA)\n#include <psp2/kernel/threadmgr.h>\n#elif defined(_3DS)\n#include <3ds.h>\n#else\n#include <time.h>\n#endif\n\n#if defined(_WIN32) && !defined(_XBOX)\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#elif defined(_WIN32) && defined(_XBOX)\n#include <Xtl.h>\n#endif\n\n#include <limits.h>\n\n#ifdef _MSC_VER\n#include <compat/msvc.h>\n#endif\n#include <retro_inline.h>\n\n#ifdef DJGPP\n#define timespec timeval\n#define tv_nsec tv_usec\n#include <unistd.h>\n\nextern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);\n\nstatic int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)\n{\n   usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);\n\n   if (rmtp)\n      rmtp->tv_sec = rmtp->tv_nsec=0;\n\n   return 0;\n}\n\n#define nanosleep nanosleepDOS\n#endif\n\n/**\n * Briefly suspends the running thread.\n *\n * @param msec The time to sleep for, in milliseconds.\n **/\n#if defined(VITA)\n#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))\n#elif defined(_3DS)\n#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))\n#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP\n#define retro_sleep(msec) (SleepEx((msec), FALSE))\n#elif defined(_WIN32)\n#define retro_sleep(msec) (Sleep((msec)))\n#elif defined(XENON)\n#define retro_sleep(msec) (udelay(1000 * (msec)))\n#elif !defined(__PSL1GHT__) && defined(__PS3__)\n#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))\n#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)\n#define retro_sleep(msec) (usleep(1000 * (msec)))\n#elif defined(WIIU)\n#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))\n#elif defined(__EMSCRIPTEN__)\n/* defined in frontend */\n#ifdef __cplusplus\nextern \"C\" {\n#endif\nvoid retro_sleep(unsigned msec);\n#ifdef __cplusplus\n}\n#endif\n#else\nstatic INLINE void retro_sleep(unsigned msec)\n{\n   struct timespec tv;\n   tv.tv_sec          = msec / 1000;\n   tv.tv_nsec         = (msec % 1000) * 1000000;\n   nanosleep(&tv, NULL);\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/rthreads/async_job.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (async_job.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_ASYNC_JOB_H\n#define __LIBRETRO_SDK_ASYNC_JOB_H\n\ntypedef struct async_job async_job_t;\ntypedef void (*async_task_t)(void *payload);\n\nasync_job_t *async_job_new(void);\n\nvoid async_job_free(async_job_t *ajob);\n\nint async_job_add(async_job_t *ajob, async_task_t task, void *payload);\n\n#endif /* __LIBRETRO_SDK_ASYNC_JOB_H */\n"
  },
  {
    "path": "include/rthreads/rthreads.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rthreads.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_RTHREADS_H__\n#define __LIBRETRO_SDK_RTHREADS_H__\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n#include <stdint.h>\n#include <retro_inline.h>\n#include <retro_miscellaneous.h>\n\nRETRO_BEGIN_DECLS\n\n/** Platform-agnostic handle to a thread. */\ntypedef struct sthread sthread_t;\n\n/** Platform-agnostic handle to a mutex. */\ntypedef struct slock slock_t;\n\n/** Platform-agnostic handle to a condition variable. */\ntypedef struct scond scond_t;\n\n#ifdef HAVE_THREAD_STORAGE\n/** Platform-agnostic handle to thread-local storage. */\ntypedef unsigned sthread_tls_t;\n#endif\n\n/**\n * Creates a new thread and starts running it.\n *\n * @param thread_func Function to run in the new thread.\n * Called with the value given in \\c userdata as an argument.\n * @param userdata Pointer to anything (even \\c NULL), passed directly to \\c thread_func.\n * Must be cleaned up by the caller or the thread.\n * @return Pointer to the new thread,\n * or \\c NULL if there was an error.\n * @warn Make sure that the thread can respond to cancellation requests,\n * especially if used in a core.\n * If a core-created thread isn't terminated by the time the core is unloaded,\n * it may leak into the frontend and cause undefined behavior\n * (especially if another session with the core is started).\n */\nsthread_t *sthread_create(void (*thread_func)(void*), void *userdata);\n\n/**\n * Creates a new thread with a specific priority hint and starts running it.\n *\n * @param thread_func Function to run in the new thread.\n * Called with the value given in \\c userdata as an argument.\n * @param userdata Pointer to anything (even \\c NULL), passed directly to \\c thread_func.\n * Must be cleaned up by the caller or the thread.\n * @param thread_priority Priority hint for the new thread.\n * Threads with a higher number are more likely to be scheduled first.\n * Should be between 1 and 100, inclusive;\n * if not, the operating system will assign a default priority.\n * May be ignored.\n * @return Pointer to the new thread,\n * or \\c NULL if there was an error.\n */\nsthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority);\n\n/**\n * Detaches the given thread.\n *\n * When a detached thread terminates,\n * its resources are automatically released back to the operating system\n * without needing another thread to join with it.\n *\n * @param thread Thread to detach.\n * @return 0 on success, a non-zero error code on failure.\n * @warn Once a thread is detached, it cannot be joined.\n * @see sthread_join\n */\nint sthread_detach(sthread_t *thread);\n\n/**\n * Waits for the given thread to terminate.\n *\n * @param thread The thread to wait for.\n * Must be joinable.\n * Returns immediately if it's already terminated\n * or if it's \\c NULL.\n */\nvoid sthread_join(sthread_t *thread);\n\n/**\n * Returns whether the given thread is the same as the calling thread.\n *\n * @param thread Thread to check.\n * @return \\c true if \\c thread is the same as the calling thread,\n * \\c false if not or if it's \\c NULL.\n * @note libretro does not have a notion of a \"main\" thread,\n * since the core may not be running on the same thread\n * that called \\c main (or local equivalent).\n * @see sthread_get_thread_id\n */\nbool sthread_isself(sthread_t *thread);\n\n/**\n * Creates a new mutex (a.k.a. lock) that can be used to synchronize shared data.\n *\n * Must be manually freed with \\c slock_free.\n *\n * @return Pointer to the new mutex,\n * or \\c NULL if there was an error.\n */\nslock_t *slock_new(void);\n\n/**\n * Frees a mutex.\n *\n * Behavior is undefined if \\c lock was previously freed.\n *\n * @param lock Pointer to the mutex to free.\n * May be \\c NULL, in which this function does nothing.\n */\nvoid slock_free(slock_t *lock);\n\n/**\n * Locks a mutex, preventing other threads from claiming it until it's unlocked.\n *\n * If the mutex is already locked by another thread,\n * the calling thread will block until the mutex is unlocked.\n *\n * @param lock Pointer to the mutex to lock.\n * If \\c NULL, will return without further action.\n * @see slock_try_lock\n */\nvoid slock_lock(slock_t *lock);\n\n/**\n * Tries to lock a mutex if it's not already locked by another thread.\n *\n * If the mutex is already in use by another thread,\n * returns immediately without waiting for it.\n *\n * @param lock The mutex to try to lock.\n * @return \\c true if the mutex was successfully locked,\n * \\c false if it was already locked by another thread or if \\c lock is \\c NULL.\n * @see slock_lock\n */\nbool slock_try_lock(slock_t *lock);\n\n/**\n * Unlocks a mutex, allowing other threads to claim it.\n *\n * @post The mutex is unlocked,\n * and another thread may lock it.\n * @param lock The mutex to unlock.\n * If \\c NULL, this function is a no-op.\n */\nvoid slock_unlock(slock_t *lock);\n\n/**\n * Creates and initializes a condition variable.\n *\n * Must be manually freed with \\c scond_free.\n *\n * @return Pointer to the new condition variable,\n * or \\c NULL if there was an error.\n */\nscond_t *scond_new(void);\n\n/**\n * Frees a condition variable.\n *\n * @param cond Pointer to the condition variable to free.\n * If \\c NULL, this function is a no-op.\n * Behavior is undefined if \\c cond was previously freed.\n */\nvoid scond_free(scond_t *cond);\n\n/**\n * Blocks until the given condition variable is signaled or broadcast.\n *\n * @param cond Condition variable to wait on.\n * This function blocks until another thread\n * calls \\c scond_signal or \\c scond_broadcast with this condition variable.\n * @param lock Mutex to lock while waiting.\n *\n * @see scond_signal\n * @see scond_broadcast\n * @see scond_wait_timeout\n */\nvoid scond_wait(scond_t *cond, slock_t *lock);\n\n/**\n * Blocks until the given condition variable is signaled or broadcast,\n * or until the specified time has passed.\n *\n * @param cond Condition variable to wait on.\n * This function blocks until another thread\n * calls \\c scond_signal or \\c scond_broadcast with this condition variable.\n * @param lock Mutex to lock while waiting.\n * @param timeout_us Time to wait for a signal, in microseconds.\n *\n * @return \\c false if \\c timeout_us elapses\n * before \\c cond is signaled or broadcast, otherwise \\c true.\n */\nbool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);\n\n/**\n * Unblocks all threads waiting on the specified condition variable.\n *\n * @param cond Condition variable to broadcast.\n * @return 0 on success, non-zero on failure.\n */\nint scond_broadcast(scond_t *cond);\n\n/**\n * Unblocks at least one thread waiting on the specified condition variable.\n *\n * @param cond Condition variable to signal.\n */\nvoid scond_signal(scond_t *cond);\n\n#ifdef HAVE_THREAD_STORAGE\n/**\n * Creates a thread-local storage key.\n *\n * Thread-local storage keys have a single value associated with them\n * that is unique to the thread that uses them.\n *\n * New thread-local storage keys have a value of \\c NULL for all threads,\n * and new threads initialize all existing thread-local storage to \\c NULL.\n *\n * @param tls[in,out] Pointer to the thread local storage key that will be initialized.\n * Must be cleaned up with \\c sthread_tls_delete.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if the operation succeeded, \\c false otherwise.\n * @see sthread_tls_delete\n */\nbool sthread_tls_create(sthread_tls_t *tls);\n\n/**\n * Deletes a thread local storage key.\n *\n * The value must be cleaned up separately \\em before calling this function,\n * if necessary.\n *\n * @param tls The thread local storage key to delete.\n * Behavior is undefined if \\c NULL.\n * @return \\c true if the operation succeeded, \\c false otherwise.\n */\nbool sthread_tls_delete(sthread_tls_t *tls);\n\n/**\n * Gets the calling thread's local data for the given key.\n *\n * @param tls The thread-local storage key to get the data for.\n * @return The calling thread's local data associated with \\c tls,\n * which should previously have been set with \\c sthread_tls_set.\n * Will be \\c NULL if this thread has not set a value or if there was an error.\n */\nvoid *sthread_tls_get(sthread_tls_t *tls);\n\n/**\n * Sets the calling thread's local data for the given key.\n *\n * @param tls The thread-local storage key to set the data for.\n * @param data Pointer to the data that will be associated with \\c tls.\n * May be \\c NULL.\n * @return \\c true if \\c data was successfully assigned to \\c tls,\n * \\c false if there was an error.\n */\nbool sthread_tls_set(sthread_tls_t *tls, const void *data);\n#endif\n\n/**\n * Gets a thread's unique ID.\n *\n * @param thread The thread to get the ID of.\n * @return The provided thread's ID,\n * or 0 if it's \\c NULL.\n */\nuintptr_t sthread_get_thread_id(sthread_t *thread);\n\n/**\n * Get the calling thread's unique ID.\n * @return The calling thread's ID.\n * @see sthread_get_thread_id\n */\nuintptr_t sthread_get_current_thread_id(void);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/rthreads/tpool.h",
    "content": "/*\n * Copyright (c) 2010-2020 The RetroArch team\n * Copyright (c) 2017 John Schember <john@nachtimwald.com>\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (tpool.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE\n */\n\n#ifndef __LIBRETRO_SDK_TPOOL_H__\n#define __LIBRETRO_SDK_TPOOL_H__\n\n#include <retro_common_api.h>\n\n#include <boolean.h>\n\n#include <retro_inline.h>\n#include <retro_miscellaneous.h>\n\nRETRO_BEGIN_DECLS\n\nstruct tpool;\ntypedef struct tpool tpool_t;\n\n/**\n * (*thread_func_t):\n * @arg           : Argument.\n *\n * Callback function that the pool will call to do work.\n **/\ntypedef void (*thread_func_t)(void *arg);\n\n/**\n * tpool_create:\n * @num           : Number of threads the pool should have.\n *                  If 0 defaults to 2.\n *\n * Create a thread pool.\n *\n * Returns: pool.\n */\ntpool_t *tpool_create(size_t num);\n\n/**\n * tpool_destroy:\n * @tp            : Thread pool.\n *\n * Destroy a thread pool\n * The pool can be destroyed while there is outstanding work to process. All\n * outstanding unprocessed work will be discarded. There may be a delay before\n * this function returns because it will block for work that is processing to\n * complete.\n **/\nvoid tpool_destroy(tpool_t *tp);\n\n/**\n * tpool_add_work:\n * @tp         : Thread pool.\n * @func       : Function the pool should call.\n * @arg        : Argument to pass to func.\n *\n * Add work to a thread pool.\n *\n * Returns: true if work was added, otherwise false.\n **/\nbool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg);\n\n/**\n * tpool_wait:\n * @tp Thread pool.\n *\n * Wait for all work in the pool to be completed.\n */\nvoid tpool_wait(tpool_t *tp);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/chd_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (chd_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_FILE_CHD_STREAM_H\n#define _LIBRETRO_SDK_FILE_CHD_STREAM_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct chdstream chdstream_t;\n\n/* First data track */\n#define CHDSTREAM_TRACK_FIRST_DATA (-1)\n/* Last track */\n#define CHDSTREAM_TRACK_LAST (-2)\n/* Primary (largest) data track, used for CRC identification purposes */\n#define CHDSTREAM_TRACK_PRIMARY (-3)\n\nchdstream_t *chdstream_open(const char *path, int32_t track);\n\nvoid chdstream_close(chdstream_t *stream);\n\nssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes);\n\nint chdstream_getc(chdstream_t *stream);\n\nchar *chdstream_gets(chdstream_t *stream, char *buffer, size_t len);\n\nuint64_t chdstream_tell(chdstream_t *stream);\n\nvoid chdstream_rewind(chdstream_t *stream);\n\nint64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence);\n\nssize_t chdstream_get_size(chdstream_t *stream);\n\nuint32_t chdstream_get_track_start(chdstream_t* stream);\n\nuint32_t chdstream_get_frame_size(chdstream_t* stream);\n\nuint32_t chdstream_get_first_track_sector(chdstream_t* stream);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/file_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_FILE_STREAM_H\n#define __LIBRETRO_SDK_FILE_STREAM_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <stddef.h>\n\n#include <sys/types.h>\n\n#include <libretro.h>\n#include <retro_common_api.h>\n#include <retro_inline.h>\n#include <boolean.h>\n\n#include <stdarg.h>\n#include <vfs/vfs_implementation.h>\n\n/** @defgroup file_stream File Streams\n *\n * All functions in this header will use the VFS interface set in \\ref filestream_vfs_init if possible,\n * or else they will fall back to built-in equivalents.\n *\n * @note These functions are modeled after those in the C standard library\n * (and may even use them internally),\n * but identical behavior is not guaranteed.\n *\n * @{\n */\n\n/**\n * The minimum version of the VFS interface required by the \\c filestream functions.\n */\n#define FILESTREAM_REQUIRED_VFS_VERSION 2\n\nRETRO_BEGIN_DECLS\n\n/**\n * Opaque handle to a file stream.\n * @warning This is not interchangeable with \\c FILE* or \\c retro_vfs_file_handle.\n */\ntypedef struct RFILE RFILE;\n\n#define FILESTREAM_REQUIRED_VFS_VERSION 2\n\n/**\n * Initializes the \\c filestream functions to use the VFS interface provided by the frontend.\n * Optional; if not called, all \\c filestream functions\n * will use libretro-common's built-in implementations.\n *\n * @param vfs_info The VFS interface returned by the frontend.\n * If \\c vfs_info::iface (but \\em not \\c vfs_info itself) is \\c NULL,\n * then libretro-common's built-in VFS implementation will be used.\n */\nvoid filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);\n\n/**\n * Returns the size of the given file, in bytes.\n *\n * @param stream The open file to query.\n * @return The size of \\c stream in bytes,\n * or -1 if there was an error.\n * @see retro_vfs_size_t\n */\nint64_t filestream_get_size(RFILE *stream);\n\n/**\n * Sets the size of the given file,\n * truncating or extending it as necessary.\n *\n * @param stream The file to resize.\n * @param length The new size of \\c stream, in bytes.\n * @return 0 if the resize was successful,\n * or -1 if there was an error.\n * @see retro_vfs_truncate_t\n */\nint64_t filestream_truncate(RFILE *stream, int64_t length);\n\n/**\n * Opens a file for reading or writing.\n *\n * @param path Path to the file to open.\n * Should be in the format described in \\ref GET_VFS_INTERFACE.\n * @param mode The mode to open the file in.\n * Should be one or more of the flags in \\refitem RETRO_VFS_FILE_ACCESS OR'd together,\n * and \\c RETRO_VFS_FILE_ACCESS_READ or \\c RETRO_VFS_FILE_ACCESS_WRITE\n * (or both) must be included.\n * @param hints Optional hints to pass to the frontend.\n *\n * @return The opened file, or \\c NULL if there was an error.\n * Must be cleaned up with \\c filestream_close when no longer needed.\n * @see retro_vfs_open_t\n */\nRFILE* filestream_open(const char *path, unsigned mode, unsigned hints);\n\n/**\n * Sets the current position of the file stream.\n * Use this to read specific sections of a file.\n *\n * @param stream The file to set the stream position of.\n * @param offset The new stream position, in bytes.\n * @param seek_position The position to seek from.\n * Should be one of the values in \\refitem RETRO_VFS_SEEK_POSITION.\n * @return The new stream position in bytes relative to the beginning,\n * or -1 if there was an error.\n * @see RETRO_VFS_SEEK_POSITION\n * @see retro_vfs_seek_t\n */\nint64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);\n\n/**\n * Reads data from the given file into a buffer.\n * If the read is successful,\n * the file's stream position will advance by the number of bytes read.\n *\n * @param stream The file to read from.\n * @param data The buffer in which to store the read data.\n * @param len The size of \\c data, in bytes.\n * @return The number of bytes read,\n * or -1 if there was an error.\n * May be less than \\c len, but never more.\n * @see retro_vfs_read_t\n */\nint64_t filestream_read(RFILE *stream, void *data, int64_t len);\n\n/**\n * Writes data from a buffer to the given file.\n * If the write is successful,\n * the file's stream position will advance by the number of bytes written.\n *\n * @param stream The file to write to.\n * @param data The buffer containing the data to write.\n * @param len The size of \\c data, in bytes.\n * @return The number of bytes written,\n * or -1 if there was an error.\n * May be less than \\c len, but never more.\n * @see retro_vfs_write_t\n */\nint64_t filestream_write(RFILE *stream, const void *data, int64_t len);\n\n/**\n * Returns the current position of the given file in bytes.\n *\n * @param stream The file to return the stream position for.\n * @return The current stream position in bytes relative to the beginning,\n * or -1 if there was an error.\n * @see retro_vfs_tell_t\n */\nint64_t filestream_tell(RFILE *stream);\n\n/**\n * Rewinds the given file to the beginning.\n * Equivalent to <tt>filestream_seek(stream, 0, RETRO_VFS_SEEK_POSITION_START)</tt>.\n\n * @param stream The file to rewind.\n * May be \\c NULL, in which case this function does nothing.\n */\nvoid filestream_rewind(RFILE *stream);\n\n/**\n * Closes the given file.\n *\n * @param stream The file to close.\n * This should have been created with \\c filestream_open.\n * Behavior is undefined if \\c NULL.\n * @return 0 if the file was closed successfully,\n * or -1 if there was an error.\n * @post \\c stream is no longer valid and should not be used,\n * even if this function fails.\n * @see retro_vfs_close_t\n */\nint filestream_close(RFILE *stream);\n\n/**\n * Opens a file, reads its contents into a newly-allocated buffer,\n * then closes it.\n *\n * @param path[in] Path to the file to read.\n * Should be in the format described in \\ref GET_VFS_INTERFACE.\n * @param buf[out] A pointer to the address of the newly-allocated buffer.\n * The buffer will contain the entirety of the file at \\c path.\n * Will be allocated with \\c malloc and must be freed with \\c free.\n * @param len[out] Pointer to the size of the buffer in bytes.\n * May be \\c NULL, in which case the length is not written.\n * Value is unspecified if this function fails.\n * @return 1 if the file was read successfully,\n * 0 if there was an error.\n * @see filestream_write_file\n */\nint64_t filestream_read_file(const char *path, void **buf, int64_t *len);\n\n/**\n * Reads a line of text from the given file,\n * up to a given length.\n *\n * Will read to the next newline or until the buffer is full,\n * whichever comes first.\n *\n * @param stream The file to read from.\n * @param s The buffer to write the retrieved line to.\n * Will contain at most \\c len - 1 characters\n * plus a null terminator.\n * The newline character (if any) will not be included.\n * The line delimiter must be Unix-style (\\c '\\n').\n * Carriage returns (\\c '\\r') will not be treated specially.\n * @param len The length of the buffer \\c s, in bytes.\n * @return \\s if successful, \\c NULL if there was an error.\n */\nchar* filestream_gets(RFILE *stream, char *s, size_t len);\n\n/**\n * Reads a single character from the given file.\n *\n * @param stream The file to read from.\n * @return The character read, or -1 upon reaching the end of the file.\n */\nint filestream_getc(RFILE *stream);\n\n/**\n * Reads formatted text from the given file,\n * with arguments provided as a standard \\c va_list.\n *\n * @param stream The file to read from.\n * @param format The string to write, possibly including scanf-compatible format specifiers.\n * @param args Argument list with zero or more elements\n * whose values will be updated according to the semantics of \\c format.\n * @return The number of arguments in \\c args that were successfully assigned,\n * or -1 if there was an error.\n * @see https://en.cppreference.com/w/c/io/fscanf\n * @see https://en.cppreference.com/w/c/variadic\n */\nint filestream_vscanf(RFILE *stream, const char* format, va_list *args);\n\n/**\n * Reads formatted text from the given file.\n *\n * @param stream The file to read from.\n * @param format The string to write, possibly including scanf-compatible format specifiers.\n * @param ... Zero or more arguments that will be updated according to the semantics of \\c format.\n * @return The number of arguments in \\c ... that were successfully assigned,\n * or -1 if there was an error.\n * @see https://en.cppreference.com/w/c/io/fscanf\n */\nint filestream_scanf(RFILE *stream, const char* format, ...);\n\n/**\n * Determines if there's any more data left to read from this file.\n *\n * @param stream The file to check the position of.\n * @return -1 if this stream has reached the end of the file,\n * 0 if not.\n */\nint filestream_eof(RFILE *stream);\n\n/**\n * Writes the entirety of a given buffer to a file at a given path.\n * Any file that already exists will be overwritten.\n *\n * @param path Path to the file that will be written to.\n * @param data The buffer to write to \\c path.\n * @param size The size of \\c data, in bytes.\n * @return \\c true if the file was written successfully,\n * \\c false if there was an error.\n */\nbool filestream_write_file(const char *path, const void *data, int64_t size);\n\n/**\n * Writes a single character to the given file.\n *\n * @param stream The file to write to.\n * @param c The character to write.\n * @return The character written,\n * or -1 if there was an error.\n * Will return -1 if \\c stream is \\c NULL.\n */\nint filestream_putc(RFILE *stream, int c);\n\n/**\n * Writes formatted text to the given file,\n * with arguments provided as a standard \\c va_list.\n *\n * @param stream The file to write to.\n * @param format The string to write, possibly including printf-compatible format specifiers.\n * @param args A list of arguments to be formatted and inserted in the resulting string.\n * @return The number of characters written,\n * or -1 if there was an error.\n * @see https://en.cppreference.com/w/c/io/vfprintf\n * @see https://en.cppreference.com/w/c/variadic\n */\nint filestream_vprintf(RFILE *stream, const char* format, va_list args);\n\n/**\n * Writes formatted text to the given file.\n *\n * @param stream The file to write to.\n * @param format The string to write, possibly including printf-compatible format specifiers.\n * @param ... Zero or more arguments to be formatted and inserted into the resulting string.\n * @return The number of characters written,\n * or -1 if there was an error.\n * @see https://en.cppreference.com/w/c/io/printf\n */\nint filestream_printf(RFILE *stream, const char* format, ...);\n\n/**\n * Checks if there was an error in using the given file stream.\n *\n * @param stream The file stream to check for errors.\n * @return \\c true if there was an error in using this stream,\n * \\c false if not or if \\c stream is \\c NULL.\n */\nint filestream_error(RFILE *stream);\n\n/**\n * Flushes pending writes to the operating system's file layer.\n * There is no guarantee that pending writes will be written to disk immediately.\n *\n * @param stream The file to flush.\n * @return 0 if the flush was successful,\n * or -1 if there was an error.\n * @see retro_vfs_flush_t\n */\nint filestream_flush(RFILE *stream);\n\n/**\n * Deletes the file at the given path.\n * If the file is open by any process,\n * the behavior is platform-specific.\n *\n * @note This function might or might not delete directories recursively,\n * depending on the platform and the underlying VFS implementation.\n *\n * @param path The file to delete.\n * @return 0 if the file was deleted successfully,\n * or -1 if there was an error.\n * @see retro_vfs_remove_t\n */\nint filestream_delete(const char *path);\n\n/**\n * Moves a file to a new location, with a new name.\n *\n * @param old_path Path to the file to rename.\n * @param new_path The target name and location of the file.\n * @return 0 if the file was renamed successfully,\n * or -1 if there was an error.\n * @see retro_vfs_rename_t\n */\nint filestream_rename(const char *old_path, const char *new_path);\n\n/**\n * Copies a file to a new location.\n *\n * @param src_path Path to the file to rename.\n * @param dst_path The target name and location of the file.\n * @return 0 if the file was copied successfully,\n * or -1 if there was an error.\n */\nint filestream_copy(const char *src_path, const char *dst_path);\n\n/**\n * Compares and verifies files.\n *\n * @param src_path Path to the file.\n * @param dst_path Path to the other file.\n * @return 0 if the files are equal,\n * or -1 if there was an error.\n */\nint filestream_cmp(const char *src_path, const char *dst_path);\n\n/**\n * Get the path that was used to open a file.\n *\n * @param stream The file to get the path of.\n * @return The path that was used to open \\c stream,\n * or \\c NULL if there was an error.\n * The string is owned by \\c stream and must not be modified or freed by the caller.\n */\nconst char* filestream_get_path(RFILE *stream);\n\n/**\n * Determines if a file exists at the given path.\n *\n * @param path The path to check for existence.\n * @return \\c true if a file exists at \\c path,\n * \\c false if not or if \\c path is \\c NULL or empty.\n */\nbool filestream_exists(const char *path);\n\n/**\n * Reads a line from the given file into a newly-allocated buffer.\n *\n * @param stream The file to read from.\n * @return Pointer to the line read from \\c stream,\n * or \\c NULL if there was an error.\n * Must be freed with \\c free when no longer needed.\n */\nchar* filestream_getline(RFILE *stream);\n\n/**\n * Returns the open file handle\n * that was originally returned by the VFS interface.\n *\n * @param stream File handle returned by \\c filestream_open.\n * @return The file handle returned by the underlying VFS implementation.\n */\nlibretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);\n\nRETRO_END_DECLS\n\n/** @} */\n\n#endif\n"
  },
  {
    "path": "include/streams/file_stream_transforms.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (file_stream_transforms.h).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H\n#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H\n\n#include <stdint.h>\n#include <string.h>\n#include <retro_common_api.h>\n#include <streams/file_stream.h>\n\n/**\n * @file file_stream_transforms.h\n *\n * Contains macros that redirect standard C I/O functions\n * to libretro's own file stream API.\n * Useful when porting an existing emulator to a core.\n * To use these functions without overriding the standard I/O functions,\n * define \\c SKIP_STDIO_REDEFINES before including this header.\n *\n * @see https://man7.org/linux/man-pages/man3/stdio.3.html\n */\n\nRETRO_BEGIN_DECLS\n\n#ifndef SKIP_STDIO_REDEFINES\n\n/** @see https://en.cppreference.com/w/c/io/FILE */\n#define FILE RFILE\n\n#undef fopen\n#undef fclose\n#undef ftell\n#undef fseek\n#undef fread\n#undef fgets\n#undef fgetc\n#undef fwrite\n#undef fputc\n#undef fflush\n#undef fprintf\n#undef ferror\n#undef feof\n#undef fscanf\n\n#define fopen rfopen\n#define fclose rfclose\n#define ftell rftell\n#define fseek rfseek\n#define fread rfread\n#define fgets rfgets\n#define fgetc rfgetc\n#define fwrite rfwrite\n#define fputc rfputc\n#define fflush rfflush\n#define fprintf rfprintf\n#define ferror rferror\n#define feof rfeof\n#define fscanf rfscanf\n\n#endif\n\n/** @see https://en.cppreference.com/w/c/io/fopen */\nRFILE* rfopen(const char *path, const char *mode);\n\n/** @see https://en.cppreference.com/w/c/io/fclose */\nint rfclose(RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/ftell */\nint64_t rftell(RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/fseek */\nint64_t rfseek(RFILE* stream, int64_t offset, int origin);\n\n/** @see https://en.cppreference.com/w/c/io/fread */\nint64_t rfread(void* buffer,\n   size_t elem_size, size_t elem_count, RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/fgets */\nchar *rfgets(char *s, int maxCount, RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/fgetc */\nint rfgetc(RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/fwrite */\nint64_t rfwrite(void const* buffer,\n   size_t elem_size, size_t elem_count, RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/fputc */\nint rfputc(int character, RFILE * stream);\n\n/** @see https://en.cppreference.com/w/c/io/fflush */\nint64_t rfflush(RFILE * stream);\n\n/** @see https://en.cppreference.com/w/c/io/fprintf */\nint rfprintf(RFILE * stream, const char * format, ...);\n\n/** @see https://en.cppreference.com/w/c/io/ferror */\nint rferror(RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/feof */\nint rfeof(RFILE* stream);\n\n/** @see https://en.cppreference.com/w/c/io/fscanf */\nint rfscanf(RFILE * stream, const char * format, ...);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/interface_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (interface_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_INTERFACE_STREAM_H\n#define _LIBRETRO_SDK_INTERFACE_STREAM_H\n\n#include <stdint.h>\n#include <stddef.h>\n#include <sys/types.h>\n\n#include <retro_common_api.h>\n#include <boolean.h>\n\nRETRO_BEGIN_DECLS\n\nenum intfstream_type\n{\n   INTFSTREAM_FILE = 0,\n   INTFSTREAM_MEMORY,\n   INTFSTREAM_CHD,\n   INTFSTREAM_RZIP\n};\n\ntypedef struct intfstream_internal intfstream_internal_t, intfstream_t;\n\ntypedef struct intfstream_info\n{\n   struct\n   {\n      struct\n      {\n         uint8_t *data;\n         uint64_t size;\n      } buf;\n      bool writable;\n   } memory;\n   struct\n   {\n      void *handle;\n      int32_t track;\n   } chd;\n   enum intfstream_type type;\n} intfstream_info_t;\n\nvoid *intfstream_init(intfstream_info_t *info);\n\nbool intfstream_resize(intfstream_internal_t *intf,\n      intfstream_info_t *info);\n\nbool intfstream_open(intfstream_internal_t *intf,\n      const char *path, unsigned mode, unsigned hints);\n\nint64_t intfstream_read(intfstream_internal_t *intf,\n      void *s, uint64_t len);\n\nint64_t intfstream_write(intfstream_internal_t *intf,\n      const void *s, uint64_t len);\n\nint intfstream_printf(intfstream_internal_t *intf,\n      const char* format, ...);\n\nint64_t intfstream_get_ptr(intfstream_internal_t *intf);\n\nchar *intfstream_gets(intfstream_internal_t *intf,\n      char *buffer, uint64_t len);\n\nint intfstream_getc(intfstream_internal_t *intf);\n\nint64_t intfstream_seek(intfstream_internal_t *intf,\n      int64_t offset, int whence);\n\nint64_t intfstream_truncate(intfstream_internal_t *intf,\n      uint64_t len);\n\nvoid intfstream_rewind(intfstream_internal_t *intf);\n\nint64_t intfstream_tell(intfstream_internal_t *intf);\n\nint intfstream_eof(intfstream_internal_t *intf);\n\nvoid intfstream_putc(intfstream_internal_t *intf, int c);\n\nint intfstream_close(intfstream_internal_t *intf);\n\nint64_t intfstream_get_size(intfstream_internal_t *intf);\n\nint intfstream_flush(intfstream_internal_t *intf);\n\nuint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf);\n\nuint32_t intfstream_get_frame_size(intfstream_internal_t *intf);\n\nuint32_t intfstream_get_first_sector(intfstream_internal_t* intf);\n\nbool intfstream_is_compressed(intfstream_internal_t *intf);\n\nbool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc);\n\nintfstream_t *intfstream_open_file(const char *path,\n      unsigned mode, unsigned hints);\n\nintfstream_t *intfstream_open_memory(void *data,\n      unsigned mode, unsigned hints, uint64_t size);\n\n/* Deprecated.  Has the same effect as `intfstream_open_memory` with\n   a mode including `RETRO_VFS_FILE_ACCESS_WRITE`. */\nintfstream_t *intfstream_open_writable_memory(void *data,\n      unsigned mode, unsigned hints, uint64_t size);\n\nintfstream_t *intfstream_open_chd_track(const char *path,\n      unsigned mode, unsigned hints, int32_t track);\n\nintfstream_t *intfstream_open_rzip_file(const char *path,\n      unsigned mode);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/memory_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (memory_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_FILE_MEMORY_STREAM_H\n#define _LIBRETRO_SDK_FILE_MEMORY_STREAM_H\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct memstream memstream_t;\n\nmemstream_t *memstream_open(unsigned writing);\n\nvoid memstream_close(memstream_t *stream);\n\nuint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes);\n\nuint64_t memstream_write(memstream_t *stream, const void *data, uint64_t bytes);\n\nint memstream_getc(memstream_t *stream);\n\nvoid memstream_putc(memstream_t *stream, int c);\n\nchar *memstream_gets(memstream_t *stream, char *s, size_t len);\n\nuint64_t memstream_pos(memstream_t *stream);\n\nvoid memstream_rewind(memstream_t *stream);\n\nint64_t memstream_seek(memstream_t *stream, int64_t offset, int whence);\n\nvoid memstream_set_buffer(uint8_t *buffer, uint64_t size);\n\nuint64_t memstream_get_last_size(void);\n\nuint64_t memstream_get_ptr(memstream_t *stream);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/network_stream.h",
    "content": "/* Copyright  (C) 2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (network_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_NETWORK_STREAM_H\n#define _LIBRETRO_SDK_NETWORK_STREAM_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include <boolean.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nenum\n{\n   /**\n    * Indicates that \\c netstream_seek should seek\n    * relative to the beginning of the stream.\n    */\n   NETSTREAM_SEEK_SET = 0,\n\n   /**\n    * Indicates that \\c netstream_seek should seek\n    * relative to its current position.\n    */\n   NETSTREAM_SEEK_CUR,\n\n   /**\n    * Indicates that \\c netstream_seek should seek\n    * relative to the end of the stream.\n    */\n   NETSTREAM_SEEK_END\n};\n\n/**\n * A stream that ensures data is read/written in network byte order (big endian).\n *\n * @note Despite what the name may suggests,\n * this object does \\em not actually perform any network operations.\n * It is intended to be used as input/output for functions that do.\n */\ntypedef struct netstream\n{\n   /** The buffer used by the stream for reading or writing. */\n   void   *buf;\n\n   /** The size of \\c buf in bytes. */\n   size_t size;\n\n   /** The number of bytes that have been written to \\c buf. */\n   size_t used;\n\n   /**\n    * The current position of the stream, in bytes.\n    * @see netstream_seek\n    */\n   size_t pos;\n} netstream_t;\n\n/**\n * Opens a network-order stream.\n *\n * @param stream Pointer to the network-order stream to initialize.\n * Behavior is undefined if \\c NULL.\n * @param buf Pre-allocated buffer.\n * May be \\c NULL, in which case a new buffer will be created with \\c malloc.\n * @param size Buffer size in bytes.\n * If \\c buf is \\c NULL, then this will be the size of the newly-allocated buffer.\n * If not, then this is the size of the existing buffer.\n * If zero, then a buffer will not be allocated.\n * @param used The number of bytes in use.\n * Ignored for non pre-allocated buffers.\n * @return \\c true if the stream was opened.\n * For new buffers, \\c false if allocation failed.\n * For existing buffers, \\c false if \\c size is zero\n * or less than \\c used.\n * @see netstream_close\n */\nbool netstream_open(netstream_t *stream, void *buf, size_t len, size_t used);\n\n/**\n * Closes a network-order stream.\n *\n * @param stream Pointer to the network-order stream to close.\n * The stream itself is not deallocated,\n * but its fields will be reset.\n * Behavior is undefined if \\c NULL.\n * @param dealloc Whether to release the underlying buffer with \\c free.\n * Set to \\c true if the creating \\c netstream_open call allocated a buffer,\n * or else its memory will be leaked.\n * @note \\c stream itself is not deallocated.\n * This function can be used on static or local variables.\n * @see netstream_open\n */\nvoid netstream_close(netstream_t *stream, bool dealloc);\n\n/**\n * Resets the stream to the beginning and discards any used bytes.\n *\n * @param stream The network-order stream to reset.\n * Behavior is undefined if \\c NULL.\n *\n * @note This does not deallocate the underlying buffer,\n * nor does it wipe its memory.\n */\nvoid netstream_reset(netstream_t *stream);\n\n/**\n * Resizes the \"used\" portion of the stream.\n *\n * @param stream The network-order stream to resize.\n * Behavior is undefined if \\c NULL.\n * @param used The number of bytes in the stream that are considered written.\n * @return \\c true if the stream's \"used\" region was resized,\n * \\c false if it would've been extended past the buffer's capacity.\n * @note This function does not reallocate or clear the underlying buffer.\n * It only sets the boundaries of the \"used\" portion of the stream.\n */\nbool netstream_truncate(netstream_t *stream, size_t used);\n\n/**\n * Retrieves the network-order stream's data.\n *\n * @param stream Pointer to the network-order stream.\n * Behavior is undefined if \\c NULL.\n * @param data[out] Pointer to a variable to store the stream's data.\n * The data itself is not copied,\n * so the pointer will be invalidated\n * if the stream is closed or reallocated.\n * @param len[out] Set to the length of the stream's data in bytes.\n */\nvoid netstream_data(netstream_t *stream, void **data, size_t *len);\n\n/**\n * Checks whether the network-order stream has any more data to read,\n * or any more room to write data.\n *\n * @param stream The network-order stream to check.\n * @return \\c true if the stream is at EOF, \\c false otherwise.\n */\nbool netstream_eof(netstream_t *stream);\n\n/**\n * Gets the network-order stream's current position.\n *\n * @param stream Pointer to a network-order stream.\n * @return The stream's position indicator.\n */\nsize_t netstream_tell(netstream_t *stream);\n\n/**\n * Sets the network-order stream's current position.\n *\n * @param stream Pointer to a network-order stream.\n * @param offset The new position of the stream, in bytes.\n * @param origin The position used as reference for the offset.\n * Must be one of \\c NETSTREAM_SEEK_SET, \\c NETSTREAM_SEEK_CUR or \\c NETSTREAM_SEEK_END.\n * @return \\c true on success, \\c false on failure.\n */\nbool netstream_seek(netstream_t *stream, long offset, int origin);\n\n/**\n * Reads data from the network-order stream.\n * Does not byte-swap any data;\n * this is useful for reading strings or unspecified binary data.\n *\n * @param stream The network-order stream to read from.\n * @param data The buffer that will receive data from the stream.\n * @param len The number of bytes to read.\n * If 0, will read all remaining bytes.\n * @return \\c true on success, \\c false on failure.\n */\nbool netstream_read(netstream_t *stream, void *data, size_t len);\n\n/**\n * Reads a single byte from the network-order stream.\n *\n * @param stream[in] The network-order stream to read from.\n * @param data[out] Pointer to the byte that will receive the read value.\n * @return \\c true on success, \\c false if there was an error.\n */\nbool netstream_read_byte(netstream_t   *stream, uint8_t  *data);\n\n/**\n * Reads an unsigned 16-bit integer from the network-order stream,\n * byte-swapping it from big endian to host-native byte order if necessary.\n *\n * @param stream[in] The network-order stream to read from.\n * @param data[out] Pointer to the value that will receive the read value.\n * @return \\c true on success, \\c false if there was an error.\n */\nbool netstream_read_word(netstream_t   *stream, uint16_t *data);\n\n/**\n * Reads an unsigned 32-bit integer from the network-order stream,\n * byte-swapping it from big endian to host-native byte order if necessary.\n *\n * @param stream[in] The network-order stream to read from.\n * @param data[out] Pointer to the value that will receive the read value.\n * @return \\c true on success, \\c false if there was an error.\n */\nbool netstream_read_dword(netstream_t  *stream, uint32_t *data);\n\n/**\n * Reads an unsigned 64-bit integer from the network-order stream,\n * byte-swapping it from big endian to host-native byte order if necessary.\n *\n * @param stream[in] The network-order stream to read from.\n * @param data[out] Pointer to the value that will receive the read value.\n * @return \\c true on success, \\c false if there was an error.\n */\nbool netstream_read_qword(netstream_t  *stream, uint64_t *data);\n#ifdef __STDC_IEC_559__\n/**\n * Reads a 32-bit floating-point number from the network-order stream,\n * byte-swapping it from big endian to host-native byte order if necessary.\n *\n * @param stream[in] The network-order stream to read from.\n * @param data[out] Pointer to the value that will receive the read value.\n * @return \\c true on success, \\c false if there was an error.\n */\nbool netstream_read_float(netstream_t  *stream, float    *data);\n\n/**\n * Reads a 64-bit floating-point number from the network-order stream,\n * byte-swapping it from big endian to host-native byte order if necessary.\n *\n * @param stream[in] The network-order stream to read from.\n * @param data[out] Pointer to the value that will receive the read value.\n * @return \\c true on success, \\c false if there was an error.\n */\nbool netstream_read_double(netstream_t *stream, double   *data);\n#endif\n\n/**\n * Reads a null-terminated string from the network-order stream,\n * up to the given length.\n *\n * @param stream Pointer to a network stream object.\n * @param s[out] The buffer that will receive the string.\n * Will be \\c NULL-terminated.\n * @param len The length of \\c s, in bytes.\n * @return The length of the read string in bytes,\n * or -1 if there was an error.\n */\nint netstream_read_string(netstream_t *stream, char *s, size_t len);\n\n/**\n * Reads a string of fixed length from a network-order stream.\n * Will fail if there isn't enough data to read.\n *\n * @param stream Pointer to a network stream object.\n * @param s The buffer that will receive the string.\n * Will be \\c NULL-terminated.\n * @param len The length of \\c s in bytes,\n * including the \\c NULL terminator.\n *\n * @return \\c true if a string of the exact length was read,\n * \\c false if there was an error.\n */\nbool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len);\n\n/**\n * Writes arbitrary data to a network-order stream.\n * Does not byte-swap any data;\n * this is useful for writing strings or unspecified binary data.\n *\n * @param stream Pointer to a network stream object.\n * @param data The data to write into the network stream.\n * @param len The length of \\c data, in bytes.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write(netstream_t *stream, const void *data, size_t len);\n\n/**\n * Writes a single byte to a network-order stream.\n *\n * @param stream Pointer to a network stream object.\n * @param data The byte to write to the stream.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_byte(netstream_t   *stream, uint8_t  data);\n\n/**\n * Writes an unsigned 16-bit integer to a network-order stream,\n * byte-swapping it from host-native byte order to big-endian if necessary.\n *\n * @param stream Pointer to a network stream object.\n * @param data The value to write to the stream.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_word(netstream_t   *stream, uint16_t data);\n\n/**\n * Writes an unsigned 32-bit integer to a network-order stream,\n * byte-swapping it from host-native byte order to big-endian if necessary.\n *\n * @param stream Pointer to a network stream object.\n * @param data The value to write to the stream.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_dword(netstream_t  *stream, uint32_t data);\n\n/**\n * Writes an unsigned 64-bit integer to a network-order stream,\n * byte-swapping it from host-native byte order to big-endian if necessary.\n *\n * @param stream Pointer to a network stream object.\n * @param data The value to write to the stream.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_qword(netstream_t  *stream, uint64_t data);\n#ifdef __STDC_IEC_559__\n\n/**\n * Writes a 32-bit floating-point number to a network-order stream,\n * byte-swapping it from host-native byte order to big-endian if necessary.\n *\n * @param stream Pointer to a network stream object.\n * @param data The value to write to the stream.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_float(netstream_t  *stream, float    data);\n\n/**\n * Writes a 64-bit floating-point number to a network-order stream,\n * byte-swapping it from host-native byte order to big-endian if necessary.\n *\n * @param stream Pointer to a network stream object.\n * @param data The value to write to the stream.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_double(netstream_t *stream, double   data);\n#endif\n\n/**\n * Writes a null-terminated string to a network-order stream.\n * Does not byte-swap any data.\n *\n * @param stream Pointer to a network stream object.\n * @param s A \\c NULL-terminated string.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_string(netstream_t *stream, const char *s);\n\n/**\n * Writes a string of fixed length to a network-order stream,\n * \\c NULL-terminating it if necessary.\n *\n * @param stream Pointer to a network stream object.\n * @param s Pointer to a string.\n * Does not need to be \\c NULL-terminated,\n * but \\c NULL values will not stop processing.\n * Will be \\c NULL\n * @param len Length of \\c s in bytes,\n * including the \\c NULL terminator.\n * Exactly this many bytes will be written to the stream;\n * the last character will be set to \\c NULL.\n * @return \\c true on success,\n * \\c false if there was an error.\n */\nbool netstream_write_fixed_string(netstream_t *stream, const char *s,\n      size_t len);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/rzip_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rzip_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _LIBRETRO_SDK_FILE_RZIP_STREAM_H\n#define _LIBRETRO_SDK_FILE_RZIP_STREAM_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <stdarg.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/* Rudimentary interface for streaming data to/from a\n * zlib-compressed chunk-based RZIP archive file.\n * \n * This is somewhat less efficient than using regular\n * gzip code, but this is by design - the intention here\n * is to create an interface that integrates seamlessly\n * with normal RetroArch functionality, using only\n * standard/existing libretro-common routines.\n * (Actual efficiency is pretty good, regardless:\n * archived file size is almost identical to a solid\n * zip file, and compression/decompression speed is\n * not substantially worse than external archiving tools;\n * it is certainly acceptable for use in real-time\n * frontend applications)\n * \n * When reading existing files, uncompressed content\n * is handled automatically. File type (compressed/\n * uncompressed) is detected via the RZIP header.\n * \n * ## RZIP file format:\n * \n * <file id header>:                8 bytes\n *                                  - [#][R][Z][I][P][v][file format version][#]\n * <uncompressed chunk size>:       4 bytes, little endian order\n *                                  - nominal (maximum) size of each uncompressed\n *                                    chunk, in bytes\n * <total uncompressed data size>:  8 bytes, little endian order\n * <size of next compressed chunk>: 4 bytes, little endian order\n *                                  - size on-disk of next compressed data\n *                                    chunk, in bytes\n * <next compressed chunk>:         n bytes of zlib compressed data\n * ...\n * <size of next compressed chunk> : repeated until end of file\n * <next compressed chunk>         :\n * \n */\n\n/* Prevent direct access to rzipstream_t members */\ntypedef struct rzipstream rzipstream_t;\n\n/* File Open */\n\n/* Opens a new or existing RZIP file\n * > Supported 'mode' values are:\n *   - RETRO_VFS_FILE_ACCESS_READ\n *   - RETRO_VFS_FILE_ACCESS_WRITE\n * > When reading, 'path' may reference compressed\n *   or uncompressed data\n * Returns NULL if arguments are invalid, file\n * is invalid or an IO error occurs */\nrzipstream_t* rzipstream_open(const char *path, unsigned mode);\n\n/* File Read */\n\n/* Reads (a maximum of) 'len' bytes from an RZIP file.\n * Returns actual number of bytes read, or -1 in\n * the event of an error */\nint64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len);\n\n/* Reads next character from an RZIP file.\n * Returns character value, or EOF if no data\n * remains.\n * Note: Always returns EOF if file is open\n * for writing. */\nint rzipstream_getc(rzipstream_t *stream);\n\n/* Reads one line from an RZIP file and stores it\n * in the character array pointed to by 's'.\n * It stops reading when either (len-1) characters\n * are read, the newline character is read, or the\n * end-of-file is reached, whichever comes first.\n * On success, returns 's'. In the event of an error,\n * or if end-of-file is reached and no characters\n * have been read, returns NULL. */\nchar* rzipstream_gets(rzipstream_t *stream, char *s, size_t len);\n\n/* Reads all data from file specified by 'path' and\n * copies it to 'buf'.\n * - 'buf' will be allocated and must be free()'d manually.\n * - Allocated 'buf' size is equal to 'len'.\n * Returns false in the event of an error */\nbool rzipstream_read_file(const char *path, void **buf, int64_t *len);\n\n/* File Write */\n\n/* Writes 'len' bytes to an RZIP file.\n * Returns actual number of bytes written, or -1\n * in the event of an error */\nint64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len);\n\n/* Writes a single character to an RZIP file.\n * Returns character written, or EOF in the event\n * of an error */\nint rzipstream_putc(rzipstream_t *stream, int c);\n\n/* Writes a variable argument list to an RZIP file.\n * Ugly 'internal' function, required to enable\n * 'printf' support in the higher level 'interface_stream'.\n * Returns actual number of bytes written, or -1\n * in the event of an error */\nint rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args);\n\n/* Writes formatted output to an RZIP file.\n * Returns actual number of bytes written, or -1\n * in the event of an error */\nint rzipstream_printf(rzipstream_t *stream, const char* format, ...);\n\n/* Writes contents of 'data' buffer to file\n * specified by 'path'.\n * Returns false in the event of an error */\nbool rzipstream_write_file(const char *path, const void *data, int64_t len);\n\n/* File Control */\n\n/* Sets file position to the beginning of the\n * specified RZIP file.\n * Note: It is not recommended to rewind a file\n * that is open for writing, since the caller\n * may end up with a file containing junk data\n * at the end (harmless, but a waste of space). */\nvoid rzipstream_rewind(rzipstream_t *stream);\n\n/* File Status */\n\n/* Returns total size (in bytes) of the *uncompressed*\n * data in an RZIP file.\n * (If reading an uncompressed file, this corresponds\n * to the 'physical' file size in bytes)\n * Returns -1 in the event of a error. */\nint64_t rzipstream_get_size(rzipstream_t *stream);\n\n/* Returns EOF when no further *uncompressed* data\n * can be read from an RZIP file. */\nint rzipstream_eof(rzipstream_t *stream);\n\n/* Returns the offset of the current byte of *uncompressed*\n * data relative to the beginning of an RZIP file.\n * Returns -1 in the event of a error. */\nint64_t rzipstream_tell(rzipstream_t *stream);\n\n/* Returns true if specified RZIP file contains\n * compressed content */\nbool rzipstream_is_compressed(rzipstream_t *stream);\n\n/* File Close */\n\n/* Closes RZIP file. If file is open for writing,\n * flushes any remaining buffered data to disk.\n * Returns -1 in the event of a error. */\nint rzipstream_close(rzipstream_t *stream);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/stdin_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (stdin_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_SDK_STDIN_STREAM_H__\n#define LIBRETRO_SDK_STDIN_STREAM_H__\n\n#include <stdint.h>\n#include <stddef.h>\n\n#include <retro_miscellaneous.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\n/**\n * Reads data from \\c stdin if supported by the current platform.\n * @param buf[out] The buffer to read data into.\n * @param size The length of \\c buf in bytes.\n * @return The number of bytes that were read,\n * or 0 if there was an error\n * (including a lack of platform support).\n * @note \\c stdin is commonly used for text,\n * but this function can read binary data as well.\n * @see https://man7.org/linux/man-pages/man3/stdout.3.html\n */\nsize_t read_stdin(char *s, size_t len);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/streams/trans_stream.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (trans_stream.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef LIBRETRO_SDK_TRANS_STREAM_H__\n#define LIBRETRO_SDK_TRANS_STREAM_H__\n\n#include <stdint.h>\n#include <stddef.h>\n#include <boolean.h>\n\n#ifdef _WIN32\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\n#include <retro_miscellaneous.h>\n\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\nenum trans_stream_error\n{\n    TRANS_STREAM_ERROR_NONE = 0,\n    TRANS_STREAM_ERROR_AGAIN, /* more work to do */\n    TRANS_STREAM_ERROR_ALLOCATION_FAILURE, /* malloc failure */\n    TRANS_STREAM_ERROR_INVALID, /* invalid state */\n    TRANS_STREAM_ERROR_BUFFER_FULL, /* output buffer full */\n    TRANS_STREAM_ERROR_OTHER\n};\n\nstruct trans_stream_backend\n{\n   const char *ident;\n   const struct trans_stream_backend *reverse;\n\n   /* Create a stream data structure */\n   void *(*stream_new)(void);\n\n   /* Free it */\n   void  (*stream_free)(void *);\n\n   /* (Optional) Set extra properties, defined per transcoder */\n   bool  (*define)(void *, const char *, uint32_t);\n\n   /* Set our input source */\n   void  (*set_in)(void *, const uint8_t *, uint32_t);\n\n   /* Set our output target */\n   void  (*set_out)(void *, uint8_t *, uint32_t);\n\n   /* Perform a transcoding, flushing/finalizing if asked to. Writes out how\n    * many bytes were read and written. Error target optional. */\n   bool  (*trans)(void *, bool, uint32_t *, uint32_t *, enum trans_stream_error *);\n};\n\n/**\n * trans_stream_trans_full:\n * @backend                     : transcoding backend\n * @data                        : (optional) existing stream data, or a target\n *                                for the new stream data to be saved\n * @in                          : input data\n * @in_size                     : input size\n * @out                         : output data\n * @out_size                    : output size\n * @error                       : (optional) output for error code\n *\n * Perform a full transcoding from a source to a destination.\n */\nbool trans_stream_trans_full(\n    struct trans_stream_backend *backend, void **data,\n    const uint8_t *in, uint32_t in_size,\n    uint8_t *out, uint32_t out_size,\n    enum trans_stream_error *error);\n\nconst struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void);\nconst struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void);\nconst struct trans_stream_backend* trans_stream_get_pipe_backend(void);\n\nextern const struct trans_stream_backend zlib_deflate_backend;\nextern const struct trans_stream_backend zlib_inflate_backend;\nextern const struct trans_stream_backend pipe_backend;\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/string/stdstring.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (stdstring.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_STDSTRING_H\n#define __LIBRETRO_SDK_STDSTRING_H\n\n#include <stdlib.h>\n#include <stddef.h>\n#include <ctype.h>\n#include <string.h>\n#include <boolean.h>\n\n#include <retro_common_api.h>\n#include <retro_inline.h>\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n\nRETRO_BEGIN_DECLS\n\n#define STRLEN_CONST(x)                   ((sizeof((x))-1))\n\n#define string_is_not_equal(a, b)         !string_is_equal((a), (b))\n\n#define TOLOWER(c)   ((c) |  (lr_char_props[(unsigned char)(c)] & 0x20))\n#define TOUPPER(c)   ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))\n\n/* C standard says \\f \\v are space, but this one disagrees */\n#define ISSPACE(c)   (lr_char_props[(unsigned char)(c)] & 0x80)\n\n#define ISDIGIT(c)   (lr_char_props[(unsigned char)(c)] & 0x40)\n#define ISALPHA(c)   (lr_char_props[(unsigned char)(c)] & 0x20)\n#define ISLOWER(c)   (lr_char_props[(unsigned char)(c)] & 0x04)\n#define ISUPPER(c)   (lr_char_props[(unsigned char)(c)] & 0x02)\n#define ISALNUM(c)   (lr_char_props[(unsigned char)(c)] & 0x60)\n#define ISUALPHA(c)  (lr_char_props[(unsigned char)(c)] & 0x28)\n#define ISUALNUM(c)  (lr_char_props[(unsigned char)(c)] & 0x68)\n#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)\n\n/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */\n#define string_is_equal_noncase string_is_equal_case_insensitive\n\nstatic INLINE bool string_is_empty(const char *data)\n{\n   return !data || !*data;\n}\n\nstatic INLINE bool string_is_equal(const char *a, const char *b)\n{\n   if (a == b)\n      return true;\n   if (!a || !b)\n      return false;\n   return !strcmp(a, b);\n}\n\nstatic INLINE bool string_starts_with_size(const char *str, const char *prefix,\n      size_t len)\n{\n   return (str && prefix) ? !strncmp(prefix, str, len) : false;\n}\n\nstatic INLINE bool string_starts_with(const char *str, const char *prefix)\n{\n   return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;\n}\n\nstatic INLINE bool string_ends_with_size(const char *s, const char *suffix,\n      size_t len, size_t suffix_len)\n{\n   return (len < suffix_len) ? false :\n         !memcmp(suffix, s + (len - suffix_len), suffix_len);\n}\n\nstatic INLINE bool string_ends_with(const char *s, const char *suffix)\n{\n   return s && suffix && string_ends_with_size(s, suffix, strlen(s), strlen(suffix));\n}\n\n/**\n * strlen_size:\n *\n * Leaf function.\n *\n * @return the length of 'str' (c.f. strlen()), but only\n * checks the first 'size' characters\n * - If 'str' is NULL, returns 0\n * - If 'str' is not NULL and no '\\0' character is found\n *   in the first 'size' characters, returns 'size'\n **/\nstatic INLINE size_t strlen_size(const char *str, size_t len)\n{\n   size_t i = 0;\n   if (str)\n      while (i < len && str[i]) i++;\n   return i;\n}\n\nstatic INLINE bool string_is_equal_case_insensitive(const char *a,\n      const char *b)\n{\n   int result              = 0;\n   const unsigned char *p1 = (const unsigned char*)a;\n   const unsigned char *p2 = (const unsigned char*)b;\n\n   if (!a || !b)\n      return false;\n   if (p1 == p2)\n      return true;\n\n   while ((result = tolower (*p1) - tolower (*p2++)) == 0)\n      if (*p1++ == '\\0')\n         break;\n\n   return (result == 0);\n}\n\nstatic INLINE bool string_starts_with_case_insensitive(const char *str,\n      const char *prefix)\n{\n   int result              = 0;\n   const unsigned char *p1 = (const unsigned char*)str;\n   const unsigned char *p2 = (const unsigned char*)prefix;\n\n   if (!str || !prefix)\n      return false;\n   if (p1 == p2)\n      return true;\n\n   while ((result = tolower (*p1++) - tolower (*p2)) == 0)\n      if (*p2++ == '\\0')\n         break;\n\n   return (result == 0 || *p2 == '\\0');\n}\n\nchar *string_to_upper(char *s);\n\nchar *string_to_lower(char *s);\n\nchar *string_ucwords(char *s);\n\nchar *string_replace_substring(\n      const char *in,          size_t in_len,\n      const char *pattern,     size_t pattern_len,\n      const char *replacement, size_t replacement_len);\n\n/**\n * string_trim_whitespace_left:\n *\n * Remove leading whitespaces\n **/\nchar *string_trim_whitespace_left(char *const s);\n\n/**\n * string_trim_whitespace_right:\n *\n * Remove trailing whitespaces\n **/\nchar *string_trim_whitespace_right(char *const s);\n\n/**\n * string_trim_whitespace:\n *\n * Remove leading and trailing whitespaces\n **/\nchar *string_trim_whitespace(char *const s);\n\n/**\n * word_wrap:\n * @dst                : pointer to destination buffer.\n * @dst_size           : size of destination buffer.\n * @src                : pointer to input string.\n * @src_len            : length of @src\n * @line_width         : max number of characters per line.\n * @wideglyph_width    : not used, but is necessary to keep\n *                       compatibility with word_wrap_wideglyph().\n * @max_lines          : max lines of destination string.\n *                       0 means no limit.\n *\n * Wraps string specified by 'src' to destination buffer\n * specified by 'dst' and 'dst_size'.\n * This function assumes that all glyphs in the string\n * have an on-screen pixel width similar to that of\n * regular Latin characters - i.e. it will not wrap\n * correctly any text containing so-called 'wide' Unicode\n * characters (e.g. CJK languages, emojis, etc.).\n **/\nsize_t word_wrap(char *dst, size_t dst_size, const char *src, size_t src_len,\n      int line_width, int wideglyph_width, unsigned max_lines);\n\n/**\n * word_wrap_wideglyph:\n * @dst                : pointer to destination buffer.\n * @dst_size           : size of destination buffer.\n * @src                : pointer to input string.\n * @src_len            : length of @src\n * @line_width         : max number of characters per line.\n * @wideglyph_width    : effective width of 'wide' Unicode glyphs.\n *                       the value here is normalised relative to the\n *                       typical on-screen pixel width of a regular\n *                       Latin character:\n *                       - a regular Latin character is defined to\n *                         have an effective width of 100\n *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)\n *                       - e.g. if 'wide' Unicode characters in 'src'\n *                         have an on-screen pixel width twice that of\n *                         regular Latin characters, wideglyph_width\n *                         would be 200\n * @max_lines          : max lines of destination string.\n *                       0 means no limit.\n *\n * Wraps string specified by @src to destination buffer\n * specified by @dst and @dst_size.\n * This function assumes that all glyphs in the string\n * are:\n * - EITHER 'non-wide' Unicode glyphs, with an on-screen\n *   pixel width similar to that of regular Latin characters\n * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)\n *   with an on-screen pixel width defined by @wideglyph_width\n * Note that wrapping may occur in inappropriate locations\n * if @src string contains 'wide' Unicode characters whose\n * on-screen pixel width deviates greatly from the set\n * @wideglyph_width value.\n **/\nsize_t word_wrap_wideglyph(\n      char *dst, size_t dst_size,\n      const char *src, size_t src_len,\n      int line_width, int wideglyph_width,\n      unsigned max_lines);\n\n/**\n * string_tokenize:\n *\n * Splits string into tokens separated by @delim\n * > Returned token string must be free()'d\n * > Returns NULL if token is not found\n * > After each call, @str is set to the position after the\n *   last found token\n * > Tokens *include* empty strings\n * Usage example:\n *    char *str      = \"1,2,3,4,5,6,7,,,10,\";\n *    char **str_ptr = &str;\n *    char *token    = NULL;\n *    while ((token = string_tokenize(str_ptr, \",\")))\n *    {\n *        printf(\"%s\\n\", token);\n *        free(token);\n *        token = NULL;\n *    }\n **/\nchar *string_tokenize(char **str, const char *delim);\n\n/**\n * string_remove_all_chars:\n * @s                 : input string (must be non-NULL, otherwise UB)\n *\n * Leaf function.\n *\n * Removes every instance of character @c from @s\n *\n * Returns the length of the resulting string.\n **/\nsize_t string_remove_all_chars(char *s, char c);\n\n/**\n * string_replace_all_chars:\n * @str                : input string (must be non-NULL, otherwise UB)\n * @find               : character to find\n * @replace            : character to replace @find with\n *\n * Hidden non-leaf function cost:\n * - Calls strchr (in a loop)\n *\n * Replaces every instance of character @find in @str\n * with character @replace\n **/\nvoid string_replace_all_chars(char *str, char find, char replace);\n\n/**\n * string_to_unsigned:\n * @str                : input string\n *\n * Converts string to unsigned integer.\n *\n * @return 0 if string is invalid, otherwise > 0\n **/\nunsigned string_to_unsigned(const char *str);\n\n/**\n * string_hex_to_unsigned:\n * @str                : input string (must be non-NULL, otherwise UB)\n *\n * Converts hexadecimal string to unsigned integer.\n * Handles optional leading '0x'.\n *\n * @return 0 if string is invalid, otherwise > 0\n **/\nunsigned string_hex_to_unsigned(const char *str);\n\n/**\n * string_count_occurrences_single_character:\n *\n * Leaf function.\n *\n * Get the total number of occurrences of character @c in @str.\n *\n * @return Total number of occurrences of character @c\n */\nint string_count_occurrences_single_character(const char *str, char c);\n\n/**\n * string_replace_whitespace_with_single_character:\n *\n * Leaf function.\n *\n * Replaces all spaces with given character @c.\n **/\nvoid string_replace_whitespace_with_single_character(char *str, char c);\n\n/**\n * string_replace_multi_space_with_single_space:\n *\n * Leaf function.\n *\n * Replaces multiple spaces with a single space in a string.\n **/\nvoid string_replace_multi_space_with_single_space(char *str);\n\n/**\n * string_remove_all_whitespace:\n *\n * Leaf function.\n *\n * Remove all spaces from the given string.\n * Returns the length of the resulting string.\n **/\nsize_t string_remove_all_whitespace(char *str_trimmed, const char *str);\n\n/**\n * strlcpy_append:\n * @s                  : destination buffer\n * @len                : total size of @s, including space for the NUL\n * @pos                : in-out cursor.  On entry, the offset within\n *                       @s where @src should be appended; on\n *                       successful return advanced past the appended\n *                       bytes.  On truncation clamped to @len - 1 so\n *                       subsequent calls in a chain short-circuit.\n * @src                : NUL-terminated source string to append\n *\n * Bound-checked replacement for the unsafe pattern\n *\n *     *pos += strlcpy(@s + *pos, @src, @len - *pos);\n *\n * which is widely used to build strings piece-by-piece but is\n * NOT self-bounding -- strlcpy returns strlen(@src) regardless\n * of how much was actually written, so on truncation *pos\n * overshoots @len and the next @len - *pos subtraction underflows\n * size_t, corrupting subsequent appends.\n *\n * On success returns 0 and advances *pos by strlen(@src).  On\n * truncation (the appended bytes plus a NUL would exceed @len)\n * returns -1, leaves @s NUL-terminated at @len - 1, and clamps\n * *pos to @len - 1 so a chain of strlcpy_append calls can\n * short-circuit cleanly -- the caller need only check the bitwise\n * OR of the chain's results once at the end.\n *\n * @return 0 on success, -1 on truncation or invalid arguments\n **/\nint strlcpy_append(char *s, size_t len, size_t *pos, const char *src);\n\n/* Retrieve the last occurance of the given character in a string. */\nint string_index_last_occurance(const char *str, char c);\n\n/**\n * string_find_index_substring_string:\n * @str                : input string (must be non-NULL, otherwise UB)\n * @substr             : substring to find in @str\n *\n * Hidden non-leaf function cost:\n * - Calls strstr\n *\n * Find the position of substring @substr in string @str.\n **/\nint string_find_index_substring_string(const char *str, const char *substr);\n\n/**\n * string_copy_only_ascii:\n *\n * Leaf function.\n *\n * Strips non-ASCII characters from a string.\n **/\nvoid string_copy_only_ascii(char *str_stripped, const char *str);\n\n/**\n * string_ext_list_find:\n * @delim_str : '|'-delimited extension string (e.g. \"bin|iso|cue\")\n * @delim_len : length of @delim_str\n * @ext       : single extension token to look for\n * @ext_len   : length of @ext\n *\n * Checks whether @ext exists as an exact token inside @delim_str.\n * \"bi\" will not match \"bin\".\n *\n * Returns: true if found, false otherwise.\n **/\nbool string_ext_list_find(const char *delim_str, size_t delim_len,\n      const char *ext, size_t ext_len);\n\n/**\n * string_ext_list_append_dedup:\n * @dst      : destination '|'-delimited string being built\n * @dst_len  : pointer to current length of content in @dst (updated in place)\n * @dst_size : total buffer capacity of @dst\n * @ext      : a single extension token (no '|') to append if not duplicate\n * @ext_len  : length of @ext\n *\n * Appends a single extension to @dst with a '|' separator,\n * but only if @ext is not already present in @dst.\n **/\nvoid string_ext_list_append_dedup(char *dst, size_t *dst_len,\n      size_t dst_size, const char *ext, size_t ext_len);\n\n/**\n * string_ext_list_merge_dedup:\n * @dst      : destination '|'-delimited string being built\n * @dst_len  : pointer to current length of content in @dst (updated in place)\n * @dst_size : total buffer capacity of @dst\n * @src      : source '|'-delimited extension string (may contain many tokens)\n *\n * Splits @src on '|' and appends each unique extension to @dst.\n * Extensions already present in @dst are skipped.\n **/\nvoid string_ext_list_merge_dedup(char *dst, size_t *dst_len,\n      size_t dst_size, const char *src);\n\nextern const unsigned char lr_char_props[256];\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/time/rtime.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rtime.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_RTIME_H__\n#define __LIBRETRO_SDK_RTIME_H__\n\n#include <retro_common_api.h>\n\n#include <stdint.h>\n#include <stddef.h>\n#include <time.h>\n\nRETRO_BEGIN_DECLS\n\n/* TODO/FIXME: Move all generic time handling functions\n * to this file */\n\n/**\n * Must be called before using \\c rtime_localtime().\n * May be called multiple times without ill effects,\n * but must only be called from the main thread.\n */\nvoid rtime_init(void);\n\n/**\n * Must be called upon program or core termination.\n * May be called multiple times without ill effects,\n * but must only be called from the main thread.\n */\nvoid rtime_deinit(void);\n\n/**\n * Thread-safe wrapper around standard \\c localtime(),\n * which by itself is not guaranteed to be thread-safe.\n * @param timep Pointer to a time_t object to convert.\n * @param result Pointer to a tm object to store the result in.\n * @return \\c result.\n * @see https://en.cppreference.com/w/c/chrono/localtime\n */\nstruct tm *rtime_localtime(const time_t *timep, struct tm *result);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/utils/md5.h",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * See md5.c for more information.\n */\n\n#ifdef HAVE_OPENSSL\n#include <openssl/md5.h>\n#elif !defined(_MD5_H)\n#define _MD5_H\n\n#include <stdint.h>\n#include <retro_common_api.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct {\n\tuint32_t lo, hi;\n\tuint32_t a, b, c, d;\n\tunsigned char buffer[64];\n\tuint32_t block[16];\n} MD5_CTX;\n\nextern void MD5_Init(MD5_CTX *ctx);\nextern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);\nextern void MD5_Final(unsigned char *result, MD5_CTX *ctx);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/vfs/vfs.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation.h).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#ifndef __LIBRETRO_SDK_VFS_H\n#define __LIBRETRO_SDK_VFS_H\n\n#include <retro_common_api.h>\n#include <boolean.h>\n#include <stdint.h>\n\n#ifdef RARCH_INTERNAL\n#ifndef VFS_FRONTEND\n#define VFS_FRONTEND\n#endif\n#endif\n\nRETRO_BEGIN_DECLS\n\n#ifdef _WIN32\ntypedef void* HANDLE;\n#endif\n\n#ifdef HAVE_CDROM\ntypedef struct\n{\n   int64_t byte_pos;\n   char *cue_buf;\n   size_t cue_len;\n   unsigned cur_lba;\n   unsigned last_frame_lba;\n   unsigned char cur_min;\n   unsigned char cur_sec;\n   unsigned char cur_frame;\n   unsigned char cur_track;\n   unsigned char last_frame[2352];\n   char drive;\n   bool last_frame_valid;\n} vfs_cdrom_t;\n#endif\n\nenum vfs_scheme\n{\n   VFS_SCHEME_NONE = 0,\n   VFS_SCHEME_CDROM,\n   VFS_SCHEME_SAF,\n   VFS_SCHEME_SMB\n};\n\n#if !(defined(__WINRT__) && defined(__cplusplus_winrt))\n#ifdef VFS_FRONTEND\nstruct retro_vfs_file_handle\n#else\nstruct libretro_vfs_implementation_file\n#endif\n{\n#ifdef HAVE_CDROM\n   vfs_cdrom_t cdrom; /* int64_t alignment */\n#endif\n   int64_t size;\n   uint64_t mappos;\n   uint64_t mapsize;\n   FILE *fp;\n#ifdef _WIN32\n   HANDLE fh;\n#endif\n   char *buf;\n   char* orig_path;\n   uint8_t *mapped;\n   int fd;\n   unsigned hints;\n   enum vfs_scheme scheme;\n#ifdef HAVE_SMBCLIENT\n   intptr_t smb_fh;\n   intptr_t smb_ctx;\n#endif\n};\n#endif\n\n/* Replace the following symbol with something appropriate\n * to signify the file is being compiled for a front end instead of a core.\n * This allows the same code to act as reference implementation\n * for VFS and as fallbacks for when the front end does not provide VFS functionality.\n */\n\n#ifdef VFS_FRONTEND\ntypedef struct retro_vfs_file_handle libretro_vfs_implementation_file;\n#else\ntypedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;\n#endif\n\n#ifdef VFS_FRONTEND\ntypedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;\n#else\ntypedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;\n#endif\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/vfs/vfs_implementation.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation.h).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H\n#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <libretro.h>\n#include <retro_environment.h>\n#include <vfs/vfs.h>\n\nRETRO_BEGIN_DECLS\n\nlibretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);\n\nint retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);\n\nint retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);\n\nint64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);\n\nint64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);\n\nint64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);\n\nint64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);\n\nint64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);\n\nint64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);\n\nint retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);\n\nint retro_vfs_file_remove_impl(const char *path);\n\nint retro_vfs_file_rename_impl(const char *old_path, const char *new_path);\n\nconst char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);\n\nint retro_vfs_stat_impl(const char *path, int32_t *size);\n\nint retro_vfs_stat_64_impl(const char *path, int64_t *size);\n\nint retro_vfs_mkdir_impl(const char *dir);\n\nlibretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);\n\nbool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);\n\nconst char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);\n\nbool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);\n\nint retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);\n\n#ifdef __WINRT__\n\nvoid uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);\n\n#endif\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/vfs/vfs_implementation_cdrom.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (vfs_implementation_cdrom.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H\n#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_CDROM_H\n\n#include <vfs/vfs.h>\n#include <cdrom/cdrom.h>\n\nRETRO_BEGIN_DECLS\n\nint64_t retro_vfs_file_seek_cdrom(libretro_vfs_implementation_file *stream, int64_t offset, int whence);\n\nvoid retro_vfs_file_open_cdrom(\n      libretro_vfs_implementation_file *stream,\n      const char *path, unsigned mode, unsigned hints);\n\nint retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream);\n\nint64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream);\n\nint64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,\n      void *s, uint64_t len);\n\nint retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream);\n\nconst cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void);\n\nconst vfs_cdrom_t* retro_vfs_file_get_cdrom_position(const libretro_vfs_implementation_file *stream);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/vfs/vfs_implementation_saf.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation_saf.h).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_SAF_H\n#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_SAF_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <jni.h>\n#include <libretro.h>\n#include <retro_environment.h>\n#include <vfs/vfs.h>\n#include <vfs/vfs_implementation.h>\n\nRETRO_BEGIN_DECLS\n\ntypedef struct libretro_vfs_implementation_saf_dir\n{\n   jobject directory_object;\n   jstring dirent_name_object;\n   const char *dirent_name;\n   bool dirent_is_dir;\n} libretro_vfs_implementation_saf_dir;\n\nstruct libretro_vfs_implementation_saf_path_split_result\n{\n   char *tree;\n   char *path;\n};\n\n/*\n * Initialize this VFS backend. This must be called prior to using any of the VFS operations provided by this backend.\n * get_jni_env should be a function that returns the JNIEnv for the current thread.\n * activity_object should be the current Android android.app.Activity.\n */\nbool retro_vfs_init_saf(JNIEnv *(*get_jni_env)(void), jobject activity_object);\n\n/*\n * Deinitialize this VFS backend.\n */\nbool retro_vfs_deinit_saf(void);\n\n/*\n * Split a serialized \"saf://\" path string into tree and path components for use with this backend.\n * Returns true if successful or false if not.\n * The results will be returned in `out` and must be freed by the caller.\n */\nbool retro_vfs_path_split_saf(struct libretro_vfs_implementation_saf_path_split_result *out, const char *serialized_path);\n\n/*\n * Join the tree and path components into a single serialized \"saf://\" path string.\n * Returns the serialized path if successful or NULL if not.\n * The returned path must be freed by the caller.\n */\nchar *retro_vfs_path_join_saf(const char *tree, const char *path);\n\n/*\n * Split a \"content://\" document URI returned by the Android Storage Access Framework into tree and path components for use with this backend.\n * Returns true if successful or false if not.\n * The results will be returned in `out` and must be freed by the caller.\n */\nbool retro_vfs_path_split_content_saf(struct libretro_vfs_implementation_saf_path_split_result *out, const char *content_uri);\n\n/*\n * Open a file, returning its file descriptor if successful or -1 if not.\n * The file descriptor can be operated on using the POSIX file system API (`read()`, `write()`, `lseek()`, `close()`, etc).\n * You can also turn the file descriptor into a `FILE *` by calling `fdopen()` on it.\n */\nint retro_vfs_file_open_saf(const char *tree, const char *path, unsigned mode);\n\nint retro_vfs_file_remove_saf(const char *tree, const char *path);\n\nint retro_vfs_file_rename_saf(const char *old_tree, const char *old_path, const char *new_tree, const char *new_path);\n\nint retro_vfs_stat_saf(const char *tree, const char *path, int64_t *size);\n\nint retro_vfs_mkdir_saf(const char *tree, const char *dir);\n\nlibretro_vfs_implementation_saf_dir *retro_vfs_opendir_saf(const char *tree, const char *dir, bool include_hidden);\n\nbool retro_vfs_readdir_saf(libretro_vfs_implementation_saf_dir *dirstream);\n\nconst char *retro_vfs_dirent_get_name_saf(libretro_vfs_implementation_saf_dir *dirstream);\n\nbool retro_vfs_dirent_is_dir_saf(libretro_vfs_implementation_saf_dir *dirstream);\n\nint retro_vfs_closedir_saf(libretro_vfs_implementation_saf_dir *dirstream);\n\nRETRO_END_DECLS\n\n#endif\n"
  },
  {
    "path": "include/vulkan/vulkan_symbol_wrapper.h",
    "content": "\n/* This header is autogenerated by vulkan_loader_generator.py */\n#ifndef VULKAN_SYMBOL_WRAPPER_H\n#define VULKAN_SYMBOL_WRAPPER_H\n#define VK_NO_PROTOTYPES\n#include <vulkan/vulkan.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern PFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;\n#define vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance\nextern PFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;\n#define vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion\nextern PFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;\n#define vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties\nextern PFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;\n#define vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties\nextern PFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;\n#define vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance\nextern PFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;\n#define vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices\nextern PFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;\n#define vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures\nextern PFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;\n#define vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties\nextern PFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;\n#define vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties\nextern PFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;\n#define vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties\nextern PFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;\n#define vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties\nextern PFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;\n#define vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties\nextern PFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;\n#define vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr\nextern PFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;\n#define vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice\nextern PFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;\n#define vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice\nextern PFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;\n#define vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties\nextern PFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;\n#define vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties\nextern PFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;\n#define vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue\nextern PFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;\n#define vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit\nextern PFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;\n#define vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle\nextern PFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;\n#define vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle\nextern PFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;\n#define vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory\nextern PFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;\n#define vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory\nextern PFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;\n#define vkMapMemory vulkan_symbol_wrapper_vkMapMemory\nextern PFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;\n#define vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory\nextern PFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;\n#define vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges\nextern PFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;\n#define vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges\nextern PFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;\n#define vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment\nextern PFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;\n#define vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory\nextern PFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;\n#define vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory\nextern PFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;\n#define vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements\nextern PFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;\n#define vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements\nextern PFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;\n#define vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements\nextern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;\n#define vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties\nextern PFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;\n#define vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse\nextern PFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;\n#define vkCreateFence vulkan_symbol_wrapper_vkCreateFence\nextern PFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;\n#define vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence\nextern PFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;\n#define vkResetFences vulkan_symbol_wrapper_vkResetFences\nextern PFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;\n#define vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus\nextern PFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;\n#define vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences\nextern PFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;\n#define vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore\nextern PFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;\n#define vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore\nextern PFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;\n#define vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent\nextern PFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;\n#define vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent\nextern PFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;\n#define vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus\nextern PFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;\n#define vkSetEvent vulkan_symbol_wrapper_vkSetEvent\nextern PFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;\n#define vkResetEvent vulkan_symbol_wrapper_vkResetEvent\nextern PFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;\n#define vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool\nextern PFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;\n#define vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool\nextern PFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;\n#define vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults\nextern PFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;\n#define vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer\nextern PFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;\n#define vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer\nextern PFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;\n#define vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView\nextern PFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;\n#define vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView\nextern PFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;\n#define vkCreateImage vulkan_symbol_wrapper_vkCreateImage\nextern PFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;\n#define vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage\nextern PFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;\n#define vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout\nextern PFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;\n#define vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView\nextern PFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;\n#define vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView\nextern PFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;\n#define vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule\nextern PFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;\n#define vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule\nextern PFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;\n#define vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache\nextern PFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;\n#define vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache\nextern PFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;\n#define vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData\nextern PFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;\n#define vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches\nextern PFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;\n#define vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines\nextern PFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;\n#define vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines\nextern PFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;\n#define vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline\nextern PFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;\n#define vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout\nextern PFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;\n#define vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout\nextern PFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;\n#define vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler\nextern PFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;\n#define vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler\nextern PFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;\n#define vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout\nextern PFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;\n#define vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout\nextern PFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;\n#define vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool\nextern PFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;\n#define vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool\nextern PFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;\n#define vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool\nextern PFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;\n#define vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets\nextern PFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;\n#define vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets\nextern PFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;\n#define vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets\nextern PFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;\n#define vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer\nextern PFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;\n#define vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer\nextern PFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;\n#define vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass\nextern PFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;\n#define vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass\nextern PFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;\n#define vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity\nextern PFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;\n#define vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool\nextern PFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;\n#define vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool\nextern PFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;\n#define vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool\nextern PFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;\n#define vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers\nextern PFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;\n#define vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers\nextern PFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;\n#define vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer\nextern PFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;\n#define vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer\nextern PFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;\n#define vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer\nextern PFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;\n#define vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline\nextern PFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;\n#define vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport\nextern PFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;\n#define vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor\nextern PFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;\n#define vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth\nextern PFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;\n#define vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias\nextern PFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;\n#define vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants\nextern PFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;\n#define vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds\nextern PFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;\n#define vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask\nextern PFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;\n#define vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask\nextern PFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;\n#define vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference\nextern PFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;\n#define vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets\nextern PFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;\n#define vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer\nextern PFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;\n#define vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers\nextern PFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;\n#define vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw\nextern PFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;\n#define vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed\nextern PFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;\n#define vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect\nextern PFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;\n#define vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect\nextern PFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;\n#define vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch\nextern PFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;\n#define vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect\nextern PFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;\n#define vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer\nextern PFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;\n#define vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage\nextern PFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;\n#define vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage\nextern PFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;\n#define vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage\nextern PFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;\n#define vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer\nextern PFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;\n#define vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer\nextern PFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;\n#define vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer\nextern PFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;\n#define vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage\nextern PFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;\n#define vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage\nextern PFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;\n#define vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments\nextern PFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;\n#define vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage\nextern PFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;\n#define vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent\nextern PFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;\n#define vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent\nextern PFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;\n#define vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents\nextern PFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;\n#define vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier\nextern PFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;\n#define vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery\nextern PFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;\n#define vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery\nextern PFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;\n#define vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool\nextern PFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;\n#define vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp\nextern PFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;\n#define vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults\nextern PFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;\n#define vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants\nextern PFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;\n#define vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass\nextern PFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;\n#define vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass\nextern PFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;\n#define vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass\nextern PFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;\n#define vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands\nextern PFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;\n#define vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR\nextern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;\n#define vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR\nextern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;\n#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR\nextern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;\n#define vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR\nextern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;\n#define vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR\nextern PFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;\n#define vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR\nextern PFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;\n#define vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR\nextern PFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;\n#define vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR\nextern PFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;\n#define vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR\nextern PFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;\n#define vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR\nextern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;\n#define vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR\nextern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;\n#define vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR\nextern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;\n#define vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR\nextern PFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;\n#define vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR\nextern PFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;\n#define vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR\nextern PFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;\n#define vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR\nextern PFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;\n#define vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR\nextern PFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;\n#define vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR\n\nextern PFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;\n#define vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT\nextern PFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;\n#define vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT\nextern PFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;\n#define vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT\n\nvoid vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr);\nPFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void);\nVkBool32 vulkan_symbol_wrapper_load_global_symbols(void);\nVkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance);\nVkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance);\nVkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device);\nVkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol);\nVkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol);\n\n#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, name, pfn) vulkan_symbol_wrapper_load_instance_symbol(instance, name, (PFN_vkVoidFunction*) &(pfn))\n#define VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, name) vulkan_symbol_wrapper_load_instance_symbol(instance, #name, (PFN_vkVoidFunction*) & name)\n#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, name, pfn) vulkan_symbol_wrapper_load_device_symbol(device, name, (PFN_vkVoidFunction*) &(pfn))\n#define VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, name) vulkan_symbol_wrapper_load_device_symbol(device, #name, (PFN_vkVoidFunction*) & name)\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "libco/aarch64.c",
    "content": "/*\n  libco.aarch64 (2017-06-26)\n  author: webgeek1234\n  license: public domain\n*/\n\n#define LIBCO_C\n#include \"libco.h\"\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#ifndef __APPLE__\n#include <malloc.h>\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic thread_local uint64_t co_active_buffer[64];\nstatic thread_local cothread_t co_active_handle;\n\nasm (\n      \".globl co_switch_aarch64\\n\"\n      \".globl _co_switch_aarch64\\n\"\n      \"co_switch_aarch64:\\n\"\n      \"_co_switch_aarch64:\\n\"\n      \"  stp x8,  x9,  [x1]\\n\"\n      \"  stp x10, x11, [x1, #16]\\n\"\n      \"  stp x12, x13, [x1, #32]\\n\"\n      \"  stp x14, x15, [x1, #48]\\n\"\n      \"  str x19, [x1, #72]\\n\"\n      \"  stp x20, x21, [x1, #80]\\n\"\n      \"  stp x22, x23, [x1, #96]\\n\"\n      \"  stp x24, x25, [x1, #112]\\n\"\n      \"  stp x26, x27, [x1, #128]\\n\"\n      \"  stp x28, x29, [x1, #144]\\n\"\n      \"  mov x16, sp\\n\"\n      \"  stp x16, x30, [x1, #160]\\n\"\n\n      \"  ldp x8,  x9,  [x0]\\n\"\n      \"  ldp x10, x11, [x0, #16]\\n\"\n      \"  ldp x12, x13, [x0, #32]\\n\"\n      \"  ldp x14, x15, [x0, #48]\\n\"\n      \"  ldr x19, [x0, #72]\\n\"\n      \"  ldp x20, x21, [x0, #80]\\n\"\n      \"  ldp x22, x23, [x0, #96]\\n\"\n      \"  ldp x24, x25, [x0, #112]\\n\"\n      \"  ldp x26, x27, [x0, #128]\\n\"\n      \"  ldp x28, x29, [x0, #144]\\n\"\n      \"  ldp x16, x17, [x0, #160]\\n\"\n      \"  mov sp, x16\\n\"\n      \"  br x17\\n\"\n    );\n\n/* ASM */\nvoid co_switch_aarch64(cothread_t handle, cothread_t current);\n\nstatic void crash(void)\n{\n   /* Called only if cothread_t entrypoint returns. */\n   assert(0);\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void))\n{\n\tuint64_t *ptr     = NULL;\n   cothread_t handle = 0;\n   size              = (size + 1023) & ~1023;\n#if HAVE_POSIX_MEMALIGN >= 1\n   if (posix_memalign(&handle, 1024, size + 512) < 0)\n      return 0;\n#else\n   handle            = memalign(1024, size + 512);\n#endif\n\n   if (!handle)\n      return handle;\n\n   ptr     = (uint64_t*)handle;\n   /* Non-volatiles.  */\n   ptr[0]  = 0; /* x8  */\n   ptr[1]  = 0; /* x9  */\n   ptr[2]  = 0; /* x10 */\n   ptr[3]  = 0; /* x11 */\n   ptr[4]  = 0; /* x12 */\n   ptr[5]  = 0; /* x13 */\n   ptr[6]  = 0; /* x14 */\n   ptr[7]  = 0; /* x15 */\n   ptr[8]  = 0; /* padding */\n   ptr[9]  = 0; /* x19 */\n   ptr[10] = 0; /* x20 */\n   ptr[11] = 0; /* x21 */\n   ptr[12] = 0; /* x22 */\n   ptr[13] = 0; /* x23 */\n   ptr[14] = 0; /* x24 */\n   ptr[15] = 0; /* x25 */\n   ptr[16] = 0; /* x26 */\n   ptr[17] = 0; /* x27 */\n   ptr[18] = 0; /* x28 */\n   ptr[20] = (uintptr_t)ptr + size + 512 - 16; /* x30, stack pointer */\n   ptr[19] = ptr[20]; /* x29, frame pointer */\n   ptr[21] = (uintptr_t)entrypoint; /* PC (link register x31 gets saved here). */\n   return handle;\n}\n\ncothread_t co_active(void)\n{\n   if (!co_active_handle)\n      co_active_handle = co_active_buffer;\n   return co_active_handle;\n}\n\nvoid co_delete(cothread_t handle)\n{\n   free(handle);\n}\n\nvoid co_switch(cothread_t handle)\n{\n   cothread_t co_previous_handle = co_active();\n   co_switch_aarch64(co_active_handle = handle, co_previous_handle);\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/amd64.c",
    "content": "/*\n  libco.amd64 (2009-10-12)\n  author: byuu\n  license: public domain\n*/\n\n#define LIBCO_C\n#include <libco.h>\n#include <assert.h>\n#include <stdlib.h>\n\n#if defined(__GNUC__) && !defined(_WIN32) && !defined(__cplusplus)\n#define CO_USE_INLINE_ASM\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic thread_local long long co_active_buffer[64];\nstatic thread_local cothread_t co_active_handle = 0;\n#ifndef CO_USE_INLINE_ASM\nstatic void (*co_swap)(cothread_t, cothread_t)  = 0;\n#endif\n\n#ifdef _WIN32\n/* ABI: Win64 */\n  /* On windows handle is allocated by malloc and there it's guaranteed to\n     have at least 16-byte alignment. Hence we don't need to align\n     it in order to use movaps.  */\nstatic unsigned char co_swap_function[] = {\n    0x48, 0x89, 0x22,              /* mov [rdx],rsp          */\n    0x48, 0x8b, 0x21,              /* mov rsp,[rcx]          */\n    0x58,                          /* pop rax                */\n    0x48, 0x89, 0x6a, 0x08,        /* mov [rdx+ 8],rbp       */\n    0x48, 0x89, 0x72, 0x10,        /* mov [rdx+16],rsi       */\n    0x48, 0x89, 0x7a, 0x18,        /* mov [rdx+24],rdi       */\n    0x48, 0x89, 0x5a, 0x20,        /* mov [rdx+32],rbx       */\n    0x4c, 0x89, 0x62, 0x28,        /* mov [rdx+40],r12       */\n    0x4c, 0x89, 0x6a, 0x30,        /* mov [rdx+48],r13       */\n    0x4c, 0x89, 0x72, 0x38,        /* mov [rdx+56],r14       */\n    0x4c, 0x89, 0x7a, 0x40,        /* mov [rdx+64],r15       */\n  #if !defined(LIBCO_NO_SSE)\n    0x0f, 0x29, 0x72, 0x50,        /* movaps [rdx+ 80],xmm6  */\n    0x0f, 0x29, 0x7a, 0x60,        /* movaps [rdx+ 96],xmm7  */\n    0x44, 0x0f, 0x29, 0x42, 0x70,  /* movaps [rdx+112],xmm8  */\n    0x48, 0x83, 0xc2, 0x70,        /* add rdx,112            */\n    0x44, 0x0f, 0x29, 0x4a, 0x10,  /* movaps [rdx+ 16],xmm9  */\n    0x44, 0x0f, 0x29, 0x52, 0x20,  /* movaps [rdx+ 32],xmm10 */\n    0x44, 0x0f, 0x29, 0x5a, 0x30,  /* movaps [rdx+ 48],xmm11 */\n    0x44, 0x0f, 0x29, 0x62, 0x40,  /* movaps [rdx+ 64],xmm12 */\n    0x44, 0x0f, 0x29, 0x6a, 0x50,  /* movaps [rdx+ 80],xmm13 */\n    0x44, 0x0f, 0x29, 0x72, 0x60,  /* movaps [rdx+ 96],xmm14 */\n    0x44, 0x0f, 0x29, 0x7a, 0x70,  /* movaps [rdx+112],xmm15 */\n  #endif\n    0x48, 0x8b, 0x69, 0x08,        /* mov rbp,[rcx+ 8]       */\n    0x48, 0x8b, 0x71, 0x10,        /* mov rsi,[rcx+16]       */\n    0x48, 0x8b, 0x79, 0x18,        /* mov rdi,[rcx+24]       */\n    0x48, 0x8b, 0x59, 0x20,        /* mov rbx,[rcx+32]       */\n    0x4c, 0x8b, 0x61, 0x28,        /* mov r12,[rcx+40]       */\n    0x4c, 0x8b, 0x69, 0x30,        /* mov r13,[rcx+48]       */\n    0x4c, 0x8b, 0x71, 0x38,        /* mov r14,[rcx+56]       */\n    0x4c, 0x8b, 0x79, 0x40,        /* mov r15,[rcx+64]       */\n  #if !defined(LIBCO_NO_SSE)\n    0x0f, 0x28, 0x71, 0x50,        /* movaps xmm6, [rcx+ 80] */\n    0x0f, 0x28, 0x79, 0x60,        /* movaps xmm7, [rcx+ 96] */\n    0x44, 0x0f, 0x28, 0x41, 0x70,  /* movaps xmm8, [rcx+112] */\n    0x48, 0x83, 0xc1, 0x70,        /* add rcx,112            */\n    0x44, 0x0f, 0x28, 0x49, 0x10,  /* movaps xmm9, [rcx+ 16] */\n    0x44, 0x0f, 0x28, 0x51, 0x20,  /* movaps xmm10,[rcx+ 32] */\n    0x44, 0x0f, 0x28, 0x59, 0x30,  /* movaps xmm11,[rcx+ 48] */\n    0x44, 0x0f, 0x28, 0x61, 0x40,  /* movaps xmm12,[rcx+ 64] */\n    0x44, 0x0f, 0x28, 0x69, 0x50,  /* movaps xmm13,[rcx+ 80] */\n    0x44, 0x0f, 0x28, 0x71, 0x60,  /* movaps xmm14,[rcx+ 96] */\n    0x44, 0x0f, 0x28, 0x79, 0x70,  /* movaps xmm15,[rcx+112] */\n  #endif\n    0xff, 0xe0,                    /* jmp rax                */\n};\n\n#include <windows.h>\n\nstatic void co_init(void)\n{\n   DWORD old_privileges;\n   VirtualProtect(co_swap_function,\n         sizeof(co_swap_function), PAGE_EXECUTE_READWRITE, &old_privileges);\n}\n#else\n/* ABI: SystemV */\n#ifndef CO_USE_INLINE_ASM\nstatic unsigned char co_swap_function[] = {\n  0x48, 0x89, 0x26,                                 /* mov    [rsi],rsp      */\n  0x48, 0x8b, 0x27,                                 /* mov    rsp,[rdi]      */\n  0x58,                                             /* pop    rax            */\n  0x48, 0x89, 0x6e, 0x08,                           /* mov    [rsi+0x08],rbp */\n  0x48, 0x89, 0x5e, 0x10,                           /* mov    [rsi+0x10],rbx */\n  0x4c, 0x89, 0x66, 0x18,                           /* mov    [rsi+0x18],r12 */\n  0x4c, 0x89, 0x6e, 0x20,                           /* mov    [rsi+0x20],r13 */\n  0x4c, 0x89, 0x76, 0x28,                           /* mov    [rsi+0x28],r14 */\n  0x4c, 0x89, 0x7e, 0x30,                           /* mov    [rsi+0x30],r15 */\n  0x48, 0x8b, 0x6f, 0x08,                           /* mov    rbp,[rdi+0x08] */\n  0x48, 0x8b, 0x5f, 0x10,                           /* mov    rbx,[rdi+0x10] */\n  0x4c, 0x8b, 0x67, 0x18,                           /* mov    r12,[rdi+0x18] */\n  0x4c, 0x8b, 0x6f, 0x20,                           /* mov    r13,[rdi+0x20] */\n  0x4c, 0x8b, 0x77, 0x28,                           /* mov    r14,[rdi+0x28] */\n  0x4c, 0x8b, 0x7f, 0x30,                           /* mov    r15,[rdi+0x30] */\n  0xff, 0xe0,                                       /* jmp    rax            */\n};\n\n#include <unistd.h>\n#include <sys/mman.h>\n\nstatic void co_init(void)\n{\n   unsigned long long addr = (unsigned long long)co_swap_function;\n   unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));\n   unsigned long long size = (addr - base) + sizeof(co_swap_function);\n   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);\n}\n#else\nstatic void co_init(void) {}\n#endif\n#endif\n\nstatic void crash(void)\n{\n  assert(0); /* called only if cothread_t entrypoint returns */\n}\n\ncothread_t co_active(void)\n{\n  if (!co_active_handle)\n     co_active_handle = &co_active_buffer;\n  return co_active_handle;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void))\n{\n   cothread_t handle;\n#ifndef CO_USE_INLINE_ASM\n   if (!co_swap)\n   {\n      co_init();\n      co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;\n   }\n#endif\n\n   if (!co_active_handle)\n      co_active_handle = &co_active_buffer;\n   size += 512; /* allocate additional space for storage */\n   size &= ~15; /* align stack to 16-byte boundary */\n\n#ifdef __GENODE__\n   if ((handle = (cothread_t)genode_alloc_secondary_stack(size)))\n   {\n      long long *p        = (long long*)((char*)handle); /* OS returns top of stack */\n      *--p                = (long long)crash;            /* crash if entrypoint returns */\n      *--p                = (long long)entrypoint;       /* start of function */\n      *(long long*)handle = (long long)p;                /* stack pointer */\n   }\n#else\n   if ((handle = (cothread_t)malloc(size)))\n   {\n      long long *p = (long long*)((char*)handle + size); /* seek to top of stack */\n      *--p = (long long)crash;                           /* crash if entrypoint returns */\n      *--p = (long long)entrypoint;                      /* start of function */\n      *(long long*)handle = (long long)p;                /* stack pointer */\n   }\n#endif\n\n   return handle;\n}\n\nvoid co_delete(cothread_t handle)\n{\n#ifdef __GENODE__\n   genode_free_secondary_stack(handle);\n#else\n   free(handle);\n#endif\n}\n\n#ifndef CO_USE_INLINE_ASM\nvoid co_switch(cothread_t handle)\n{\n  register cothread_t co_previous_handle = co_active_handle;\n  co_swap(co_active_handle = handle, co_previous_handle);\n}\n#else\n#ifdef __APPLE__\n#define ASM_PREFIX \"_\"\n#else\n#define ASM_PREFIX \"\"\n#endif\n__asm__(\n\".intel_syntax noprefix         \\n\"\n\".globl \" ASM_PREFIX \"co_switch              \\n\"\nASM_PREFIX \"co_switch:                     \\n\"\n\"mov rsi, [rip+\" ASM_PREFIX \"co_active_handle]\\n\"\n\"mov [rsi],rsp                  \\n\"\n\"mov [rsi+0x08],rbp             \\n\"\n\"mov [rsi+0x10],rbx             \\n\"\n\"mov [rsi+0x18],r12             \\n\"\n\"mov [rsi+0x20],r13             \\n\"\n\"mov [rsi+0x28],r14             \\n\"\n\"mov [rsi+0x30],r15             \\n\"\n\"mov [rip+\" ASM_PREFIX \"co_active_handle], rdi\\n\"\n\"mov rsp,[rdi]                  \\n\"\n\"mov rbp,[rdi+0x08]             \\n\"\n\"mov rbx,[rdi+0x10]             \\n\"\n\"mov r12,[rdi+0x18]             \\n\"\n\"mov r13,[rdi+0x20]             \\n\"\n\"mov r14,[rdi+0x28]             \\n\"\n\"mov r15,[rdi+0x30]             \\n\"\n\"ret                            \\n\"\n\".att_syntax                    \\n\"\n);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/armeabi.c",
    "content": "/*\n  libco.armeabi (2013-04-05)\n  author: Themaister\n  license: public domain\n*/\n\n#define LIBCO_C\n#include <libco.h>\n#include <assert.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#ifndef __APPLE__\n#include <malloc.h>\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic thread_local uint32_t co_active_buffer[64];\nstatic thread_local cothread_t co_active_handle;\n\n__asm__ (\n#if defined(__thumb2__)\n      \".align 2\\n\"\n      \".globl co_switch_arm\\n\"\n      \".globl _co_switch_arm\\n\"\n      \".thumb\\n\"\n      \".thumb_func\\n\"\n      \".type   co_switch_arm, %function\\n\"\n      \".type   _co_switch_arm, %function\\n\"\n      \"co_switch_arm:\\n\"\n      \"_co_switch_arm:\\n\"\n      \" mov r3, sp\\n\"\n      \" stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\\n\"\n      \" stmia r1!, {r3, lr}\\n\"\n      \" ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\\n\"\n      \" ldmfd r0!, { r3 }\\n\"\n      \" mov sp, r3\\n\"\n      \" ldmfd r0!, { r3 }\\n\"\n      \" mov pc, r3\\n\"\n#else\n      \".arm\\n\"\n      \".align 4\\n\"\n      \".globl co_switch_arm\\n\"\n      \".globl _co_switch_arm\\n\"\n      \"co_switch_arm:\\n\"\n      \"_co_switch_arm:\\n\"\n      \"  stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\\n\"\n      \"  ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\\n\"\n#endif\n    );\n\n/* ASM */\nvoid co_switch_arm(cothread_t handle, cothread_t current);\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void))\n{\n   uint32_t *ptr     = NULL;\n   cothread_t handle = 0;\n   size              = (size + 1023) & ~1023;\n#if defined(__APPLE__) || HAVE_POSIX_MEMALIGN >= 1\n   if (posix_memalign(&handle, 1024, size + 256) < 0)\n      return 0;\n#else\n   handle = memalign(1024, size + 256);\n#endif\n\n   if (!handle)\n      return handle;\n\n   ptr    = (uint32_t*)handle;\n   /* Non-volatiles.  */\n   ptr[0] = 0; /* r4  */\n   ptr[1] = 0; /* r5  */\n   ptr[2] = 0; /* r6  */\n   ptr[3] = 0; /* r7  */\n   ptr[4] = 0; /* r8  */\n   ptr[5] = 0; /* r9  */\n   ptr[6] = 0; /* r10 */\n   ptr[7] = 0; /* r11 */\n   /* Align stack to 64-bit */\n   ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */\n   ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */\n   return handle;\n}\n\ncothread_t co_active(void)\n{\n   if (!co_active_handle)\n      co_active_handle = co_active_buffer;\n   return co_active_handle;\n}\n\nvoid co_delete(cothread_t handle)\n{\n   free(handle);\n}\n\nvoid co_switch(cothread_t handle)\n{\n   cothread_t co_previous_handle = co_active();\n   co_switch_arm(co_active_handle = handle, co_previous_handle);\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/fiber.c",
    "content": "/*\n  libco.win (2008-01-28)\n  authors: Nach, byuu\n  license: public domain\n*/\n\n#define LIBCO_C\n#include <libco.h>\n#define WINVER 0x0400\n#define _WIN32_WINNT 0x0400\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic thread_local cothread_t co_active_ = 0;\n\nstatic void __stdcall co_thunk(void *coentry)\n{\n   ((void (*)(void))coentry)();\n}\n\ncothread_t co_active(void)\n{\n   if (!co_active_)\n   {\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);\n#else\n      ConvertThreadToFiber(0);\n#endif\n      co_active_ = GetCurrentFiber();\n   }\n   return co_active_;\n}\n\ncothread_t co_create(unsigned int heapsize, void (*coentry)(void))\n{\n   if (!co_active_)\n   {\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n      ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);\n#else\n      ConvertThreadToFiber(0);\n#endif\n      co_active_ = GetCurrentFiber();\n   }\n\n#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n   return (cothread_t)CreateFiberEx(heapsize, heapsize, FIBER_FLAG_FLOAT_SWITCH, co_thunk, (void*)coentry);\n#else\n   return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);\n#endif\n}\n\nvoid co_delete(cothread_t cothread)\n{\n   DeleteFiber(cothread);\n}\n\nvoid co_switch(cothread_t cothread)\n{\n   co_active_ = cothread;\n   SwitchToFiber(cothread);\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/genode.cpp",
    "content": "/*\n  libco.genode_secondary_stack (2018-09-15)\n  author: Emery Hemingway\n  license: public domain\n*/\n\n/* Genode include */\n#include <base/thread.h>\n\n/* Libco include */\n#include <libco.h>\n\nextern \"C\"\nvoid *genode_alloc_secondary_stack(unsigned long stack_size)\n{\n\ttry\n   {\n\t\treturn Genode::Thread::myself()->alloc_secondary_stack(\"libco\", stack_size);\n   }\n\tcatch (...)\n   {\n\t\tGenode::error(\"libco: failed to allocate \", stack_size, \" byte secondary stack\");\n\t\treturn nullptr;\n\t}\n}\n\nextern \"C\"\nvoid genode_free_secondary_stack(void *stack)\n{\n\tGenode::Thread::myself()->free_secondary_stack(stack);\n}\n"
  },
  {
    "path": "libco/libco.c",
    "content": "/*\n  libco\n  auto-selection module\n  license: public domain\n*/\n\n#ifdef __GENODE__\nvoid *genode_alloc_secondary_stack(unsigned long stack_size);\nvoid genode_free_secondary_stack(void *stack);\n#endif\n\n#if defined _MSC_VER\n  #include <Windows.h>\n  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n    #include \"fiber.c\"\n  #elif defined _M_IX86\n    #include \"x86.c\"\n  #elif defined _M_AMD64\n    #include \"amd64.c\"\n  #else\n    #include \"fiber.c\"\n  #endif\n#elif defined __GNUC__\n  #if defined __i386__\n    #include \"x86.c\"\n  #elif defined __amd64__\n    #include \"amd64.c\"\n  #elif defined _ARCH_PPC\n    #include \"ppc.c\"\n  #elif defined(__aarch64__)\n    #include \"aarch64.c\"\n  #elif defined(PS2)\n    #include \"ps2.c\"\n  #elif defined(PSP)\n    #include \"psp1.c\"\n  #elif defined VITA\n    #include \"scefiber.c\"\n  #elif defined(__ARM_EABI__) || defined(__arm__)\n    #include \"armeabi.c\"\n  #else\n    #include \"sjlj.c\"\n  #endif\n#else\n  #error \"libco: unsupported processor, compiler or operating system\"\n#endif\n"
  },
  {
    "path": "libco/ppc.c",
    "content": "/*\n  libco.ppc (2010-10-17)\n  author: blargg\n  license: public domain\n*/\n\n/* PowerPC 32/64 using embedded or external asm, with optional\nfloating-point and AltiVec save/restore */\n\n#define LIBCO_C\n#include <libco.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)\n\n#if LIBCO_MPROTECT\n#include <unistd.h>\n#include <sys/mman.h>\n#endif\n\n/* State format (offsets in 32-bit words)\n\n+0\tPointer to swap code\n\tRest of function descriptor for entry function\n+8\tPC\n+10\tSP\n\tSpecial regs\n\tGPRs\n\tFPRs\n\tVRs\n\tstack\n*/\n\nenum { state_size  = 1024 };\nenum { above_stack = 2048 };\nenum { stack_align = 256  };\n\nstatic thread_local cothread_t co_active_handle = 0;\n\n/**** Determine environment ****/\n\n#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)\n\n/* Whether function calls are indirect through a descriptor,\nor are directly to function */\n#ifndef LIBCO_PPCDESC\n\t#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)\n\t\t#define LIBCO_PPCDESC 1\n\t#endif\n#endif\n\n/* Whether the code should be inline asm stored in .text, or the original\narray buffer */\n#ifndef LIBCO_STATIC_TEXT\n   #if defined(WIIU)\n      #define LIBCO_STATIC_TEXT 1\n   #endif\n#endif\n\n#ifdef LIBCO_PPC_ASM\n\n\t#ifdef __cplusplus\n\t\textern \"C\"\n\t#endif\n\n\t/* Swap code is in ppc.S */\n\tvoid co_swap_asm(cothread_t, cothread_t);\n\t#define CO_SWAP_ASM(x, y) co_swap_asm(x, y)\n\n#elif LIBCO_STATIC_TEXT\n\nasm(\n\t\".globl libco_ppc_code\\n\"\n\t\"libco_ppc_code:\\n\"\n#if LIBCO_PPC64\n\t\"mfcr    %r8\\n\"\n\t\"std     %r1,40(%r4)\\n\"\n\t\"mflr    %r9\\n\"\n\t\"std     %r14,72(%r4)\\n\"\n\t\"std     %r15,80(%r4)\\n\"\n\t\"std     %r16,88(%r4)\\n\"\n\t\"std     %r17,96(%r4)\\n\"\n\t\"std     %r18,104(%r4)\\n\"\n\t\"std     %r19,112(%r4)\\n\"\n\t\"std     %r20,120(%r4)\\n\"\n\t\"std     %r21,128(%r4)\\n\"\n\t\"std     %r22,136(%r4)\\n\"\n\t\"std     %r23,144(%r4)\\n\"\n\t\"std     %r24,152(%r4)\\n\"\n\t\"std     %r25,160(%r4)\\n\"\n\t\"std     %r26,168(%r4)\\n\"\n\t\"std     %r27,176(%r4)\\n\"\n\t\"std     %r28,184(%r4)\\n\"\n\t\"std     %r29,192(%r4)\\n\"\n\t\"std     %r30,200(%r4)\\n\"\n\t\"std     %r31,208(%r4)\\n\"\n\t\"std     %r9,32(%r4)\\n\"\n\t\"ld      %r7,32(%r3)\\n\"\n\t\"ld      %r1,40(%r3)\\n\"\n\t\"bl      1f\\n\"\n\t\"trap\\n\"\n\t\"1:stw     %r8,48(%r4)\\n\"\n\t\"lwz     %r6,48(%r3)\\n\"\n\t\"mtctr   %r7\\n\"\n\t\"ld      %r14,72(%r3)\\n\"\n\t\"ld      %r15,80(%r3)\\n\"\n\t\"ld      %r16,88(%r3)\\n\"\n\t\"ld      %r17,96(%r3)\\n\"\n\t\"ld      %r18,104(%r3)\\n\"\n\t\"ld      %r19,112(%r3)\\n\"\n\t\"ld      %r20,120(%r3)\\n\"\n\t\"ld      %r21,128(%r3)\\n\"\n\t\"ld      %r22,136(%r3)\\n\"\n\t\"ld      %r23,144(%r3)\\n\"\n\t\"ld      %r24,152(%r3)\\n\"\n\t\"ld      %r25,160(%r3)\\n\"\n\t\"ld      %r26,168(%r3)\\n\"\n\t\"ld      %r27,176(%r3)\\n\"\n\t\"ld      %r28,184(%r3)\\n\"\n\t\"ld      %r29,192(%r3)\\n\"\n\t\"ld      %r30,200(%r3)\\n\"\n\t\"ld      %r31,208(%r3)\\n\"\n\t\"mtcr    %r6\\n\"\n#else\n\t\"mfcr    %r8\\n\"\n\t\"stw     %r1,40(%r4)\\n\"\n\t\"mflr    %r9\\n\"\n\t\"stw     %r13,60(%r4)\\n\"\n\t\"stw     %r14,64(%r4)\\n\"\n\t\"stw     %r15,68(%r4)\\n\"\n\t\"stw     %r16,72(%r4)\\n\"\n\t\"stw     %r17,76(%r4)\\n\"\n\t\"stw     %r18,80(%r4)\\n\"\n\t\"stw     %r19,84(%r4)\\n\"\n\t\"stw     %r20,88(%r4)\\n\"\n\t\"stw     %r21,92(%r4)\\n\"\n\t\"stw     %r22,96(%r4)\\n\"\n\t\"stw     %r23,100(%r4)\\n\"\n\t\"stw     %r24,104(%r4)\\n\"\n\t\"stw     %r25,108(%r4)\\n\"\n\t\"stw     %r26,112(%r4)\\n\"\n\t\"stw     %r27,116(%r4)\\n\"\n\t\"stw     %r28,120(%r4)\\n\"\n\t\"stw     %r29,124(%r4)\\n\"\n\t\"stw     %r30,128(%r4)\\n\"\n\t\"stw     %r31,132(%r4)\\n\"\n\t\"stw     %r9,32(%r4)\\n\"\n\t\"lwz     %r7,32(%r3)\\n\"\n\t\"lwz     %r1,40(%r3)\\n\"\n\t\"bl      1f\\n\"\n\t\"trap\\n\"\n\t\"1:stw     %r8,48(%r4)\\n\"\n\t\"lwz     %r6,48(%r3)\\n\"\n\t\"mtctr   %r7\\n\"\n\t\"lwz     %r13,60(%r3)\\n\"\n\t\"lwz     %r14,64(%r3)\\n\"\n\t\"lwz     %r15,68(%r3)\\n\"\n\t\"lwz     %r16,72(%r3)\\n\"\n\t\"lwz     %r17,76(%r3)\\n\"\n\t\"lwz     %r18,80(%r3)\\n\"\n\t\"lwz     %r19,84(%r3)\\n\"\n\t\"lwz     %r20,88(%r3)\\n\"\n\t\"lwz     %r21,92(%r3)\\n\"\n\t\"lwz     %r22,96(%r3)\\n\"\n\t\"lwz     %r23,100(%r3)\\n\"\n\t\"lwz     %r24,104(%r3)\\n\"\n\t\"lwz     %r25,108(%r3)\\n\"\n\t\"lwz     %r26,112(%r3)\\n\"\n\t\"lwz     %r27,116(%r3)\\n\"\n\t\"lwz     %r28,120(%r3)\\n\"\n\t\"lwz     %r29,124(%r3)\\n\"\n\t\"lwz     %r30,128(%r3)\\n\"\n\t\"lwz     %r31,132(%r3)\\n\"\n\t\"mtcr    %r6\\n\"\n#endif\n\n#ifndef LIBCO_PPC_NOFP\n\t\"stfd    %f14,224(%r4)\\n\"\n\t\"stfd    %f15,232(%r4)\\n\"\n\t\"stfd    %f16,240(%r4)\\n\"\n\t\"stfd    %f17,248(%r4)\\n\"\n\t\"stfd    %f18,256(%r4)\\n\"\n\t\"stfd    %f19,264(%r4)\\n\"\n\t\"stfd    %f20,272(%r4)\\n\"\n\t\"stfd    %f21,280(%r4)\\n\"\n\t\"stfd    %f22,288(%r4)\\n\"\n\t\"stfd    %f23,296(%r4)\\n\"\n\t\"stfd    %f24,304(%r4)\\n\"\n\t\"stfd    %f25,312(%r4)\\n\"\n\t\"stfd    %f26,320(%r4)\\n\"\n\t\"stfd    %f27,328(%r4)\\n\"\n\t\"stfd    %f28,336(%r4)\\n\"\n\t\"stfd    %f29,344(%r4)\\n\"\n\t\"stfd    %f30,352(%r4)\\n\"\n\t\"stfd    %f31,360(%r4)\\n\"\n\t\"lfd     %f14,224(%r3)\\n\"\n\t\"lfd     %f15,232(%r3)\\n\"\n\t\"lfd     %f16,240(%r3)\\n\"\n\t\"lfd     %f17,248(%r3)\\n\"\n\t\"lfd     %f18,256(%r3)\\n\"\n\t\"lfd     %f19,264(%r3)\\n\"\n\t\"lfd     %f20,272(%r3)\\n\"\n\t\"lfd     %f21,280(%r3)\\n\"\n\t\"lfd     %f22,288(%r3)\\n\"\n\t\"lfd     %f23,296(%r3)\\n\"\n\t\"lfd     %f24,304(%r3)\\n\"\n\t\"lfd     %f25,312(%r3)\\n\"\n\t\"lfd     %f26,320(%r3)\\n\"\n\t\"lfd     %f27,328(%r3)\\n\"\n\t\"lfd     %f28,336(%r3)\\n\"\n\t\"lfd     %f29,344(%r3)\\n\"\n\t\"lfd     %f30,352(%r3)\\n\"\n\t\"lfd     %f31,360(%r3)\\n\"\n#endif\n\n#ifdef __ALTIVEC__\n\t\"mfvrsave %r5\\n\"\n\t\"addi    %r8,%r4,384\\n\"\n\t\"addi    %r9,%r4,400\\n\"\n\t\"andi.   %r0,%r5,4095\\n\"\n\t\"stw     %r5,52(%r4)\\n\"\n\t\"beq-    2\\n\"\n\t\"stvx    %v20,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"stvx    %v21,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"stvx    %v22,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"stvx    %v23,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"stvx    %v24,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"stvx    %v25,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"stvx    %v26,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"stvx    %v27,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"stvx    %v28,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"stvx    %v29,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"stvx    %v30,%r0,%r8\\n\"\n\t\"stvx    %v31,%r0,%r9\\n\"\n\t\"2:lwz     %r5,52(%r3)\\n\"\n\t\"addi    %r8,%r3,384\\n\"\n\t\"addi    %r9,%r3,400\\n\"\n\t\"andi.   %r0,%r5,4095\\n\"\n\t\"mtvrsave %r5\\n\"\n\t\"beqctr  \\n\"\n\t\"lvx     %v20,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"lvx     %v21,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"lvx     %v22,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"lvx     %v23,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"lvx     %v24,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"lvx     %v25,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"lvx     %v26,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"lvx     %v27,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"lvx     %v28,%r0,%r8\\n\"\n\t\"addi    %r8,%r8,32\\n\"\n\t\"lvx     %v29,%r0,%r9\\n\"\n\t\"addi    %r9,%r9,32\\n\"\n\t\"lvx     %v30,%r0,%r8\\n\"\n\t\"lvx     %v31,%r0,%r9\\n\"\n#endif\n\t\"bctr\"\n);\n\nextern void libco_ppc_code(cothread_t, cothread_t);\n\n#if LIBCO_PPCDESC\n/* Function call goes through indirect descriptor */\n#define CO_SWAP_ASM(x, y) \\\n\t\t\t((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)\n#else\n/* Function call goes directly to code */\n#define CO_SWAP_ASM(x, y) \\\n\t\t\tlibco_ppc_code(x, y)\n#endif\n\n#else\n\n/* Swap code is here in array. Please leave dieassembly comments,\nas they make it easy to see what it does, and reorder instructions\nif one wants to see whether that improves performance. */\nstatic const uint32_t libco_ppc_code [] = {\n#if LIBCO_PPC64\n    0x7d000026, /* mfcr    r8 */\n    0xf8240028, /* std     r1,40(r4) */\n    0x7d2802a6, /* mflr    r9 */\n    0xf9c40048, /* std     r14,72(r4) */\n    0xf9e40050, /* std     r15,80(r4) */\n    0xfa040058, /* std     r16,88(r4) */\n    0xfa240060, /* std     r17,96(r4) */\n    0xfa440068, /* std     r18,104(r4) */\n    0xfa640070, /* std     r19,112(r4) */\n    0xfa840078, /* std     r20,120(r4) */\n    0xfaa40080, /* std     r21,128(r4) */\n    0xfac40088, /* std     r22,136(r4) */\n    0xfae40090, /* std     r23,144(r4) */\n    0xfb040098, /* std     r24,152(r4) */\n    0xfb2400a0, /* std     r25,160(r4) */\n    0xfb4400a8, /* std     r26,168(r4) */\n    0xfb6400b0, /* std     r27,176(r4) */\n    0xfb8400b8, /* std     r28,184(r4) */\n    0xfba400c0, /* std     r29,192(r4) */\n    0xfbc400c8, /* std     r30,200(r4) */\n    0xfbe400d0, /* std     r31,208(r4) */\n    0xf9240020, /* std     r9,32(r4) */\n    0xe8e30020, /* ld      r7,32(r3) */\n    0xe8230028, /* ld      r1,40(r3) */\n    0x48000009, /* bl      1 */\n\t0x7fe00008, /* trap */\n    0x91040030,/*1:stw     r8,48(r4) */\n    0x80c30030, /* lwz     r6,48(r3) */\n    0x7ce903a6, /* mtctr   r7 */\n    0xe9c30048, /* ld      r14,72(r3) */\n    0xe9e30050, /* ld      r15,80(r3) */\n    0xea030058, /* ld      r16,88(r3) */\n    0xea230060, /* ld      r17,96(r3) */\n    0xea430068, /* ld      r18,104(r3) */\n    0xea630070, /* ld      r19,112(r3) */\n    0xea830078, /* ld      r20,120(r3) */\n    0xeaa30080, /* ld      r21,128(r3) */\n    0xeac30088, /* ld      r22,136(r3) */\n    0xeae30090, /* ld      r23,144(r3) */\n    0xeb030098, /* ld      r24,152(r3) */\n    0xeb2300a0, /* ld      r25,160(r3) */\n    0xeb4300a8, /* ld      r26,168(r3) */\n    0xeb6300b0, /* ld      r27,176(r3) */\n    0xeb8300b8, /* ld      r28,184(r3) */\n    0xeba300c0, /* ld      r29,192(r3) */\n    0xebc300c8, /* ld      r30,200(r3) */\n    0xebe300d0, /* ld      r31,208(r3) */\n    0x7ccff120, /* mtcr    r6 */\n#else\n\t0x7d000026, /* mfcr    r8 */\n\t0x90240028, /* stw     r1,40(r4) */\n\t0x7d2802a6, /* mflr    r9 */\n\t0x91a4003c, /* stw     r13,60(r4) */\n\t0x91c40040, /* stw     r14,64(r4) */\n\t0x91e40044, /* stw     r15,68(r4) */\n\t0x92040048, /* stw     r16,72(r4) */\n\t0x9224004c, /* stw     r17,76(r4) */\n\t0x92440050, /* stw     r18,80(r4) */\n\t0x92640054, /* stw     r19,84(r4) */\n\t0x92840058, /* stw     r20,88(r4) */\n\t0x92a4005c, /* stw     r21,92(r4) */\n\t0x92c40060, /* stw     r22,96(r4) */\n\t0x92e40064, /* stw     r23,100(r4) */\n\t0x93040068, /* stw     r24,104(r4) */\n\t0x9324006c, /* stw     r25,108(r4) */\n\t0x93440070, /* stw     r26,112(r4) */\n\t0x93640074, /* stw     r27,116(r4) */\n\t0x93840078, /* stw     r28,120(r4) */\n\t0x93a4007c, /* stw     r29,124(r4) */\n\t0x93c40080, /* stw     r30,128(r4) */\n\t0x93e40084, /* stw     r31,132(r4) */\n\t0x91240020, /* stw     r9,32(r4) */\n\t0x80e30020, /* lwz     r7,32(r3) */\n\t0x80230028, /* lwz     r1,40(r3) */\n\t0x48000009, /* bl      1 */\n\t0x7fe00008, /* trap */\n\t0x91040030,/*1:stw     r8,48(r4) */\n\t0x80c30030, /* lwz     r6,48(r3) */\n\t0x7ce903a6, /* mtctr   r7 */\n\t0x81a3003c, /* lwz     r13,60(r3) */\n\t0x81c30040, /* lwz     r14,64(r3) */\n\t0x81e30044, /* lwz     r15,68(r3) */\n\t0x82030048, /* lwz     r16,72(r3) */\n\t0x8223004c, /* lwz     r17,76(r3) */\n\t0x82430050, /* lwz     r18,80(r3) */\n\t0x82630054, /* lwz     r19,84(r3) */\n\t0x82830058, /* lwz     r20,88(r3) */\n\t0x82a3005c, /* lwz     r21,92(r3) */\n\t0x82c30060, /* lwz     r22,96(r3) */\n\t0x82e30064, /* lwz     r23,100(r3) */\n\t0x83030068, /* lwz     r24,104(r3) */\n\t0x8323006c, /* lwz     r25,108(r3) */\n\t0x83430070, /* lwz     r26,112(r3) */\n\t0x83630074, /* lwz     r27,116(r3) */\n\t0x83830078, /* lwz     r28,120(r3) */\n\t0x83a3007c, /* lwz     r29,124(r3) */\n\t0x83c30080, /* lwz     r30,128(r3) */\n\t0x83e30084, /* lwz     r31,132(r3) */\n\t0x7ccff120, /* mtcr    r6 */\n#endif\n\n#ifndef LIBCO_PPC_NOFP\n\t0xd9c400e0, /* stfd    f14,224(r4) */\n\t0xd9e400e8, /* stfd    f15,232(r4) */\n\t0xda0400f0, /* stfd    f16,240(r4) */\n\t0xda2400f8, /* stfd    f17,248(r4) */\n\t0xda440100, /* stfd    f18,256(r4) */\n\t0xda640108, /* stfd    f19,264(r4) */\n\t0xda840110, /* stfd    f20,272(r4) */\n\t0xdaa40118, /* stfd    f21,280(r4) */\n\t0xdac40120, /* stfd    f22,288(r4) */\n\t0xdae40128, /* stfd    f23,296(r4) */\n\t0xdb040130, /* stfd    f24,304(r4) */\n\t0xdb240138, /* stfd    f25,312(r4) */\n\t0xdb440140, /* stfd    f26,320(r4) */\n\t0xdb640148, /* stfd    f27,328(r4) */\n\t0xdb840150, /* stfd    f28,336(r4) */\n\t0xdba40158, /* stfd    f29,344(r4) */\n\t0xdbc40160, /* stfd    f30,352(r4) */\n\t0xdbe40168, /* stfd    f31,360(r4) */\n\t0xc9c300e0, /* lfd     f14,224(r3) */\n\t0xc9e300e8, /* lfd     f15,232(r3) */\n\t0xca0300f0, /* lfd     f16,240(r3) */\n\t0xca2300f8, /* lfd     f17,248(r3) */\n\t0xca430100, /* lfd     f18,256(r3) */\n\t0xca630108, /* lfd     f19,264(r3) */\n\t0xca830110, /* lfd     f20,272(r3) */\n\t0xcaa30118, /* lfd     f21,280(r3) */\n\t0xcac30120, /* lfd     f22,288(r3) */\n\t0xcae30128, /* lfd     f23,296(r3) */\n\t0xcb030130, /* lfd     f24,304(r3) */\n\t0xcb230138, /* lfd     f25,312(r3) */\n\t0xcb430140, /* lfd     f26,320(r3) */\n\t0xcb630148, /* lfd     f27,328(r3) */\n\t0xcb830150, /* lfd     f28,336(r3) */\n\t0xcba30158, /* lfd     f29,344(r3) */\n\t0xcbc30160, /* lfd     f30,352(r3) */\n\t0xcbe30168, /* lfd     f31,360(r3) */\n#endif\n\n#ifdef __ALTIVEC__\n\t0x7ca042a6, /* mfvrsave r5 */\n\t0x39040180, /* addi    r8,r4,384 */\n\t0x39240190, /* addi    r9,r4,400 */\n\t0x70a00fff, /* andi.   r0,r5,4095 */\n\t0x90a40034, /* stw     r5,52(r4) */\n\t0x4182005c, /* beq-    2 */\n\t0x7e8041ce, /* stvx    v20,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7ea049ce, /* stvx    v21,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7ec041ce, /* stvx    v22,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7ee049ce, /* stvx    v23,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7f0041ce, /* stvx    v24,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7f2049ce, /* stvx    v25,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7f4041ce, /* stvx    v26,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7f6049ce, /* stvx    v27,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7f8041ce, /* stvx    v28,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7fa049ce, /* stvx    v29,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7fc041ce, /* stvx    v30,r0,r8 */\n\t0x7fe049ce, /* stvx    v31,r0,r9 */\n\t0x80a30034,/*2:lwz     r5,52(r3) */\n\t0x39030180, /* addi    r8,r3,384 */\n\t0x39230190, /* addi    r9,r3,400 */\n\t0x70a00fff, /* andi.   r0,r5,4095 */\n\t0x7ca043a6, /* mtvrsave r5 */\n\t0x4d820420, /* beqctr   */\n\t0x7e8040ce, /* lvx     v20,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7ea048ce, /* lvx     v21,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7ec040ce, /* lvx     v22,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7ee048ce, /* lvx     v23,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7f0040ce, /* lvx     v24,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7f2048ce, /* lvx     v25,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7f4040ce, /* lvx     v26,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7f6048ce, /* lvx     v27,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7f8040ce, /* lvx     v28,r0,r8 */\n\t0x39080020, /* addi    r8,r8,32 */\n\t0x7fa048ce, /* lvx     v29,r0,r9 */\n\t0x39290020, /* addi    r9,r9,32 */\n\t0x7fc040ce, /* lvx     v30,r0,r8 */\n\t0x7fe048ce, /* lvx     v31,r0,r9 */\n#endif\n\n\t0x4e800420, /* bctr */\n};\n\n\t#if LIBCO_PPCDESC\n\t\t/* Function call goes through indirect descriptor */\n\t\t#define CO_SWAP_ASM(x, y) \\\n\t\t\t((void (*)(cothread_t, cothread_t)) (uintptr_t) x)(x, y)\n\t#else\n\t\t/* Function call goes directly to code */\n\t\t#define CO_SWAP_ASM(x, y) \\\n\t\t\t((void (*)(cothread_t, cothread_t)) (uintptr_t) libco_ppc_code)(x, y)\n\t#endif\n\n#endif\n\nstatic uint32_t* co_create_( unsigned size, uintptr_t entry)\n{\n\tuint32_t *t = (uint32_t*)malloc(size);\n\n#if LIBCO_PPCDESC\n   if (t)\n   {\n      /* Copy entry's descriptor */\n      memcpy(t, (void*)entry, sizeof(void*) * 3);\n\n      /* Set function pointer to swap routine */\n#ifdef LIBCO_PPC_ASM\n      *(const void**) t = *(void**) &co_swap_asm;\n#else\n      *(const void**) t = libco_ppc_code;\n#endif\n   }\n\t#endif\n\n\treturn t;\n}\n\ncothread_t co_create(unsigned int size, void (*entry_)(void))\n{\n\tuintptr_t entry = (uintptr_t) entry_;\n\tuint32_t *t     = NULL;\n\n\t/* Be sure main thread was successfully allocated */\n\tif (co_active())\n\t{\n\t\tsize += state_size + above_stack + stack_align;\n\t\tt     = co_create_(size, entry);\n\t}\n\n\tif (t)\n   {\n      uintptr_t sp;\n#if LIBCO_PPC64\n      int shift = 16;\n#else\n      int shift = 0;\n#endif\n      /* Save current registers into new thread, so that any special ones will\n         have proper values when thread is begun */\n      CO_SWAP_ASM(t, t);\n\n#if LIBCO_PPCDESC\n      /* Get real address */\n      entry     = (uintptr_t) *(void**)entry;\n#endif\n\n      /* Put stack near end of block, and align */\n      sp        = (uintptr_t) t + size - above_stack;\n      sp       -= sp % stack_align;\n\n      /* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we\n         save and restore them as 64 bits, regardless of the size the ABI\n         uses. So, we manually write pointers at the proper size. We always\n         save and restore at the same address, and since PPC is big-endian,\n         we must put the low byte first on PPC32. */\n\n      /* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts\n         and don't have to care how many bits uintptr_t is. */\n\n      /* Set up so entry will be called on next swap */\n      t [8]  = (uint32_t) (entry >> shift >> shift);\n      t [9]  = (uint32_t) entry;\n\n      t [10] = (uint32_t) (sp    >> shift >> shift);\n      t [11] = (uint32_t) sp;\n   }\n\n\treturn t;\n}\n\nvoid co_delete(cothread_t t)\n{\n   free(t);\n}\n\nstatic void co_init_(void)\n{\n#if LIBCO_MPROTECT && !LIBCO_STATIC_TEXT\n   /* TODO: pre- and post-pad PPC code so that this doesn't make other\n      data executable and writable */\n   long page_size = sysconf(_SC_PAGESIZE);\n   if (page_size > 0)\n   {\n      uintptr_t align = page_size;\n      uintptr_t begin = (uintptr_t) libco_ppc_code;\n      uintptr_t end   = begin + sizeof libco_ppc_code;\n\n      /* Align beginning and end */\n      end            += align - 1;\n      end            -= end   % align;\n      begin          -= begin % align;\n\n      mprotect((void*)begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC);\n   }\n#endif\n\n   co_active_handle = co_create_(state_size, (uintptr_t) &co_switch);\n}\n\ncothread_t co_active(void)\n{\n   if (!co_active_handle)\n      co_init_();\n\n   return co_active_handle;\n}\n\nvoid co_switch(cothread_t t)\n{\n   cothread_t old   = co_active_handle;\n   co_active_handle = t;\n   CO_SWAP_ASM(t, old);\n}\n"
  },
  {
    "path": "libco/ps2.c",
    "content": "#define LIBCO_C\n#include \"libco.h\"\n\n#include <stdlib.h>\n#include <stdint.h>\n#include <kernel.h>\n\n/* Since cothread_t is a void pointer it must contain an address. We can't return a reference to a local variable\n * because it would go out of scope, so we create a static variable instead so we can return a reference to it.\n */\nstatic int32_t active_thread_id = -1;\nextern void *_gp;\n\ncothread_t co_active()\n{\n  active_thread_id = GetThreadId();\n  return &active_thread_id;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void))\n{\n   /* Similar scenario as with active_thread_id except there will only be one active_thread_id while there could be many\n    * new threads each with their own handle, so we create them on the heap instead and delete them manually when they're\n    * no longer needed in co_delete().\n    */\n   ee_thread_t thread;\n   int32_t new_thread_id;\n   cothread_t handle       = malloc(sizeof(cothread_t));\n   void *threadStack       = (void *)malloc(size);\n\n   if (!threadStack)\n      return -1;\n\n   thread.stack_size\t\t   = size;\n   thread.gp_reg\t\t\t   = &_gp;\n   thread.func\t\t\t\t   = (void *)entrypoint;\n   thread.stack\t\t\t   = threadStack;\n   thread.option\t\t\t   = 0;\n   thread.initial_priority = 1;\n\n   new_thread_id           = CreateThread(&thread);\n   StartThread(new_thread_id, NULL);\n   *(uint32_t *)handle     = new_thread_id;\n   return handle;\n}\n\nvoid co_delete(cothread_t handle)\n{\n   TerminateThread(*(uint32_t *)handle);\n   DeleteThread(*(uint32_t *)handle);\n   free(handle);\n}\n\nvoid co_switch(cothread_t handle)\n{\n   WakeupThread(*(uint32_t *)handle);\n   /* Sleep the currently active thread so the new thread can start */\n   SleepThread();\n}\n"
  },
  {
    "path": "libco/ps3.S",
    "content": ".globl .co_swap_asm\n.globl co_swap_asm\n.type .co_swap_asm, @function\n.type co_swap_asm, @function\n.co_swap_asm:\nco_swap_asm:\n      mfcr    8\n      std     1,40(4)\n      mflr    9\n      std     14,72(4)\n      std     15,80(4)\n      std     16,88(4)\n      std     17,96(4)\n      std     18,104(4)\n      std     19,112(4)\n      std     20,120(4)\n      std     21,128(4)\n      std     22,136(4)\n      std     23,144(4)\n      std     24,152(4)\n      std     25,160(4)\n      std     26,168(4)\n      std     27,176(4)\n      std     28,184(4)\n      std     29,192(4)\n      std     30,200(4)\n      std     31,208(4)\n      std     9,32(4)\n      ld      7,32(3)\n      ld      1,40(3)\n      bl      swap\n      trap\nswap: stw     8,48(4)\n      lwz     6,48(3)\n      mtctr   7\n      ld      14,72(3)\n      ld      15,80(3)\n      ld      16,88(3)\n      ld      17,96(3)\n      ld      18,104(3)\n      ld      19,112(3)\n      ld      20,120(3)\n      ld      21,128(3)\n      ld      22,136(3)\n      ld      23,144(3)\n      ld      24,152(3)\n      ld      25,160(3)\n      ld      26,168(3)\n      ld      27,176(3)\n      ld      28,184(3)\n      ld      29,192(3)\n      ld      30,200(3)\n      ld      31,208(3)\n      mtcr    6\n      bctr\n"
  },
  {
    "path": "libco/psp1.c",
    "content": "#define LIBCO_C\n#include \"libco.h\"\n\n#include <stdlib.h>\n#include <pspthreadman.h>\n\ntypedef void (*entrypoint_t)(void);\n\ncothread_t co_active(void)\n{\n  return (void *)sceKernelGetThreadId();\n}\n\nstatic int thread_wrap(unsigned int argc, void *argp)\n{\n  entrypoint_t entrypoint = *(entrypoint_t *) argp;\n  sceKernelSleepThread();\n  entrypoint();\n  return 0;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void))\n{\n  SceUID new_thread_id = sceKernelCreateThread(\"cothread\", thread_wrap, 0x12, size, 0, NULL);\n  sceKernelStartThread(new_thread_id, sizeof (entrypoint), &entrypoint);\n  return (void *) new_thread_id;\n}\n\nvoid co_delete(cothread_t handle)\n{\n  SceUID id = (SceUID) handle;\n  sceKernelTerminateDeleteThread(id);\n}\n\nvoid co_switch(cothread_t handle)\n{\n  SceUID id = (SceUID) handle;\n  sceKernelWakeupThread(id);\n  /* Sleep the currently active thread so the new thread can start */\n  sceKernelSleepThread();\n}\n"
  },
  {
    "path": "libco/psp2.c",
    "content": "/*\nlibco.arm (2015-06-18)\nlicense: public domain\n*/\n\n#define LIBCO_C\n#include \"libco.h\"\n\n#include <assert.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <psp2/kernel/sysmem.h>\n#include <stdio.h>\n#include <string.h>\n\n#define FOUR_KB_ALIGN(x) align(x, 12)\n#define MB_ALIGN(x)      align(x, 20)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n   static inline int align(int x, int n)\n   {\n      return (((x >> n) + 1) << n);\n   }\n\n   static thread_local unsigned long co_active_buffer[64];\n   static thread_local cothread_t co_active_handle = 0;\n   static void(*co_swap)(cothread_t, cothread_t) = 0;\n   static int block;\n   static uint32_t co_swap_function[] = {\n      0xe8a16ff0,  /* stmia r1!, {r4-r11,sp,lr} */\n      0xe8b0aff0,  /* ldmia r0!, {r4-r11,sp,pc} */\n      0xe12fff1e,  /* bx lr                     */\n   };\n\n   static void co_init(void)\n   {\n      int ret;\n      void *base;\n\n      block = sceKernelAllocMemBlockForVM(\"libco\",\n            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));\n      if (block < 0)\n         return;\n\n      /* Get base address */\n      if ((ret = sceKernelGetMemBlockBase(block, &base)) < 0)\n         return;\n\n      /* Set domain to be writable by user */\n      if ((ret = sceKernelOpenVMDomain()) < 0)\n         return;\n\n      memcpy(base, co_swap_function, sizeof co_swap_function);\n\n      /* Set domain back to read-only */\n      if ((ret = sceKernelCloseVMDomain()) < 0)\n         return;\n\n      /* Flush icache */\n      ret = sceKernelSyncVMDomain(block, base,\n            MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));\n      if (ret < 0)\n         return;\n\n      co_swap = (void(*)(cothread_t, cothread_t))base;\n   }\n\n   cothread_t co_active(void)\n   {\n      if (!co_active_handle)\n         co_active_handle = &co_active_buffer;\n      return co_active_handle;\n   }\n\n   cothread_t co_create(unsigned int size, void(*entrypoint)(void))\n   {\n      unsigned long* handle = 0;\n      if (!co_swap)\n         co_init();\n      if (!co_active_handle)\n         co_active_handle   = &co_active_buffer;\n      size                 += 256;\n      size                 &= ~15;\n\n      if ((handle = (unsigned long*)malloc(size)))\n      {\n         unsigned long *p   = (unsigned long*)((unsigned char*)handle + size);\n         handle[8]          = (unsigned long)p;\n         handle[9]          = (unsigned long)entrypoint;\n      }\n\n      return handle;\n   }\n\n   void co_delete(cothread_t handle)\n   {\n      free(handle);\n      sceKernelFreeMemBlock(block);\n   }\n\n   void co_switch(cothread_t handle)\n   {\n      cothread_t co_previous_handle = co_active_handle;\n      co_swap(co_active_handle = handle, co_previous_handle);\n   }\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/scefiber.c",
    "content": "/*\n  libco.win (2016-09-06)\n  authors: frangarcj\n  license: public domain\n*/\n\n#define LIBCO_C\n#include <libco.h>\n#include <stdlib.h>\n#include <psp2/sysmodule.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic thread_local cothread_t co_active_ = 0;\n\ntypedef struct SceFiber\n{\n\tchar reserved[128];\n} SceFiber __attribute__( ( aligned ( 8 ) ) ) ;\n\n/* Forward declarations */\nint32_t _sceFiberInitializeImpl(SceFiber *fiber, char *name, void *entry, uint32_t argOnInitialize,\n      void* addrContext, int32_t sizeContext, void* params);\nint32_t sceFiberFinalize(SceFiber* fiber);\nint32_t sceFiberRun(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);\nint32_t sceFiberSwitch(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);\nint32_t sceFiberReturnToThread(uint32_t argOnReturn, uint32_t* argOnRun);\n\nstatic void co_thunk(uint32_t argOnInitialize, uint32_t argOnRun)\n{\n   ((void (*)(void))argOnInitialize)();\n}\n\ncothread_t co_active(void)\n{\n   if (!co_active_)\n   {\n      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);\n      co_active_ = (cothread_t)1;\n   }\n   return co_active_;\n}\n\ncothread_t co_create(unsigned int heapsize, void (*coentry)(void))\n{\n   int ret;\n   SceFiber* tail_fiber   = (SceFiber*)malloc(sizeof(SceFiber));\n   char * m_ctxbuf        = (char*)malloc(heapsize * sizeof(char));\n   if (!co_active_)\n   {\n      sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);\n      co_active_          = (cothread_t)1;\n   }\n\n   /* _sceFiberInitializeImpl */\n   if ((ret = _sceFiberInitializeImpl(\n               tail_fiber, \"tailFiber\", co_thunk,\n               (uint32_t)coentry, (void*)m_ctxbuf, heapsize, NULL)) == 0)\n      return (cothread_t)tail_fiber;\n   return (cothread_t)ret;\n}\n\nvoid co_delete(cothread_t cothread)\n{\n   if (cothread != (cothread_t)1)\n      sceFiberFinalize((SceFiber*)cothread);\n}\n\nvoid co_switch(cothread_t cothread)\n{\n   uint32_t argOnReturn  = 0;\n   if (cothread == (cothread_t)1)\n   {\n      co_active_         = cothread;\n      sceFiberReturnToThread(0, NULL);\n   }\n   else\n   {\n      SceFiber* theFiber = (SceFiber*)cothread;\n      co_active_         = cothread;\n      if (co_active_ == (cothread_t)1)\n         sceFiberRun(theFiber, 0, &argOnReturn);\n      else\n         sceFiberSwitch(theFiber, 0, &argOnReturn);\n   }\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/sjlj.c",
    "content": "/*\n  libco.sjlj (2008-01-28)\n  author: Nach\n  license: public domain\n*/\n\n/*\n * Note this was designed for UNIX systems. Based on ideas expressed in a paper\n * by Ralf Engelschall.\n * For SJLJ on other systems, one would want to rewrite springboard() and\n * co_create() and hack the jmb_buf stack pointer.\n */\n\n#define LIBCO_C\n#include <libco.h>\n#include <stdlib.h>\n#include <signal.h>\n#include <setjmp.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct\n{\n   sigjmp_buf context;\n   void (*coentry)(void);\n   void *stack;\n} cothread_struct;\n\nstatic thread_local cothread_struct co_primary;\nstatic thread_local cothread_struct *creating, *co_running = 0;\n\nstatic void springboard(int ignored)\n{\n   if (sigsetjmp(creating->context, 0))\n      co_running->coentry();\n}\n\ncothread_t co_active(void)\n{\n  if (!co_running)\n     co_running = &co_primary;\n  return (cothread_t)co_running;\n}\n\ncothread_t co_create(unsigned int size, void (*coentry)(void))\n{\n   cothread_struct *thread;\n   if (!co_running)\n      co_running = &co_primary;\n\n   if ((thread = (cothread_struct*)malloc(sizeof(cothread_struct))))\n   {\n      stack_t stack;\n      stack_t old_stack;\n\n      thread->coentry = thread->stack = 0;\n\n      stack.ss_flags  = 0;\n      stack.ss_size   = size;\n      thread->stack   = stack.ss_sp = malloc(size);\n\n      if (stack.ss_sp && !sigaltstack(&stack, &old_stack))\n      {\n         struct sigaction old_handler = {{0}};\n         struct sigaction handler     = {{0}};\n         handler.sa_handler           = springboard;\n         handler.sa_flags             = SA_ONSTACK;\n         sigemptyset(&handler.sa_mask);\n         creating                     = thread;\n\n         if (!sigaction(SIGUSR1, &handler, &old_handler))\n         {\n            if (!raise(SIGUSR1))\n               thread->coentry        = coentry;\n            sigaltstack(&old_stack, 0);\n            sigaction(SIGUSR1, &old_handler, 0);\n         }\n      }\n\n      if (thread->coentry != coentry)\n      {\n         co_delete(thread);\n         thread = 0;\n      }\n   }\n\n   return (cothread_t)thread;\n}\n\nvoid co_delete(cothread_t cothread)\n{\n   if (cothread)\n   {\n      if (((cothread_struct*)cothread)->stack)\n         free(((cothread_struct*)cothread)->stack);\n      free(cothread);\n   }\n}\n\nvoid co_switch(cothread_t cothread)\n{\n   if (!sigsetjmp(co_running->context, 0))\n   {\n      co_running = (cothread_struct*)cothread;\n      siglongjmp(co_running->context, 1);\n   }\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/ucontext.c",
    "content": "/*\n  libco.ucontext (2008-01-28)\n  author: Nach\n  license: public domain\n*/\n\n/*\n * WARNING: the overhead of POSIX ucontext is very high,\n * assembly versions of libco or libco_sjlj should be much faster\n *\n * This library only exists for two reasons:\n * 1 - as an initial test for the viability of a ucontext implementation\n * 2 - to demonstrate the power and speed of libco over existing implementations,\n *     such as pth (which defaults to wrapping ucontext on unix targets)\n *\n * Use this library only as a *last resort*\n */\n\n#define LIBCO_C\n#include <libco.h>\n#include <stdlib.h>\n#include <ucontext.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstatic thread_local ucontext_t co_primary;\nstatic thread_local ucontext_t *co_running = 0;\n\ncothread_t co_active(void)\n{\n   if (!co_running)\n      co_running = &co_primary;\n   return (cothread_t)co_running;\n}\n\ncothread_t co_create(unsigned int heapsize, void (*coentry)(void))\n{\n   ucontext_t *thread;\n   if (!co_running)\n      co_running = &co_primary;\n\n   if ((thread = (ucontext_t*)malloc(sizeof(ucontext_t))))\n   {\n      if ((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize)))\n      {\n         thread->uc_link = co_running;\n         thread->uc_stack.ss_size = heapsize;\n         makecontext(thread, coentry, 0);\n      }\n      else\n      {\n         co_delete((cothread_t)thread);\n         thread = 0;\n      }\n   }\n   return (cothread_t)thread;\n}\n\nvoid co_delete(cothread_t cothread)\n{\n   if (!cothread)\n      return;\n\n   if (((ucontext_t*)cothread)->uc_stack.ss_sp)\n      free(((ucontext_t*)cothread)->uc_stack.ss_sp);\n   free(cothread);\n}\n\nvoid co_switch(cothread_t cothread)\n{\n   ucontext_t *old_thread = co_running;\n   co_running             = (ucontext_t*)cothread;\n   swapcontext(old_thread, co_running);\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "libco/x86.c",
    "content": "/*\n  libco.x86 (2009-10-12)\n  author: byuu\n  license: public domain\n*/\n\n#define LIBCO_C\n#include <libco.h>\n#include <assert.h>\n#include <stdlib.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(_MSC_VER)\n  #define fastcall __fastcall\n#elif defined(__GNUC__)\n  #define fastcall __attribute__((fastcall))\n#else\n  #error \"libco: please define fastcall macro\"\n#endif\n\nstatic thread_local long co_active_buffer[64];\nstatic thread_local cothread_t co_active_handle = 0;\nstatic void (fastcall *co_swap)(cothread_t, cothread_t) = 0;\n\n/* ABI: fastcall */\nstatic unsigned char co_swap_function[] = {\n  0x89, 0x22,         /* mov [edx],esp      */\n  0x8b, 0x21,         /* mov esp,[ecx]      */\n  0x58,               /* pop eax            */\n  0x89, 0x6a, 0x04,   /* mov [edx+0x04],ebp */\n  0x89, 0x72, 0x08,   /* mov [edx+0x08],esi */\n  0x89, 0x7a, 0x0c,   /* mov [edx+0x0c],edi */\n  0x89, 0x5a, 0x10,   /* mov [edx+0x10],ebx */\n  0x8b, 0x69, 0x04,   /* mov ebp,[ecx+0x04] */\n  0x8b, 0x71, 0x08,   /* mov esi,[ecx+0x08] */\n  0x8b, 0x79, 0x0c,   /* mov edi,[ecx+0x0c] */\n  0x8b, 0x59, 0x10,   /* mov ebx,[ecx+0x10] */\n  0xff, 0xe0,         /* jmp eax            */\n};\n\n#ifdef _WIN32\n#include <windows.h>\n\nstatic void co_init(void)\n{\n   DWORD old_privileges;\n   VirtualProtect(co_swap_function,\n         sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);\n}\n#else\n#include <unistd.h>\n#include <sys/mman.h>\n\nstatic void co_init(void)\n{\n   unsigned long addr = (unsigned long)co_swap_function;\n   unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));\n   unsigned long size = (addr - base) + sizeof co_swap_function;\n   mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);\n}\n#endif\n\nstatic void crash(void)\n{\n   assert(0); /* called only if cothread_t entrypoint returns */\n}\n\ncothread_t co_active(void)\n{\n   if (!co_active_handle)\n      co_active_handle = &co_active_buffer;\n   return co_active_handle;\n}\n\ncothread_t co_create(unsigned int size, void (*entrypoint)(void))\n{\n   cothread_t handle;\n   if (!co_swap)\n   {\n      co_init();\n      co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;\n   }\n\n   if (!co_active_handle)\n      co_active_handle = &co_active_buffer;\n\n   size += 256; /* allocate additional space for storage */\n   size &= ~15; /* align stack to 16-byte boundary */\n\n   if ((handle = (cothread_t)malloc(size)))\n   {\n      long *p        = (long*)((char*)handle + size); /* seek to top of stack */\n      *--p           = (long)crash;                   /* crash if entrypoint returns */\n      *--p           = (long)entrypoint;              /* start of function */\n      *(long*)handle = (long)p;                       /* stack pointer */\n   }\n\n   return handle;\n}\n\nvoid co_delete(cothread_t handle)\n{\n   free(handle);\n}\n\nvoid co_switch(cothread_t handle)\n{\n   register cothread_t co_previous_handle = co_active_handle;\n   co_swap(co_active_handle = handle, co_previous_handle);\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "lists/dir_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (dir_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n\n#if defined(_WIN32) && defined(_XBOX)\n#include <xtl.h>\n#elif defined(_WIN32)\n#include <windows.h>\n#endif\n\n#include <lists/dir_list.h>\n#include <lists/string_list.h>\n#include <file/file_path.h>\n\n#include <compat/strl.h>\n#include <retro_dirent.h>\n\n#include <retro_miscellaneous.h>\n\nstatic int qstrcmp_plain(const void *a_, const void *b_)\n{\n   const struct string_list_elem *a = (const struct string_list_elem*)a_;\n   const struct string_list_elem *b = (const struct string_list_elem*)b_;\n   const char *s1 = a->data;\n   const char *s2 = b->data;\n\n   for (;;)\n   {\n      int c1 = tolower((unsigned char)*s1);\n      int c2 = tolower((unsigned char)*s2);\n      if (c1 != c2)\n         return c1 - c2;\n      if (c1 == '\\0')\n         return 0;\n      s1++;\n      s2++;\n   }\n}\n\n/**\n * find_ext_dot:\n * @path : file path\n *\n * Finds the '.' that begins the file extension, considering only\n * dots after the last directory separator. This avoids treating\n * dots in directory names (e.g. \".config\") as extension separators.\n *\n * @return pointer to the extension '.', or to the trailing '\\0'\n * if no extension is found.\n **/\nstatic const char *find_ext_dot(const char *path)\n{\n   const char *last_slash = strrchr(path, '/');\n#ifdef _WIN32\n   {\n      const char *last_bslash = strrchr(path, '\\\\');\n      if (last_bslash && (!last_slash || last_bslash > last_slash))\n         last_slash = last_bslash;\n   }\n#endif\n   {\n      const char *start = last_slash ? last_slash + 1 : path;\n      const char *dot   = strrchr(start, '.');\n      return dot ? dot : path + strlen(path);\n   }\n}\n\nstatic int qstrcmp_plain_noext(const void *a_, const void *b_)\n{\n   const struct string_list_elem *a = (const struct string_list_elem*)a_;\n   const struct string_list_elem *b = (const struct string_list_elem*)b_;\n   const char *ea = find_ext_dot(a->data);\n   const char *eb = find_ext_dot(b->data);\n   size_t la      = (size_t)(ea - a->data);\n   size_t lb      = (size_t)(eb - b->data);\n   size_t len     = la < lb ? la : lb;\n   int rv         = strncasecmp(a->data, b->data, len);\n   if (rv != 0)\n      return rv;\n   if (la != lb)\n      return (la < lb) ? -1 : 1;\n   return 0;\n}\n\nstatic int qstrcmp_dir(const void *a_, const void *b_)\n{\n   const struct string_list_elem *a = (const struct string_list_elem*)a_;\n   const struct string_list_elem *b = (const struct string_list_elem*)b_;\n   int a_type = a->attr.i;\n   int b_type = b->attr.i;\n\n   /* Sort directories before files. */\n   if (a_type != b_type)\n      return b_type - a_type;\n   return strcasecmp(a->data, b->data);\n}\n\nstatic int qstrcmp_dir_noext(const void *a_, const void *b_)\n{\n   const struct string_list_elem *a = (const struct string_list_elem*)a_;\n   const struct string_list_elem *b = (const struct string_list_elem*)b_;\n   int a_type = a->attr.i;\n   int b_type = b->attr.i;\n\n   /* Sort directories before files. */\n   if (a_type != b_type)\n      return b_type - a_type;\n   return qstrcmp_plain_noext(a, b);\n}\n\n/**\n * dir_list_sort:\n * @list      : pointer to the directory listing.\n * @dir_first : move the directories in the listing to the top?\n *\n * Sorts a directory listing.\n **/\nvoid dir_list_sort(struct string_list *list, bool dir_first)\n{\n   if (list)\n      qsort(list->elems, list->size, sizeof(struct string_list_elem),\n            dir_first ? qstrcmp_dir : qstrcmp_plain);\n}\n\n/**\n * dir_list_sort_ignore_ext:\n * @list      : pointer to the directory listing.\n * @dir_first : move the directories in the listing to the top?\n *\n * Sorts a directory listing. File extensions are ignored.\n **/\nvoid dir_list_sort_ignore_ext(struct string_list *list, bool dir_first)\n{\n   if (list)\n      qsort(list->elems, list->size, sizeof(struct string_list_elem),\n            dir_first ? qstrcmp_dir_noext : qstrcmp_plain_noext);\n}\n\n/**\n * dir_list_free:\n * @list : pointer to the directory listing\n *\n * Frees a directory listing.\n **/\nvoid dir_list_free(struct string_list *list)\n{\n   string_list_free(list);\n}\n\nbool dir_list_deinitialize(struct string_list *list)\n{\n   if (!list)\n      return false;\n   return string_list_deinitialize(list);\n}\n\n/**\n * dir_list_read:\n * @dir                : directory path.\n * @list               : the string list to add files to\n * @ext_list           : the string list of extensions to include\n * @include_dirs       : include directories as part of the finished directory listing?\n * @include_hidden     : include hidden files and directories as part of the finished directory listing?\n * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.\n * @recursive          : list directory contents recursively\n *\n * Add files within a directory to an existing string list\n *\n * @return -1 on error, 0 on success.\n **/\nstatic int dir_list_read(const char *dir,\n      struct string_list *list, struct string_list *ext_list,\n      bool include_dirs, bool include_hidden,\n      bool include_compressed, bool recursive)\n{\n   struct RDIR *entry = retro_opendir_include_hidden(dir, include_hidden);\n\n   if (!entry)\n      return -1;\n   if (retro_dirent_error(entry))\n   {\n      retro_closedir(entry);\n      return -1;\n   }\n\n   while (retro_readdir(entry))\n   {\n      union string_list_elem_attr attr;\n      char file_path[PATH_MAX_LENGTH];\n      const char *name = retro_dirent_get_name(entry);\n\n      if (name[0] == '.' || name[0] == '$')\n      {\n         /* Do not include hidden files and directories */\n         if (!include_hidden)\n            continue;\n\n         /* char-wise comparisons to avoid string comparison */\n\n         /* Do not include current dir */\n         if (name[1] == '\\0')\n            continue;\n         /* Do not include parent dir */\n         if (name[1] == '.' && name[2] == '\\0')\n            continue;\n      }\n\n      fill_pathname_join_special(file_path, dir, name, sizeof(file_path));\n\n      if (retro_dirent_is_dir(entry, NULL))\n      {\n         /* Exclude this frequent hidden dir on platforms which can not handle hidden attribute */\n         if (!include_hidden && strcmp(name, \"System Volume Information\") == 0)\n            continue;\n\n#if defined(IOS) || defined(OSX)\n         {\n            size_t name_len = strlen(name);\n            if (name_len >= 10\n                  && !memcmp(name + name_len - 10, \".framework\", 10))\n            {\n               attr.i = RARCH_PLAIN_FILE;\n               if (!string_list_append(list, file_path, attr))\n               {\n                  retro_closedir(entry);\n                  return -1;\n               }\n               continue;\n            }\n         }\n#endif\n         if (recursive)\n            dir_list_read(file_path, list, ext_list, include_dirs,\n                  include_hidden, include_compressed, recursive);\n\n         if (!include_dirs)\n            continue;\n         attr.i = RARCH_DIRECTORY;\n      }\n      else\n      {\n         const char *file_ext    = path_get_extension(name);\n\n         attr.i                  = RARCH_FILETYPE_UNSET;\n\n         /*\n          * If the file format is explicitly supported by the libretro-core, we\n          * need to immediately load it and not designate it as a compressed file.\n          *\n          * Example: .zip could be supported as a image by the core and as a\n          * compressed_file. In that case, we have to interpret it as a image.\n          *\n          * */\n         if (string_list_find_elem_prefix(ext_list, \".\", file_ext))\n            attr.i            = RARCH_PLAIN_FILE;\n         else\n         {\n            bool is_compressed_file;\n            if ((is_compressed_file = path_is_compressed_file(file_path)))\n               attr.i               = RARCH_COMPRESSED_ARCHIVE;\n\n            if (ext_list &&\n                  (!is_compressed_file || !include_compressed))\n               continue;\n         }\n      }\n\n      if (!string_list_append(list, file_path, attr))\n      {\n         retro_closedir(entry);\n         return -1;\n      }\n   }\n\n   retro_closedir(entry);\n\n   return 0;\n}\n\n/**\n * dir_list_append:\n * @list               : existing list to append to.\n * @dir                : directory path.\n * @ext                : allowed extensions of file directory entries to include.\n * @include_dirs       : include directories as part of the finished directory listing?\n * @include_hidden     : include hidden files and directories as part of the finished directory listing?\n * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.\n * @recursive          : list directory contents recursively\n *\n * Create a directory listing, appending to an existing list\n *\n * @return Returns true on success, otherwise false.\n **/\nbool dir_list_append(struct string_list *list,\n      const char *dir,\n      const char *ext, bool include_dirs,\n      bool include_hidden, bool include_compressed,\n      bool recursive)\n{\n   bool ret                         = false;\n   struct string_list ext_list      = {0};\n   struct string_list *ext_list_ptr = NULL;\n\n   if (ext)\n   {\n      string_list_initialize(&ext_list);\n      string_split_noalloc(&ext_list, ext, \"|\");\n      ext_list_ptr                  = &ext_list;\n   }\n   ret                            = dir_list_read(dir, list, ext_list_ptr,\n         include_dirs, include_hidden, include_compressed, recursive) != -1;\n   string_list_deinitialize(&ext_list);\n   return ret;\n}\n\n/**\n * dir_list_new:\n * @dir                : directory path.\n * @ext                : allowed extensions of file directory entries to include.\n * @include_dirs       : include directories as part of the finished directory listing?\n * @include_hidden     : include hidden files and directories as part of the finished directory listing?\n * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc.\n * @recursive          : list directory contents recursively\n *\n * Create a directory listing.\n *\n * @return pointer to a directory listing of type 'struct string_list *' on success,\n * NULL in case of error. Has to be freed manually.\n **/\nstruct string_list *dir_list_new(const char *dir,\n      const char *ext, bool include_dirs,\n      bool include_hidden, bool include_compressed,\n      bool recursive)\n{\n   struct string_list *list       = string_list_new();\n\n   if (!list)\n      return NULL;\n\n   if (!dir_list_append(list, dir, ext, include_dirs,\n            include_hidden, include_compressed, recursive))\n   {\n      string_list_free(list);\n      return NULL;\n   }\n\n   return list;\n}\n\n/**\n * dir_list_initialize:\n *\n * NOTE: @list must zero initialised before\n * calling this function, otherwise UB.\n **/\nbool dir_list_initialize(struct string_list *list,\n      const char *dir,\n      const char *ext, bool include_dirs,\n      bool include_hidden, bool include_compressed,\n      bool recursive)\n{\n   if (list && string_list_initialize(list))\n      return dir_list_append(list, dir, ext, include_dirs,\n            include_hidden, include_compressed, recursive);\n   return false;\n}\n"
  },
  {
    "path": "lists/file_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_common.h>\n#include <retro_inline.h>\n#include <lists/file_list.h>\n#include <compat/strcasestr.h>\n\nstatic bool file_list_deinitialize_internal(file_list_t *list)\n{\n   size_t i;\n   for (i = 0; i < list->size; i++)\n   {\n      file_list_free_userdata(list, i);\n      file_list_free_actiondata(list, i);\n\n      if (list->list[i].path)\n         free(list->list[i].path);\n      list->list[i].path = NULL;\n\n      if (list->list[i].label)\n         free(list->list[i].label);\n      list->list[i].label = NULL;\n\n      if (list->list[i].alt)\n         free(list->list[i].alt);\n      list->list[i].alt = NULL;\n   }\n   if (list->list)\n      free(list->list);\n   list->list = NULL;\n   return true;\n}\n\nbool file_list_reserve(file_list_t *list, size_t nitems)\n{\n   const size_t item_size = sizeof(struct item_file);\n   struct item_file *new_data;\n\n   if (nitems < list->capacity || nitems > (size_t)-1/item_size)\n      return false;\n\n   if (!(new_data = (struct item_file*)realloc(list->list, nitems * item_size)))\n      return false;\n\n   memset(&new_data[list->capacity], 0, item_size * (nitems - list->capacity));\n\n   list->list     = new_data;\n   list->capacity = nitems;\n\n   return true;\n}\n\n/* Helper function to initialize item_file structure */\nstatic INLINE void init_item_file(struct item_file *item,\n    const char *path, const char *label, unsigned type,\n    size_t directory_ptr, size_t entry_idx)\n{\n    /* NULL-gate both strdup calls: strdup(NULL) is undefined\n     * behaviour (glibc crashes).  The sibling file_list_append\n     * uses the same gating pattern.  Callers have been seen to\n     * pass NULL path here via menu_entries_prepend when\n     * msg_hash_to_str returns NULL for an enum that no active\n     * language handler recognises. */\n    item->path          = path  ? strdup(path)  : NULL;\n    item->label         = label ? strdup(label) : NULL;\n    item->alt           = NULL;\n    item->type          = type;\n    item->directory_ptr = directory_ptr;\n    item->entry_idx     = entry_idx;\n    item->userdata      = NULL;\n    item->actiondata    = NULL;\n}\n\nbool file_list_insert(file_list_t *list,\n      const char *path, const char *label,\n      unsigned type, size_t directory_ptr,\n      size_t entry_idx,\n      size_t idx)\n{\n   /* Expand file list if needed */\n   if (list->size >= list->capacity)\n   {\n      size_t new_capacity = list->capacity > 0 ? list->capacity * 2 : 1;\n      if (!file_list_reserve(list, new_capacity))\n         return false;\n   }\n\n   /* Shift elements to the right using memmove */\n   if (idx < list->size)\n      memmove(&list->list[idx + 1], &list->list[idx],\n            (list->size - idx) * sizeof(struct item_file));\n\n   init_item_file(&list->list[idx], path, label, type, directory_ptr, entry_idx);\n   list->size++;\n\n   return true;\n}\n\nbool file_list_append(file_list_t *list,\n      const char *path, const char *label,\n      unsigned type, size_t directory_ptr,\n      size_t entry_idx)\n{\n   unsigned idx = (unsigned)list->size;\n   /* Expand file list if needed */\n   if (idx >= list->capacity)\n      if (!file_list_reserve(list, list->capacity * 2 + 1))\n         return false;\n\n   list->list[idx].path          = NULL;\n   list->list[idx].label         = NULL;\n   list->list[idx].alt           = NULL;\n   list->list[idx].type          = type;\n   list->list[idx].directory_ptr = directory_ptr;\n   list->list[idx].entry_idx     = entry_idx;\n   list->list[idx].userdata      = NULL;\n   list->list[idx].actiondata    = NULL;\n\n   if (label)\n      list->list[idx].label      = strdup(label);\n   if (path)\n      list->list[idx].path       = strdup(path);\n\n   list->size++;\n\n   return true;\n}\n\nvoid file_list_pop(file_list_t *list, size_t *directory_ptr)\n{\n   if (!list)\n      return;\n\n   if (list->size != 0)\n   {\n      --list->size;\n      if (list->list[list->size].path)\n         free(list->list[list->size].path);\n      list->list[list->size].path = NULL;\n\n      if (list->list[list->size].label)\n         free(list->list[list->size].label);\n      list->list[list->size].label = NULL;\n   }\n\n   if (directory_ptr)\n      *directory_ptr = list->list[list->size].directory_ptr;\n}\n\nvoid file_list_free(file_list_t *list)\n{\n   if (!list)\n      return;\n   file_list_deinitialize_internal(list);\n   free(list);\n}\n\nbool file_list_deinitialize(file_list_t *list)\n{\n   if (!list)\n      return false;\n   if (!file_list_deinitialize_internal(list))\n      return false;\n   list->capacity = 0;\n   list->size     = 0;\n   return true;\n}\n\nvoid file_list_clear(file_list_t *list)\n{\n   size_t i;\n\n   if (!list)\n      return;\n\n   for (i = 0; i < list->size; i++)\n   {\n      if (list->list[i].path)\n         free(list->list[i].path);\n      list->list[i].path = NULL;\n\n      if (list->list[i].label)\n         free(list->list[i].label);\n      list->list[i].label = NULL;\n\n      if (list->list[i].alt)\n         free(list->list[i].alt);\n      list->list[i].alt = NULL;\n   }\n\n   list->size = 0;\n}\n\nstatic void file_list_get_label_at_offset(const file_list_t *list, size_t idx,\n      const char **label)\n{\n   if (!label || !list)\n      return;\n\n   *label = list->list[idx].path;\n   if (list->list[idx].label)\n      *label = list->list[idx].label;\n}\n\nvoid file_list_set_alt_at_offset(file_list_t *list, size_t idx,\n      const char *alt)\n{\n   if (!list || !alt)\n      return;\n   if (list->list[idx].alt)\n      free(list->list[idx].alt);\n   list->list[idx].alt   = strdup(alt);\n}\n\nstatic int file_list_alt_cmp(const void *a_, const void *b_)\n{\n   const struct item_file *a = (const struct item_file*)a_;\n   const struct item_file *b = (const struct item_file*)b_;\n   const char *cmp_a         = a->alt ? a->alt : a->path;\n   const char *cmp_b         = b->alt ? b->alt : b->path;\n   return strcasecmp(cmp_a, cmp_b);\n}\n\nstatic int file_list_type_cmp(const void *a_, const void *b_)\n{\n   const struct item_file *a = (const struct item_file*)a_;\n   const struct item_file *b = (const struct item_file*)b_;\n   if (a->type < b->type)\n      return -1;\n   if (a->type == b->type)\n      return 0;\n\n   return 1;\n}\n\nvoid file_list_sort_on_alt(file_list_t *list)\n{\n   qsort(list->list, list->size, sizeof(list->list[0]), file_list_alt_cmp);\n}\n\nvoid file_list_sort_on_type(file_list_t *list)\n{\n   qsort(list->list, list->size, sizeof(list->list[0]), file_list_type_cmp);\n}\n\nvoid *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx)\n{\n   if (!list)\n      return NULL;\n   return list->list[idx].userdata;\n}\n\nvoid *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx)\n{\n   if (!list)\n      return NULL;\n   return list->list[idx].actiondata;\n}\n\nvoid file_list_free_actiondata(const file_list_t *list, size_t idx)\n{\n   if (!list)\n      return;\n   if (list->list[idx].actiondata)\n       free(list->list[idx].actiondata);\n   list->list[idx].actiondata = NULL;\n}\n\nvoid file_list_free_userdata(const file_list_t *list, size_t idx)\n{\n   if (!list)\n      return;\n   if (list->list[idx].userdata)\n       free(list->list[idx].userdata);\n   list->list[idx].userdata = NULL;\n}\n\nbool file_list_search(const file_list_t *list, const char *needle, size_t *idx)\n{\n   size_t i;\n   bool ret        = false;\n\n   if (!list)\n      return false;\n\n   for (i = 0; i < list->size; i++)\n   {\n      const char *str = NULL;\n      const char *alt = list->list[i].alt\n            ? list->list[i].alt\n            : list->list[i].path;\n\n      if (!alt)\n      {\n         file_list_get_label_at_offset(list, i, &alt);\n         if (!alt)\n            continue;\n      }\n\n      if ((str = (const char *)strcasestr(alt, needle)) == alt)\n      {\n         /* Found match with first chars, best possible match. */\n         *idx = i;\n         ret  = true;\n         break;\n      }\n      else if (str && !ret)\n      {\n         /* Found mid-string match, but try to find a match with\n          * first characters before we settle. */\n         *idx = i;\n         ret  = true;\n      }\n   }\n\n   return ret;\n}\n"
  },
  {
    "path": "lists/linked_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (linked_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <boolean.h>\n#include <stddef.h>\n#include <stdlib.h>\n\n#include <lists/linked_list.h>\n\nstruct linked_list_item_t\n{\n   void *value;\n   struct linked_list_item_t *previous;\n   struct linked_list_item_t *next;\n};\n\nstruct linked_list\n{\n   struct linked_list_item_t *first_item;\n   struct linked_list_item_t *last_item;\n   size_t length;\n};\n\nstruct linked_list_iterator\n{\n   linked_list_t *list;\n   struct linked_list_item_t *item;\n   bool forward;\n};\n\nlinked_list_t *linked_list_new(void)\n{\n   linked_list_t *list;\n\n   list = (linked_list_t *)calloc(1, sizeof(linked_list_t));\n   return list;\n}\n\nvoid linked_list_free(linked_list_t *list, void (*free_value)(void *value))\n{\n   if (!list)\n   {\n      return;\n   }\n\n   while (list->first_item)\n   {\n      struct linked_list_item_t *next;\n\n      next = list->first_item->next;\n      if (free_value)\n         free_value(list->first_item->value);\n      free(list->first_item);\n\n      list->first_item = next;\n   }\n\n   free (list);\n}\n\nvoid linked_list_add(linked_list_t *list, void *value)\n{\n   struct linked_list_item_t *new_item;\n\n   if (!list)\n      return;\n\n   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));\n   new_item->value = value;\n   new_item->previous = list->last_item;\n   new_item->next = NULL;\n\n   if (list->length == 0)\n      list->first_item = new_item;\n   else\n      list->last_item->next = new_item;\n\n   list->last_item = new_item;\n   list->length++;\n}\n\nvoid linked_list_insert(linked_list_t *list, size_t index, void *value)\n{\n   size_t i;\n   struct linked_list_item_t *previous_item;\n   struct linked_list_item_t *next_item;\n   struct linked_list_item_t *new_item;\n\n   if (!list || index > list->length)\n      return;\n\n   previous_item = NULL;\n   next_item = list->first_item;\n   for (i = 1; i <= index; i++)\n   {\n      previous_item = next_item;\n      next_item = next_item->next;\n   }\n\n   new_item = (struct linked_list_item_t *)malloc(sizeof(struct linked_list_item_t));\n   new_item->value = value;\n\n   if (previous_item)\n      previous_item->next = new_item;\n   else\n      list->first_item = new_item;\n   new_item->previous = previous_item;\n\n   if (next_item)\n      next_item->previous = new_item;\n   else\n      list->last_item = new_item;\n   new_item->next = next_item;\n\n   list->length++;\n}\n\nvoid *linked_list_get(linked_list_t *list, size_t index)\n{\n   size_t i;\n   struct linked_list_item_t *item;\n\n   if (!list)\n      return NULL;\n\n   if (index >= list->length)\n      return NULL;\n\n   item = list->first_item;\n   for (i = 1; i <= index; i++)\n      item = item->next;\n\n   return item->value;\n}\n\nvoid *linked_list_get_first_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)\n{\n   struct linked_list_item_t *item;\n\n   if (!list || !matches)\n      return NULL;\n\n   for (item = list->first_item; item; item = item->next)\n   {\n      if (matches(item->value, usrptr))\n         return item->value;\n   }\n\n   return NULL;\n}\n\nvoid *linked_list_get_last_matching(linked_list_t *list, bool (*matches)(void *item, void *usrptr), void *usrptr)\n{\n   struct linked_list_item_t *item;\n\n   if (!list || !matches)\n      return NULL;\n\n   for (item = list->last_item; item; item = item->previous)\n   {\n      if (matches(item->value, usrptr))\n         return item->value;\n   }\n\n   return NULL;\n}\n\nstatic void _linked_list_remove_item(linked_list_t *list, struct linked_list_item_t *item)\n{\n   struct linked_list_item_t *previous_item;\n   struct linked_list_item_t *next_item;\n\n   previous_item = item->previous;\n   next_item = item->next;\n   free(item);\n   list->length--;\n\n   if (previous_item)\n      previous_item->next = next_item;\n   else\n      list->first_item = next_item;\n\n   if (next_item)\n      next_item->previous = previous_item;\n   else\n      list->last_item = previous_item;\n}\n\nvoid *linked_list_remove_at(linked_list_t *list, size_t index)\n{\n   size_t i = 0;\n   struct linked_list_item_t *item;\n   void *value;\n\n   if (!list || list->length == 0 || index >= list->length)\n      return NULL;\n\n   item = list->first_item;\n   for (i = 1; i <= index; i++)\n      item = item->next;\n\n   value = item->value;\n   _linked_list_remove_item(list, item);\n   return value;\n}\n\nvoid *linked_list_remove_first(linked_list_t *list, void *value)\n{\n   struct linked_list_item_t *item;\n\n   if (!list)\n      return NULL;\n\n   for (item = list->first_item; item; item = item->next)\n   {\n      if (item->value == value)\n         break;\n   }\n\n   if (item)\n   {\n      _linked_list_remove_item(list, item);\n      return value;\n   }\n\n   return NULL;\n}\n\nvoid *linked_list_remove_last(linked_list_t *list, void *value)\n{\n   struct linked_list_item_t *item;\n\n   if (!list)\n      return NULL;\n\n   for (item = list->last_item; item; item = item->previous)\n   {\n      if (item->value == value)\n         break;\n   }\n\n   if (item)\n   {\n      _linked_list_remove_item(list, item);\n      return value;\n   }\n\n   return NULL;\n}\n\nvoid *linked_list_remove_all(linked_list_t *list, void *value)\n{\n   struct linked_list_item_t *item;\n   bool found = false;\n\n   if (!list)\n      return NULL;\n\n   for (item = list->first_item; item;)\n   {\n      if (item->value == value)\n      {\n         struct linked_list_item_t *next_item;\n\n         next_item = item->next;\n         _linked_list_remove_item(list, item);\n         found = true;\n         item = next_item;\n      } else\n      {\n         item = item->next;\n      }\n   }\n\n   return found ? value : NULL;\n}\n\nvoid *linked_list_remove_first_matching(linked_list_t *list, bool (*matches)(void *value))\n{\n   struct linked_list_item_t *item;\n\n   if (!list)\n      return NULL;\n\n   for (item = list->first_item; item; item = item->next)\n   {\n      if (matches(item->value))\n         break;\n   }\n\n   if (item)\n   {\n      void *value;\n\n      value = item->value;\n      _linked_list_remove_item(list, item);\n      return value;\n   }\n\n   return NULL;\n}\n\nvoid *linked_list_remove_last_matching(linked_list_t *list, bool (*matches)(void *value))\n{\n   struct linked_list_item_t *item;\n\n   if (!list)\n      return NULL;\n\n   for (item = list->last_item; item; item = item->previous)\n   {\n      if (matches(item->value))\n         break;\n   }\n\n   if (item)\n   {\n      void *value;\n\n      value = item->value;\n      _linked_list_remove_item(list, item);\n      return value;\n   }\n\n   return NULL;\n}\n\nvoid linked_list_remove_all_matching(linked_list_t *list, bool (*matches)(void *value))\n{\n   struct linked_list_item_t *item;\n\n   if (!list)\n      return;\n\n   for (item = list->first_item; item;)\n   {\n      if (matches(item->value))\n      {\n         struct linked_list_item_t *next_item;\n\n         next_item = item->next;\n         _linked_list_remove_item(list, item);\n         item = next_item;\n      } else\n      {\n         item = item->next;\n      }\n   }\n}\n\nbool linked_list_set_at(linked_list_t *list, size_t index, void *value)\n{\n   struct linked_list_item_t *item;\n   size_t i;\n\n   if (!list || list->length == 0 || index >= list->length)\n      return false;\n\n   item = list->first_item;\n   for (i = 1; i <= index; i++)\n      item = item->next;\n\n   if (item)\n   {\n      item->value = value;\n      return true;\n   }\n\n   return false;\n}\n\nsize_t linked_list_size(linked_list_t *list)\n{\n   if (list)\n      return list->length;\n\n   return 0;\n}\n\nlinked_list_iterator_t *linked_list_iterator(linked_list_t *list, bool forward)\n{\n   linked_list_iterator_t *iterator;\n\n   if (!list || !list->first_item)\n      return NULL;\n\n   iterator = (linked_list_iterator_t *)malloc(sizeof(linked_list_iterator_t));\n   iterator->list = list;\n   iterator->item = forward ? list->first_item : list->last_item;\n   iterator->forward = forward;\n\n   return iterator;\n}\n\nlinked_list_iterator_t *linked_list_iterator_next(linked_list_iterator_t *iterator)\n{\n   struct linked_list_item_t *item;\n\n   if (!iterator)\n      return NULL;\n\n   item = iterator->forward ? iterator->item->next : iterator->item->previous;\n   if (item)\n   {\n      iterator->item = item;\n      return iterator;\n   } else\n   {\n      free(iterator);\n      return NULL;\n   }\n}\n\nvoid *linked_list_iterator_value(linked_list_iterator_t *iterator)\n{\n   if (iterator)\n      return iterator->item->value;\n\n   return NULL;\n}\n\nlinked_list_iterator_t *linked_list_iterator_remove(linked_list_iterator_t *iterator)\n{\n   struct linked_list_item_t *next_item;\n\n   if (!iterator)\n      return NULL;\n\n   next_item = iterator->forward ? iterator->item->next : iterator->item->previous;\n   _linked_list_remove_item(iterator->list, iterator->item);\n\n   if (next_item)\n   {\n      iterator->item = next_item;\n      return iterator;\n   } else\n   {\n      free(iterator);\n      return NULL;\n   }\n}\n\nvoid linked_list_iterator_free(linked_list_iterator_t *iterator)\n{\n   if (iterator)\n      free(iterator);\n}\n\nvoid linked_list_foreach(linked_list_t *list, void (*fn)(size_t index, void *value))\n{\n   size_t i;\n   struct linked_list_item_t *item;\n\n   if (!list || !fn)\n      return;\n\n   i = 0;\n   for (item = list->first_item; item; item = item->next)\n      fn(i++, item->value);\n}\n"
  },
  {
    "path": "lists/nested_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (nested_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include <compat/strl.h>\n#include <lists/string_list.h>\n#include <array/rbuf.h>\n#include <array/rhmap.h>\n\n#include <lists/nested_list.h>\n\nstruct nested_list_item\n{\n   nested_list_item_t *parent_item;\n   nested_list_t *parent_list;\n   nested_list_t *children;\n   char *id;\n   const void *value;\n};\n\nstruct nested_list\n{\n   nested_list_item_t **items;\n   nested_list_item_t **item_map;\n};\n\n/**************************************/\n/* Initialisation / De-Initialisation */\n/**************************************/\n\n/* Forward declaration - required since\n * nested_list_free_list() is recursive */\nstatic void nested_list_free_list(nested_list_t *list);\n\n/* Frees contents of a nested list item */\nstatic void nested_list_free_item(nested_list_item_t *item)\n{\n   if (!item)\n      return;\n\n   item->parent_item = NULL;\n   item->parent_list = NULL;\n\n   if (item->children)\n   {\n      nested_list_free_list(item->children);\n      item->children = NULL;\n   }\n\n   if (item->id)\n   {\n      free(item->id);\n      item->id = NULL;\n   }\n\n   item->value = NULL;\n   free(item);\n}\n\n/* Frees contents of a nested list */\nstatic void nested_list_free_list(nested_list_t *list)\n{\n   size_t i;\n\n   if (!list)\n      return;\n\n   for (i = 0; i < RBUF_LEN(list->items); i++)\n      nested_list_free_item(list->items[i]);\n\n   RBUF_FREE(list->items);\n   RHMAP_FREE(list->item_map);\n   free(list);\n}\n\n/**\n * nested_list_init:\n *\n * Creates a new empty nested list. Returned pointer\n * must be freed using nested_list_free.\n *\n * Returns: Valid nested_list_t pointer if successful,\n * otherwise NULL.\n */\nnested_list_t *nested_list_init(void)\n{\n   /* Create nested list */\n   nested_list_t *list = (nested_list_t*)malloc(sizeof(*list));\n\n   if (!list)\n      return NULL;\n\n   /* Initialise members */\n   list->items    = NULL;\n   list->item_map = NULL;\n\n   return list;\n}\n\n/**\n * nested_list_free:\n * @list : pointer to nested_list_t object\n *\n * Frees specified nested list.\n */\nvoid nested_list_free(nested_list_t *list)\n{\n   nested_list_free_list(list);\n}\n\n/***********/\n/* Setters */\n/***********/\n\n/* Creates and adds a new item to the specified\n * nested list. Returns NULL if item matching 'id'\n * already exists */\nstatic nested_list_item_t *nested_list_add_item_to_list(nested_list_t *list,\n      nested_list_item_t *parent_item, const char *id, const void *value)\n{\n   size_t num_items             = 0;\n   nested_list_item_t *new_item = NULL;\n   nested_list_t *child_list    = NULL;\n\n   if (!list || !id || !*id)\n      return NULL;\n\n   num_items = RBUF_LEN(list->items);\n\n   /* Ensure that item does not already exist */\n   if (RHMAP_HAS_STR(list->item_map, id))\n      return NULL;\n\n   /* Attempt to allocate a buffer slot for the\n    * new item */\n   if (!RBUF_TRYFIT(list->items, num_items + 1))\n      return NULL;\n\n   /* Create new empty child list */\n   child_list = nested_list_init();\n   if (!child_list)\n      return NULL;\n\n   /* Create new list item */\n   new_item = (nested_list_item_t*)malloc(sizeof(*new_item));\n   if (!new_item)\n   {\n      nested_list_free(child_list);\n      return NULL;\n   }\n\n   /* Assign members */\n   new_item->parent_item = parent_item;\n   new_item->parent_list = list;\n   new_item->children    = child_list;\n   new_item->id          = strdup(id);\n   new_item->value       = value;\n\n   /* Increment item buffer size */\n   RBUF_RESIZE(list->items, num_items + 1);\n\n   /* Add new item to buffer */\n   list->items[num_items] = new_item;\n\n   /* Update map */\n   RHMAP_SET_STR(list->item_map, id, new_item);\n   return new_item;\n}\n\n/**\n * nested_list_add_item:\n *\n * @list    : pointer to nested_list_t object\n * @address : a delimited list of item identifiers,\n *            corresponding to item 'levels'\n * @delim   : delimiter to use when splitting @address\n *            into individual ids\n * @value   : optional value (user data) associated with\n *            new list item. This is added to the last\n *            item specified by @address\n *\n * Appends a new item to the specified nested list.\n * If @delim is NULL, item is added to the top level\n * list (@list itself) with id equal to @address.\n * Otherwise, @address is split by @delim and each\n * id is added as new 'layer'. For example:\n *\n * > @address = \"one:two:three\", @delim = \":\" will\n *   produce:\n *      top_level_list:one\n *                     `- \"one\" list:two\n *                                   `- \"two\" list:three\n *   where @value is assigned to the \"two\" list:three\n *   item.\n *\n * Returns: true if successful, otherwise false. Will\n * always return false if item specified by @address\n * already exists in the nested list.\n */\nbool nested_list_add_item(nested_list_t *list,\n      const char *address, const char *delim, const void *value)\n{\n   struct string_list id_list = {0};\n   const char *top_id         = NULL;\n   bool success               = false;\n   if (!list || !address || !*address)\n      return false;\n   if (!delim || !*delim)\n      top_id = address;\n   else\n   {\n      string_list_initialize(&id_list);\n      if (  !string_split_noalloc(&id_list, address, delim)\n          || (id_list.size < 1))\n         goto end;\n      if (id_list.size == 1)\n         top_id = id_list.elems[0].data;\n   }\n   if (top_id && *top_id)\n   {\n      if (nested_list_add_item_to_list(list, NULL, top_id, value))\n         success = true;\n   }\n   else\n   {\n      size_t i;\n      nested_list_t *current_list     = list;\n      nested_list_item_t *parent_item = NULL;\n      nested_list_item_t *next_item   = NULL;\n      for (i = 0; i < id_list.size; i++)\n      {\n         const char *id = id_list.elems[i].data;\n         if (!id || !*id)\n            goto end;\n         if (i == (id_list.size - 1))\n         {\n            if (nested_list_add_item_to_list(current_list,\n                  parent_item, id, value))\n               success = true;\n            break;\n         }\n         else\n         {\n            next_item = RHMAP_GET_STR(current_list->item_map, id);\n            if (!next_item)\n               next_item = nested_list_add_item_to_list(current_list,\n                     parent_item, id, NULL);\n            if (!next_item)\n               break;\n            parent_item  = next_item;\n            current_list = next_item->children;\n         }\n      }\n   }\nend:\n   string_list_deinitialize(&id_list);\n   return success;\n}\n\n/***********/\n/* Getters */\n/***********/\n\n/**\n * nested_list_get_size:\n *\n * @list : pointer to nested_list_t object\n *\n * Fetches the current size (number of items) in\n * the specified list.\n *\n * Returns: list size.\n */\nsize_t nested_list_get_size(nested_list_t *list)\n{\n   if (!list)\n      return 0;\n\n   return RBUF_LEN(list->items);\n}\n\n/**\n * nested_list_get_item:\n *\n * @list    : pointer to nested_list_t object\n * @address : a delimited list of item identifiers,\n *            corresponding to item 'levels'\n * @delim   : delimiter to use when splitting @address\n *            into individual ids\n *\n * Searches for (and returns) the list item corresponding\n * to @address. If @delim is NULL, the top level list\n * (@list itself) is searched for an item with an id\n * equal to @address. Otherwise, @address is split by\n * @delim and each id is searched for in a subsequent\n * list level.\n *\n * Returns: valid nested_list_item_t pointer if item\n * is found, otherwise NULL.\n */\nnested_list_item_t *nested_list_get_item(nested_list_t *list,\n      const char *address, const char *delim)\n{\n   nested_list_item_t *search_item = NULL;\n   struct string_list id_list      = {0};\n   const char *top_id              = NULL;\n   if (!list || !address || !*address)\n      return NULL;\n   if (!delim || !*delim)\n      top_id = address;\n   else\n   {\n      string_list_initialize(&id_list);\n      if (  !string_split_noalloc(&id_list, address, delim)\n          || (id_list.size < 1))\n         goto end;\n      if (id_list.size == 1)\n         top_id = id_list.elems[0].data;\n   }\n   if (top_id && *top_id)\n      search_item = RHMAP_GET_STR(list->item_map, top_id);\n   else\n   {\n      nested_list_t *current_list   = list;\n      nested_list_item_t *next_item = NULL;\n      size_t i;\n      for (i = 0; i < id_list.size; i++)\n      {\n         const char *id = id_list.elems[i].data;\n         if (!id || !*id)\n            goto end;\n         if (i == (id_list.size - 1))\n         {\n            search_item = RHMAP_GET_STR(current_list->item_map, id);\n            break;\n         }\n         else\n         {\n            next_item = RHMAP_GET_STR(current_list->item_map, id);\n            if (!next_item)\n               break;\n            current_list = next_item->children;\n         }\n      }\n   }\nend:\n   string_list_deinitialize(&id_list);\n   return search_item;\n}\n\n/**\n * nested_list_get_item_idx:\n *\n * @list : pointer to nested_list_t object\n * @idx  : item index\n *\n * Fetches the item corresponding to index @idx in\n * the top level list (@list itself) of the specified\n * nested list.\n *\n * Returns: valid nested_list_item_t pointer if item\n * exists, otherwise NULL.\n */\nnested_list_item_t *nested_list_get_item_idx(nested_list_t *list,\n      size_t idx)\n{\n   if (!list || (idx >= RBUF_LEN(list->items)))\n      return NULL;\n\n   return list->items[idx];\n}\n\n/**\n * nested_list_item_get_parent:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches the parent item of the specified nested\n * list item. If returned value is NULL, specified\n * nested list item belongs to a top level list.\n *\n * Returns: valid nested_list_item_t pointer if item\n * has a parent, otherwise NULL.\n */\nnested_list_item_t *nested_list_item_get_parent(nested_list_item_t *list_item)\n{\n   if (!list_item)\n      return NULL;\n\n   return list_item->parent_item;\n}\n\n/**\n * nested_list_item_get_parent_list:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches a pointer to the nested list of which the\n * specified list item is a direct member.\n *\n * Returns: valid nested_list_t pointer if successful,\n * otherwise NULL.\n */\nnested_list_t *nested_list_item_get_parent_list(nested_list_item_t *list_item)\n{\n   if (!list_item)\n      return NULL;\n\n   return list_item->parent_list;\n}\n\n/**\n * nested_list_item_get_children:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches a pointer to the nested list of child items\n * belonging to the specified list item.\n *\n * Returns: valid nested_list_t pointer if item has\n * children, otherwise NULL.\n */\nnested_list_t *nested_list_item_get_children(nested_list_item_t *list_item)\n{\n   if (   !list_item\n       || !list_item->children\n       || (RBUF_LEN(list_item->children->items) < 1))\n      return NULL;\n\n   return list_item->children;\n}\n\n/**\n * nested_list_item_get_id:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches the id string of the specified list item,\n * as set by nested_list_add_item().\n *\n * Returns: item id if successful, otherwise NULL.\n */\nconst char *nested_list_item_get_id(nested_list_item_t *list_item)\n{\n   if (!list_item)\n      return NULL;\n   return list_item->id;\n}\n\n/**\n * nested_list_item_get_address:\n *\n * @list_item : pointer to nested_list_item_t object\n * @delim     : delimiter to use when concatenating\n *              individual item ids into a an @address\n *              string\n * @s         : a delimited list of item identifiers,\n *              corresponding to item 'levels'\n * @len       : length of supplied @address char array\n\n * Fetches a compound @address string corresponding to\n * the specified item's 'position' in the top level\n * nested list of which it is a member. The resultant\n * @address may be used to find the item when calling\n * nested_list_get_item() on the top level nested list.\n *\n * Returns: true if successful, otherwise false.\n */\nbool nested_list_item_get_address(nested_list_item_t *list_item,\n      const char *delim, char *s, size_t len)\n{\n   if (  !list_item\n       || !delim\n       || !s\n       || (len < 1))\n      return false;\n   s[0] = '\\0';\n   /* We have to combine the IDs\n    * of the item and all of its 'ancestors' */\n   if (list_item->parent_item)\n   {\n      size_t i;\n      union string_list_elem_attr attr;\n      struct string_list id_list       = {0};\n      nested_list_item_t *current_item = list_item;\n      string_list_initialize(&id_list);\n      attr.i     = 0;\n      /* Fetch all ids */\n      do\n      {\n         if (!string_list_append(&id_list, current_item->id, attr))\n         {\n            string_list_deinitialize(&id_list);\n            return false;\n         }\n         current_item = current_item->parent_item;\n      } while (current_item);\n      /* Build address string */\n      {\n         size_t _offset = 0;\n         for (i = id_list.size; i > 0; i--)\n         {\n            size_t _len;\n            const char *id = id_list.elems[i - 1].data;\n            _len    = strlcpy(s + _offset, id, len - _offset);\n            _offset += _len;\n            if (_offset >= len)\n            {\n               string_list_deinitialize(&id_list);\n               return false;\n            }\n            if (i > 1)\n            {\n               _len     = strlcpy(s + _offset, delim, len - _offset);\n               _offset += _len;\n               if (_offset >= len)\n               {\n                  string_list_deinitialize(&id_list);\n                  return false;\n               }\n            }\n         }\n      }\n      string_list_deinitialize(&id_list);\n   }\n   /* If this is an item of the top level\n    * list, just copy the item ID directly */\n   else\n      strlcpy(s, list_item->id, len);\n   return true;\n}\n\n/**\n * nested_list_item_get_value:\n *\n * @list_item : pointer to nested_list_item_t object\n *\n * Fetches the value (user data) associated with the\n * specified list item.\n *\n * Returns: pointer to user data if set, otherwise\n * NULL.\n */\nconst void *nested_list_item_get_value(nested_list_item_t *list_item)\n{\n   if (!list_item)\n      return NULL;\n\n   return list_item->value;\n}\n"
  },
  {
    "path": "lists/string_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (string_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <string.h>\n#include <ctype.h>\n\n#include <lists/string_list.h>\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n\nstatic bool string_list_deinitialize_internal(struct string_list *list)\n{\n   if (!list)\n      return false;\n\n   if (list->elems)\n   {\n      unsigned i;\n      for (i = 0; i < (unsigned)list->size; i++)\n      {\n         if (list->elems[i].data)\n            free(list->elems[i].data);\n         if (list->elems[i].userdata)\n            free(list->elems[i].userdata);\n      }\n\n      free(list->elems);\n   }\n\n   list->elems = NULL;\n\n   return true;\n}\n\nbool string_list_capacity(struct string_list *list, size_t cap)\n{\n   struct string_list_elem *new_data = (struct string_list_elem*)\n      realloc(list->elems, cap * sizeof(*new_data));\n\n   if (!new_data)\n      return false;\n\n   if (cap > list->cap)\n      memset(&new_data[list->cap], 0,\n            sizeof(*new_data) * (cap - list->cap));\n\n   list->elems = new_data;\n   list->cap   = cap;\n   return true;\n}\n\nvoid string_list_free(struct string_list *list)\n{\n   if (!list)\n      return;\n\n   string_list_deinitialize_internal(list);\n\n   free(list);\n}\n\nbool string_list_deinitialize(struct string_list *list)\n{\n   if (!list)\n      return false;\n   if (!string_list_deinitialize_internal(list))\n      return false;\n   list->elems = NULL;\n   list->size  = 0;\n   list->cap   = 0;\n   return true;\n}\n\nstruct string_list *string_list_new(void)\n{\n   struct string_list_elem *elems = NULL;\n   struct string_list *list = (struct string_list*)\n      malloc(sizeof(*list));\n   if (!list)\n      return NULL;\n\n   list->cap  = 0;\n   list->size = 0;\n   list->elems = NULL;\n\n   elems = (struct string_list_elem*)\n      calloc(32, sizeof(*elems));\n   if (!elems)\n   {\n      free(list);\n      return NULL;\n   }\n\n   list->elems = elems;\n   list->cap   = 32;\n\n   return list;\n}\n\nbool string_list_initialize(struct string_list *list)\n{\n   struct string_list_elem *elems = NULL;\n   if (!list)\n      return false;\n\n   elems = (struct string_list_elem*)\n      calloc(32, sizeof(*elems));\n   if (!elems)\n   {\n      string_list_deinitialize(list);\n      return false;\n   }\n\n   list->elems = elems;\n   list->size  = 0;\n   list->cap   = 32;\n   return true;\n}\n\nbool string_list_append(struct string_list *list, const char *elem,\n      union string_list_elem_attr attr)\n{\n   char *data_dup = NULL;\n\n   if (      list->size >= list->cap\n         && !string_list_capacity(list,\n               (list->cap > 0) ? (list->cap * 2) : 32))\n      return false;\n\n   data_dup = strdup(elem);\n   if (!data_dup)\n      return false;\n\n   list->elems[list->size].data = data_dup;\n   list->elems[list->size].attr = attr;\n   list->size++;\n\n   return true;\n}\n\nbool string_list_append_n(struct string_list *list, const char *elem,\n      size_t len, union string_list_elem_attr attr)\n{\n   char *data_dup = NULL;\n\n   if (      list->size >= list->cap\n         && !string_list_capacity(list,\n               (list->cap > 0) ? (list->cap * 2) : 32))\n      return false;\n\n   data_dup = (char*)malloc(len + 1);\n   if (!data_dup)\n      return false;\n   memcpy(data_dup, elem, len);\n   data_dup[len] = '\\0';\n\n   list->elems[list->size].data = data_dup;\n   list->elems[list->size].attr = attr;\n   list->size++;\n   return true;\n}\n\nvoid string_list_join_concat(char *s, size_t len,\n      const struct string_list *list, const char *delim)\n{\n   size_t _len = strlen(s);\n\n   /* If @s is already 'full', nothing\n    * further can be added\n    * > This condition will also be triggered\n    *   if @s is not NULL-terminated,\n    *   in which case any attempt to increment\n    *   @s or decrement @len would lead to\n    *   undefined behaviour */\n   if (_len < len)\n   {\n      size_t i;\n      for (i = 0; i < list->size; i++)\n      {\n         _len += strlcpy(s + _len, list->elems[i].data, len - _len);\n         if ((i + 1) < list->size)\n            _len += strlcpy(s + _len, delim, len - _len);\n      }\n   }\n}\n\nvoid string_list_join_concat_special(char *s, size_t len,\n      const struct string_list *list, const char *delim)\n{\n   size_t i;\n   size_t _len = strlen(s);\n   for (i = 0; i < list->size; i++)\n   {\n      _len += strlcpy(s + _len, list->elems[i].data, len - _len);\n      if ((i + 1) < list->size)\n         _len += strlcpy(s + _len, delim, len - _len);\n   }\n}\n\n/**\n * Count delimited tokens in @str without modifying it.\n * Treats any character in @delim as a separator (same as strtok).\n * Returns the number of non-empty tokens.\n */\nstatic size_t string_count_tokens(const char *str, const char *delim)\n{\n   size_t count   = 0;\n   bool   in_tok  = false;\n   const char *p  = str;\n\n   for (; *p != '\\0'; p++)\n   {\n      if (strchr(delim, (unsigned char)*p))\n         in_tok = false;\n      else if (!in_tok)\n      {\n         in_tok = true;\n         count++;\n      }\n   }\n\n   return count;\n}\n\nstruct string_list *string_split(const char *str, const char *delim)\n{\n   const char *p = str;\n   struct string_list *list = string_list_new();\n   if (!list)\n      return NULL;\n\n   while (*p)\n   {\n      union string_list_elem_attr attr;\n      const char *tok;\n\n      while (*p && strchr(delim, *p))\n         p++;\n      if (!*p)\n         break;\n\n      tok = p;\n      while (*p && !strchr(delim, *p))\n         p++;\n\n      attr.i = 0;\n      if (!string_list_append_n(list, tok, p - tok, attr))\n         goto error;\n   }\n\n   return list;\n\nerror:\n   string_list_free(list);\n   return NULL;\n}\n\nbool string_split_noalloc(struct string_list *list,\n      const char *str, const char *delim)\n{\n   size_t _len;\n   const char *end;\n   const char *p   = str;\n\n   if (!list || !str || !delim || !*delim)\n      return false;\n\n   /* Compute delimiter length once. */\n   {\n      const char *d = delim;\n      while (*d)\n         d++;\n      _len = d - delim;\n   }\n\n   /* Pre-size to avoid repeated reallocs. */\n   {\n      size_t __len = string_count_tokens(str, delim);\n      if (__len > list->cap)\n      {\n         if (!string_list_capacity(list, __len))\n            return false;\n      }\n   }\n\n   while (*p)\n   {\n      union string_list_elem_attr attr;\n      size_t __len;\n\n      attr.i = 0;\n      end    = strstr(p, delim);\n\n      if (end)\n      {\n         __len = end - p;\n         if (__len > 0)\n         {\n            if (!string_list_append_n(list, p, __len, attr))\n               return false;\n         }\n         p = end + _len;\n      }\n      else\n      {\n         const char *s = p;\n         while (*s)\n            s++;\n         __len = s - p;\n         if (__len > 0)\n         {\n            if (!string_list_append_n(list, p, __len, attr))\n               return false;\n         }\n         break;\n      }\n   }\n\n   return true;\n}\n\nint string_list_find_elem(const struct string_list *list, const char *elem)\n{\n   if (list && elem)\n   {\n      size_t i;\n      for (i = 0; i < list->size; i++)\n      {\n         const unsigned char *p1 = (const unsigned char*)list->elems[i].data;\n         const unsigned char *p2 = (const unsigned char*)elem;\n         while ((*p1 | 32) == (*p2 | 32) || (*p1 == *p2))\n         {\n            if (*p1 == '\\0')\n               return (int)(i + 1);\n            p1++;\n            p2++;\n         }\n      }\n   }\n   return 0;\n}\n\nbool string_list_find_elem_prefix(const struct string_list *list,\n      const char *prefix, const char *elem)\n{\n   if (list)\n   {\n      size_t i;\n      char prefixed[255];\n      size_t _len = strlcpy(prefixed, prefix, sizeof(prefixed));\n      strlcpy(prefixed + _len, elem, sizeof(prefixed) - _len);\n      for (i = 0; i < list->size; i++)\n      {\n         const char *data = list->elems[i].data;\n         const char *a    = data;\n         const char *b    = elem;\n         while (tolower((unsigned char)*a) == tolower((unsigned char)*b))\n         {\n            if (*a == '\\0')\n               return true;\n            a++;\n            b++;\n         }\n\n         a = data;\n         b = prefixed;\n         while (tolower((unsigned char)*a) == tolower((unsigned char)*b))\n         {\n            if (*a == '\\0')\n               return true;\n            a++;\n            b++;\n         }\n      }\n   }\n   return false;\n}\n\nstruct string_list *string_list_clone(const struct string_list *src)\n{\n   size_t i;\n   struct string_list_elem *elems = NULL;\n   struct string_list *dest       = (struct string_list*)\n      malloc(sizeof(struct string_list));\n\n   if (!dest)\n      return NULL;\n\n   dest->elems = NULL;\n   dest->size  = src->size;\n   dest->cap   = (src->cap < dest->size) ? dest->size : src->cap;\n\n   elems = (struct string_list_elem*)\n      calloc(dest->cap, sizeof(struct string_list_elem));\n   if (!elems)\n   {\n      free(dest);\n      return NULL;\n   }\n\n   dest->elems = elems;\n\n   for (i = 0; i < src->size; i++)\n   {\n      const char *_src = src->elems[i].data;\n      size_t      slen = _src ? strlen(_src) : 0;\n\n      dest->elems[i].data = NULL;\n      dest->elems[i].attr = src->elems[i].attr;\n\n      if (slen != 0)\n      {\n         char *ret = (char*)malloc(slen + 1);\n         /* Pre-patch: on malloc failure 'dest->elems[i].data'\n          * silently stayed NULL and the loop moved on.  That left\n          * the caller holding a dest with dest->size set to\n          * src->size but some .data pointers NULL - a trap for\n          * every consumer that assumes .data is non-NULL.\n          * string_list_find_elem (line 349), string_list_\n          * join_concat (line 200), and others all dereference\n          * .data unconditionally.  Single empty-string inputs\n          * are represented by slen == 0 and never hit this\n          * branch, so NULL here always means OOM, not 'empty\n          * element was intended'.\n          *\n          * Tear down the partially-cloned destination and\n          * return NULL.  Callers of string_list_clone already\n          * handle NULL returns (clone-failure is an OOM signal)\n          * - NULL is both safer and more informative than a\n          * silently-corrupted list. */\n         if (!ret)\n         {\n            size_t j;\n            for (j = 0; j < i; j++)\n               if (dest->elems[j].data)\n                  free(dest->elems[j].data);\n            free(dest->elems);\n            free(dest);\n            return NULL;\n         }\n         memcpy(ret, _src, slen + 1);  /* memcpy > strcpy: no NUL scan */\n         dest->elems[i].data = ret;\n      }\n   }\n\n   return dest;\n}\n"
  },
  {
    "path": "lists/vector_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (vector_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <boolean.h>\n#include <stdlib.h>\n#include <stddef.h>\n\n/* default type is void*, override by defining VECTOR_LIST_TYPE before inclusion */\n#ifndef VECTOR_LIST_TYPE\n#define VECTOR_LIST_TYPE void*\n#define VECTOR_LIST_TYPE_DEFINED\n#endif\n\n/* default name is void, override by defining VECTOR_LIST_NAME before inclusion */\n#ifndef VECTOR_LIST_NAME\n#define VECTOR_LIST_NAME void\n#define VECTOR_LIST_NAME_DEFINED\n#endif\n\n#define CAT_I(a,b) a##b\n#define CAT(a,b) CAT_I(a, b)\n#define MAKE_TYPE_NAME() CAT(VECTOR_LIST_NAME, _vector_list)\n#define TYPE_NAME() MAKE_TYPE_NAME()\n\nstruct TYPE_NAME()\n{\n   /* VECTOR_LIST_TYPE for pointers will expand to a pointer-to-pointer */\n   VECTOR_LIST_TYPE *data;\n   unsigned size;\n   unsigned count;\n};\n\nstatic struct TYPE_NAME()* CAT(TYPE_NAME(), _new(void))\n{\n   struct TYPE_NAME() *list = (struct TYPE_NAME()*)calloc(1, sizeof(*list));\n\n   list->size = 8;\n   list->data = (VECTOR_LIST_TYPE*)calloc(list->size, sizeof(*list->data));\n\n   return list;\n}\n\nstatic bool CAT(TYPE_NAME(), _append(struct TYPE_NAME() *list, VECTOR_LIST_TYPE elem))\n{\n   if (list->size == list->count)\n   {\n      list->size *= 2;\n      list->data = (VECTOR_LIST_TYPE*)realloc(list->data, list->size * sizeof(*list->data));\n\n      if (!list->data)\n         return false;\n   }\n\n   list->data[list->count] = elem;\n   list->count++;\n\n   return true;\n}\n\nstatic void CAT(TYPE_NAME(), _free(struct TYPE_NAME() *list))\n{\n   if (list)\n   {\n      if (list->data)\n         free(list->data);\n      free(list);\n   }\n}\n\n#ifdef VECTOR_LIST_TYPE_DEFINED\n#undef VECTOR_LIST_TYPE\n#endif\n\n#ifdef VECTOR_LIST_NAME_DEFINED\n#undef VECTOR_LIST_NAME\n#endif\n"
  },
  {
    "path": "media/media_detect_cd.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (media_detect_cd.c).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <media/media_detect_cd.h>\n#include <streams/file_stream.h>\n#include <string/stdstring.h>\n#include <file/file_path.h>\n#include <retro_miscellaneous.h>\n\n/*#define MEDIA_CUE_PARSE_DEBUG*/\n\nstatic void media_zero_trailing_spaces(char *s, size_t len)\n{\n   int i;\n   for (i = len - 1; i >= 0; i--)\n   {\n      if (s[i] == ' ')\n         s[i] = '\\0';\n      else if (s[i] != '\\0')\n         break;\n   }\n}\n\nstatic bool media_skip_spaces(const char **s, size_t len)\n{\n   if (s && *s && **s)\n   {\n      size_t i;\n      for (i = 0; i < len; i++)\n      {\n         if ((*s)[i] == ' ' || (*s)[i] == '\\t')\n            continue;\n         *s += i;\n         return true;\n      }\n   }\n   return false;\n}\n\n/* 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. */\nbool media_detect_cd_info_cue(const char *path, media_detect_cd_info_t *info)\n{\n   RFILE *file                          = NULL;\n   char *line                           = NULL;\n   char track_path[PATH_MAX_LENGTH]     = {0};\n   char track_abs_path[PATH_MAX_LENGTH] = {0};\n   char track_mode[11]                  = {0};\n   bool found_file                      = false;\n   bool found_track                     = false;\n   unsigned first_data_track            = 0;\n   uint64_t data_track_pregap_bytes     = 0;\n\n   if (!path || !*path || !info)\n      return false;\n\n   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))\n   {\n#ifdef MEDIA_CUE_PARSE_DEBUG\n      printf(\"[MEDIA] Could not open cue path for reading: %s\\n\", path);\n      fflush(stdout);\n#endif\n      return false;\n   }\n\n   while (!filestream_eof(file) && (line = filestream_getline(file)))\n   {\n      size_t _len = 0;\n      const char *command = NULL;\n\n      if (!line || !*line)\n      {\n         free(line);\n         continue;\n      }\n\n      _len    = strlen(line);\n      command = line;\n\n      media_skip_spaces(&command, _len);\n\n      if (!found_file && !strncasecmp(command, \"FILE\", 4))\n      {\n         const char *file = command + 4;\n         media_skip_spaces(&file, _len - 4);\n\n         if (file && *file)\n         {\n            const char *file_end = NULL;\n            size_t file_len      = 0;\n            bool quoted          = false;\n\n            if (file[0] == '\"')\n            {\n               quoted = true;\n               file++;\n            }\n\n            if (quoted)\n               file_end = strchr(file, '\\\"');\n            else\n               file_end = strchr(file, ' ');\n\n            if (file_end)\n            {\n               file_len = file_end - file;\n               memcpy(track_path, file, file_len);\n               found_file = true;\n#ifdef MEDIA_CUE_PARSE_DEBUG\n               printf(\"Found file: %s\\n\", track_path);\n               fflush(stdout);\n#endif\n            }\n         }\n      }\n      else if (found_file && !found_track && !strncasecmp(command, \"TRACK\", 5))\n      {\n         const char *track = command + 5;\n         media_skip_spaces(&track, _len - 5);\n\n         if (track && *track)\n         {\n            char *ptr             = NULL;\n            unsigned track_number = (unsigned)strtol(track, &ptr, 10);\n#ifdef MEDIA_CUE_PARSE_DEBUG\n            printf(\"Found track: %d\\n\", track_number);\n            fflush(stdout);\n#endif\n            track++;\n\n            if (track[0] && track[0] != ' ' && track[0] != '\\t')\n               track++;\n\n            if (track && *track)\n            {\n               media_skip_spaces(&track, strlen(track));\n#ifdef MEDIA_CUE_PARSE_DEBUG\n               printf(\"Found track type: %s\\n\", track);\n               fflush(stdout);\n#endif\n               if (!strncasecmp(track, \"MODE\", 4))\n               {\n                  first_data_track = track_number;\n                  found_track = true;\n                  strlcpy(track_mode, track, sizeof(track_mode));\n               }\n               else\n                  found_file = false;\n            }\n         }\n      }\n      else if (found_file && found_track && first_data_track && !strncasecmp(command, \"INDEX\", 5))\n      {\n         const char *index = command + 5;\n         media_skip_spaces(&index, _len - 5);\n\n         if (index && *index)\n         {\n            char *ptr             = NULL;\n            unsigned index_number = (unsigned)strtol(index, &ptr, 10);\n\n            if (index_number == 1)\n            {\n               const char *pregap = index + 1;\n\n               if (pregap[0] && pregap[0] != ' ' && pregap[0] != '\\t')\n                  pregap++;\n\n               if (pregap && *pregap)\n               {\n                  media_skip_spaces(&pregap, strlen(pregap));\n                  found_file  = false;\n                  found_track = false;\n\n                  if (first_data_track && *track_mode)\n                  {\n                     unsigned track_sector_size = 0;\n                     unsigned track_mode_number = 0;\n\n                     if (strlen(track_mode) == 10)\n                     {\n                        if (!strncasecmp(track_mode, \"MODE\", 4))\n                        {\n                           char *ptr = NULL;\n                           track_mode_number  = (unsigned)strtol(track_mode + 4, &ptr, 10);\n                           if (ptr && *ptr == '/')\n                              track_sector_size = (unsigned)strtol(ptr + 1, NULL, 10);\n                        }\n#ifdef MEDIA_CUE_PARSE_DEBUG\n                        printf(\"Found track mode %d with sector size %d\\n\", track_mode_number, track_sector_size);\n                        fflush(stdout);\n#endif\n                        if ((track_mode_number == 1 || track_mode_number == 2) && track_sector_size)\n                        {\n                           unsigned min = 0;\n                           unsigned sec = 0;\n                           unsigned frame = 0;\n                           {\n                              char *ptr = NULL;\n                              min   = (unsigned)strtol(pregap, &ptr, 10);\n                              if (ptr && *ptr == ':')\n                              {\n                                 sec   = (unsigned)strtol(ptr + 1, &ptr, 10);\n                                 if (ptr && *ptr == ':')\n                                    frame = (unsigned)strtol(ptr + 1, NULL, 10);\n                              }\n                           }\n\n                           if (min || sec || frame || strstr(pregap, \"00:00:00\"))\n                           {\n                              data_track_pregap_bytes = ((min * 60 + sec) * 75 + frame) * track_sector_size;\n#ifdef MEDIA_CUE_PARSE_DEBUG\n                              printf(\"Found pregap of %02d:%02d:%02d (bytes: %\" PRIu64 \")\\n\", min, sec, frame, data_track_pregap_bytes);\n                              fflush(stdout);\n#endif\n                              break;\n                           }\n                        }\n                     }\n                  }\n               }\n            }\n         }\n      }\n\n      free(line);\n   }\n\n   filestream_close(file);\n\n   if (*track_path)\n   {\n      size_t _len;\n      if (strchr(track_path, '/') || strchr(track_path, '\\\\'))\n      {\n#ifdef MEDIA_CUE_PARSE_DEBUG\n         printf(\"using path %s\\n\", track_path);\n         fflush(stdout);\n#endif\n         return media_detect_cd_info(track_path, data_track_pregap_bytes, info);\n      }\n\n      _len = fill_pathname_basedir(track_abs_path, path, sizeof(track_abs_path));\n      strlcpy(track_abs_path + _len, track_path, sizeof(track_abs_path) - _len);\n#ifdef MEDIA_CUE_PARSE_DEBUG\n      printf(\"using abs path %s\\n\", track_abs_path);\n      fflush(stdout);\n#endif\n      return media_detect_cd_info(track_abs_path, data_track_pregap_bytes, info);\n   }\n\n   return true;\n}\n\n/* Fill in \"info\" with detected CD info. Use this when you want to open a specific track file directly, and the pregap is known. */\nbool media_detect_cd_info(const char *path, uint64_t pregap_bytes, media_detect_cd_info_t *info)\n{\n   RFILE *file;\n\n   if (!path || !*path || !info)\n      return false;\n\n   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))\n   {\n#ifdef MEDIA_CUE_PARSE_DEBUG\n      printf(\"[MEDIA] Could not open path for reading: %s\\n\", path);\n      fflush(stdout);\n#endif\n      return false;\n   }\n\n   {\n      unsigned offset      = 0;\n      unsigned sector_size = 0;\n      unsigned buf_size    = 17 * 2352;\n      char *buf            = (char*)calloc(1, buf_size);\n      int64_t read_bytes   = 0;\n\n      if (!buf)\n         return false;\n\n      if (pregap_bytes)\n         filestream_seek(file, pregap_bytes, RETRO_VFS_SEEK_POSITION_START);\n\n      read_bytes = filestream_read(file, buf, buf_size);\n\n      if (read_bytes != buf_size)\n      {\n#ifdef MEDIA_CUE_PARSE_DEBUG\n         printf(\"[MEDIA] Could not read from media: got %\" PRId64 \" bytes instead of %d.\\n\", read_bytes, buf_size);\n         fflush(stdout);\n#endif\n         filestream_close(file);\n         free(buf);\n         return false;\n      }\n\n      /* 12-byte sync field at the start of every sector, common to both mode1 and mode2 data tracks\n       * (when at least sync data is requested). This is a CD-ROM standard feature and not specific to any game devices,\n       * and as such should not be part of any system-specific detection or \"magic\" bytes.\n       * Depending on what parts of a sector were requested from the disc, the user data might start at\n       * byte offset 0, 4, 8, 12, 16 or 24. Cue sheets only specify the total number of bytes requested from the sectors\n       * of a track (like 2048 or 2352) and it is then assumed based on the size/mode as to what fields are present. */\n      if (!memcmp(buf, \"\\x00\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\x00\", 12))\n      {\n         /* Assume track data contains all fields. */\n         sector_size = 2352;\n\n         /* Assume Mode 2 formed (formless is rarely used) */\n         if (buf[15] == 2)\n            offset   = 24;\n         else /* Assume Mode 1 */\n            offset   = 16;\n      }\n      else /* Assume sectors only contain user data instead. */\n         sector_size = 2048;\n\n      if (!memcmp(buf + offset, \"SEGADISCSYSTEM\",\n               STRLEN_CONST(\"SEGADISCSYSTEM\")))\n      {\n         const char *title_pos  = NULL;\n         const char *serial_pos = NULL;\n\n         /* All discs currently in Redump for MCD start with SEGADISCSYSTEM. There are other strings mentioned elsewhere online,\n          * but I have not seen any real examples of them. */\n         info->system_id = MEDIA_CD_SYSTEM_MEGA_CD;\n\n         strlcpy(info->system, \"Sega CD / Mega CD\", sizeof(info->system));\n\n         title_pos = buf + offset + 0x150;\n\n         if (media_skip_spaces(&title_pos, 48))\n         {\n            memcpy(info->title, title_pos, 48 - (title_pos - (buf + offset + 0x150)));\n            media_zero_trailing_spaces(info->title, sizeof(info->title));\n         }\n         else\n            strlcpy(info->title, \"N/A\", sizeof(info->title));\n\n         serial_pos = buf + offset + 0x183;\n\n         if (media_skip_spaces(&serial_pos, 8))\n         {\n            memcpy(info->serial, serial_pos, 8 - (serial_pos - (buf + offset + 0x183)));\n            media_zero_trailing_spaces(info->serial, sizeof(info->serial));\n         }\n         else\n         {\n            info->serial[0] = 'N';\n            info->serial[1] = '/';\n            info->serial[2] = 'A';\n            info->serial[3] = '\\0';\n         }\n      }\n      else if (!memcmp(buf + offset, \"SEGA SEGASATURN\",\n               STRLEN_CONST(\"SEGA SEGASATURN\")))\n      {\n         const char *title_pos        = NULL;\n         const char *serial_pos       = NULL;\n         const char *version_pos      = NULL;\n         const char *release_date_pos = NULL;\n\n         info->system_id = MEDIA_CD_SYSTEM_SATURN;\n\n         strlcpy(info->system, \"Sega Saturn\", sizeof(info->system));\n\n         title_pos = buf + offset + 0x60;\n\n         if (media_skip_spaces(&title_pos, 112))\n         {\n            memcpy(info->title, title_pos, 112 - (title_pos - (buf + offset + 0x60)));\n            media_zero_trailing_spaces(info->title, sizeof(info->title));\n         }\n         else\n            strlcpy(info->title, \"N/A\", sizeof(info->title));\n\n         serial_pos = buf + offset + 0x20;\n\n         if (media_skip_spaces(&serial_pos, 10))\n         {\n            memcpy(info->serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x20)));\n            media_zero_trailing_spaces(info->serial, sizeof(info->serial));\n         }\n         else\n         {\n            info->serial[0] = 'N';\n            info->serial[1] = '/';\n            info->serial[2] = 'A';\n            info->serial[3] = '\\0';\n         }\n\n         version_pos = buf + offset + 0x2a;\n\n         if (media_skip_spaces(&version_pos, 6))\n         {\n            memcpy(info->version, version_pos, 6 - (version_pos - (buf + offset + 0x2a)));\n            media_zero_trailing_spaces(info->version, sizeof(info->version));\n         }\n         else\n         {\n            info->version[0] = 'N';\n            info->version[1] = '/';\n            info->version[2] = 'A';\n            info->version[3] = '\\0';\n         }\n\n         release_date_pos = buf + offset + 0x30;\n\n         if (media_skip_spaces(&release_date_pos, 8))\n         {\n            memcpy(info->release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x30)));\n            media_zero_trailing_spaces(info->release_date, sizeof(info->release_date));\n         }\n         else\n         {\n            info->release_date[0] = 'N';\n            info->release_date[1] = '/';\n            info->release_date[2] = 'A';\n            info->release_date[3] = '\\0';\n         }\n      }\n      else if (!memcmp(buf + offset, \"SEGA SEGAKATANA\", STRLEN_CONST(\"SEGA SEGAKATANA\")))\n      {\n         const char *title_pos        = NULL;\n         const char *serial_pos       = NULL;\n         const char *version_pos      = NULL;\n         const char *release_date_pos = NULL;\n\n         info->system_id = MEDIA_CD_SYSTEM_DREAMCAST;\n\n         strlcpy(info->system, \"Sega Dreamcast\", sizeof(info->system));\n\n         title_pos = buf + offset + 0x80;\n\n         if (media_skip_spaces(&title_pos, 96))\n         {\n            memcpy(info->title, title_pos, 96 - (title_pos - (buf + offset + 0x80)));\n            media_zero_trailing_spaces(info->title, sizeof(info->title));\n         }\n         else\n            strlcpy(info->title, \"N/A\", sizeof(info->title));\n\n         serial_pos = buf + offset + 0x40;\n\n         if (media_skip_spaces(&serial_pos, 10))\n         {\n            memcpy(info->serial, serial_pos, 10 - (serial_pos - (buf + offset + 0x40)));\n            media_zero_trailing_spaces(info->serial, sizeof(info->serial));\n         }\n         else\n         {\n            info->serial      [0] = 'N';\n            info->serial      [1] = '/';\n            info->serial      [2] = 'A';\n            info->serial      [3] = '\\0';\n         }\n\n         version_pos = buf + offset + 0x4a;\n\n         if (media_skip_spaces(&version_pos, 6))\n         {\n            memcpy(info->version, version_pos, 6 - (version_pos - (buf + offset + 0x4a)));\n            media_zero_trailing_spaces(info->version, sizeof(info->version));\n         }\n         else\n         {\n            info->version     [0] = 'N';\n            info->version     [1] = '/';\n            info->version     [2] = 'A';\n            info->version     [3] = '\\0';\n         }\n\n         release_date_pos = buf + offset + 0x50;\n\n         if (media_skip_spaces(&release_date_pos, 8))\n         {\n            memcpy(info->release_date, release_date_pos, 8 - (release_date_pos - (buf + offset + 0x50)));\n            media_zero_trailing_spaces(info->release_date, sizeof(info->release_date));\n         }\n         else\n         {\n            info->release_date[0] = 'N';\n            info->release_date[1] = '/';\n            info->release_date[2] = 'A';\n            info->release_date[3] = '\\0';\n         }\n      }\n      /* Primary Volume Descriptor fields of ISO9660 */\n      else if (!memcmp(buf + offset + (16 * sector_size), \"\\1CD001\\1\\0PLAYSTATION\", 19))\n      {\n         const char *title_pos = NULL;\n\n         info->system_id = MEDIA_CD_SYSTEM_PSX;\n\n         strlcpy(info->system, \"Sony PlayStation\", sizeof(info->system));\n\n         title_pos = buf + offset + (16 * sector_size) + 40;\n\n         if (media_skip_spaces(&title_pos, 32))\n         {\n            memcpy(info->title, title_pos, 32 - (title_pos - (buf + offset + (16 * sector_size) + 40)));\n            media_zero_trailing_spaces(info->title, sizeof(info->title));\n         }\n         else\n            strlcpy(info->title, \"N/A\", sizeof(info->title));\n      }\n      else if (!memcmp(buf + offset, \"\\x01\\x5a\\x5a\\x5a\\x5a\\x5a\\x01\\x00\\x00\\x00\\x00\\x00\", 12))\n      {\n         info->system_id = MEDIA_CD_SYSTEM_3DO;\n         strlcpy(info->system, \"3DO\", sizeof(info->system));\n      }\n      else if (!memcmp(buf + offset + 0x950, \"PC Engine CD-ROM SYSTEM\", 23))\n      {\n         info->system_id = MEDIA_CD_SYSTEM_PC_ENGINE_CD;\n         strlcpy(info->system, \"TurboGrafx-CD / PC-Engine CD\", sizeof(info->system));\n      }\n\n      free(buf);\n   }\n\n   filestream_close(file);\n\n   return true;\n}\n"
  },
  {
    "path": "memmap/memalign.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (memalign.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n\n#include <memalign.h>\n\nvoid *memalign_alloc(size_t boundary, size_t len)\n{\n   void **place   = NULL;\n   uintptr_t addr = 0;\n   void *ptr      = (void*)malloc(boundary + len + sizeof(uintptr_t));\n   if (!ptr)\n      return NULL;\n   addr           = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary)\n      & ~(boundary - 1);\n   place          = (void**)addr;\n   place[-1]      = ptr;\n   return (void*)addr;\n}\n\nvoid memalign_free(void *ptr)\n{\n   void **p = NULL;\n   if (!ptr)\n      return;\n\n   p = (void**)ptr;\n   free(p[-1]);\n}\n\nvoid *memalign_alloc_aligned(size_t len)\n{\n#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64)\n   return memalign_alloc(64, len);\n#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86)\n   return memalign_alloc(32, len);\n#else\n   return memalign_alloc(32, len);\n#endif\n}\n"
  },
  {
    "path": "memmap/memmap.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (memmap.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <memmap.h>\n\n#ifndef PROT_READ\n#define PROT_READ         0x1  /* Page can be read */\n#endif\n\n#ifndef PROT_WRITE\n#define PROT_WRITE        0x2  /* Page can be written. */\n#endif\n\n#ifndef PROT_READWRITE\n#define PROT_READWRITE    0x3  /* Page can be written to and read from. */\n#endif\n\n#ifndef PROT_EXEC\n#define PROT_EXEC         0x4  /* Page can be executed. */\n#endif\n\n#ifndef PROT_NONE\n#define PROT_NONE         0x0  /* Page can not be accessed. */\n#endif\n\n#ifndef MAP_FAILED\n#define MAP_FAILED        ((void *) -1)\n#endif\n\n#ifdef _WIN32\nvoid* mmap(void *addr, size_t len, int prot, int flags,\n      int fildes, size_t offset)\n{\n   void     *map = (void*)NULL;\n   HANDLE handle = INVALID_HANDLE_VALUE;\n\n   switch (prot)\n   {\n      case PROT_READ:\n      default:\n         handle = CreateFileMapping((HANDLE)\n               _get_osfhandle(fildes), 0, PAGE_READONLY, 0,\n               len, 0);\n         if (!handle)\n            break;\n         map = (void*)MapViewOfFile(handle, FILE_MAP_READ, 0, 0, len);\n         CloseHandle(handle);\n         break;\n      case PROT_WRITE:\n         handle = CreateFileMapping((HANDLE)\n               _get_osfhandle(fildes),0,PAGE_READWRITE,0,\n               len, 0);\n         if (!handle)\n            break;\n         map = (void*)MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, len);\n         CloseHandle(handle);\n         break;\n      case PROT_READWRITE:\n         handle = CreateFileMapping((HANDLE)\n               _get_osfhandle(fildes),0,PAGE_READWRITE,0,\n               len, 0);\n         if (!handle)\n            break;\n         map = (void*)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, len);\n         CloseHandle(handle);\n         break;\n   }\n\n   if (map == (void*)NULL)\n      return((void*)MAP_FAILED);\n   return((void*) ((int8_t*)map + offset));\n}\n\nint munmap(void *addr, size_t len)\n{\n   return (UnmapViewOfFile(addr)) ? 0 : -1;\n}\n\nint mprotect(void *addr, size_t len, int prot)\n{\n   /* Incomplete, just assumes PAGE_EXECUTE_READWRITE right now\n    * instead of correctly handling prot */\n   prot = 0;\n   if (prot & (PROT_READ | PROT_WRITE | PROT_EXEC))\n      prot = PAGE_EXECUTE_READWRITE;\n   return VirtualProtect(addr, len, prot, 0);\n}\n\n#elif !defined(HAVE_MMAN)\nvoid* mmap(void *addr, size_t len, int prot, int flags,\n      int fildes, size_t offset)\n{\n   return malloc(len);\n}\n\nint munmap(void *addr, size_t len)\n{\n   free(addr);\n   return 0;\n}\n\nint mprotect(void *addr, size_t len, int prot)\n{\n   /* stub - not really needed at this point\n    * since this codepath has no dynarecs. */\n   return 0;\n}\n\n#endif\n\n#if defined(__MACH__) && defined(__arm__)\n#include <libkern/OSCacheControl.h>\n#endif\n\nint memsync(void *start, void *end)\n{\n#if defined(__MACH__) && defined(__arm__)\n   size_t _len = (char*)end - (char*)start;\n   sys_dcache_flush(start, _len);\n   sys_icache_invalidate(start, _len);\n   return 0;\n#elif defined(__arm__) && !defined(__QNX__)\n   __clear_cache(start, end);\n   return 0;\n#elif defined(HAVE_MMAN)\n   size_t _len = (char*)end - (char*)start;\n   return msync(start, _len, MS_SYNC | MS_INVALIDATE\n#ifdef __QNX__\n         MS_CACHE_ONLY\n#endif\n         );\n#else\n   return 0;\n#endif\n}\n\nint memprotect(void *addr, size_t len)\n{\n   return mprotect(addr, len, PROT_READ | PROT_WRITE | PROT_EXEC);\n}\n"
  },
  {
    "path": "net/cacert.h",
    "content": "/* CA certificates extracted from Mozilla\n * https://curl.haxx.se/docs/caextract.html\n * NOTE: Newlines are necessary for the file to be parsed correctly!\n */\nstatic const char cacert_pem[] = {\n\"##\\n\"\n\"## Bundle of CA Root Certificates\\n\"\n\"##\\n\"\n\"## Certificate data from Mozilla as of: Wed Jun  7 03:12:05 2017 GMT\\n\"\n\"##\\n\"\n\"## This is a bundle of X.509 certificates of public Certificate Authorities\\n\"\n\"## (CA). These were automatically extracted from Mozilla's root certificates\\n\"\n\"## file (certdata.txt).  This file can be found in the mozilla source tree:\\n\"\n\"## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt\\n\"\n\"##\\n\"\n\"## It contains the certificates in PEM format and therefore\\n\"\n\"## can be directly used with curl / libcurl / php_curl, or with\\n\"\n\"## an Apache+mod_ssl webserver for SSL client authentication.\\n\"\n\"## Just configure this file as the SSLCACertificateFile.\\n\"\n\"##\\n\"\n\"## Conversion done with mk-ca-bundle.pl version 1.27.\\n\"\n\"## SHA256: 93753268e1c596aee21893fb1c6975338389132f15c942ed65fc394a904371d7\\n\"\n\"##\\n\"\n\"GlobalSign Root CA\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx\\n\"\n\"GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds\\n\"\n\"b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV\\n\"\n\"BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD\\n\"\n\"VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa\\n\"\n\"DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc\\n\"\n\"THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb\\n\"\n\"Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP\\n\"\n\"c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX\\n\"\n\"gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\\n\"\n\"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF\\n\"\n\"AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj\\n\"\n\"Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG\\n\"\n\"j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH\\n\"\n\"hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC\\n\"\n\"X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GlobalSign Root CA - R2\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv\\n\"\n\"YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh\\n\"\n\"bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT\\n\"\n\"aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln\\n\"\n\"bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6\\n\"\n\"ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp\\n\"\n\"s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN\\n\"\n\"S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL\\n\"\n\"TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C\\n\"\n\"ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E\\n\"\n\"FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i\\n\"\n\"YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN\\n\"\n\"BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp\\n\"\n\"9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu\\n\"\n\"01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7\\n\"\n\"9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\\n\"\n\"TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Verisign Class 3 Public Primary Certification Authority - G3\\n\"\n\"============================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV\\n\"\n\"UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv\\n\"\n\"cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl\\n\"\n\"IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh\\n\"\n\"dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw\\n\"\n\"CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy\\n\"\n\"dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv\\n\"\n\"cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg\\n\"\n\"Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\\n\"\n\"ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1\\n\"\n\"EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc\\n\"\n\"cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw\\n\"\n\"EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj\\n\"\n\"055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA\\n\"\n\"ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f\\n\"\n\"j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC\\n\"\n\"/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0\\n\"\n\"xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa\\n\"\n\"t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Entrust.net Premium 2048 Secure Server CA\\n\"\n\"=========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u\\n\"\n\"ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp\\n\"\n\"bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV\\n\"\n\"BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx\\n\"\n\"NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3\\n\"\n\"d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl\\n\"\n\"MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u\\n\"\n\"ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\\n\"\n\"MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL\\n\"\n\"Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr\\n\"\n\"hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW\\n\"\n\"nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi\\n\"\n\"VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E\\n\"\n\"BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ\\n\"\n\"KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy\\n\"\n\"T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf\\n\"\n\"zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT\\n\"\n\"J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e\\n\"\n\"nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Baltimore CyberTrust Root\\n\"\n\"=========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE\\n\"\n\"ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li\\n\"\n\"ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC\\n\"\n\"SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs\\n\"\n\"dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME\\n\"\n\"uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB\\n\"\n\"UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C\\n\"\n\"G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9\\n\"\n\"XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr\\n\"\n\"l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI\\n\"\n\"VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB\\n\"\n\"BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh\\n\"\n\"cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5\\n\"\n\"hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa\\n\"\n\"Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H\\n\"\n\"RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AddTrust Low-Value Services Root\\n\"\n\"================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\\n\"\n\"QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU\\n\"\n\"cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw\\n\"\n\"CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO\\n\"\n\"ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB\\n\"\n\"AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6\\n\"\n\"54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr\\n\"\n\"oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1\\n\"\n\"Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui\\n\"\n\"GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w\\n\"\n\"HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT\\n\"\n\"RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw\\n\"\n\"HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt\\n\"\n\"ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph\\n\"\n\"iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY\\n\"\n\"eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr\\n\"\n\"mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj\\n\"\n\"ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AddTrust External Root\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\\n\"\n\"QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD\\n\"\n\"VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw\\n\"\n\"NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU\\n\"\n\"cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg\\n\"\n\"Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821\\n\"\n\"+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw\\n\"\n\"Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo\\n\"\n\"aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy\\n\"\n\"2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7\\n\"\n\"7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P\\n\"\n\"BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL\\n\"\n\"VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk\\n\"\n\"VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB\\n\"\n\"IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl\\n\"\n\"j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5\\n\"\n\"6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355\\n\"\n\"e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u\\n\"\n\"G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AddTrust Public Services Root\\n\"\n\"=============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\\n\"\n\"QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU\\n\"\n\"cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ\\n\"\n\"BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l\\n\"\n\"dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF\\n\"\n\"AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu\\n\"\n\"nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i\\n\"\n\"d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG\\n\"\n\"Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw\\n\"\n\"HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G\\n\"\n\"A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux\\n\"\n\"FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G\\n\"\n\"A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4\\n\"\n\"JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL\\n\"\n\"+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao\\n\"\n\"GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9\\n\"\n\"Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H\\n\"\n\"EufOX1362KqxMy3ZdvJOOjMMK7MtkAY=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AddTrust Qualified Certificates Root\\n\"\n\"====================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML\\n\"\n\"QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU\\n\"\n\"cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx\\n\"\n\"CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ\\n\"\n\"IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG\\n\"\n\"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx\\n\"\n\"64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3\\n\"\n\"KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o\\n\"\n\"L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR\\n\"\n\"wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU\\n\"\n\"MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/\\n\"\n\"BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE\\n\"\n\"BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y\\n\"\n\"azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD\\n\"\n\"ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG\\n\"\n\"GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X\\n\"\n\"dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze\\n\"\n\"RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB\\n\"\n\"iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Entrust Root Certification Authority\\n\"\n\"====================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV\\n\"\n\"BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw\\n\"\n\"b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG\\n\"\n\"A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0\\n\"\n\"MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu\\n\"\n\"MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu\\n\"\n\"Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v\\n\"\n\"dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\\n\"\n\"ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz\\n\"\n\"A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww\\n\"\n\"Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68\\n\"\n\"j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN\\n\"\n\"rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw\\n\"\n\"DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1\\n\"\n\"MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH\\n\"\n\"hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\\n\"\n\"A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM\\n\"\n\"Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa\\n\"\n\"v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS\\n\"\n\"W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0\\n\"\n\"tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Global CA\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK\\n\"\n\"Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw\\n\"\n\"MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j\\n\"\n\"LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\\n\"\n\"CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo\\n\"\n\"BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet\\n\"\n\"8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc\\n\"\n\"T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU\\n\"\n\"vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk\\n\"\n\"DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q\\n\"\n\"zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4\\n\"\n\"d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2\\n\"\n\"mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p\\n\"\n\"XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm\\n\"\n\"Mw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Global CA 2\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\\n\"\n\"R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw\\n\"\n\"MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j\\n\"\n\"LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\\n\"\n\"ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/\\n\"\n\"NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k\\n\"\n\"LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA\\n\"\n\"Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b\\n\"\n\"HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF\\n\"\n\"MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH\\n\"\n\"K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7\\n\"\n\"srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh\\n\"\n\"ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL\\n\"\n\"OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC\\n\"\n\"x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF\\n\"\n\"H4z1Ir+rzoPz4iIprn2DQKi6bA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Universal CA\\n\"\n\"=====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\\n\"\n\"R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1\\n\"\n\"MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu\\n\"\n\"Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP\\n\"\n\"ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t\\n\"\n\"JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e\\n\"\n\"RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs\\n\"\n\"7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d\\n\"\n\"8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V\\n\"\n\"qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga\\n\"\n\"Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB\\n\"\n\"Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu\\n\"\n\"KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08\\n\"\n\"ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0\\n\"\n\"XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB\\n\"\n\"hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc\\n\"\n\"aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2\\n\"\n\"qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL\\n\"\n\"oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK\\n\"\n\"xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF\\n\"\n\"KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2\\n\"\n\"DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK\\n\"\n\"xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU\\n\"\n\"p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI\\n\"\n\"P/rmMuGNG2+k5o7Y+SlIis5z/iw=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Universal CA 2\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN\\n\"\n\"R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0\\n\"\n\"MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg\\n\"\n\"SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA\\n\"\n\"A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0\\n\"\n\"DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17\\n\"\n\"j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q\\n\"\n\"JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a\\n\"\n\"QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2\\n\"\n\"WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP\\n\"\n\"20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn\\n\"\n\"ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC\\n\"\n\"SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG\\n\"\n\"8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2\\n\"\n\"+/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E\\n\"\n\"BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z\\n\"\n\"dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ\\n\"\n\"4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+\\n\"\n\"mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq\\n\"\n\"A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg\\n\"\n\"Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP\\n\"\n\"pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d\\n\"\n\"FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp\\n\"\n\"gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm\\n\"\n\"X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Visa eCommerce Root\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG\\n\"\n\"EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug\\n\"\n\"QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2\\n\"\n\"WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm\\n\"\n\"VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv\\n\"\n\"bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL\\n\"\n\"F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b\\n\"\n\"RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0\\n\"\n\"TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI\\n\"\n\"/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs\\n\"\n\"GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG\\n\"\n\"MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc\\n\"\n\"CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW\\n\"\n\"YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz\\n\"\n\"zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu\\n\"\n\"YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt\\n\"\n\"398znM/jra6O1I7mT1GvFpLgXPYHDw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certum Root CA\\n\"\n\"==============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK\\n\"\n\"ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla\\n\"\n\"Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u\\n\"\n\"by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x\\n\"\n\"wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL\\n\"\n\"kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ\\n\"\n\"89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K\\n\"\n\"Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P\\n\"\n\"NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq\\n\"\n\"hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+\\n\"\n\"GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg\\n\"\n\"GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/\\n\"\n\"0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS\\n\"\n\"qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Comodo AAA Services root\\n\"\n\"========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS\\n\"\n\"R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg\\n\"\n\"TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw\\n\"\n\"MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl\\n\"\n\"c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV\\n\"\n\"BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\\n\"\n\"ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG\\n\"\n\"C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs\\n\"\n\"i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW\\n\"\n\"Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH\\n\"\n\"Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK\\n\"\n\"Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f\\n\"\n\"BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl\\n\"\n\"cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz\\n\"\n\"LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm\\n\"\n\"7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\\n\"\n\"Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z\\n\"\n\"8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C\\n\"\n\"12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Comodo Secure Services root\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS\\n\"\n\"R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg\\n\"\n\"TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw\\n\"\n\"MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu\\n\"\n\"Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi\\n\"\n\"BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\\n\"\n\"ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP\\n\"\n\"9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc\\n\"\n\"rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC\\n\"\n\"oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V\\n\"\n\"p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E\\n\"\n\"FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\\n\"\n\"gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj\\n\"\n\"YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm\\n\"\n\"aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm\\n\"\n\"4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj\\n\"\n\"Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL\\n\"\n\"DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw\\n\"\n\"pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H\\n\"\n\"RR3B7Hzs/Sk=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Comodo Trusted Services root\\n\"\n\"============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS\\n\"\n\"R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg\\n\"\n\"TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw\\n\"\n\"MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h\\n\"\n\"bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw\\n\"\n\"IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC\\n\"\n\"AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7\\n\"\n\"3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y\\n\"\n\"/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6\\n\"\n\"juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS\\n\"\n\"ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud\\n\"\n\"DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp\\n\"\n\"ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl\\n\"\n\"cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw\\n\"\n\"uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32\\n\"\n\"pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA\\n\"\n\"BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l\\n\"\n\"R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O\\n\"\n\"9y5Xt5hwXsjEeLBi\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"QuoVadis Root CA\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE\\n\"\n\"ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\\n\"\n\"eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz\\n\"\n\"MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp\\n\"\n\"cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD\\n\"\n\"EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF\\n\"\n\"AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk\\n\"\n\"J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL\\n\"\n\"F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL\\n\"\n\"YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen\\n\"\n\"AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w\\n\"\n\"PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y\\n\"\n\"ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7\\n\"\n\"MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj\\n\"\n\"YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs\\n\"\n\"ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh\\n\"\n\"Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW\\n\"\n\"Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu\\n\"\n\"BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw\\n\"\n\"FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0\\n\"\n\"aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6\\n\"\n\"tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo\\n\"\n\"fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul\\n\"\n\"LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x\\n\"\n\"gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi\\n\"\n\"5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi\\n\"\n\"5nrQNiOKSnQ2+Q==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"QuoVadis Root CA 2\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\\n\"\n\"EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx\\n\"\n\"ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\\n\"\n\"aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC\\n\"\n\"DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6\\n\"\n\"XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk\\n\"\n\"lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB\\n\"\n\"lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy\\n\"\n\"lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt\\n\"\n\"66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn\\n\"\n\"wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh\\n\"\n\"D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy\\n\"\n\"BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie\\n\"\n\"J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud\\n\"\n\"DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU\\n\"\n\"a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT\\n\"\n\"ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv\\n\"\n\"Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3\\n\"\n\"UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm\\n\"\n\"VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK\\n\"\n\"+JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW\\n\"\n\"IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1\\n\"\n\"WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X\\n\"\n\"f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II\\n\"\n\"4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8\\n\"\n\"VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"QuoVadis Root CA 3\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT\\n\"\n\"EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx\\n\"\n\"OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\\n\"\n\"aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\\n\"\n\"DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg\\n\"\n\"DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij\\n\"\n\"KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K\\n\"\n\"DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv\\n\"\n\"BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp\\n\"\n\"p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8\\n\"\n\"nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX\\n\"\n\"MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM\\n\"\n\"Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz\\n\"\n\"uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT\\n\"\n\"BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj\\n\"\n\"YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0\\n\"\n\"aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB\\n\"\n\"BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD\\n\"\n\"VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4\\n\"\n\"ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE\\n\"\n\"AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV\\n\"\n\"qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s\\n\"\n\"hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z\\n\"\n\"POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2\\n\"\n\"Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp\\n\"\n\"8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC\\n\"\n\"bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu\\n\"\n\"g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p\\n\"\n\"vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr\\n\"\n\"qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Security Communication Root CA\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP\\n\"\n\"U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw\\n\"\n\"HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP\\n\"\n\"U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw\\n\"\n\"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw\\n\"\n\"8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM\\n\"\n\"DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX\\n\"\n\"5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd\\n\"\n\"DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2\\n\"\n\"JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw\\n\"\n\"DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g\\n\"\n\"0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a\\n\"\n\"mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ\\n\"\n\"s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ\\n\"\n\"6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi\\n\"\n\"FL39vmwLAw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Sonera Class 2 Root CA\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG\\n\"\n\"U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw\\n\"\n\"NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh\\n\"\n\"IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3\\n\"\n\"/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT\\n\"\n\"dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG\\n\"\n\"f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P\\n\"\n\"tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH\\n\"\n\"nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT\\n\"\n\"XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt\\n\"\n\"0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI\\n\"\n\"cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph\\n\"\n\"Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx\\n\"\n\"EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH\\n\"\n\"llpwrN9M\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"UTN USERFirst Hardware Root CA\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE\\n\"\n\"BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl\\n\"\n\"IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd\\n\"\n\"BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx\\n\"\n\"OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0\\n\"\n\"eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz\\n\"\n\"ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3\\n\"\n\"DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI\\n\"\n\"wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd\\n\"\n\"tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8\\n\"\n\"i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf\\n\"\n\"Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw\\n\"\n\"gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF\\n\"\n\"lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF\\n\"\n\"UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF\\n\"\n\"BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM\\n\"\n\"//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW\\n\"\n\"XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2\\n\"\n\"lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn\\n\"\n\"iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67\\n\"\n\"nfhmqA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Camerfirma Chambers of Commerce Root\\n\"\n\"====================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe\\n\"\n\"QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i\\n\"\n\"ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx\\n\"\n\"NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp\\n\"\n\"cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn\\n\"\n\"MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC\\n\"\n\"AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU\\n\"\n\"xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH\\n\"\n\"NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW\\n\"\n\"DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV\\n\"\n\"d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud\\n\"\n\"EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v\\n\"\n\"cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P\\n\"\n\"AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh\\n\"\n\"bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD\\n\"\n\"VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz\\n\"\n\"aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi\\n\"\n\"fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD\\n\"\n\"L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN\\n\"\n\"UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n\\n\"\n\"ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1\\n\"\n\"erfutGWaIZDgqtCYvDi1czyL+Nw=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Camerfirma Global Chambersign Root\\n\"\n\"==================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe\\n\"\n\"QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i\\n\"\n\"ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx\\n\"\n\"NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt\\n\"\n\"YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg\\n\"\n\"MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw\\n\"\n\"ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J\\n\"\n\"1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O\\n\"\n\"by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl\\n\"\n\"6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c\\n\"\n\"8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/\\n\"\n\"BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j\\n\"\n\"aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B\\n\"\n\"Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj\\n\"\n\"aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y\\n\"\n\"ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh\\n\"\n\"bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA\\n\"\n\"PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y\\n\"\n\"gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ\\n\"\n\"PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4\\n\"\n\"IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes\\n\"\n\"t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"XRamp Global CA Root\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE\\n\"\n\"BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj\\n\"\n\"dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB\\n\"\n\"dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx\\n\"\n\"HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg\\n\"\n\"U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\\n\"\n\"dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu\\n\"\n\"IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx\\n\"\n\"foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE\\n\"\n\"zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs\\n\"\n\"AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry\\n\"\n\"xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud\\n\"\n\"EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap\\n\"\n\"oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC\\n\"\n\"AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc\\n\"\n\"/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt\\n\"\n\"qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n\\n\"\n\"nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz\\n\"\n\"8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Go Daddy Class 2 CA\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY\\n\"\n\"VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp\\n\"\n\"ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG\\n\"\n\"A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g\\n\"\n\"RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD\\n\"\n\"ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv\\n\"\n\"2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32\\n\"\n\"qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j\\n\"\n\"YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY\\n\"\n\"vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O\\n\"\n\"BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o\\n\"\n\"atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu\\n\"\n\"MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG\\n\"\n\"A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim\\n\"\n\"PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt\\n\"\n\"I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\\n\"\n\"HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI\\n\"\n\"Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b\\n\"\n\"vZ8=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Starfield Class 2 CA\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc\\n\"\n\"U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg\\n\"\n\"Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo\\n\"\n\"MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG\\n\"\n\"A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG\\n\"\n\"SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY\\n\"\n\"bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ\\n\"\n\"JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm\\n\"\n\"epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN\\n\"\n\"F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF\\n\"\n\"MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f\\n\"\n\"hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo\\n\"\n\"bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g\\n\"\n\"QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs\\n\"\n\"afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM\\n\"\n\"PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\\n\"\n\"xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD\\n\"\n\"KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3\\n\"\n\"QBFGmh95DmK/D5fs4C8fF5Q=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"StartCom Certification Authority\\n\"\n\"================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\\n\"\n\"U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu\\n\"\n\"ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0\\n\"\n\"NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk\\n\"\n\"LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg\\n\"\n\"U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\\n\"\n\"ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y\\n\"\n\"o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/\\n\"\n\"Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d\\n\"\n\"eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt\\n\"\n\"2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z\\n\"\n\"6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ\\n\"\n\"osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/\\n\"\n\"untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc\\n\"\n\"UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT\\n\"\n\"37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE\\n\"\n\"FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0\\n\"\n\"Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj\\n\"\n\"YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH\\n\"\n\"AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw\\n\"\n\"Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg\\n\"\n\"U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5\\n\"\n\"LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl\\n\"\n\"cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh\\n\"\n\"cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT\\n\"\n\"dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC\\n\"\n\"AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh\\n\"\n\"3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm\\n\"\n\"vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk\\n\"\n\"fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3\\n\"\n\"fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ\\n\"\n\"EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq\\n\"\n\"yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl\\n\"\n\"1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/\\n\"\n\"lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro\\n\"\n\"g14=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Taiwan GRCA\\n\"\n\"===========\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG\\n\"\n\"EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X\\n\"\n\"DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv\\n\"\n\"dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD\\n\"\n\"ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN\\n\"\n\"w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5\\n\"\n\"BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O\\n\"\n\"1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO\\n\"\n\"htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov\\n\"\n\"J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7\\n\"\n\"Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t\\n\"\n\"B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB\\n\"\n\"O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8\\n\"\n\"lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV\\n\"\n\"HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2\\n\"\n\"09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ\\n\"\n\"TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj\\n\"\n\"Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2\\n\"\n\"Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU\\n\"\n\"D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz\\n\"\n\"DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk\\n\"\n\"Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk\\n\"\n\"7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ\\n\"\n\"CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy\\n\"\n\"+fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Swisscom Root CA 1\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG\\n\"\n\"EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy\\n\"\n\"dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4\\n\"\n\"MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln\\n\"\n\"aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC\\n\"\n\"IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM\\n\"\n\"MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF\\n\"\n\"NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe\\n\"\n\"AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC\\n\"\n\"b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn\\n\"\n\"7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN\\n\"\n\"cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp\\n\"\n\"WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5\\n\"\n\"haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY\\n\"\n\"MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw\\n\"\n\"HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j\\n\"\n\"BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9\\n\"\n\"MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn\\n\"\n\"jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ\\n\"\n\"MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H\\n\"\n\"VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl\\n\"\n\"vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl\\n\"\n\"OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3\\n\"\n\"1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq\\n\"\n\"nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy\\n\"\n\"x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW\\n\"\n\"NY6E0F/6MBr1mmz0DlP5OlvRHA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Assured ID Root CA\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG\\n\"\n\"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\\n\"\n\"IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx\\n\"\n\"MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\\n\"\n\"ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew\\n\"\n\"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO\\n\"\n\"9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy\\n\"\n\"UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW\\n\"\n\"/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy\\n\"\n\"oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf\\n\"\n\"GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF\\n\"\n\"66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq\\n\"\n\"hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc\\n\"\n\"EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn\\n\"\n\"SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i\\n\"\n\"8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\\n\"\n\"+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Global Root CA\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG\\n\"\n\"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\\n\"\n\"HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw\\n\"\n\"MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\\n\"\n\"dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq\\n\"\n\"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn\\n\"\n\"TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5\\n\"\n\"BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H\\n\"\n\"4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y\\n\"\n\"7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB\\n\"\n\"o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm\\n\"\n\"8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF\\n\"\n\"BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr\\n\"\n\"EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt\\n\"\n\"tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886\\n\"\n\"UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\\n\"\n\"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert High Assurance EV Root CA\\n\"\n\"==================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG\\n\"\n\"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw\\n\"\n\"KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw\\n\"\n\"MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ\\n\"\n\"MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu\\n\"\n\"Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t\\n\"\n\"Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS\\n\"\n\"OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3\\n\"\n\"MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ\\n\"\n\"NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe\\n\"\n\"h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB\\n\"\n\"Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY\\n\"\n\"JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ\\n\"\n\"V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp\\n\"\n\"myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK\\n\"\n\"mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\\n\"\n\"vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certplus Class 2 Primary CA\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE\\n\"\n\"BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN\\n\"\n\"OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy\\n\"\n\"dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\\n\"\n\"ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR\\n\"\n\"5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ\\n\"\n\"Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO\\n\"\n\"YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e\\n\"\n\"e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME\\n\"\n\"CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ\\n\"\n\"YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t\\n\"\n\"L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD\\n\"\n\"P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R\\n\"\n\"TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+\\n\"\n\"7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW\\n\"\n\"//1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7\\n\"\n\"l7+ijrRU\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DST Root CA X3\\n\"\n\"==============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK\\n\"\n\"ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X\\n\"\n\"DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1\\n\"\n\"cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD\\n\"\n\"ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT\\n\"\n\"rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9\\n\"\n\"UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy\\n\"\n\"xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d\\n\"\n\"utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T\\n\"\n\"AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ\\n\"\n\"MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug\\n\"\n\"dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE\\n\"\n\"GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw\\n\"\n\"RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS\\n\"\n\"fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DST ACES CA X6\\n\"\n\"==============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG\\n\"\n\"EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT\\n\"\n\"MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha\\n\"\n\"MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE\\n\"\n\"CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC\\n\"\n\"AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI\\n\"\n\"DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa\\n\"\n\"pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow\\n\"\n\"GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy\\n\"\n\"MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud\\n\"\n\"EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu\\n\"\n\"Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy\\n\"\n\"dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU\\n\"\n\"CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2\\n\"\n\"5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t\\n\"\n\"Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq\\n\"\n\"nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs\\n\"\n\"vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3\\n\"\n\"oKfN5XozNmr6mis=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"SwissSign Gold CA - G2\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw\\n\"\n\"EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN\\n\"\n\"MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp\\n\"\n\"c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B\\n\"\n\"AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq\\n\"\n\"t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C\\n\"\n\"jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg\\n\"\n\"vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF\\n\"\n\"ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR\\n\"\n\"AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend\\n\"\n\"jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO\\n\"\n\"peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR\\n\"\n\"7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi\\n\"\n\"GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw\\n\"\n\"AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64\\n\"\n\"OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov\\n\"\n\"L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm\\n\"\n\"5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr\\n\"\n\"44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf\\n\"\n\"Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m\\n\"\n\"Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp\\n\"\n\"mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk\\n\"\n\"vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf\\n\"\n\"KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br\\n\"\n\"NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj\\n\"\n\"viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"SwissSign Silver CA - G2\\n\"\n\"========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT\\n\"\n\"BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X\\n\"\n\"DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3\\n\"\n\"aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG\\n\"\n\"9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644\\n\"\n\"N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm\\n\"\n\"+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH\\n\"\n\"6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu\\n\"\n\"MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h\\n\"\n\"qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5\\n\"\n\"FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs\\n\"\n\"ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc\\n\"\n\"celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X\\n\"\n\"CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\\n\"\n\"BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB\\n\"\n\"tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0\\n\"\n\"cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P\\n\"\n\"4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F\\n\"\n\"kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L\\n\"\n\"3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx\\n\"\n\"/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa\\n\"\n\"DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP\\n\"\n\"e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu\\n\"\n\"WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ\\n\"\n\"DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub\\n\"\n\"DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Primary Certification Authority\\n\"\n\"========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG\\n\"\n\"EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD\\n\"\n\"ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx\\n\"\n\"CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ\\n\"\n\"cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\\n\"\n\"CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN\\n\"\n\"b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9\\n\"\n\"nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge\\n\"\n\"RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt\\n\"\n\"tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI\\n\"\n\"hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K\\n\"\n\"Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN\\n\"\n\"NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa\\n\"\n\"Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG\\n\"\n\"1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"thawte Primary Root CA\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE\\n\"\n\"BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2\\n\"\n\"aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv\\n\"\n\"cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3\\n\"\n\"MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg\\n\"\n\"SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv\\n\"\n\"KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT\\n\"\n\"FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs\\n\"\n\"oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ\\n\"\n\"1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc\\n\"\n\"q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K\\n\"\n\"aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p\\n\"\n\"afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD\\n\"\n\"VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF\\n\"\n\"AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE\\n\"\n\"uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX\\n\"\n\"xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89\\n\"\n\"jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH\\n\"\n\"z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"VeriSign Class 3 Public Primary Certification Authority - G5\\n\"\n\"============================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\\n\"\n\"BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO\\n\"\n\"ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk\\n\"\n\"IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp\\n\"\n\"ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB\\n\"\n\"yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln\\n\"\n\"biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh\\n\"\n\"dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt\\n\"\n\"YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\\n\"\n\"ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz\\n\"\n\"j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD\\n\"\n\"Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/\\n\"\n\"Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r\\n\"\n\"fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/\\n\"\n\"BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv\\n\"\n\"Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\\n\"\n\"aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG\\n\"\n\"SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+\\n\"\n\"X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE\\n\"\n\"KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC\\n\"\n\"Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE\\n\"\n\"ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"SecureTrust CA\\n\"\n\"==============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG\\n\"\n\"EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy\\n\"\n\"dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe\\n\"\n\"BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC\\n\"\n\"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX\\n\"\n\"OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t\\n\"\n\"DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH\\n\"\n\"GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b\\n\"\n\"01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH\\n\"\n\"ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/\\n\"\n\"BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj\\n\"\n\"aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ\\n\"\n\"KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu\\n\"\n\"SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf\\n\"\n\"mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ\\n\"\n\"nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR\\n\"\n\"3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Secure Global CA\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG\\n\"\n\"EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH\\n\"\n\"bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg\\n\"\n\"MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg\\n\"\n\"Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx\\n\"\n\"YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ\\n\"\n\"bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g\\n\"\n\"8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV\\n\"\n\"HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi\\n\"\n\"0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud\\n\"\n\"EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn\\n\"\n\"oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA\\n\"\n\"MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+\\n\"\n\"OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn\\n\"\n\"CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5\\n\"\n\"3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc\\n\"\n\"f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"COMODO Certification Authority\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE\\n\"\n\"BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\\n\"\n\"A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1\\n\"\n\"dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb\\n\"\n\"MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD\\n\"\n\"T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\\n\"\n\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH\\n\"\n\"+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww\\n\"\n\"xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV\\n\"\n\"4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA\\n\"\n\"1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI\\n\"\n\"rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E\\n\"\n\"BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k\\n\"\n\"b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC\\n\"\n\"AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP\\n\"\n\"OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\\n\"\n\"RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc\\n\"\n\"IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN\\n\"\n\"+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Network Solutions Certificate Authority\\n\"\n\"=======================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG\\n\"\n\"EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr\\n\"\n\"IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx\\n\"\n\"MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu\\n\"\n\"MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G\\n\"\n\"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx\\n\"\n\"jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT\\n\"\n\"aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT\\n\"\n\"crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc\\n\"\n\"/Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB\\n\"\n\"AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP\\n\"\n\"BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv\\n\"\n\"bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA\\n\"\n\"A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q\\n\"\n\"4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/\\n\"\n\"GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv\\n\"\n\"wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD\\n\"\n\"ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"COMODO ECC Certification Authority\\n\"\n\"==================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC\\n\"\n\"R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\\n\"\n\"ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB\\n\"\n\"dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix\\n\"\n\"GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\\n\"\n\"Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo\\n\"\n\"b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X\\n\"\n\"4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni\\n\"\n\"wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E\\n\"\n\"BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG\\n\"\n\"FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA\\n\"\n\"U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Security Communication EV RootCA1\\n\"\n\"=================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc\\n\"\n\"U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh\\n\"\n\"dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE\\n\"\n\"BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl\\n\"\n\"Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\n\"\n\"AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO\\n\"\n\"/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX\\n\"\n\"WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z\\n\"\n\"ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4\\n\"\n\"bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK\\n\"\n\"9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG\\n\"\n\"SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm\\n\"\n\"iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG\\n\"\n\"Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW\\n\"\n\"mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW\\n\"\n\"T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"OISTE WISeKey Global Root GA CA\\n\"\n\"===============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE\\n\"\n\"BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG\\n\"\n\"A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH\\n\"\n\"bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD\\n\"\n\"VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw\\n\"\n\"IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5\\n\"\n\"IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9\\n\"\n\"Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg\\n\"\n\"Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD\\n\"\n\"d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ\\n\"\n\"/yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R\\n\"\n\"LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw\\n\"\n\"AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ\\n\"\n\"KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm\\n\"\n\"MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4\\n\"\n\"+vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa\\n\"\n\"hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY\\n\"\n\"okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certigna\\n\"\n\"========\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw\\n\"\n\"EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3\\n\"\n\"MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI\\n\"\n\"Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q\\n\"\n\"XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH\\n\"\n\"GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p\\n\"\n\"ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg\\n\"\n\"DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf\\n\"\n\"Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ\\n\"\n\"tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ\\n\"\n\"BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J\\n\"\n\"SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA\\n\"\n\"hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+\\n\"\n\"ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu\\n\"\n\"PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY\\n\"\n\"1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw\\n\"\n\"WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Deutsche Telekom Root CA 2\\n\"\n\"==========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT\\n\"\n\"RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG\\n\"\n\"A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5\\n\"\n\"MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G\\n\"\n\"A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS\\n\"\n\"b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5\\n\"\n\"bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI\\n\"\n\"KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY\\n\"\n\"AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK\\n\"\n\"Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV\\n\"\n\"jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV\\n\"\n\"HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr\\n\"\n\"E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy\\n\"\n\"zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8\\n\"\n\"rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G\\n\"\n\"dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU\\n\"\n\"Cm26OWMohpLzGITY+9HPBVZkVw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Cybertrust Global Root\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li\\n\"\n\"ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4\\n\"\n\"MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD\\n\"\n\"ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\\n\"\n\"+Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW\\n\"\n\"0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL\\n\"\n\"AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin\\n\"\n\"89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT\\n\"\n\"8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP\\n\"\n\"BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2\\n\"\n\"MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G\\n\"\n\"A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO\\n\"\n\"lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi\\n\"\n\"5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2\\n\"\n\"hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T\\n\"\n\"X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW\\n\"\n\"WL1WMRJOEcgh4LMRkWXbtKaIOM5V\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"ePKI Root Certification Authority\\n\"\n\"=================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG\\n\"\n\"EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg\\n\"\n\"Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx\\n\"\n\"MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq\\n\"\n\"MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B\\n\"\n\"AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs\\n\"\n\"IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi\\n\"\n\"lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv\\n\"\n\"qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX\\n\"\n\"12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O\\n\"\n\"WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+\\n\"\n\"ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao\\n\"\n\"lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/\\n\"\n\"vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi\\n\"\n\"Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi\\n\"\n\"MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH\\n\"\n\"ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0\\n\"\n\"1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq\\n\"\n\"KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV\\n\"\n\"xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP\\n\"\n\"NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r\\n\"\n\"GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE\\n\"\n\"xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx\\n\"\n\"gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy\\n\"\n\"sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD\\n\"\n\"BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"T\\xc3\\x9c\\x42\\xC4\\xB0TAK UEKAE K\\xC3\\xB6k Sertifika Hizmet Sa\\xC4\\x9Flay\\xc4\\xb1\\x63\\xc4\\xb1s\\xc4\\xb1 - S\\xC3\\xBCr\\xC3\\xBCm 3\\n\"\n\"=============================================================================================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH\\n\"\n\"DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q\\n\"\n\"aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry\\n\"\n\"b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV\\n\"\n\"BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg\\n\"\n\"S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4\\n\"\n\"MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl\\n\"\n\"IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF\\n\"\n\"n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl\\n\"\n\"IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft\\n\"\n\"dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl\\n\"\n\"cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B\\n\"\n\"AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO\\n\"\n\"Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1\\n\"\n\"xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR\\n\"\n\"6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL\\n\"\n\"hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd\\n\"\n\"BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\\n\"\n\"MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4\\n\"\n\"N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT\\n\"\n\"y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh\\n\"\n\"LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M\\n\"\n\"dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"certSIGN ROOT CA\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD\\n\"\n\"VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa\\n\"\n\"Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE\\n\"\n\"CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I\\n\"\n\"JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH\\n\"\n\"rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2\\n\"\n\"ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD\\n\"\n\"0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943\\n\"\n\"AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\\n\"\n\"Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB\\n\"\n\"AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8\\n\"\n\"SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0\\n\"\n\"x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt\\n\"\n\"vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz\\n\"\n\"TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"CNNIC ROOT\\n\"\n\"==========\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE\\n\"\n\"ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw\\n\"\n\"OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw\\n\"\n\"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD\\n\"\n\"o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz\\n\"\n\"VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT\\n\"\n\"VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or\\n\"\n\"czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK\\n\"\n\"y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC\\n\"\n\"wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S\\n\"\n\"lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5\\n\"\n\"Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM\\n\"\n\"O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8\\n\"\n\"BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2\\n\"\n\"G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m\\n\"\n\"mxE=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Primary Certification Authority - G3\\n\"\n\"=============================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE\\n\"\n\"BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0\\n\"\n\"IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy\\n\"\n\"eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz\\n\"\n\"NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo\\n\"\n\"YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT\\n\"\n\"LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI\\n\"\n\"hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j\\n\"\n\"K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE\\n\"\n\"c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C\\n\"\n\"IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu\\n\"\n\"dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC\\n\"\n\"MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr\\n\"\n\"2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9\\n\"\n\"cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE\\n\"\n\"Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD\\n\"\n\"AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s\\n\"\n\"t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"thawte Primary Root CA - G2\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC\\n\"\n\"VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu\\n\"\n\"IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg\\n\"\n\"Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV\\n\"\n\"MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG\\n\"\n\"b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt\\n\"\n\"IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS\\n\"\n\"LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5\\n\"\n\"8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU\\n\"\n\"mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN\\n\"\n\"G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K\\n\"\n\"rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"thawte Primary Root CA - G3\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE\\n\"\n\"BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2\\n\"\n\"aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv\\n\"\n\"cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w\\n\"\n\"ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh\\n\"\n\"d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD\\n\"\n\"VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG\\n\"\n\"A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\\n\"\n\"MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At\\n\"\n\"P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC\\n\"\n\"+BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY\\n\"\n\"7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW\\n\"\n\"vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E\\n\"\n\"BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ\\n\"\n\"KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK\\n\"\n\"A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu\\n\"\n\"t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC\\n\"\n\"8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm\\n\"\n\"er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GeoTrust Primary Certification Authority - G2\\n\"\n\"=============================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC\\n\"\n\"VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu\\n\"\n\"Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD\\n\"\n\"ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1\\n\"\n\"OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg\\n\"\n\"MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl\\n\"\n\"b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG\\n\"\n\"BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc\\n\"\n\"KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD\\n\"\n\"VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+\\n\"\n\"EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m\\n\"\n\"ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2\\n\"\n\"npaqBA+K\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"VeriSign Universal Root Certification Authority\\n\"\n\"===============================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE\\n\"\n\"BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO\\n\"\n\"ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk\\n\"\n\"IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u\\n\"\n\"IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV\\n\"\n\"UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv\\n\"\n\"cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl\\n\"\n\"IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0\\n\"\n\"aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj\\n\"\n\"1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP\\n\"\n\"MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72\\n\"\n\"9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I\\n\"\n\"AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR\\n\"\n\"tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G\\n\"\n\"CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O\\n\"\n\"a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud\\n\"\n\"DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3\\n\"\n\"Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx\\n\"\n\"Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx\\n\"\n\"P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P\\n\"\n\"wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4\\n\"\n\"mJO37M2CYfE45k+XmCpajQ==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"VeriSign Class 3 Public Primary Certification Authority - G4\\n\"\n\"============================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC\\n\"\n\"VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3\\n\"\n\"b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz\\n\"\n\"ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj\\n\"\n\"YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL\\n\"\n\"MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU\\n\"\n\"cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo\\n\"\n\"b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5\\n\"\n\"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8\\n\"\n\"Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz\\n\"\n\"rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw\\n\"\n\"HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u\\n\"\n\"Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD\\n\"\n\"A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx\\n\"\n\"AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"NetLock Arany (Class Gold) Főtanúsítvány\\n\"\n\"========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G\\n\"\n\"A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610\\n\"\n\"dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB\\n\"\n\"cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx\\n\"\n\"MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO\\n\"\n\"ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv\\n\"\n\"biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6\\n\"\n\"c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu\\n\"\n\"0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw\\n\"\n\"/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk\\n\"\n\"H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw\\n\"\n\"fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1\\n\"\n\"neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB\\n\"\n\"BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW\\n\"\n\"qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta\\n\"\n\"YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC\\n\"\n\"bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna\\n\"\n\"NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu\\n\"\n\"dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Staat der Nederlanden Root CA - G2\\n\"\n\"==================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE\\n\"\n\"CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g\\n\"\n\"Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC\\n\"\n\"TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l\\n\"\n\"ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ\\n\"\n\"5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn\\n\"\n\"vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj\\n\"\n\"CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil\\n\"\n\"e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR\\n\"\n\"OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI\\n\"\n\"CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65\\n\"\n\"48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi\\n\"\n\"trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737\\n\"\n\"qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB\\n\"\n\"AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC\\n\"\n\"ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV\\n\"\n\"HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA\\n\"\n\"A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz\\n\"\n\"+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj\\n\"\n\"f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN\\n\"\n\"kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk\\n\"\n\"CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF\\n\"\n\"URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb\\n\"\n\"CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h\\n\"\n\"oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV\\n\"\n\"IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm\\n\"\n\"66+KAQ==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Hongkong Post Root CA 1\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT\\n\"\n\"DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx\\n\"\n\"NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n\\n\"\n\"IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF\\n\"\n\"AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1\\n\"\n\"ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr\\n\"\n\"auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh\\n\"\n\"qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY\\n\"\n\"V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV\\n\"\n\"HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i\\n\"\n\"h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio\\n\"\n\"l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei\\n\"\n\"IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps\\n\"\n\"T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT\\n\"\n\"c4afU9hDDl3WY4JxHYB0yvbiAmvZWg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"SecureSign RootCA11\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi\\n\"\n\"SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS\\n\"\n\"b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw\\n\"\n\"KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1\\n\"\n\"cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL\\n\"\n\"TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO\\n\"\n\"wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq\\n\"\n\"g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP\\n\"\n\"O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA\\n\"\n\"bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX\\n\"\n\"t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh\\n\"\n\"OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r\\n\"\n\"bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ\\n\"\n\"Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01\\n\"\n\"y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061\\n\"\n\"lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"ACEDICOM Root\\n\"\n\"=============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD\\n\"\n\"T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4\\n\"\n\"MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG\\n\"\n\"A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF\\n\"\n\"AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk\\n\"\n\"WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD\\n\"\n\"YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew\\n\"\n\"MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb\\n\"\n\"m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk\\n\"\n\"HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT\\n\"\n\"xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2\\n\"\n\"3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9\\n\"\n\"2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq\\n\"\n\"TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz\\n\"\n\"4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU\\n\"\n\"9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv\\n\"\n\"bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg\\n\"\n\"aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP\\n\"\n\"eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk\\n\"\n\"zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1\\n\"\n\"ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI\\n\"\n\"KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq\\n\"\n\"nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE\\n\"\n\"I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp\\n\"\n\"MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o\\n\"\n\"tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Microsec e-Szigno Root CA 2009\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER\\n\"\n\"MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv\\n\"\n\"c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o\\n\"\n\"dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE\\n\"\n\"BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt\\n\"\n\"U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw\\n\"\n\"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA\\n\"\n\"fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG\\n\"\n\"0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA\\n\"\n\"pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm\\n\"\n\"1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC\\n\"\n\"AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf\\n\"\n\"QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE\\n\"\n\"FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o\\n\"\n\"lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX\\n\"\n\"I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775\\n\"\n\"tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02\\n\"\n\"yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi\\n\"\n\"LXpUq3DDfSJlgnCW\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GlobalSign Root CA - R3\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv\\n\"\n\"YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh\\n\"\n\"bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT\\n\"\n\"aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln\\n\"\n\"bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt\\n\"\n\"iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ\\n\"\n\"0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3\\n\"\n\"rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl\\n\"\n\"OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2\\n\"\n\"xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\\n\"\n\"FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7\\n\"\n\"lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8\\n\"\n\"EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E\\n\"\n\"bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18\\n\"\n\"YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r\\n\"\n\"kpeDMdmztcpHWD9f\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Autoridad de Certificacion Firmaprofesional CIF A62634068\\n\"\n\"=========================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA\\n\"\n\"BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2\\n\"\n\"MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw\\n\"\n\"QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB\\n\"\n\"NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD\\n\"\n\"Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P\\n\"\n\"B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY\\n\"\n\"7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH\\n\"\n\"ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI\\n\"\n\"plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX\\n\"\n\"MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX\\n\"\n\"LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK\\n\"\n\"bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU\\n\"\n\"vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud\\n\"\n\"EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH\\n\"\n\"DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp\\n\"\n\"cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA\\n\"\n\"bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx\\n\"\n\"ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx\\n\"\n\"51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk\\n\"\n\"R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP\\n\"\n\"T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f\\n\"\n\"Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl\\n\"\n\"osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR\\n\"\n\"crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR\\n\"\n\"saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD\\n\"\n\"KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi\\n\"\n\"6Et8Vcad+qMUu2WFbm5PEn4KPJ2V\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Izenpe.com\\n\"\n\"==========\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG\\n\"\n\"EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz\\n\"\n\"MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu\\n\"\n\"QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ\\n\"\n\"03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK\\n\"\n\"ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU\\n\"\n\"+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC\\n\"\n\"PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT\\n\"\n\"OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK\\n\"\n\"F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK\\n\"\n\"0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+\\n\"\n\"0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB\\n\"\n\"leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID\\n\"\n\"AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+\\n\"\n\"SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG\\n\"\n\"NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx\\n\"\n\"MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\\n\"\n\"BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l\\n\"\n\"Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga\\n\"\n\"kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q\\n\"\n\"hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs\\n\"\n\"g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5\\n\"\n\"aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5\\n\"\n\"nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC\\n\"\n\"ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo\\n\"\n\"Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z\\n\"\n\"WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Chambers of Commerce Root - 2008\\n\"\n\"================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD\\n\"\n\"MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv\\n\"\n\"bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu\\n\"\n\"QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy\\n\"\n\"Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl\\n\"\n\"ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF\\n\"\n\"EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl\\n\"\n\"cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\\n\"\n\"AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA\\n\"\n\"XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj\\n\"\n\"h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/\\n\"\n\"ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk\\n\"\n\"NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g\\n\"\n\"D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331\\n\"\n\"lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ\\n\"\n\"0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj\\n\"\n\"ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2\\n\"\n\"EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI\\n\"\n\"G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ\\n\"\n\"BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh\\n\"\n\"bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh\\n\"\n\"bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC\\n\"\n\"CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH\\n\"\n\"AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1\\n\"\n\"wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH\\n\"\n\"3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU\\n\"\n\"RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6\\n\"\n\"M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1\\n\"\n\"YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF\\n\"\n\"9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK\\n\"\n\"zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG\\n\"\n\"nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg\\n\"\n\"OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Global Chambersign Root - 2008\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD\\n\"\n\"MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv\\n\"\n\"bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu\\n\"\n\"QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx\\n\"\n\"NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg\\n\"\n\"Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ\\n\"\n\"QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD\\n\"\n\"aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf\\n\"\n\"VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf\\n\"\n\"XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0\\n\"\n\"ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB\\n\"\n\"/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA\\n\"\n\"TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M\\n\"\n\"H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe\\n\"\n\"Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF\\n\"\n\"HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh\\n\"\n\"wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB\\n\"\n\"AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT\\n\"\n\"BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE\\n\"\n\"BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm\\n\"\n\"aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm\\n\"\n\"aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp\\n\"\n\"1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0\\n\"\n\"dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG\\n\"\n\"/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6\\n\"\n\"ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s\\n\"\n\"dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg\\n\"\n\"9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH\\n\"\n\"foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du\\n\"\n\"qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr\\n\"\n\"P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq\\n\"\n\"c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z\\n\"\n\"09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Go Daddy Root Certificate Authority - G2\\n\"\n\"========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\\n\"\n\"B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu\\n\"\n\"MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5\\n\"\n\"MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\\n\"\n\"b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G\\n\"\n\"A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI\\n\"\n\"hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq\\n\"\n\"9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD\\n\"\n\"+qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd\\n\"\n\"fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl\\n\"\n\"NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC\\n\"\n\"MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9\\n\"\n\"BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac\\n\"\n\"vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r\\n\"\n\"5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV\\n\"\n\"N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\\n\"\n\"LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Starfield Root Certificate Authority - G2\\n\"\n\"=========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\\n\"\n\"B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\\n\"\n\"b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0\\n\"\n\"eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw\\n\"\n\"DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg\\n\"\n\"VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB\\n\"\n\"dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv\\n\"\n\"W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs\\n\"\n\"bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk\\n\"\n\"N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf\\n\"\n\"ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU\\n\"\n\"JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\\n\"\n\"AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol\\n\"\n\"TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx\\n\"\n\"4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw\\n\"\n\"F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\\n\"\n\"pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ\\n\"\n\"c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Starfield Services Root Certificate Authority - G2\\n\"\n\"==================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT\\n\"\n\"B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s\\n\"\n\"b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl\\n\"\n\"IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV\\n\"\n\"BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT\\n\"\n\"dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg\\n\"\n\"Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\\n\"\n\"AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2\\n\"\n\"h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa\\n\"\n\"hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP\\n\"\n\"LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB\\n\"\n\"rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw\\n\"\n\"AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG\\n\"\n\"SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP\\n\"\n\"E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy\\n\"\n\"xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd\\n\"\n\"iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza\\n\"\n\"YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AffirmTrust Commercial\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS\\n\"\n\"BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw\\n\"\n\"MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\\n\"\n\"bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF\\n\"\n\"AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb\\n\"\n\"DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV\\n\"\n\"C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6\\n\"\n\"BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww\\n\"\n\"MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV\\n\"\n\"HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\\n\"\n\"AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG\\n\"\n\"hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi\\n\"\n\"qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv\\n\"\n\"0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh\\n\"\n\"sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AffirmTrust Networking\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS\\n\"\n\"BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw\\n\"\n\"MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly\\n\"\n\"bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF\\n\"\n\"AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE\\n\"\n\"Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI\\n\"\n\"dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24\\n\"\n\"/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb\\n\"\n\"h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV\\n\"\n\"HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\\n\"\n\"AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu\\n\"\n\"UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6\\n\"\n\"12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23\\n\"\n\"WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9\\n\"\n\"/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AffirmTrust Premium\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS\\n\"\n\"BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy\\n\"\n\"OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy\\n\"\n\"dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\\n\"\n\"MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn\\n\"\n\"BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV\\n\"\n\"5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs\\n\"\n\"+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd\\n\"\n\"GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R\\n\"\n\"p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI\\n\"\n\"S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04\\n\"\n\"6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5\\n\"\n\"/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo\\n\"\n\"+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB\\n\"\n\"/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv\\n\"\n\"MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\\n\"\n\"Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC\\n\"\n\"6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S\\n\"\n\"L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK\\n\"\n\"+4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV\\n\"\n\"BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg\\n\"\n\"IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60\\n\"\n\"g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb\\n\"\n\"zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AffirmTrust Premium ECC\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV\\n\"\n\"BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx\\n\"\n\"MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U\\n\"\n\"cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA\\n\"\n\"IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ\\n\"\n\"N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW\\n\"\n\"BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK\\n\"\n\"BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X\\n\"\n\"57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM\\n\"\n\"eQ==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certum Trusted Network CA\\n\"\n\"=========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK\\n\"\n\"ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv\\n\"\n\"biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy\\n\"\n\"MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU\\n\"\n\"ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\\n\"\n\"MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\\n\"\n\"AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC\\n\"\n\"l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J\\n\"\n\"J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4\\n\"\n\"fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0\\n\"\n\"cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB\\n\"\n\"Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw\\n\"\n\"DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj\\n\"\n\"jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1\\n\"\n\"mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj\\n\"\n\"Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI\\n\"\n\"03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certinomis - Autorité Racine\\n\"\n\"============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK\\n\"\n\"Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg\\n\"\n\"LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG\\n\"\n\"A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw\\n\"\n\"JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD\\n\"\n\"ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa\\n\"\n\"wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly\\n\"\n\"Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw\\n\"\n\"2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N\\n\"\n\"jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q\\n\"\n\"c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC\\n\"\n\"lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb\\n\"\n\"xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g\\n\"\n\"530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna\\n\"\n\"4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\\n\"\n\"A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ\\n\"\n\"KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x\\n\"\n\"WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva\\n\"\n\"R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40\\n\"\n\"nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B\\n\"\n\"CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv\\n\"\n\"JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE\\n\"\n\"qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b\\n\"\n\"WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE\\n\"\n\"wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/\\n\"\n\"vgt2Fl43N+bYdJeimUV5\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"TWCA Root Certification Authority\\n\"\n\"=================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ\\n\"\n\"VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh\\n\"\n\"dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG\\n\"\n\"EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB\\n\"\n\"IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\\n\"\n\"AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx\\n\"\n\"QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC\\n\"\n\"oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP\\n\"\n\"4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r\\n\"\n\"y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB\\n\"\n\"BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG\\n\"\n\"9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC\\n\"\n\"mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW\\n\"\n\"QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY\\n\"\n\"T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny\\n\"\n\"Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Security Communication RootCA2\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc\\n\"\n\"U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh\\n\"\n\"dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC\\n\"\n\"SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy\\n\"\n\"aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\\n\"\n\"ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++\\n\"\n\"+T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R\\n\"\n\"3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV\\n\"\n\"spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K\\n\"\n\"EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8\\n\"\n\"QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB\\n\"\n\"CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj\\n\"\n\"u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk\\n\"\n\"3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q\\n\"\n\"tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29\\n\"\n\"mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"EC-ACC\\n\"\n\"======\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE\\n\"\n\"BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w\\n\"\n\"ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD\\n\"\n\"VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE\\n\"\n\"CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT\\n\"\n\"BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7\\n\"\n\"MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt\\n\"\n\"SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl\\n\"\n\"Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh\\n\"\n\"cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND\\n\"\n\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK\\n\"\n\"w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT\\n\"\n\"ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4\\n\"\n\"HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a\\n\"\n\"E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw\\n\"\n\"0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E\\n\"\n\"BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD\\n\"\n\"VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0\\n\"\n\"Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l\\n\"\n\"dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ\\n\"\n\"lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa\\n\"\n\"Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe\\n\"\n\"l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2\\n\"\n\"E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D\\n\"\n\"5EI=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Hellenic Academic and Research Institutions RootCA 2011\\n\"\n\"=======================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT\\n\"\n\"O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y\\n\"\n\"aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z\\n\"\n\"IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT\\n\"\n\"AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z\\n\"\n\"IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo\\n\"\n\"IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\\n\"\n\"AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI\\n\"\n\"1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa\\n\"\n\"71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u\\n\"\n\"8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH\\n\"\n\"3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/\\n\"\n\"MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8\\n\"\n\"MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu\\n\"\n\"b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt\\n\"\n\"XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8\\n\"\n\"TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD\\n\"\n\"/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N\\n\"\n\"7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Actalis Authentication Root CA\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM\\n\"\n\"BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE\\n\"\n\"AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky\\n\"\n\"MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz\\n\"\n\"IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290\\n\"\n\"IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ\\n\"\n\"wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa\\n\"\n\"by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6\\n\"\n\"zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f\\n\"\n\"YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2\\n\"\n\"oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l\\n\"\n\"EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7\\n\"\n\"hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8\\n\"\n\"EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5\\n\"\n\"jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY\\n\"\n\"iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt\\n\"\n\"ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI\\n\"\n\"WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0\\n\"\n\"JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx\\n\"\n\"K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+\\n\"\n\"Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC\\n\"\n\"4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo\\n\"\n\"2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz\\n\"\n\"lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem\\n\"\n\"OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9\\n\"\n\"vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Trustis FPS Root CA\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG\\n\"\n\"EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290\\n\"\n\"IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV\\n\"\n\"BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ\\n\"\n\"KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ\\n\"\n\"RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk\\n\"\n\"H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa\\n\"\n\"cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt\\n\"\n\"o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA\\n\"\n\"AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd\\n\"\n\"BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c\\n\"\n\"GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC\\n\"\n\"yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P\\n\"\n\"8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV\\n\"\n\"l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl\\n\"\n\"iB6XzCGcKQENZetX2fNXlrtIzYE=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"StartCom Certification Authority\\n\"\n\"================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\\n\"\n\"U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu\\n\"\n\"ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0\\n\"\n\"NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk\\n\"\n\"LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg\\n\"\n\"U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\\n\"\n\"ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y\\n\"\n\"o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/\\n\"\n\"Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d\\n\"\n\"eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt\\n\"\n\"2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z\\n\"\n\"6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ\\n\"\n\"osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/\\n\"\n\"untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc\\n\"\n\"UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT\\n\"\n\"37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD\\n\"\n\"VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ\\n\"\n\"Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0\\n\"\n\"dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu\\n\"\n\"c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv\\n\"\n\"bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0\\n\"\n\"aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0\\n\"\n\"aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t\\n\"\n\"L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG\\n\"\n\"cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5\\n\"\n\"fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm\\n\"\n\"N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN\\n\"\n\"Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T\\n\"\n\"tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX\\n\"\n\"e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA\\n\"\n\"2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs\\n\"\n\"HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE\\n\"\n\"JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib\\n\"\n\"D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"StartCom Certification Authority G2\\n\"\n\"===================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN\\n\"\n\"U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\\n\"\n\"RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE\\n\"\n\"ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp\\n\"\n\"dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O\\n\"\n\"o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG\\n\"\n\"4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi\\n\"\n\"Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul\\n\"\n\"Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs\\n\"\n\"O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H\\n\"\n\"vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L\\n\"\n\"nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS\\n\"\n\"FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa\\n\"\n\"z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E\\n\"\n\"BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ\\n\"\n\"KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K\\n\"\n\"2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk\\n\"\n\"J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+\\n\"\n\"JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG\\n\"\n\"/+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc\\n\"\n\"nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld\\n\"\n\"blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc\\n\"\n\"l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm\\n\"\n\"7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm\\n\"\n\"obp573PYtlNXLfbQ4ddI\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Buypass Class 2 Root CA\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\\n\"\n\"QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X\\n\"\n\"DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\\n\"\n\"eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw\\n\"\n\"DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1\\n\"\n\"g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn\\n\"\n\"9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b\\n\"\n\"/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU\\n\"\n\"CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff\\n\"\n\"awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI\\n\"\n\"zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn\\n\"\n\"Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX\\n\"\n\"Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs\\n\"\n\"M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\\n\"\n\"VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\\n\"\n\"AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s\\n\"\n\"A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI\\n\"\n\"osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S\\n\"\n\"aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd\\n\"\n\"DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD\\n\"\n\"LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0\\n\"\n\"oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC\\n\"\n\"wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS\\n\"\n\"CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN\\n\"\n\"rJgWVqA=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Buypass Class 3 Root CA\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU\\n\"\n\"QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X\\n\"\n\"DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1\\n\"\n\"eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw\\n\"\n\"DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH\\n\"\n\"sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR\\n\"\n\"5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh\\n\"\n\"7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ\\n\"\n\"ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH\\n\"\n\"2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV\\n\"\n\"/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ\\n\"\n\"RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA\\n\"\n\"Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq\\n\"\n\"j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\\n\"\n\"VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF\\n\"\n\"AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV\\n\"\n\"cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G\\n\"\n\"uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG\\n\"\n\"Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8\\n\"\n\"ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2\\n\"\n\"KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz\\n\"\n\"6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug\\n\"\n\"UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe\\n\"\n\"eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi\\n\"\n\"Cp/HuZc=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"T-TeleSec GlobalRoot Class 3\\n\"\n\"============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\\n\"\n\"IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\\n\"\n\"cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx\\n\"\n\"MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\\n\"\n\"dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\\n\"\n\"ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3\\n\"\n\"DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK\\n\"\n\"9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU\\n\"\n\"NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF\\n\"\n\"iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W\\n\"\n\"0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA\\n\"\n\"MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr\\n\"\n\"AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb\\n\"\n\"fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT\\n\"\n\"ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h\\n\"\n\"P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml\\n\"\n\"e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"EE Certification Centre Root CA\\n\"\n\"===============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG\\n\"\n\"EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy\\n\"\n\"dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw\\n\"\n\"MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB\\n\"\n\"UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy\\n\"\n\"ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB\\n\"\n\"DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM\\n\"\n\"TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2\\n\"\n\"rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw\\n\"\n\"93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN\\n\"\n\"P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T\\n\"\n\"AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ\\n\"\n\"MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF\\n\"\n\"BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj\\n\"\n\"xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM\\n\"\n\"lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u\\n\"\n\"uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU\\n\"\n\"3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM\\n\"\n\"dcGWxZ0=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"TURKTRUST Certificate Services Provider Root 2007\\n\"\n\"=================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF\\n\"\n\"bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP\\n\"\n\"MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg\\n\"\n\"QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X\\n\"\n\"DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl\\n\"\n\"a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN\\n\"\n\"BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp\\n\"\n\"bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw\\n\"\n\"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N\\n\"\n\"YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv\\n\"\n\"KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya\\n\"\n\"KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT\\n\"\n\"rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC\\n\"\n\"AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP\\n\"\n\"BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s\\n\"\n\"Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I\\n\"\n\"aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO\\n\"\n\"Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb\\n\"\n\"BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK\\n\"\n\"poRq0Tl9\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"D-TRUST Root Class 3 CA 2 2009\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK\\n\"\n\"DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe\\n\"\n\"Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE\\n\"\n\"LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw\\n\"\n\"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD\\n\"\n\"ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA\\n\"\n\"BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv\\n\"\n\"KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z\\n\"\n\"p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC\\n\"\n\"AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ\\n\"\n\"4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y\\n\"\n\"eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw\\n\"\n\"MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G\\n\"\n\"PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw\\n\"\n\"OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm\\n\"\n\"2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0\\n\"\n\"o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV\\n\"\n\"dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph\\n\"\n\"X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"D-TRUST Root Class 3 CA 2 EV 2009\\n\"\n\"=================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\\n\"\n\"DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\\n\"\n\"OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK\\n\"\n\"DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw\\n\"\n\"OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS\\n\"\n\"egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh\\n\"\n\"zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T\\n\"\n\"7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60\\n\"\n\"sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35\\n\"\n\"11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv\\n\"\n\"cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v\\n\"\n\"ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El\\n\"\n\"MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp\\n\"\n\"b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh\\n\"\n\"c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+\\n\"\n\"PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05\\n\"\n\"nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX\\n\"\n\"ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA\\n\"\n\"NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv\\n\"\n\"w9y4AyHqnxbxLFS1\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"PSCProcert\\n\"\n\"==========\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk\\n\"\n\"ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ\\n\"\n\"MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz\\n\"\n\"dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl\\n\"\n\"cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw\\n\"\n\"IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw\\n\"\n\"MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w\\n\"\n\"DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD\\n\"\n\"ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp\\n\"\n\"Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw\\n\"\n\"DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC\\n\"\n\"wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA\\n\"\n\"3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh\\n\"\n\"RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO\\n\"\n\"EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2\\n\"\n\"0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH\\n\"\n\"0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU\\n\"\n\"td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw\\n\"\n\"Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp\\n\"\n\"r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/\\n\"\n\"AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz\\n\"\n\"Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId\\n\"\n\"xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp\\n\"\n\"ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH\\n\"\n\"EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h\\n\"\n\"Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k\\n\"\n\"ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG\\n\"\n\"9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG\\n\"\n\"MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG\\n\"\n\"LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52\\n\"\n\"ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy\\n\"\n\"YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v\\n\"\n\"Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o\\n\"\n\"dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq\\n\"\n\"T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN\\n\"\n\"g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q\\n\"\n\"uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1\\n\"\n\"n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn\\n\"\n\"FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo\\n\"\n\"5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq\\n\"\n\"3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5\\n\"\n\"poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y\\n\"\n\"eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"China Internet Network Information Center EV Certificates Root\\n\"\n\"==============================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV\\n\"\n\"BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D\\n\"\n\"aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg\\n\"\n\"Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG\\n\"\n\"A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM\\n\"\n\"PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl\\n\"\n\"cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y\\n\"\n\"jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV\\n\"\n\"98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H\\n\"\n\"klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23\\n\"\n\"KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC\\n\"\n\"7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV\\n\"\n\"HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD\\n\"\n\"glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5\\n\"\n\"0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM\\n\"\n\"7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws\\n\"\n\"ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0\\n\"\n\"5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Swisscom Root CA 2\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG\\n\"\n\"EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy\\n\"\n\"dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2\\n\"\n\"MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln\\n\"\n\"aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC\\n\"\n\"IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM\\n\"\n\"LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo\\n\"\n\"ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ\\n\"\n\"wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH\\n\"\n\"Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a\\n\"\n\"SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS\\n\"\n\"NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab\\n\"\n\"mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY\\n\"\n\"Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3\\n\"\n\"qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw\\n\"\n\"HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O\\n\"\n\"BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu\\n\"\n\"MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO\\n\"\n\"v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ\\n\"\n\"82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz\\n\"\n\"o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs\\n\"\n\"a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx\\n\"\n\"OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW\\n\"\n\"mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o\\n\"\n\"+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC\\n\"\n\"rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX\\n\"\n\"5OfNeOI5wSsSnqaeG8XmDtkx2Q==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Swisscom Root EV CA 2\\n\"\n\"=====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE\\n\"\n\"BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl\\n\"\n\"cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN\\n\"\n\"MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT\\n\"\n\"HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg\\n\"\n\"Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz\\n\"\n\"o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy\\n\"\n\"Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti\\n\"\n\"GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li\\n\"\n\"qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH\\n\"\n\"Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG\\n\"\n\"alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa\\n\"\n\"m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox\\n\"\n\"bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi\\n\"\n\"xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/\\n\"\n\"BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED\\n\"\n\"MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB\\n\"\n\"bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL\\n\"\n\"j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU\\n\"\n\"wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7\\n\"\n\"XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH\\n\"\n\"59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/\\n\"\n\"23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq\\n\"\n\"J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA\\n\"\n\"HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi\\n\"\n\"uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW\\n\"\n\"l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"CA Disig Root R1\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw\\n\"\n\"EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp\\n\"\n\"ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx\\n\"\n\"EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp\\n\"\n\"c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy\\n\"\n\"3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8\\n\"\n\"u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2\\n\"\n\"m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk\\n\"\n\"CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa\\n\"\n\"YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6\\n\"\n\"vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL\\n\"\n\"LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX\\n\"\n\"ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is\\n\"\n\"XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV\\n\"\n\"HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ\\n\"\n\"04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR\\n\"\n\"xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B\\n\"\n\"LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM\\n\"\n\"CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb\\n\"\n\"VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85\\n\"\n\"YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS\\n\"\n\"ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix\\n\"\n\"lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N\\n\"\n\"UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ\\n\"\n\"a7+h89n07eLw4+1knj0vllJPgFOL\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"CA Disig Root R2\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw\\n\"\n\"EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp\\n\"\n\"ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx\\n\"\n\"EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp\\n\"\n\"c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC\\n\"\n\"w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia\\n\"\n\"xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7\\n\"\n\"A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S\\n\"\n\"GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV\\n\"\n\"g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa\\n\"\n\"5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE\\n\"\n\"koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A\\n\"\n\"Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i\\n\"\n\"Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV\\n\"\n\"HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u\\n\"\n\"Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM\\n\"\n\"tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV\\n\"\n\"sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je\\n\"\n\"dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8\\n\"\n\"1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx\\n\"\n\"mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01\\n\"\n\"utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0\\n\"\n\"sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg\\n\"\n\"UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV\\n\"\n\"7+ZtsH8tZ/3zbBt1RqPlShfppNcL\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"ACCVRAIZ1\\n\"\n\"=========\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB\\n\"\n\"SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1\\n\"\n\"MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH\\n\"\n\"UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC\\n\"\n\"DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM\\n\"\n\"jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0\\n\"\n\"RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD\\n\"\n\"aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ\\n\"\n\"0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG\\n\"\n\"WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7\\n\"\n\"8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR\\n\"\n\"5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J\\n\"\n\"9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK\\n\"\n\"Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw\\n\"\n\"Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu\\n\"\n\"Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2\\n\"\n\"VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM\\n\"\n\"Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA\\n\"\n\"QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh\\n\"\n\"AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA\\n\"\n\"YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj\\n\"\n\"AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA\\n\"\n\"IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk\\n\"\n\"aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0\\n\"\n\"dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2\\n\"\n\"MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI\\n\"\n\"hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E\\n\"\n\"R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN\\n\"\n\"YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49\\n\"\n\"nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ\\n\"\n\"TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3\\n\"\n\"sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\\n\"\n\"I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg\\n\"\n\"Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd\\n\"\n\"3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p\\n\"\n\"EfbRD0tVNEYqi4Y7\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"TWCA Global Root CA\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT\\n\"\n\"CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD\\n\"\n\"QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK\\n\"\n\"EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg\\n\"\n\"Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C\\n\"\n\"nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV\\n\"\n\"r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR\\n\"\n\"Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV\\n\"\n\"tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W\\n\"\n\"KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99\\n\"\n\"sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p\\n\"\n\"yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn\\n\"\n\"kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI\\n\"\n\"zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC\\n\"\n\"AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g\\n\"\n\"cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn\\n\"\n\"LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M\\n\"\n\"8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg\\n\"\n\"/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg\\n\"\n\"lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP\\n\"\n\"A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m\\n\"\n\"i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8\\n\"\n\"EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3\\n\"\n\"zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"TeliaSonera Root CA v1\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE\\n\"\n\"CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4\\n\"\n\"MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW\\n\"\n\"VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+\\n\"\n\"6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA\\n\"\n\"3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k\\n\"\n\"B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn\\n\"\n\"Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH\\n\"\n\"oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3\\n\"\n\"F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ\\n\"\n\"oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7\\n\"\n\"gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc\\n\"\n\"TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB\\n\"\n\"AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW\\n\"\n\"DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm\\n\"\n\"zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx\\n\"\n\"0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW\\n\"\n\"pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV\\n\"\n\"G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc\\n\"\n\"c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT\\n\"\n\"JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2\\n\"\n\"qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6\\n\"\n\"Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems\\n\"\n\"WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"E-Tugra Certification Authority\\n\"\n\"===============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w\\n\"\n\"DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls\\n\"\n\"ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN\\n\"\n\"ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw\\n\"\n\"NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx\\n\"\n\"QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl\\n\"\n\"cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD\\n\"\n\"DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\\n\"\n\"MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd\\n\"\n\"hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K\\n\"\n\"CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g\\n\"\n\"ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ\\n\"\n\"BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0\\n\"\n\"E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz\\n\"\n\"rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq\\n\"\n\"jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn\\n\"\n\"rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5\\n\"\n\"dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB\\n\"\n\"/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG\\n\"\n\"MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK\\n\"\n\"kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO\\n\"\n\"XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807\\n\"\n\"VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo\\n\"\n\"a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc\\n\"\n\"dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV\\n\"\n\"KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT\\n\"\n\"Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0\\n\"\n\"8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G\\n\"\n\"C7TbO6Orb1wdtn7os4I07QZcJA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"T-TeleSec GlobalRoot Class 2\\n\"\n\"============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM\\n\"\n\"IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU\\n\"\n\"cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx\\n\"\n\"MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz\\n\"\n\"dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD\\n\"\n\"ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3\\n\"\n\"DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ\\n\"\n\"SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F\\n\"\n\"vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970\\n\"\n\"2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV\\n\"\n\"WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA\\n\"\n\"MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy\\n\"\n\"YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4\\n\"\n\"r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf\\n\"\n\"vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR\\n\"\n\"3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN\\n\"\n\"9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Atos TrustedRoot 2011\\n\"\n\"=====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU\\n\"\n\"cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4\\n\"\n\"MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG\\n\"\n\"A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV\\n\"\n\"hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr\\n\"\n\"54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+\\n\"\n\"DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320\\n\"\n\"HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR\\n\"\n\"z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R\\n\"\n\"l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ\\n\"\n\"bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\\n\"\n\"CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h\\n\"\n\"k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh\\n\"\n\"TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9\\n\"\n\"61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G\\n\"\n\"3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"QuoVadis Root CA 1 G3\\n\"\n\"=====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG\\n\"\n\"A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\\n\"\n\"b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN\\n\"\n\"MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg\\n\"\n\"RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE\\n\"\n\"PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm\\n\"\n\"PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6\\n\"\n\"Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN\\n\"\n\"ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l\\n\"\n\"g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV\\n\"\n\"7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX\\n\"\n\"9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f\\n\"\n\"iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg\\n\"\n\"t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI\\n\"\n\"hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC\\n\"\n\"MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3\\n\"\n\"GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct\\n\"\n\"Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP\\n\"\n\"+V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh\\n\"\n\"3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa\\n\"\n\"wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6\\n\"\n\"O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0\\n\"\n\"FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV\\n\"\n\"hMJKzRwuJIczYOXD\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"QuoVadis Root CA 2 G3\\n\"\n\"=====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG\\n\"\n\"A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\\n\"\n\"b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN\\n\"\n\"MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg\\n\"\n\"RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh\\n\"\n\"ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY\\n\"\n\"NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t\\n\"\n\"oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o\\n\"\n\"MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l\\n\"\n\"V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo\\n\"\n\"L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ\\n\"\n\"sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD\\n\"\n\"6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh\\n\"\n\"lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI\\n\"\n\"hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66\\n\"\n\"AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K\\n\"\n\"pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9\\n\"\n\"x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz\\n\"\n\"dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X\\n\"\n\"U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw\\n\"\n\"mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD\\n\"\n\"zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN\\n\"\n\"JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr\\n\"\n\"O3jtZsSOeWmD3n+M\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"QuoVadis Root CA 3 G3\\n\"\n\"=====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG\\n\"\n\"A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv\\n\"\n\"b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN\\n\"\n\"MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg\\n\"\n\"RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286\\n\"\n\"IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL\\n\"\n\"Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe\\n\"\n\"6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3\\n\"\n\"I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U\\n\"\n\"VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7\\n\"\n\"5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi\\n\"\n\"Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM\\n\"\n\"dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt\\n\"\n\"rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI\\n\"\n\"hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px\\n\"\n\"KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS\\n\"\n\"t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ\\n\"\n\"TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du\\n\"\n\"DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib\\n\"\n\"Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD\\n\"\n\"hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX\\n\"\n\"0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW\\n\"\n\"dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2\\n\"\n\"PpxxVJkES/1Y+Zj0\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Assured ID Root G2\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG\\n\"\n\"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw\\n\"\n\"IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw\\n\"\n\"MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL\\n\"\n\"ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw\\n\"\n\"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH\\n\"\n\"35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq\\n\"\n\"bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw\\n\"\n\"VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP\\n\"\n\"YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn\\n\"\n\"lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO\\n\"\n\"w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv\\n\"\n\"0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz\\n\"\n\"d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW\\n\"\n\"hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M\\n\"\n\"jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\\n\"\n\"IhNzbM8m9Yop5w==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Assured ID Root G3\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV\\n\"\n\"UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD\\n\"\n\"VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\\n\"\n\"MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\\n\"\n\"d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ\\n\"\n\"BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb\\n\"\n\"RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs\\n\"\n\"KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF\\n\"\n\"UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy\\n\"\n\"YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy\\n\"\n\"1vUhZscv6pZjamVFkpUBtA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Global Root G2\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG\\n\"\n\"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw\\n\"\n\"HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx\\n\"\n\"MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3\\n\"\n\"dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq\\n\"\n\"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ\\n\"\n\"kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO\\n\"\n\"3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV\\n\"\n\"BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM\\n\"\n\"UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB\\n\"\n\"o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu\\n\"\n\"5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr\\n\"\n\"F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U\\n\"\n\"WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH\\n\"\n\"QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/\\n\"\n\"iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\\n\"\n\"MrY=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Global Root G3\\n\"\n\"=======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV\\n\"\n\"UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD\\n\"\n\"VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw\\n\"\n\"MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k\\n\"\n\"aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C\\n\"\n\"AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O\\n\"\n\"YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP\\n\"\n\"BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp\\n\"\n\"Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y\\n\"\n\"3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34\\n\"\n\"VOKa5Vt8sycX\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"DigiCert Trusted Root G4\\n\"\n\"========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG\\n\"\n\"EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw\\n\"\n\"HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1\\n\"\n\"MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\\n\"\n\"d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G\\n\"\n\"CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp\\n\"\n\"pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o\\n\"\n\"k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa\\n\"\n\"vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY\\n\"\n\"QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6\\n\"\n\"MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm\\n\"\n\"mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7\\n\"\n\"f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH\\n\"\n\"dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8\\n\"\n\"oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\\n\"\n\"DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\\n\"\n\"ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY\\n\"\n\"ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr\\n\"\n\"yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy\\n\"\n\"7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah\\n\"\n\"ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN\\n\"\n\"5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb\\n\"\n\"/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa\\n\"\n\"5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK\\n\"\n\"G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP\\n\"\n\"82Z+\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"WoSign\\n\"\n\"======\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG\\n\"\n\"EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g\\n\"\n\"QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ\\n\"\n\"BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh\\n\"\n\"dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA\\n\"\n\"vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO\\n\"\n\"CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX\\n\"\n\"2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5\\n\"\n\"KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR\\n\"\n\"+ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez\\n\"\n\"EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk\\n\"\n\"lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2\\n\"\n\"8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY\\n\"\n\"yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C\\n\"\n\"AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R\\n\"\n\"8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1\\n\"\n\"LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq\\n\"\n\"T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj\\n\"\n\"y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC\\n\"\n\"2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes\\n\"\n\"5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/\\n\"\n\"EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh\\n\"\n\"mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx\\n\"\n\"kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi\\n\"\n\"kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"WoSign China\\n\"\n\"============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG\\n\"\n\"EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv\\n\"\n\"geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD\\n\"\n\"VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN\\n\"\n\"BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k\\n\"\n\"8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5\\n\"\n\"uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85\\n\"\n\"dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5\\n\"\n\"Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy\\n\"\n\"b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc\\n\"\n\"76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m\\n\"\n\"+Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6\\n\"\n\"yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX\\n\"\n\"GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud\\n\"\n\"EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA\\n\"\n\"A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6\\n\"\n\"yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY\\n\"\n\"r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115\\n\"\n\"j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A\\n\"\n\"kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97\\n\"\n\"qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y\\n\"\n\"jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB\\n\"\n\"ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv\\n\"\n\"T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO\\n\"\n\"kI26oQ==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"COMODO RSA Certification Authority\\n\"\n\"==================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE\\n\"\n\"BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG\\n\"\n\"A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv\\n\"\n\"biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC\\n\"\n\"R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE\\n\"\n\"ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB\\n\"\n\"dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn\\n\"\n\"dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ\\n\"\n\"FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+\\n\"\n\"5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG\\n\"\n\"x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX\\n\"\n\"2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL\\n\"\n\"OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3\\n\"\n\"sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C\\n\"\n\"GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5\\n\"\n\"WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\\n\"\n\"FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w\\n\"\n\"DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt\\n\"\n\"rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+\\n\"\n\"nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg\\n\"\n\"tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW\\n\"\n\"sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp\\n\"\n\"pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA\\n\"\n\"zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq\\n\"\n\"ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52\\n\"\n\"7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I\\n\"\n\"LaZRfyHBNVOFBkpdn627G190\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"USERTrust RSA Certification Authority\\n\"\n\"=====================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE\\n\"\n\"BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\\n\"\n\"ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\\n\"\n\"dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE\\n\"\n\"BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK\\n\"\n\"ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh\\n\"\n\"dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz\\n\"\n\"0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j\\n\"\n\"Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn\\n\"\n\"RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O\\n\"\n\"+T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq\\n\"\n\"/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE\\n\"\n\"Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM\\n\"\n\"lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8\\n\"\n\"yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+\\n\"\n\"eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\\n\"\n\"BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\\n\"\n\"MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW\\n\"\n\"FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ\\n\"\n\"7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ\\n\"\n\"Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM\\n\"\n\"8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi\\n\"\n\"FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi\\n\"\n\"yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c\\n\"\n\"J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw\\n\"\n\"sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx\\n\"\n\"Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"USERTrust ECC Certification Authority\\n\"\n\"=====================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC\\n\"\n\"VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\\n\"\n\"aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\\n\"\n\"biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC\\n\"\n\"VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\\n\"\n\"aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv\\n\"\n\"biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2\\n\"\n\"0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez\\n\"\n\"nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV\\n\"\n\"HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB\\n\"\n\"HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu\\n\"\n\"9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GlobalSign ECC Root CA - R4\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb\\n\"\n\"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\\n\"\n\"EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb\\n\"\n\"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\\n\"\n\"EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl\\n\"\n\"OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P\\n\"\n\"AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV\\n\"\n\"MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF\\n\"\n\"JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"GlobalSign ECC Root CA - R5\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb\\n\"\n\"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\\n\"\n\"EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb\\n\"\n\"R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD\\n\"\n\"EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6\\n\"\n\"SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS\\n\"\n\"h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd\\n\"\n\"BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx\\n\"\n\"uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7\\n\"\n\"yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Staat der Nederlanden Root CA - G3\\n\"\n\"==================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE\\n\"\n\"CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g\\n\"\n\"Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC\\n\"\n\"TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l\\n\"\n\"ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y\\n\"\n\"olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t\\n\"\n\"x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy\\n\"\n\"EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K\\n\"\n\"Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur\\n\"\n\"mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5\\n\"\n\"1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp\\n\"\n\"07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo\\n\"\n\"FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE\\n\"\n\"41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB\\n\"\n\"AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu\\n\"\n\"yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD\\n\"\n\"U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq\\n\"\n\"KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1\\n\"\n\"v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA\\n\"\n\"8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b\\n\"\n\"8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r\\n\"\n\"mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq\\n\"\n\"1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI\\n\"\n\"JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV\\n\"\n\"tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Staat der Nederlanden EV Root CA\\n\"\n\"================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE\\n\"\n\"CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g\\n\"\n\"RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M\\n\"\n\"MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl\\n\"\n\"cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk\\n\"\n\"SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW\\n\"\n\"O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r\\n\"\n\"0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8\\n\"\n\"Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV\\n\"\n\"XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr\\n\"\n\"08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV\\n\"\n\"0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd\\n\"\n\"74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx\\n\"\n\"fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC\\n\"\n\"MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa\\n\"\n\"ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI\\n\"\n\"eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu\\n\"\n\"c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq\\n\"\n\"5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN\\n\"\n\"b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN\\n\"\n\"f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi\\n\"\n\"5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4\\n\"\n\"WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK\\n\"\n\"DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy\\n\"\n\"eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"IdenTrust Commercial Root CA 1\\n\"\n\"==============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG\\n\"\n\"EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS\\n\"\n\"b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES\\n\"\n\"MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB\\n\"\n\"IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld\\n\"\n\"hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/\\n\"\n\"mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi\\n\"\n\"1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C\\n\"\n\"XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl\\n\"\n\"3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy\\n\"\n\"NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV\\n\"\n\"WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg\\n\"\n\"xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix\\n\"\n\"uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC\\n\"\n\"AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI\\n\"\n\"hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH\\n\"\n\"6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg\\n\"\n\"ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt\\n\"\n\"ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV\\n\"\n\"YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX\\n\"\n\"feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro\\n\"\n\"kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe\\n\"\n\"2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz\\n\"\n\"Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R\\n\"\n\"cGzM7vRX+Bi6hG6H\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"IdenTrust Public Sector Root CA 1\\n\"\n\"=================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG\\n\"\n\"EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv\\n\"\n\"ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV\\n\"\n\"UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS\\n\"\n\"b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy\\n\"\n\"P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6\\n\"\n\"Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI\\n\"\n\"rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf\\n\"\n\"qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS\\n\"\n\"mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn\\n\"\n\"ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh\\n\"\n\"LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v\\n\"\n\"iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL\\n\"\n\"4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B\\n\"\n\"Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw\\n\"\n\"DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj\\n\"\n\"t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A\\n\"\n\"mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt\\n\"\n\"GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt\\n\"\n\"m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx\\n\"\n\"NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4\\n\"\n\"Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI\\n\"\n\"ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC\\n\"\n\"ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ\\n\"\n\"3Wl9af0AVqW3rLatt8o+Ae+c\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Entrust Root Certification Authority - G2\\n\"\n\"=========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV\\n\"\n\"BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy\\n\"\n\"bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug\\n\"\n\"b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw\\n\"\n\"HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT\\n\"\n\"DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx\\n\"\n\"OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s\\n\"\n\"eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi\\n\"\n\"MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP\\n\"\n\"/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz\\n\"\n\"HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU\\n\"\n\"s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y\\n\"\n\"TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx\\n\"\n\"AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6\\n\"\n\"0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z\\n\"\n\"iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\\n\"\n\"Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi\\n\"\n\"nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+\\n\"\n\"vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO\\n\"\n\"e4pIb4tF9g==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Entrust Root Certification Authority - EC1\\n\"\n\"==========================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx\\n\"\n\"FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn\\n\"\n\"YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl\\n\"\n\"ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\\n\"\n\"IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw\\n\"\n\"FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs\\n\"\n\"LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg\\n\"\n\"dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt\\n\"\n\"IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy\\n\"\n\"AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef\\n\"\n\"9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE\\n\"\n\"FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h\\n\"\n\"vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8\\n\"\n\"kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"CFCA EV ROOT\\n\"\n\"============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE\\n\"\n\"CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB\\n\"\n\"IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw\\n\"\n\"MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD\\n\"\n\"DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV\\n\"\n\"BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD\\n\"\n\"7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN\\n\"\n\"uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW\\n\"\n\"ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7\\n\"\n\"xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f\\n\"\n\"py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K\\n\"\n\"gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol\\n\"\n\"hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ\\n\"\n\"tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf\\n\"\n\"BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB\\n\"\n\"/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB\\n\"\n\"ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q\\n\"\n\"ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua\\n\"\n\"4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG\\n\"\n\"E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX\\n\"\n\"BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn\\n\"\n\"aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy\\n\"\n\"PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX\\n\"\n\"kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C\\n\"\n\"ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5\\n\"\n\"====================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN\\n\"\n\"BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp\\n\"\n\"bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg\\n\"\n\"RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw\\n\"\n\"ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w\\n\"\n\"SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE\\n\"\n\"n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp\\n\"\n\"ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\\n\"\n\"CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537\\n\"\n\"jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m\\n\"\n\"ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP\\n\"\n\"9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV\\n\"\n\"4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH\\n\"\n\"HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI\\n\"\n\"hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo\\n\"\n\"BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq\\n\"\n\"URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl\\n\"\n\"lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8\\n\"\n\"B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certinomis - Root CA\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK\\n\"\n\"Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg\\n\"\n\"LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx\\n\"\n\"EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD\\n\"\n\"ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos\\n\"\n\"P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo\\n\"\n\"d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap\\n\"\n\"z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00\\n\"\n\"8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x\\n\"\n\"RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE\\n\"\n\"6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t\\n\"\n\"FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV\\n\"\n\"PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH\\n\"\n\"i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj\\n\"\n\"YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I\\n\"\n\"6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF\\n\"\n\"AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV\\n\"\n\"WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw\\n\"\n\"Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX\\n\"\n\"lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ\\n\"\n\"y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9\\n\"\n\"Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng\\n\"\n\"DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi\\n\"\n\"I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM\\n\"\n\"cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr\\n\"\n\"hkIGuUE=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"OISTE WISeKey Global Root GB CA\\n\"\n\"===============================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG\\n\"\n\"EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl\\n\"\n\"ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw\\n\"\n\"MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD\\n\"\n\"VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds\\n\"\n\"b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX\\n\"\n\"scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP\\n\"\n\"rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk\\n\"\n\"9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o\\n\"\n\"Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg\\n\"\n\"GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI\\n\"\n\"hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD\\n\"\n\"dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0\\n\"\n\"VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui\\n\"\n\"HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic\\n\"\n\"Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certification Authority of WoSign G2\\n\"\n\"====================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG\\n\"\n\"EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g\\n\"\n\"QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx\\n\"\n\"CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm\\n\"\n\"aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\\n\"\n\"CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai\\n\"\n\"XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du\\n\"\n\"W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9\\n\"\n\"5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK\\n\"\n\"v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC\\n\"\n\"AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI\\n\"\n\"hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY\\n\"\n\"P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3\\n\"\n\"TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu\\n\"\n\"+sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+\\n\"\n\"7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"CA WoSign ECC Root\\n\"\n\"==================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD\\n\"\n\"TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v\\n\"\n\"dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK\\n\"\n\"ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI\\n\"\n\"zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU\\n\"\n\"t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw\\n\"\n\"QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R\\n\"\n\"MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0\\n\"\n\"Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu\\n\"\n\"a/GRspBl9JrmkO5K\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"SZAFIR ROOT CA2\\n\"\n\"===============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG\\n\"\n\"A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV\\n\"\n\"BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ\\n\"\n\"BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD\\n\"\n\"VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q\\n\"\n\"qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK\\n\"\n\"DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE\\n\"\n\"2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ\\n\"\n\"ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi\\n\"\n\"ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P\\n\"\n\"AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC\\n\"\n\"AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5\\n\"\n\"O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67\\n\"\n\"oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul\\n\"\n\"4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6\\n\"\n\"+/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certum Trusted Network CA 2\\n\"\n\"===========================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE\\n\"\n\"BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1\\n\"\n\"bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y\\n\"\n\"ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ\\n\"\n\"TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl\\n\"\n\"cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB\\n\"\n\"IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9\\n\"\n\"7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o\\n\"\n\"CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b\\n\"\n\"Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p\\n\"\n\"uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130\\n\"\n\"GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ\\n\"\n\"9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB\\n\"\n\"Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye\\n\"\n\"hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM\\n\"\n\"BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI\\n\"\n\"hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW\\n\"\n\"Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA\\n\"\n\"L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo\\n\"\n\"clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM\\n\"\n\"pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb\\n\"\n\"w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo\\n\"\n\"J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm\\n\"\n\"ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX\\n\"\n\"is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7\\n\"\n\"zAYspsbiDrW5viSP\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Hellenic Academic and Research Institutions RootCA 2015\\n\"\n\"=======================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT\\n\"\n\"BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0\\n\"\n\"aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl\\n\"\n\"YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx\\n\"\n\"MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg\\n\"\n\"QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV\\n\"\n\"BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw\\n\"\n\"MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv\\n\"\n\"bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh\\n\"\n\"iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+\\n\"\n\"6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd\\n\"\n\"FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr\\n\"\n\"i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F\\n\"\n\"GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2\\n\"\n\"fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu\\n\"\n\"iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc\\n\"\n\"Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\\n\"\n\"AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI\\n\"\n\"hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+\\n\"\n\"D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM\\n\"\n\"d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y\\n\"\n\"d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn\\n\"\n\"82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb\\n\"\n\"davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F\\n\"\n\"Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt\\n\"\n\"J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa\\n\"\n\"JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q\\n\"\n\"p/UsQu0yrbYhnr68\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Hellenic Academic and Research Institutions ECC RootCA 2015\\n\"\n\"===========================================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0\\n\"\n\"aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u\\n\"\n\"cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj\\n\"\n\"aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw\\n\"\n\"MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj\\n\"\n\"IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD\\n\"\n\"VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290\\n\"\n\"Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP\\n\"\n\"dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK\\n\"\n\"Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O\\n\"\n\"BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA\\n\"\n\"GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn\\n\"\n\"dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certplus Root CA G1\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV\\n\"\n\"BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe\\n\"\n\"Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD\\n\"\n\"ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD\\n\"\n\"ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN\\n\"\n\"r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx\\n\"\n\"Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj\\n\"\n\"BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv\\n\"\n\"LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2\\n\"\n\"z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc\\n\"\n\"4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd\\n\"\n\"4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj\\n\"\n\"jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+\\n\"\n\"ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G\\n\"\n\"A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY\\n\"\n\"lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh\\n\"\n\"66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG\\n\"\n\"YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/\\n\"\n\"2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F\\n\"\n\"6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX\\n\"\n\"CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe\\n\"\n\"tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC\\n\"\n\"VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/\\n\"\n\"+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+\\n\"\n\"qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Certplus Root CA G2\\n\"\n\"===================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT\\n\"\n\"AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x\\n\"\n\"NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0\\n\"\n\"cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA\\n\"\n\"BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN\\n\"\n\"Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD\\n\"\n\"AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud\\n\"\n\"IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV\\n\"\n\"HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl\\n\"\n\"vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"OpenTrust Root CA G1\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV\\n\"\n\"BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx\\n\"\n\"MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM\\n\"\n\"CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB\\n\"\n\"AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa\\n\"\n\"Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87\\n\"\n\"ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO\\n\"\n\"YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9\\n\"\n\"xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO\\n\"\n\"9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq\\n\"\n\"3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi\\n\"\n\"n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9\\n\"\n\"URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr\\n\"\n\"TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px\\n\"\n\"N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E\\n\"\n\"PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv\\n\"\n\"uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK\\n\"\n\"n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh\\n\"\n\"X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80\\n\"\n\"nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm\\n\"\n\"GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/\\n\"\n\"bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o\\n\"\n\"4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA\\n\"\n\"OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"OpenTrust Root CA G2\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV\\n\"\n\"BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy\\n\"\n\"MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM\\n\"\n\"CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB\\n\"\n\"AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+\\n\"\n\"Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz\\n\"\n\"4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV\\n\"\n\"eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt\\n\"\n\"UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz\\n\"\n\"3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj\\n\"\n\"3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz\\n\"\n\"9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0\\n\"\n\"0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT\\n\"\n\"y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59\\n\"\n\"M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz\\n\"\n\"Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI\\n\"\n\"mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG\\n\"\n\"S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp\\n\"\n\"EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ\\n\"\n\"6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr\\n\"\n\"gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo\\n\"\n\"SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0\\n\"\n\"YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm\\n\"\n\"u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"OpenTrust Root CA G3\\n\"\n\"====================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT\\n\"\n\"AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X\\n\"\n\"DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w\\n\"\n\"ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA\\n\"\n\"IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B\\n\"\n\"ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB\\n\"\n\"/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf\\n\"\n\"BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM\\n\"\n\"BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta\\n\"\n\"3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"ISRG Root X1\\n\"\n\"============\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE\\n\"\n\"BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD\\n\"\n\"EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG\\n\"\n\"EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT\\n\"\n\"DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r\\n\"\n\"Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1\\n\"\n\"3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K\\n\"\n\"b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN\\n\"\n\"Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ\\n\"\n\"4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf\\n\"\n\"1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu\\n\"\n\"hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH\\n\"\n\"usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r\\n\"\n\"OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G\\n\"\n\"A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY\\n\"\n\"9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\\n\"\n\"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV\\n\"\n\"0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt\\n\"\n\"hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw\\n\"\n\"TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx\\n\"\n\"e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA\\n\"\n\"JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD\\n\"\n\"YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n\\n\"\n\"JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ\\n\"\n\"m+kXQ99b21/+jh5Xos1AnX5iItreGCc=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"AC RAIZ FNMT-RCM\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT\\n\"\n\"AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw\\n\"\n\"MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD\\n\"\n\"TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\\n\"\n\"ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf\\n\"\n\"qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr\\n\"\n\"btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL\\n\"\n\"j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou\\n\"\n\"08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw\\n\"\n\"WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT\\n\"\n\"tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ\\n\"\n\"47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC\\n\"\n\"ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa\\n\"\n\"i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\\n\"\n\"FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o\\n\"\n\"dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD\\n\"\n\"nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s\\n\"\n\"D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ\\n\"\n\"j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT\\n\"\n\"Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW\\n\"\n\"+YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7\\n\"\n\"Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d\\n\"\n\"8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm\\n\"\n\"5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG\\n\"\n\"rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Amazon Root CA 1\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD\\n\"\n\"VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1\\n\"\n\"MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\\n\"\n\"bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\\n\"\n\"ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH\\n\"\n\"FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ\\n\"\n\"gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t\\n\"\n\"dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce\\n\"\n\"VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3\\n\"\n\"DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM\\n\"\n\"CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy\\n\"\n\"8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa\\n\"\n\"2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2\\n\"\n\"xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Amazon Root CA 2\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD\\n\"\n\"VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1\\n\"\n\"MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv\\n\"\n\"bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\\n\"\n\"ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4\\n\"\n\"kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp\\n\"\n\"N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9\\n\"\n\"AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd\\n\"\n\"fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx\\n\"\n\"kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS\\n\"\n\"btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0\\n\"\n\"Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN\\n\"\n\"c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+\\n\"\n\"3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw\\n\"\n\"DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA\\n\"\n\"A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\\n\"\n\"+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE\\n\"\n\"YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW\\n\"\n\"xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ\\n\"\n\"gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW\\n\"\n\"aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV\\n\"\n\"Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3\\n\"\n\"KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi\\n\"\n\"JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Amazon Root CA 3\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG\\n\"\n\"EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy\\n\"\n\"NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\\n\"\n\"MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB\\n\"\n\"f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr\\n\"\n\"Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43\\n\"\n\"rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc\\n\"\n\"eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"Amazon Root CA 4\\n\"\n\"================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG\\n\"\n\"EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy\\n\"\n\"NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ\\n\"\n\"MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN\\n\"\n\"/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri\\n\"\n\"83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\\n\"\n\"HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA\\n\"\n\"MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1\\n\"\n\"AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"LuxTrust Global Root 2\\n\"\n\"======================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG\\n\"\n\"A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh\\n\"\n\"bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW\\n\"\n\"MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC\\n\"\n\"AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm\\n\"\n\"Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2\\n\"\n\"xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC\\n\"\n\"wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm\\n\"\n\"1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm\\n\"\n\"FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF\\n\"\n\"wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/\\n\"\n\"a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U\\n\"\n\"ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ\\n\"\n\"MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB\\n\"\n\"/zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5\\n\"\n\"Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT\\n\"\n\"+Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ\\n\"\n\"FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN\\n\"\n\"H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW\\n\"\n\"7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu\\n\"\n\"ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA\\n\"\n\"VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR\\n\"\n\"TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt\\n\"\n\"/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc\\n\"\n\"7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I\\n\"\n\"iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr\\n\"\n\"-----END CERTIFICATE-----\\n\"\n\"TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1\\n\"\n\"=============================================\\n\"\n\"-----BEGIN CERTIFICATE-----\\n\"\n\"MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT\\n\"\n\"D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr\\n\"\n\"IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g\\n\"\n\"TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp\\n\"\n\"ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD\\n\"\n\"VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt\\n\"\n\"c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth\\n\"\n\"bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11\\n\"\n\"IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\\n\"\n\"MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8\\n\"\n\"6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc\\n\"\n\"wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0\\n\"\n\"3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9\\n\"\n\"WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU\\n\"\n\"ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ\\n\"\n\"KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh\\n\"\n\"AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc\\n\"\n\"lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R\\n\"\n\"e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j\\n\"\n\"q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=\\n\"\n\"-----END CERTIFICATE-----\\n\"\n};\n"
  },
  {
    "path": "net/net_compat.c",
    "content": "/* Copyright  (C) 2010-2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_compat.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <compat/strl.h>\n#include <retro_miscellaneous.h>\n#include <retro_timers.h>\n\n#include <net/net_compat.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600\nconst char *inet_ntop(int af, const void *src, char *dst, socklen_t size)\n{\n   struct sockaddr_storage addr;\n\n   switch (af)\n   {\n      case AF_INET:\n         memcpy(&((struct sockaddr_in*)&addr)->sin_addr, src,\n            sizeof(struct in_addr));\n         break;\n#ifdef HAVE_INET6\n      case AF_INET6:\n         memcpy(&((struct sockaddr_in6*)&addr)->sin6_addr, src,\n            sizeof(struct in6_addr));\n         break;\n#endif\n      default:\n         return NULL;\n   }\n\n   addr.ss_family = af;\n   if (getnameinfo((struct sockaddr*)&addr, sizeof(addr), dst, size, NULL, 0,\n         NI_NUMERICHOST))\n      return NULL;\n\n   return dst;\n}\n\nint inet_pton(int af, const char *src, void *dst)\n{\n   struct addrinfo *addr = NULL;\n   struct addrinfo hints = {0};\n\n   switch (af)\n   {\n      case AF_INET:\n#ifdef HAVE_INET6\n      case AF_INET6:\n#endif\n         break;\n      default:\n         return -1;\n   }\n\n   hints.ai_family = af;\n   hints.ai_flags  = AI_NUMERICHOST;\n   switch (getaddrinfo(src, NULL, &hints, &addr))\n   {\n      case 0:\n         break;\n      case EAI_NONAME:\n         return 0;\n      default:\n         return -1;\n   }\n\n   if (!addr)\n      return -1;\n\n   switch (af)\n   {\n      case AF_INET:\n         memcpy(dst, &((struct sockaddr_in*)addr->ai_addr)->sin_addr,\n            sizeof(struct in_addr));\n         break;\n#ifdef HAVE_INET6\n      case AF_INET6:\n         memcpy(dst, &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr,\n            sizeof(struct in6_addr));\n         break;\n#endif\n      default:\n         break;\n   }\n\n   freeaddrinfo(addr);\n\n   return 1;\n}\n#endif\n\n#elif defined(_XBOX)\nstruct hostent *gethostbyname(const char *name)\n{\n   static struct in_addr addr = {0};\n   static struct hostent he   = {0};\n   WSAEVENT event;\n   XNDNS          *dns = NULL;\n   struct hostent *ret = NULL;\n\n   if (!name)\n      return NULL;\n\n   event = WSACreateEvent();\n\n   XNetDnsLookup(name, event, &dns);\n   if (!dns)\n   {\n      WSACloseEvent(event);\n      return NULL;\n   }\n\n   WaitForSingleObject((HANDLE)event, INFINITE);\n\n   if (!dns->iStatus)\n   {\n      memcpy(&addr, dns->aina, sizeof(addr));\n\n      he.h_name      = NULL;\n      he.h_aliases   = NULL;\n      he.h_addrtype  = AF_INET;\n      he.h_length    = sizeof(addr);\n      he.h_addr_list = &he.h_addr;\n      he.h_addr      = (char*)&addr;\n\n      ret = &he;\n   }\n\n   WSACloseEvent(event);\n   XNetDnsRelease(dns);\n\n   return ret;\n}\n\n#elif defined(VITA)\n#define COMPAT_NET_INIT_SIZE 0x80000\n\nchar *inet_ntoa(struct in_addr in)\n{\n   static char ip_addr[16];\n\n   sceNetInetNtop(AF_INET, &in, ip_addr, sizeof(ip_addr));\n\n   return ip_addr;\n}\n\nint inet_aton(const char *cp, struct in_addr *inp)\n{\n   return sceNetInetPton(AF_INET, cp, inp);\n}\n\nuint32_t inet_addr(const char *cp)\n{\n   struct in_addr in;\n\n   return (sceNetInetPton(AF_INET, cp, &in) == 1) ? in.s_addr : INADDR_NONE;\n}\n\nstruct hostent *gethostbyname(const char *name)\n{\n   static struct SceNetInAddr addr = {0};\n   static struct hostent      he   = {0};\n   int rid;\n   struct hostent *ret = NULL;\n\n   if (!name)\n      return NULL;\n\n   rid = sceNetResolverCreate(\"resolver\", NULL, 0);\n   if (rid < 0)\n      return NULL;\n\n   if (sceNetResolverStartNtoa(rid, name, &addr, 0, 0, 0) < 0)\n      goto done;\n\n   he.h_name      = NULL;\n   he.h_aliases   = NULL;\n   he.h_addrtype  = AF_INET;\n   he.h_length    = sizeof(addr);\n   he.h_addr_list = &he.h_addr;\n   he.h_addr      = (char*)&addr;\n\n   ret = &he;\n\ndone:\n   sceNetResolverDestroy(rid);\n\n   return ret;\n}\n\n#elif defined(GEKKO)\nconst char *inet_ntop(int af, const void *src, char *dst, socklen_t size)\n{\n   const char *addr_str = inet_ntoa(*(struct in_addr*)src);\n\n   if (addr_str)\n   {\n      strlcpy(dst, addr_str, size);\n\n      return dst;\n   }\n\n   return NULL;\n}\n\nint inet_pton(int af, const char *src, void *dst)\n{\n   if (inet_aton(src, (struct in_addr*)dst))\n      return 1;\n\n   return 0;\n}\n\n#elif defined(WIIU)\n#include <malloc.h>\n\nstatic int _net_compat_thread_entry(int argc, const char **argv)\n{\n   void *buf = memalign(128, WIIU_RCVBUF + WIIU_SNDBUF);\n\n   if (!buf)\n      return -1;\n\n   somemopt(1, buf, WIIU_RCVBUF + WIIU_SNDBUF, 0);\n\n   free(buf);\n\n   return 0;\n}\n\nstatic void _net_compat_thread_cleanup(OSThread *thread, void *stack)\n{\n   free(stack);\n}\n\n#elif defined(_3DS)\n#include <malloc.h>\n#include <3ds/types.h>\n#include <3ds/services/soc.h>\n\n#define SOC_ALIGN      0x1000\n#define SOC_BUFFERSIZE 0x100000\n#endif\n\nint getaddrinfo_retro(const char *node, const char *service,\n      struct addrinfo *hints, struct addrinfo **res)\n{\n#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)\n   struct addrinfo default_hints = {0};\n\n   if (!hints)\n      hints            = &default_hints;\n   if (!hints->ai_family)\n      hints->ai_family = AF_INET;\n\n   if (!node)\n      node = (hints->ai_flags & AI_PASSIVE) ? \"0.0.0.0\" : \"127.0.0.1\";\n#endif\n\n#ifdef HAVE_SOCKET_LEGACY\n   {\n      struct addrinfo    *info = (struct addrinfo*)calloc(1, sizeof(*info));\n      struct sockaddr_in *addr = (struct sockaddr_in*)malloc(sizeof(*addr));\n\n      if (!info || !addr)\n         goto failure;\n\n      info->ai_family   = AF_INET;\n      info->ai_socktype = hints->ai_socktype;\n      info->ai_protocol = hints->ai_protocol;\n      info->ai_addrlen  = sizeof(*addr);\n      info->ai_addr     = (struct sockaddr*)addr;\n      /* We ignore AI_CANONNAME; ai_canonname is always NULL. */\n\n      addr->sin_family = AF_INET;\n\n      if (service)\n      {\n         /* We can only handle numeric ports; ignore AI_NUMERICSERV. */\n         char *service_end = NULL;\n         uint16_t port     = (uint16_t)strtoul(service, &service_end, 10);\n\n         if (service_end == service || *service_end)\n            goto failure;\n\n         addr->sin_port = htons(port);\n      }\n\n      if (hints->ai_flags & AI_NUMERICHOST)\n      {\n         if (!inet_aton(node, &addr->sin_addr))\n            goto failure;\n      }\n      else\n      {\n         struct hostent *host = gethostbyname(node);\n\n         if (!host || !host->h_addr)\n            goto failure;\n\n         memcpy(&addr->sin_addr, host->h_addr, sizeof(addr->sin_addr));\n      }\n\n      *res = info;\n\n      return 0;\n\nfailure:\n      free(addr);\n      free(info);\n\n      return -1;\n   }\n#else\n   return getaddrinfo(node, service, hints, res);\n#endif\n}\n\nvoid freeaddrinfo_retro(struct addrinfo *res)\n{\n#ifdef HAVE_SOCKET_LEGACY\n   if (res)\n   {\n      free(res->ai_addr);\n      free(res);\n   }\n#else\n   freeaddrinfo(res);\n#endif\n}\n\nint getnameinfo_retro(const struct sockaddr *addr, socklen_t addrlen,\n      char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)\n{\n#ifdef HAVE_SOCKET_LEGACY\n   const struct sockaddr_in *addr4 = (const struct sockaddr_in*)addr;\n\n   /* We cannot perform reverse DNS lookups here; ignore the following flags:\n      NI_NAMEREQD\n      NI_NOFQDN\n      NI_NUMERICHOST (always enforced)\n    */\n   if (host && hostlen)\n   {\n      const char *_host = inet_ntoa(addr4->sin_addr);\n\n      if (!_host)\n         return -1;\n\n      strlcpy(host, _host, hostlen);\n   }\n\n   /* We cannot get service names here; ignore the following flags:\n      NI_DGRAM\n      NI_NUMERICSERV (always enforced)\n    */\n   if (serv && servlen)\n      snprintf(serv, servlen, \"%hu\", (unsigned short)ntohs(addr4->sin_port));\n\n   return 0;\n#else\n   return getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);\n#endif\n}\n\nbool addr_6to4(struct sockaddr_storage *addr)\n{\n#ifdef HAVE_INET6\n   /* ::ffff:a.b.c.d */\n   static const uint16_t prefix[] = {0,0,0,0,0,0xffff};\n   uint32_t address;\n   uint16_t port;\n   struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)addr;\n   struct sockaddr_in  *addr4 = (struct sockaddr_in*)addr;\n\n   switch (addr->ss_family)\n   {\n      case AF_INET:\n         /* No need to convert. */\n         return true;\n      case AF_INET6:\n         /* Is the address provided an IPv4? */\n         if (!memcmp(&addr6->sin6_addr, prefix, sizeof(prefix)))\n            break;\n      default:\n         /* We don't know how to handle this. */\n         return false;\n   }\n\n   memcpy(&address, ((uint8_t*)&addr6->sin6_addr) + sizeof(prefix),\n      sizeof(address));\n   port = addr6->sin6_port;\n\n   memset(addr, 0, sizeof(*addr));\n\n   addr4->sin_family = AF_INET;\n   addr4->sin_port   = port;\n   memcpy(&addr4->sin_addr, &address, sizeof(addr4->sin_addr));\n#endif\n\n   return true;\n}\n\nbool ipv4_is_lan_address(const struct sockaddr_in *addr)\n{\n   static const uint32_t subnets[] = {0x0A000000, 0xAC100000, 0xC0A80000};\n   static const uint32_t masks[]   = {0xFF000000, 0xFFF00000, 0xFFFF0000};\n   size_t i;\n   uint32_t uaddr;\n\n   memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));\n   uaddr = ntohl(uaddr);\n\n   for (i = 0; i < ARRAY_SIZE(subnets); i++)\n      if ((uaddr & masks[i]) == subnets[i])\n         return true;\n\n   return false;\n}\n\nbool ipv4_is_cgnat_address(const struct sockaddr_in *addr)\n{\n   static const uint32_t subnet = 0x64400000;\n   static const uint32_t mask   = 0xFFC00000;\n   uint32_t uaddr;\n\n   memcpy(&uaddr, &addr->sin_addr, sizeof(uaddr));\n   uaddr = ntohl(uaddr);\n\n   return (uaddr & mask) == subnet;\n}\n\n/**\n * network_init:\n *\n * Platform specific socket library initialization.\n *\n * @return true if successful, otherwise false.\n **/\nbool network_init(void)\n{\n#if defined(_WIN32)\n   static bool initialized = false;\n\n   if (!initialized)\n   {\n      WSADATA wsaData;\n\n      if (WSAStartup(MAKEWORD(2, 2), &wsaData))\n      {\n         WSACleanup();\n\n         return false;\n      }\n\n      initialized = true;\n   }\n\n   return true;\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n   static bool initialized = false;\n\n   if (!initialized)\n   {\n      int tries;\n\n      sysModuleLoad(SYSMODULE_NET);\n\n      netInitialize();\n      if (netCtlInit() < 0)\n         goto failure;\n\n      for (tries = 10;;)\n      {\n         int state;\n\n         if (netCtlGetState(&state) < 0)\n            goto failure;\n         if (state == NET_CTL_STATE_IPObtained)\n            break;\n\n         if (!(--tries))\n            goto failure;\n\n         retro_sleep(500);\n      }\n\n      initialized = true;\n   }\n\n   return true;\n\nfailure:\n   netCtlTerm();\n   netFinalizeNetwork();\n\n   sysModuleUnload(SYSMODULE_NET);\n\n   return false;\n#elif defined(VITA)\n   if (sceNetShowNetstat() == SCE_NET_ERROR_ENOTINIT)\n   {\n      SceNetInitParam param;\n      void *net_compat_memory = malloc(COMPAT_NET_INIT_SIZE);\n\n      if (!net_compat_memory)\n         return false;\n\n      param.memory = net_compat_memory;\n      param.size   = COMPAT_NET_INIT_SIZE;\n      param.flags  = 0;\n\n      if (sceNetInit(&param) < 0)\n         goto failure;\n      if (sceNetCtlInit() < 0)\n         goto failure;\n\n      return true;\n\nfailure:\n      sceNetCtlTerm();\n      sceNetTerm();\n\n      free(net_compat_memory);\n\n      return false;\n   }\n\n   return true;\n#elif defined(GEKKO)\n   static bool initialized = false;\n\n   if (!initialized)\n   {\n      char localip[16] = {0};\n      char netmask[16] = {0};\n      char gateway[16] = {0};\n\n      if (if_config(localip, netmask, gateway, true, 10) < 0)\n      {\n         net_deinit();\n\n         return false;\n      }\n\n      initialized = true;\n   }\n\n   return true;\n#elif defined(WIIU)\n   static OSThread net_compat_thread;\n   static bool initialized = false;\n\n   if (!initialized)\n   {\n      void *stack = malloc(0x1000);\n\n      if (!stack)\n         return false;\n\n      socket_lib_init();\n\n      if (!OSCreateThread(&net_compat_thread, _net_compat_thread_entry,\n            0, NULL, (void*)((size_t)stack + 0x1000), 0x1000, 3,\n            OS_THREAD_ATTRIB_AFFINITY_ANY))\n      {\n         free(stack);\n\n         return false;\n      }\n\n      OSSetThreadName(&net_compat_thread, \"Network compat thread\");\n      OSSetThreadDeallocator(&net_compat_thread, _net_compat_thread_cleanup);\n      OSResumeThread(&net_compat_thread);\n\n      initialized = true;\n   }\n\n   return true;\n#elif defined(_3DS)\n   static bool initialized = false;\n\n   if (!initialized)\n   {\n      u32 *net_compat_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);\n\n      if (!net_compat_memory)\n         return false;\n\n      /* WIFI init */\n      if (socInit(net_compat_memory, SOC_BUFFERSIZE))\n      {\n         socExit();\n\n         free(net_compat_memory);\n\n         return false;\n      }\n\n      initialized = true;\n   }\n\n   return true;\n#else\n   static bool initialized = false;\n\n   if (!initialized)\n   {\n      /* Do not like SIGPIPE killing our app. */\n      signal(SIGPIPE, SIG_IGN);\n\n      initialized = true;\n   }\n\n   return true;\n#endif\n}\n"
  },
  {
    "path": "net/net_http.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_http.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <errno.h>\n#include <string.h>\n\n#include <net/net_http.h>\n#include <net/net_compat.h>\n#include <net/net_socket.h>\n#ifdef HAVE_SSL\n#include <net/net_socket_ssl.h>\n#endif\n#include <compat/strl.h>\n#include <features/features_cpu.h>\n#include <file/file_path.h>\n#include <lists/string_list.h>\n#include <retro_common_api.h>\n#include <retro_miscellaneous.h>\n#include <string/stdstring.h>\n#ifdef HAVE_THREADS\n#include <rthreads/rthreads.h>\n#endif\n\n/* Maximum Content-Length we'll honour from a server, to bound the\n * realloc() that follows header parsing.  256 MiB is comfortably\n * larger than any single libretro HTTP payload (core downloads,\n * thumbnail images, assets bundles) and small enough that a\n * hostile server cannot drive the client toward OOM by lying in\n * the Content-Length header. */\n#define NET_HTTP_MAX_CONTENT_LENGTH ((size_t)256 * 1024 * 1024)\n\nenum response_part\n{\n   P_HEADER_TOP = 0,\n   P_HEADER,\n   P_BODY,\n   P_BODY_CHUNKLEN,\n   P_DONE\n};\n\nenum bodytype\n{\n   T_FULL = 0,\n   T_LEN,\n   T_CHUNK\n};\n\nstruct conn_pool_entry\n{\n   char *domain;\n   int port;\n   int fd;\n   void *ssl_ctx;\n   bool ssl;\n   bool connected;\n   bool in_use;\n   struct conn_pool_entry *next;\n};\n\nstatic struct conn_pool_entry *conn_pool = NULL;\n#ifdef HAVE_THREADS\nstatic slock_t *conn_pool_lock = NULL;\n#define LOCK_POOL() slock_lock(conn_pool_lock)\n#define UNLOCK_POOL() slock_unlock(conn_pool_lock)\n#else\n#define LOCK_POOL()\n#define UNLOCK_POOL()\n#endif\n\ntypedef struct response\n{\n   char *data;\n   struct string_list *headers;\n   size_t pos;\n   size_t len;\n   size_t buflen;\n   int status;\n   enum response_part part;\n   enum bodytype bodytype;\n} response_t;\n\ntypedef struct request\n{\n   char *domain;\n   char *path;\n   char *method;\n   char *contenttype;\n   void *postdata;\n   char *useragent;\n   char *headers;\n   size_t contentlength;\n   int port;\n} request_t;\n\nstruct http_t\n{\n   bool err;\n\n   struct conn_pool_entry *conn;\n   bool ssl;\n   bool request_sent;\n\n   request_t request;\n   response_t response;\n};\n\nstruct http_connection_t\n{\n   char *domain;\n   char *path;\n   char *url;\n   char *scan;\n   char *method;\n   char *contenttype;\n   void *postdata;\n   char *useragent;\n   char *headers;\n   size_t contentlength; /* ptr alignment */\n   int port;\n   bool ssl;\n};\n\nstatic void net_http_log_transport_state(\n      const struct http_t *state, const char *stage, ssize_t io_len)\n{\n#if defined(DEBUG)\n   const char *method = \"GET\";\n   const char *domain = \"<null>\";\n   const char *path   = \"<null>\";\n   int port           = 0;\n   int fd             = -1;\n   int connected      = 0;\n\n   if (state)\n   {\n      method = state->request.method ? state->request.method : \"GET\";\n      domain = state->request.domain ? state->request.domain : \"<null>\";\n      path   = state->request.path ? state->request.path : \"<null>\";\n      port   = state->request.port;\n\n      if (state->conn)\n      {\n         fd        = state->conn->fd;\n         connected = state->conn->connected ? 1 : 0;\n      }\n   }\n\n   fprintf(stderr,\n         \"[net_http] %s: method=%s host=%s port=%d path=/%s ssl=%d fd=%d connected=%d request_sent=%d err=%d io_len=%ld errno=%d (%s)\\n\",\n         stage ? stage : \"unknown\",\n         method,\n         domain,\n         port,\n         path,\n         state ? (state->ssl ? 1 : 0) : 0,\n         fd,\n         connected,\n         state ? (state->request_sent ? 1 : 0) : 0,\n         state ? (state->err ? 1 : 0) : 0,\n         (long)io_len,\n         errno,\n         strerror(errno));\n   fflush(stderr);\n#else\n   (void)state;\n   (void)stage;\n   (void)io_len;\n#endif\n}\n\nstruct dns_cache_entry\n{\n   char *domain;\n   int port;\n   struct addrinfo *addr;\n   retro_time_t timestamp;\n   bool valid;\n#ifdef HAVE_THREADS\n   sthread_t *thread;\n#endif\n   struct dns_cache_entry *next;\n};\n\nstatic struct dns_cache_entry *dns_cache = NULL;\n/* 5 min timeout, in usec */\nstatic const retro_time_t dns_cache_timeout = 1000 /* usec/ms */ * 1000 /* ms/s */ * 60 /* s/min */ * 5 /* min */;\n/* only cache failures for 30 seconds */\nstatic const retro_time_t dns_cache_fail_timeout = 1000 /* usec/ms */ * 1000 /* ms/s */ * 30 /* s */;\n#ifdef HAVE_THREADS\nstatic slock_t *dns_cache_lock = NULL;\n#define LOCK_DNS_CACHE() slock_lock(dns_cache_lock)\n#define UNLOCK_DNS_CACHE() slock_unlock(dns_cache_lock)\n#else\n#define LOCK_DNS_CACHE()\n#define UNLOCK_DNS_CACHE()\n#endif\n\n/**\n * net_http_urlencode:\n *\n * URL Encode a string\n * caller is responsible for deleting the destination buffer\n **/\nvoid net_http_urlencode(char **dest, const char *source)\n{\n   /* Bitmask for unreserved chars: A-Z a-z 0-9 * - . / _ */\n   static const uint32_t safe[4] = {\n      0x00000000, /*  0-31:  none           */\n      0x03FFE400, /* 32-63:  * - . / 0-9    */\n      0x87FFFFFE, /* 64-95:  A-Z _          */\n      0x07FFFFFE  /* 96-127: a-z            */\n   };\n\n   const char *s;\n   char *enc;\n   size_t len = 0;\n\n   /* First pass: compute exact output length */\n   for (s = source; *s; s++)\n   {\n      unsigned char c = (unsigned char)*s;\n      if (c < 128 && (safe[c >> 5] & (1u << (c & 31))))\n         len += 1;\n      else\n         len += 3;\n   }\n\n   enc   = (char*)malloc(len + 1);\n   *dest = enc;\n\n   /* Malloc failure: leave *dest NULL and bail.  Callers that\n    * dereference the result (common in URL-builder flows) will\n    * then hit a single deliberate NULL check instead of a random\n    * crash in the encoding loop below. */\n   if (!enc)\n      return;\n\n   /* Second pass: encode */\n   for (s = source; *s; s++)\n   {\n      unsigned char c = (unsigned char)*s;\n      if (c < 128 && (safe[c >> 5] & (1u << (c & 31))))\n         *enc++ = (char)c;\n      else\n      {\n         static const char hex[] = \"0123456789ABCDEF\";\n         *enc++ = '%';\n         *enc++ = hex[c >> 4];\n         *enc++ = hex[c & 0x0F];\n      }\n   }\n\n   *enc = '\\0';\n}\n\n/**\n * net_http_urlencode_full:\n *\n * Re-encode a full URL\n **/\nvoid net_http_urlencode_full(char *s, const char *source, size_t len)\n{\n   static const char hex[] = \"0123456789ABCDEF\";\n   const char *path_start;\n   const char *p;\n   size_t domain_len;\n   size_t pos;\n   int slashes = 0;\n\n   if (!s || !source || len == 0)\n      return;\n\n   /* Find the third '/' to locate the domain/path boundary */\n   for (p = source; *p && slashes < 3; p++)\n   {\n      if (*p == '/')\n         slashes++;\n   }\n\n   /* If fewer than 3 slashes, no path to encode — just copy as-is */\n   if (slashes < 3)\n   {\n      strlcpy(s, source, len);\n      return;\n   }\n\n   path_start = p; /* points just past the third '/' */\n   domain_len = (size_t)(path_start - source);\n\n   /* Copy domain (including trailing '/') */\n   if (domain_len >= len)\n   {\n      strlcpy(s, source, len);\n      return;\n   }\n   memcpy(s, source, domain_len);\n   pos = domain_len;\n\n   /* Encode path directly into output buffer */\n   for (p = path_start; *p && pos + 1 < len; p++)\n   {\n      unsigned char c = (unsigned char)*p;\n\n      if (   (c >= 'A' && c <= 'Z')\n          || (c >= 'a' && c <= 'z')\n          || (c >= '0' && c <= '9')\n          || c == '-' || c == '_'\n          || c == '.' || c == '~'\n          || c == '/' || c == ':' \n          || c == '?' || c == '#'\n          || c == '&' || c == '=')\n      {\n         s[pos++] = c;\n      }\n      else if (pos + 3 < len)\n      {\n         s[pos++] = '%';\n         s[pos++] = hex[(c >> 4) & 0x0F];\n         s[pos++] = hex[ c       & 0x0F];\n      }\n      else\n         break; /* not enough space for encoded char */\n   }\n\n   s[pos] = '\\0';\n}\n\nstruct http_connection_t *net_http_connection_new(const char *url,\n      const char *method, const char *data)\n{\n   struct http_connection_t *conn = NULL;\n   if (!url)\n      return NULL;\n   if (!(conn = (struct http_connection_t*)calloc(1, sizeof(*conn))))\n      return NULL;\n   if (method)\n   {\n      conn->method = strdup(method);\n      if (!conn->method)\n         goto error;\n   }\n   if (data)\n   {\n      conn->postdata = strdup(data);\n      if (!conn->postdata)\n         goto error;\n      conn->contentlength = strlen(data);\n   }\n   conn->url = strdup(url);\n   if (!conn->url)\n      goto error;\n   if (memcmp(url, \"http://\", 7) == 0)\n      conn->scan = conn->url + 7;\n   else if (memcmp(url, \"https://\", 8) == 0)\n   {\n      conn->scan = conn->url + 8;\n      conn->ssl  = true;\n   }\n   else\n      goto error;\n   if (*conn->scan == '\\0')\n      goto error;\n   conn->domain = conn->scan;\n   return conn;\nerror:\n   free(conn->url);\n   free(conn->method);\n   free(conn->postdata);\n   free(conn);\n   return NULL;\n}\n\n/**\n * net_http_connection_iterate:\n *\n * Leaf function.\n **/\nbool net_http_connection_iterate(struct http_connection_t *conn)\n{\n   if (!conn)\n      return false;\n\n   while (*conn->scan != '/' && *conn->scan != ':' && *conn->scan != '\\0')\n      conn->scan++;\n\n   return true;\n}\n\nbool net_http_connection_done(struct http_connection_t *conn)\n{\n   int has_port = 0;\n\n   if (!conn || !conn->domain || !*conn->domain)\n      return false;\n\n   if (*conn->scan == ':')\n   {\n      /* domain followed by port, split off the port */\n      *conn->scan++ = '\\0';\n\n      if (!isdigit((int)(*conn->scan)))\n         return false;\n\n      conn->port = (int)strtoul(conn->scan, &conn->scan, 10);\n      has_port   = 1;\n   }\n   else if (conn->port == 0)\n   {\n      /* port not specified, default to standard HTTP or HTTPS port */\n      if (conn->ssl)\n         conn->port = 443;\n      else\n         conn->port = 80;\n   }\n\n   if (*conn->scan == '/')\n   {\n      /* domain followed by path - split off the path */\n      /*   site.com/path.html   or   site.com:80/path.html   */\n      *conn->scan    = '\\0';\n      conn->path = conn->scan + 1;\n      return true;\n   }\n   else if (!*conn->scan)\n   {\n      /* domain with no path - point path at empty string */\n      /*   site.com   or   site.com:80   */\n      conn->path = conn->scan;\n      return true;\n   }\n   else if (*conn->scan == '?')\n   {\n      /* domain with no path, but still has query parms - point path at the query parms */\n      /*   site.com?param=3   or  site.com:80?param=3   */\n      if (!has_port)\n      {\n         /* if there wasn't a port, we have to expand the urlcopy so we can separate the two parts */\n         size_t domain_len   = strlen(conn->domain);\n         size_t path_len     = strlen(conn->scan);\n         char* urlcopy       = (char*)malloc(domain_len + path_len + 2);\n         /* Malloc failure: leave conn untouched and return false\n          * so the caller does not use a partially-initialised\n          * connection.  Without this check the following memcpy\n          * would NULL-deref. */\n         if (!urlcopy)\n            return false;\n         memcpy(urlcopy, conn->domain, domain_len);\n         urlcopy[domain_len] = '\\0';\n         memcpy(urlcopy + domain_len + 1, conn->scan, path_len + 1);\n\n         free(conn->url);\n         conn->domain        = conn->url     = urlcopy;\n         conn->path          = conn->scan    = urlcopy + domain_len + 1;\n      }\n      else /* There was a port, so overwriting the : will terminate the domain and we can just point at the ? */\n         conn->path          = conn->scan;\n\n      return true;\n   }\n\n   /* invalid character after domain/port */\n   return false;\n}\n\nvoid net_http_connection_free(struct http_connection_t *conn)\n{\n   if (!conn)\n      return;\n\n   if (conn->url)\n      free(conn->url);\n\n   if (conn->method)\n      free(conn->method);\n\n   if (conn->contenttype)\n      free(conn->contenttype);\n\n   if (conn->postdata)\n      free(conn->postdata);\n\n   if (conn->useragent)\n      free(conn->useragent);\n\n   if (conn->headers)\n      free(conn->headers);\n\n   free(conn);\n}\n\nvoid net_http_connection_set_user_agent(\n      struct http_connection_t *conn, const char *user_agent)\n{\n   if (conn->useragent)\n      free(conn->useragent);\n\n   conn->useragent = user_agent ? strdup(user_agent) : NULL;\n}\n\nvoid net_http_connection_set_headers(\n      struct http_connection_t *conn, const char *headers)\n{\n   if (conn->headers)\n      free(conn->headers);\n\n   conn->headers = headers ? strdup(headers) : NULL;\n}\n\nvoid net_http_connection_set_content(\n      struct http_connection_t *conn, const char *content_type,\n      size_t content_length, const void *content)\n\n{\n   if (conn->contenttype)\n      free(conn->contenttype);\n   if (conn->postdata)\n      free(conn->postdata);\n\n   conn->contenttype   = content_type ? strdup(content_type) : NULL;\n   conn->contentlength = content_length;\n   if (content_length)\n   {\n      conn->postdata = malloc(content_length);\n      if (conn->postdata)\n         memcpy(conn->postdata, content, content_length);\n      else\n      {\n         /* Malloc failure: leave postdata NULL and reset\n          * contentlength so net_http_send_request does not\n          * advertise a Content-Length it cannot honour. */\n         conn->contentlength = 0;\n      }\n   }\n}\n\nconst char *net_http_connection_url(struct http_connection_t *conn)\n{\n   return conn->url;\n}\n\nconst char* net_http_connection_method(struct http_connection_t* conn)\n{\n   return conn->method;\n}\n\nstatic void net_http_dns_cache_remove_expired(void)\n{\n   struct dns_cache_entry *entry = dns_cache;\n   struct dns_cache_entry *prev = NULL;\n   while (entry)\n   {\n      if (     (entry->addr && (entry->timestamp + dns_cache_timeout < cpu_features_get_time_usec()))\n            || (!entry->addr && (entry->timestamp + dns_cache_fail_timeout < cpu_features_get_time_usec())))\n      {\n#ifdef HAVE_THREADS\n         if (entry->thread)\n         {\n            sthread_join(entry->thread);\n            entry->thread = NULL;\n         }\n#endif\n         if (prev)\n            prev->next = entry->next;\n         else\n            dns_cache = entry->next;\n         if (entry->addr)\n            freeaddrinfo_retro(entry->addr);\n         free(entry->domain);\n         free(entry);\n         entry = prev ? prev->next : dns_cache;\n      }\n      else\n      {\n         prev = entry;\n         entry = entry->next;\n      }\n   }\n}\n\nstatic struct dns_cache_entry *net_http_dns_cache_find(\n   const char *domain, int port)\n{\n   struct dns_cache_entry *entry;\n\n   net_http_dns_cache_remove_expired();\n\n   entry = dns_cache;\n   while (entry)\n   {\n      if (port == entry->port && strcmp(entry->domain, domain) == 0)\n      {\n#ifdef HAVE_THREADS\n         if (entry->thread && entry->valid)\n         {\n            sthread_join(entry->thread);\n            entry->thread = NULL;\n         }\n#endif\n         /* don't bump timeestamp for failures */\n         if (entry->addr)\n            entry->timestamp = cpu_features_get_time_usec();\n         return entry;\n      }\n      entry = entry->next;\n   }\n   return NULL;\n}\n\nstatic struct dns_cache_entry *net_http_dns_cache_add(\n   const char *domain, int port, struct addrinfo *addr)\n{\n   struct dns_cache_entry *entry = (struct dns_cache_entry*)\n      calloc(1, sizeof(*entry));\n   if (!entry)\n      return NULL;\n   entry->domain = strdup(domain);\n   entry->port = port;\n   entry->addr = addr;\n   entry->timestamp = cpu_features_get_time_usec();\n   entry->valid = (addr != NULL);\n#ifdef HAVE_THREADS\n   entry->thread = NULL;\n#endif\n   entry->next = dns_cache;\n   dns_cache = entry;\n   return entry;\n}\n\nstatic void net_http_conn_pool_free(struct conn_pool_entry *entry)\n{\n#ifdef HAVE_SSL\n   if (entry->ssl && entry->ssl_ctx)\n   {\n      ssl_socket_close(entry->ssl_ctx);\n      ssl_socket_free(entry->ssl_ctx);\n   }\n#endif\n   if (entry->fd >= 0)\n      socket_close(entry->fd);\n   free(entry->domain);\n   free(entry);\n}\n\nstatic void net_http_conn_pool_remove(struct conn_pool_entry *entry)\n{\n   struct conn_pool_entry *prev = NULL;\n   struct conn_pool_entry *current;\n   if (!entry)\n      return;\n\n   LOCK_POOL();\n   current = conn_pool;\n   while (current)\n   {\n      if (current == entry)\n      {\n         if (prev)\n            prev->next = current->next;\n         else\n            conn_pool = current->next;\n         net_http_conn_pool_free(current);\n         UNLOCK_POOL();\n         return;\n      }\n      prev = current;\n      current = current->next;\n   }\n   UNLOCK_POOL();\n}\n\n/* *NOT* thread safe, caller must lock */\nstatic void net_http_conn_pool_remove_expired(void)\n{\n   fd_set fds;\n   struct conn_pool_entry *entry = NULL;\n   struct conn_pool_entry *prev  = NULL;\n   struct timeval tv             = { 0 };\n   int max                       = 0;\n   FD_ZERO(&fds);\n   entry = conn_pool;\n   while (entry)\n   {\n      if (!entry->in_use && entry->fd >= 0 && entry->fd < FD_SETSIZE)\n      {\n         FD_SET(entry->fd, &fds);\n         if (entry->fd >= max)\n            max = entry->fd + 1;\n      }\n      entry = entry->next;\n   }\n   if (select(max, &fds, NULL, NULL, &tv) <= 0)\n      return;\n   entry = conn_pool;\n   while (entry)\n   {\n      if (!entry->in_use && FD_ISSET(entry->fd, &fds))\n      {\n         /* If it's not in use and it's readable,\n          * we assume that means it's closed without checking recv */\n         if (prev)\n            prev->next = entry->next;\n         else\n            conn_pool = entry->next;\n         net_http_conn_pool_free(entry);\n         entry = prev ? prev->next : conn_pool;\n      }\n      else\n      {\n         prev = entry;\n         entry = entry->next;\n      }\n   }\n}\n\n/* if it's not already in the pool, will add to end.\n   *NOT* thread safe, caller must lock */\nstatic void net_http_conn_pool_move_to_end(struct conn_pool_entry *entry)\n{\n   struct conn_pool_entry *prev    = NULL;\n   struct conn_pool_entry *current = conn_pool;\n   /* 0 items in pool */\n   if (!conn_pool)\n   {\n      conn_pool   = entry;\n      entry->next = NULL;\n      return;\n   }\n   /* already only item in pool */\n   if (conn_pool == entry && !conn_pool->next)\n      return;\n   while (current)\n   {\n      if (current != entry)\n         prev = current;\n      else\n      {\n         /* need to remove current */\n         if (prev)\n            prev->next = current->next;\n         else\n            conn_pool = current->next;\n      }\n      current = current->next;\n   }\n\n   if (prev)\n      prev->next  = entry;\n   if (entry)\n      entry->next = NULL;\n}\n\nstatic struct conn_pool_entry *net_http_conn_pool_find(\n   const char *domain, int port)\n{\n   struct conn_pool_entry *entry;\n\n   LOCK_POOL();\n\n   net_http_conn_pool_remove_expired();\n\n   entry = conn_pool;\n   while (entry)\n   {\n      if (  !entry->in_use \n          && port == entry->port\n          && strcmp(entry->domain, domain) == 0)\n      {\n         entry->in_use = true;\n         net_http_conn_pool_move_to_end(entry);\n         UNLOCK_POOL();\n         return entry;\n      }\n      entry = entry->next;\n   }\n   UNLOCK_POOL();\n   return NULL;\n}\n\nstatic struct conn_pool_entry *net_http_conn_pool_add(const char *domain, int port, int fd, bool ssl)\n{\n   struct conn_pool_entry *entry = (struct conn_pool_entry*)\n      calloc(1, sizeof(*entry));\n   if (!entry)\n      return NULL;\n   entry->domain = strdup(domain);\n   entry->port = port;\n   entry->fd = fd;\n   entry->in_use = true;\n   entry->ssl = ssl;\n   entry->connected = false;\n   LOCK_POOL();\n   net_http_conn_pool_move_to_end(entry);\n   UNLOCK_POOL();\n   return entry;\n}\n\nstruct http_t *net_http_new(struct http_connection_t *conn)\n{\n   struct http_t *state;\n\n   if (!conn)\n      return NULL;\n\n   state = (struct http_t*)calloc(1, sizeof(struct http_t));\n   if (!state)\n      return NULL;\n\n   state->ssl  = conn->ssl;\n   state->conn = NULL;\n\n   state->request.domain        = strdup(conn->domain);\n   state->request.path          = strdup(conn->path);\n   state->request.method        = strdup(conn->method);\n   state->request.contenttype   = conn->contenttype ? strdup(conn->contenttype) : NULL;\n   state->request.contentlength = conn->contentlength;\n   if (conn->postdata && conn->contentlength)\n   {\n      /* Move ownership of postdata from conn to state->request rather\n       * than malloc+memcpy.  conn is freed by the caller shortly after\n       * this function returns (see task_http.c and the sample in\n       * libretro-common/samples/net/net_http_test.c; both use conn\n       * once with net_http_new then call net_http_connection_free),\n       * and conn->postdata is only read by net_http_new and freed by\n       * net_http_connection_free - no other code paths observe it.\n       * Null the conn fields so net_http_connection_free does not\n       * double-free.  Eliminates an O(body size) copy that materially\n       * matters for multi-MB POST payloads (file uploads, netplay,\n       * translation service requests). */\n      state->request.postdata   = conn->postdata;\n      conn->postdata            = NULL;\n      conn->contentlength       = 0;\n   }\n   state->request.useragent= conn->useragent ? strdup(conn->useragent) : NULL;\n   state->request.headers  = conn->headers ? strdup(conn->headers) : NULL;\n   state->request.port     = conn->port;\n\n   state->response.status  = -1;\n   state->response.buflen  = 64 * 1024;  /* Start with larger buffer to reduce reallocations */\n   state->response.data    = (char*)malloc(state->response.buflen);\n   state->response.headers = string_list_new();\n\n   /* Any of the strdup / malloc calls above can return NULL on OOM.\n    * The dispatch path in net_http_update() dereferences\n    * request.domain and writes to response.data without guards; fail\n    * the whole setup early here rather than stack up NULL derefs\n    * later.\n    *\n    * Note on cleanup order: net_http_delete() intentionally does not\n    * free response.data or response.headers because successful callers\n    * take ownership of response.data via net_http_data() and of\n    * response.headers via net_http_headers().  On the OOM failure path\n    * those ownership transfers never happen, so we free both here\n    * before calling net_http_delete() (which then cleans up the\n    * request.* fields and the state struct itself). */\n   if (   !state->response.data\n       || !state->response.headers\n       || !state->request.domain\n       || !state->request.path\n       || !state->request.method\n       || (conn->contenttype && !state->request.contenttype)\n       || (conn->useragent && !state->request.useragent)\n       || (conn->headers   && !state->request.headers))\n   {\n      /* Note: no postdata OOM check here.  Ownership of postdata is\n       * moved from conn (above), not copied, so the transfer cannot\n       * fail.  Both conn->postdata and state->request.postdata are\n       * correctly set (NULL on conn, the original pointer on\n       * state->request) regardless of any OOM elsewhere in this\n       * function. */\n      if (state->response.data)\n         free(state->response.data);\n      if (state->response.headers)\n         string_list_free(state->response.headers);\n      state->response.data    = NULL;\n      state->response.headers = NULL;\n      net_http_delete(state);\n      return NULL;\n   }\n\n   return state;\n}\n\nstatic void net_http_resolve(void *data)\n{\n   int port;\n   char *domain;\n   char port_buf[6];\n   struct dns_cache_entry *entry = (struct dns_cache_entry*)data;\n   struct addrinfo hints         = {0};\n   struct addrinfo *addr         = NULL;\n#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)\n   int family                    = AF_INET;\n#else\n   int family                    = AF_UNSPEC;\n#endif\n\n   hints.ai_family               = family;\n   hints.ai_socktype             = SOCK_STREAM;\n   hints.ai_flags               |= AI_NUMERICSERV;\n\n   LOCK_DNS_CACHE();\n   domain = strdup(entry->domain);\n   port = entry->port;\n   UNLOCK_DNS_CACHE();\n\n   if (!network_init())\n   {\n      LOCK_DNS_CACHE();\n      entry->valid = true;\n      entry->addr = NULL;\n      UNLOCK_DNS_CACHE();\n      free(domain);\n      return;\n   }\n\n   snprintf(port_buf, sizeof(port_buf), \"%hu\", (unsigned short)port);\n\n   getaddrinfo_retro(domain, port_buf, &hints, &addr);\n   free(domain);\n\n   LOCK_DNS_CACHE();\n   entry->valid = true;\n   entry->addr = addr;\n   UNLOCK_DNS_CACHE();\n}\n\nstatic bool net_http_new_socket(struct http_t *state)\n{\n   struct addrinfo *addr = NULL;\n   struct dns_cache_entry *entry;\n\n#ifdef HAVE_THREADS\n   if (!dns_cache_lock)\n      dns_cache_lock = slock_new();\n   LOCK_DNS_CACHE();\n\n   /* need some place to create this, I guess */\n   if (!conn_pool_lock)\n      conn_pool_lock = slock_new();\n#endif\n\n   entry = net_http_dns_cache_find(state->request.domain, state->request.port);\n   if (entry)\n   {\n      if (entry->valid)\n      {\n         int fd;\n         if (!entry->addr)\n         {\n            net_http_log_transport_state(state, \"dns_lookup_failed\", -1);\n            UNLOCK_DNS_CACHE();\n            return false;\n         }\n         addr = entry->addr;\n         fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);\n         if (fd >= 0)\n            state->conn = net_http_conn_pool_add(state->request.domain, state->request.port, fd, state->ssl);\n         else\n            net_http_log_transport_state(state, \"socket_create_failed\", -1);\n         /* still waiting on thread */\n         UNLOCK_DNS_CACHE();\n         return (fd >= 0);\n      }\n      else\n      {\n         /* still waiting on thread */\n         UNLOCK_DNS_CACHE();\n         return true;\n      }\n   }\n   else\n   {\n      entry = net_http_dns_cache_add(state->request.domain, state->request.port, NULL);\n#ifdef HAVE_THREADS\n      /* create the entry for it as an indicator that the request is underway */\n      entry->thread = sthread_create(net_http_resolve, entry);\n#else\n      net_http_resolve(entry);\n#endif\n   }\n\n   UNLOCK_DNS_CACHE();\n\n   return true;\n}\n\nstatic bool net_http_connect(struct http_t *state)\n{\n   struct addrinfo *addr = NULL, *next_addr = NULL;\n   struct conn_pool_entry *conn = state->conn;\n   struct dns_cache_entry *dns_entry = net_http_dns_cache_find(state->request.domain, state->request.port);\n   /* we just used/added this in _new_socket above, if it's not there it's a big bug */\n   addr = dns_entry->addr;\n\n#ifndef HAVE_SSL\n   if (state->ssl)\n      return false;\n#else\n   if (state->ssl)\n   {\n      if (!conn)\n      {\n         net_http_log_transport_state(state, \"connect_missing_dns_or_conn\", -1);\n         return false;\n      }\n      for (next_addr = addr; conn->fd >= 0; conn->fd = socket_next((void**)&next_addr))\n      {\n         if (!(conn->ssl_ctx = ssl_socket_init(conn->fd, state->request.domain)))\n         {\n            net_http_log_transport_state(state, \"ssl_init_failed\", -1);\n            socket_close(conn->fd);\n            break;\n         }\n\n         /* TODO: Properly figure out what's going wrong when the newer\n          timeout/poll code interacts with mbed and winsock\n          https://github.com/libretro/RetroArch/issues/14742 */\n\n         /* Temp fix, don't use new timeout/poll code for cheevos http requests */\n         bool timeout = true;\n#ifdef __WIN32\n         if (!strcmp(state->request.domain, \"retroachievements.org\"))\n            timeout = false;\n#endif\n\n         if (ssl_socket_connect(conn->ssl_ctx, next_addr, timeout, true) < 0)\n         {\n            net_http_log_transport_state(state, \"ssl_connect_failed\", -1);\n            ssl_socket_close(conn->ssl_ctx);\n            ssl_socket_free(conn->ssl_ctx);\n            conn->ssl_ctx = NULL;\n         }\n         else\n         {\n            conn->connected = true;\n            return true;\n         }\n      }\n      conn->fd    = -1; /* already closed */\n      net_http_conn_pool_remove(conn);\n      state->conn = NULL;\n      state->err  = true;\n      return false;\n   }\n   else\n#endif\n   {\n      for (next_addr = addr; conn->fd >= 0; conn->fd = socket_next((void**)&next_addr))\n      {\n         if (socket_connect_with_timeout(conn->fd, next_addr, 5000))\n         {\n            conn->connected = true;\n            return true;\n         }\n\n         net_http_log_transport_state(state, \"socket_connect_failed\", -1);\n         socket_close(conn->fd);\n      }\n      conn->fd    = -1; /* already closed */\n      net_http_conn_pool_remove(conn);\n      state->conn = NULL;\n      state->err  = true;\n      return false;\n   }\n}\n\nstatic void net_http_send_str(\n      struct http_t *state, const char *text, size_t text_size)\n{\n   if (state->err)\n      return;\n#ifdef HAVE_SSL\n   if (state->ssl)\n   {\n      if (!ssl_socket_send_all_blocking(\n                  state->conn->ssl_ctx, text, text_size, true))\n      {\n         state->err = true;\n         net_http_log_transport_state(state, \"ssl_send_failed\", -1);\n      }\n   }\n   else\n#endif\n   {\n      if (!socket_send_all_blocking(\n                  state->conn->fd, text, text_size, true))\n      {\n         state->err = true;\n         net_http_log_transport_state(state, \"socket_send_failed\", -1);\n      }\n   }\n}\n\nstatic bool net_http_send_request(struct http_t *state)\n{\n   struct request *request = (struct request*)&state->request;\n   /* This is a bit lazy, but it works. */\n   if (request->method)\n   {\n      net_http_send_str(state, request->method, strlen(request->method));\n      net_http_send_str(state, \" /\", sizeof(\" /\")-1);\n   }\n   else\n      net_http_send_str(state, \"GET /\", sizeof(\"GET /\")-1);\n   net_http_send_str(state, request->path, strlen(request->path));\n   net_http_send_str(state, \" HTTP/1.1\\r\\n\", sizeof(\" HTTP/1.1\\r\\n\")-1);\n   net_http_send_str(state, \"Host: \", sizeof(\"Host: \")-1);\n   net_http_send_str(state, request->domain, strlen(request->domain));\n   if (request->port && request->port != 80 && request->port != 443)\n   {\n      char portstr[16];\n      size_t _len     = 0;\n      portstr[  _len] = ':';\n      portstr[++_len] = '\\0';\n      _len           += snprintf(portstr + _len, sizeof(portstr) - _len,\n            \"%i\", request->port);\n      net_http_send_str(state, portstr, _len);\n   }\n   net_http_send_str(state, \"\\r\\n\", sizeof(\"\\r\\n\")-1);\n   /* Pre-formatted headers */\n   if (request->headers)\n      net_http_send_str(state, request->headers, strlen(request->headers));\n   if (request->contenttype)\n   {\n      net_http_send_str(state, \"Content-Type: \", sizeof(\"Content-Type: \")-1);\n      net_http_send_str(state, request->contenttype, strlen(request->contenttype));\n      net_http_send_str(state, \"\\r\\n\", sizeof(\"\\r\\n\")-1);\n   }\n   if (request->method && request->method[0] == 'P')\n   {\n      size_t _len;\n      int    len;\n      if (     !request->postdata\n            && request->method[1] == 'O' /* POST, not PUT */\n            && request->contentlength > 0)\n      {\n         state->err = true;\n         net_http_log_transport_state(state, \"post_without_payload\", -1);\n         return true;\n      }\n      if (!request->headers && !request->contenttype)\n         net_http_send_str(state,\n               \"Content-Type: application/x-www-form-urlencoded\\r\\n\",\n               sizeof(\"Content-Type: application/x-www-form-urlencoded\\r\\n\")-1);\n      net_http_send_str(state, \"Content-Length: \", sizeof(\"Content-Length: \")-1);\n      _len = request->contentlength;\n      /* Use a stack buffer -- the maximum decimal representation\n       * of a size_t is 20 digits (UINT64_MAX) + NUL, well within\n       * 32 bytes.  Pre-patch this was a malloc/snprintf pair\n       * whose malloc was never NULL-checked; a snprintf-into-NULL\n       * crash on OOM was the tail end of that sequence. */\n      {\n         char len_buf[32];\n#ifdef _WIN32\n         len = snprintf(len_buf, sizeof(len_buf), \"%\" PRIuPTR, _len);\n#else\n         len = snprintf(len_buf, sizeof(len_buf), \"%llu\",\n               (long long unsigned)_len);\n#endif\n         if (len < 0)\n            len = 0;\n         else if ((size_t)len >= sizeof(len_buf))\n            len = sizeof(len_buf) - 1;\n         len_buf[len] = '\\0';\n         net_http_send_str(state, len_buf, (size_t)len);\n      }\n      net_http_send_str(state, \"\\r\\n\", sizeof(\"\\r\\n\")-1);\n   }\n   net_http_send_str(state, \"User-Agent: \", sizeof(\"User-Agent: \")-1);\n   if (request->useragent)\n      net_http_send_str(state, request->useragent, strlen(request->useragent));\n   else\n      net_http_send_str(state, \"libretro\", sizeof(\"libretro\")-1);\n   net_http_send_str(state, \"\\r\\n\", sizeof(\"\\r\\n\")-1);\n   net_http_send_str(state, \"\\r\\n\", sizeof(\"\\r\\n\")-1);\n   if (request->postdata && request->contentlength)\n      net_http_send_str(state, (const char*)request->postdata,\n            request->contentlength);\n   state->request_sent = true;\n   return state->err;\n}\n\n/**\n * net_http_fd:\n *\n * Leaf function.\n *\n * You can use this to call net_http_update\n * only when something will happen; select() it for reading.\n **/\nint net_http_fd(struct http_t *state)\n{\n   if (!state || !state->conn)\n      return -1;\n   return state->conn->fd;\n}\n\nstatic ssize_t net_http_receive_header(struct http_t *state, ssize_t len)\n{\n   struct response *response = (struct response*)&state->response;\n   char *scan;\n   char *dataend;\n\n   response->pos += len;\n   scan    = response->data;\n   dataend = response->data + response->pos;\n\n   while (response->part < P_BODY)\n   {\n      ssize_t remaining = dataend - scan;\n      char *lineend     = (char*)memchr(scan, '\\n', remaining);\n      if (!lineend)\n         break;\n\n      *lineend = '\\0';\n      if (lineend != scan && lineend[-1] == '\\r')\n         lineend[-1] = '\\0';\n\n      if (response->part == P_HEADER_TOP)\n      {\n         /* Status line is \"HTTP/1.x SSS <reason>\\r\\n\".  The fixed\n          * prefix is 8 bytes, then a space, then 3 status digits ->\n          * minimum line length is 12 bytes excluding the NUL we just\n          * wrote at lineend (lineend - scan >= 12).  Pre-patch this\n          * was not checked and a short malicious line like\n          * \"HTTP/1.0\\n\" let the code read scan[9..11] past the\n          * terminator into whatever followed in the receive buffer. */\n         ssize_t line_len = lineend - scan;\n         if (   line_len < 12\n             || scan[0] != 'H' || scan[1] != 'T' || scan[2] != 'T'\n             || scan[3] != 'P' || scan[4] != '/' || scan[5] != '1'\n             || scan[6] != '.' || scan[8] != ' ')\n         {\n            response->part = P_DONE;\n            state->err     = true;\n            return -1;\n         }\n         {\n            const char *p = scan + 9;\n            /* Also verify the three status chars are digits -- a\n             * non-digit would produce a negative or junk status. */\n            if (   p[0] < '0' || p[0] > '9'\n                || p[1] < '0' || p[1] > '9'\n                || p[2] < '0' || p[2] > '9')\n            {\n               response->part = P_DONE;\n               state->err     = true;\n               return -1;\n            }\n            response->status = (p[0] - '0') * 100\n                             + (p[1] - '0') * 10\n                             + (p[2] - '0');\n         }\n         response->part = P_HEADER;\n      }\n      else\n      {\n         if (scan[0] == '\\0')\n         {\n            if (response->status == 100)\n               response->part = P_HEADER_TOP;\n            else\n            {\n               response->part = P_BODY;\n               if (response->bodytype == T_CHUNK)\n               {\n                  response->part = P_BODY_CHUNKLEN;\n                  /* The chunked body parser uses response->len as\n                   * the position of the current chunklen line --\n                   * must start at 0.  A hostile server that sent\n                   * both \"Content-Length: N\" and\n                   * \"Transfer-Encoding: chunked\" would otherwise\n                   * leave response->len set to N from the\n                   * Content-Length pass, and the first chunked\n                   * parse step computed \"response->pos -\n                   * response->len\" as an unsigned wrap to a huge\n                   * value.  memchr() at that offset is a wild\n                   * OOB read. */\n                  response->len = 0;\n               }\n            }\n            scan = lineend + 1;\n            continue;\n         }\n\n         switch (scan[0] | 0x20)\n         {\n            case 'c':\n               if (strncasecmp(scan, \"Content-Length:\",\n                     sizeof(\"Content-Length:\") - 1) == 0)\n               {\n                  /* Parse Content-Length as unsigned with an explicit\n                   * cap.  Pre-patch the accumulator was a signed ssize_t\n                   * that could overflow (UB) on a very long digit string\n                   * and then sign-extend to a huge size_t when assigned\n                   * to response->len, driving realloc() toward OOM.  Cap\n                   * at NET_HTTP_MAX_CONTENT_LENGTH (256 MiB) which is\n                   * larger than any legitimate single HTTP response in\n                   * the libretro/RetroArch workflow (cores, thumbnails,\n                   * ROM manifests) and leaves a safe headroom before\n                   * buflen can wrap. */\n                  char *ptr      = scan + (sizeof(\"Content-Length:\") - 1);\n                  size_t val     = 0;\n                  int    any     = 0;\n                  int    oflow   = 0;\n                  while (*ptr == ' ' || *ptr == '\\t')\n                     ++ptr;\n                  while (*ptr >= '0' && *ptr <= '9')\n                  {\n                     size_t digit = (size_t)(*ptr++ - '0');\n                     any = 1;\n                     /* Detect overflow against the cap rather than\n                      * against SIZE_MAX, so the later realloc call\n                      * never sees an attacker-chosen huge value. */\n                     if (val > (NET_HTTP_MAX_CONTENT_LENGTH - digit) / 10)\n                     {\n                        oflow = 1;\n                        break;\n                     }\n                     val = val * 10 + digit;\n                  }\n                  if (!any || oflow)\n                  {\n                     /* Malformed header: treat as protocol error. */\n                     response->part = P_DONE;\n                     state->err     = true;\n                     return -1;\n                  }\n                  response->bodytype = T_LEN;\n                  response->len      = val;\n               }\n               break;\n            case 't':\n               if (strcasecmp(scan,\n                     \"Transfer-Encoding: chunked\") == 0)\n                  response->bodytype = T_CHUNK;\n               break;\n            default:\n               break;\n         }\n\n         {\n            union string_list_elem_attr attr;\n            attr.i = 0;\n            string_list_append(response->headers, scan, attr);\n         }\n      }\n\n      scan = lineend + 1;\n   }\n\n   if (scan != response->data)\n   {\n      ssize_t leftover = dataend - scan;\n      if (leftover > 0)\n         memmove(response->data, scan, leftover);\n      response->pos = leftover;\n   }\n\n   if (response->part >= P_BODY)\n   {\n      len           = response->pos;\n      response->pos = 0;\n      if (response->bodytype == T_LEN && response->len > 0)\n      {\n         /* Use a tmp pointer so a realloc failure does not leak the\n          * original buffer AND leave response->data NULL for later\n          * writes to dereference. */\n         char *tmp;\n         response->buflen = response->len;\n         tmp              = (char*)realloc(response->data, response->buflen);\n         if (!tmp)\n         {\n            response->part = P_DONE;\n            state->err     = true;\n            return -1;\n         }\n         response->data   = tmp;\n      }\n   }\n   else\n   {\n      if (response->pos >= response->buflen - 64)\n      {\n         char *tmp;\n         response->buflen *= 2;\n         tmp               = (char*)realloc(response->data, response->buflen);\n         if (!tmp)\n         {\n            response->part = P_DONE;\n            state->err     = true;\n            return -1;\n         }\n         response->data    = tmp;\n      }\n   }\n   return len;\n}\n\nstatic bool net_http_receive_body(struct http_t *state, ssize_t newlen)\n{\n   struct response *response = (struct response*)&state->response;\n\n   if (newlen < 0 || state->err)\n   {\n      if (response->bodytype != T_FULL)\n         return false;\n      response->part      = P_DONE;\n      if (response->buflen != response->len && response->len > 0)\n      {\n         /* Shrink response->data from buflen bytes to len bytes.\n          * Use a tmp pointer so a realloc() failure (rare on shrink\n          * but not impossible) does not overwrite response->data\n          * with NULL and leak the original buffer.  Sibling shrink\n          * path at ~line 1528 already uses this pattern; this was\n          * the lone holdout.  On failure we keep the oversized-\n          * but-valid buffer - this is a terminal state (P_DONE)\n          * and the caller tears down shortly afterwards. */\n         char *tmp = (char*)realloc(response->data, response->len);\n         if (tmp)\n            response->data = tmp;\n      }\n      return true;\n   }\n\nparse_again:\n   if (response->bodytype == T_CHUNK)\n   {\n      if (response->part == P_BODY_CHUNKLEN)\n      {\n         response->pos      += newlen;\n\n         if (response->pos - response->len >= 2)\n         {\n            /*\n             * len=start of chunk including \\r\\n\n             * pos=end of data\n             */\n\n            char *fullend = response->data + response->pos;\n            char *end     = (char*)memchr(response->data + response->len + 2,\n            '\\n', response->pos - response->len - 2);\n\n            if (end)\n            {\n               size_t chunklen = strtoul(response->data + response->len, NULL, 16);\n               /* Cap the chunk length at the same Content-Length\n                * ceiling.  A hostile server sending a chunklen\n                * like ffffffffffffffff drives the client into\n                * an effectively unbounded receive loop (each\n                * net_http_update tick nibbles at response->len\n                * and response->len never reaches zero). */\n               if (chunklen > NET_HTTP_MAX_CONTENT_LENGTH)\n               {\n                  response->part = P_DONE;\n                  state->err     = true;\n                  return false;\n               }\n               response->pos   = response->len;\n               end++;\n\n               memmove(response->data + response->len, end, fullend-end);\n\n               response->len   = chunklen;\n               newlen          = (fullend - end);\n\n               /*\n                 len=num bytes\n                 newlen=unparsed bytes after \\n\n                 pos=start of chunk including \\r\\n\n               */\n\n               response->part = P_BODY;\n               if (response->len == 0)\n               {\n                  char *tmp;\n                  response->part = P_DONE;\n                  response->len  = response->pos;\n                  tmp            = (char*)realloc(response->data,\n                        response->len);\n                  if (!tmp)\n                  {\n                     state->err = true;\n                     return false;\n                  }\n                  response->data = tmp;\n                  return true;\n               }\n               goto parse_again;\n            }\n         }\n      }\n      else if (response->part == P_BODY)\n      {\n         if ((size_t)newlen >= response->len)\n         {\n            response->pos += response->len;\n            newlen        -= response->len;\n            response->len  = response->pos;\n            response->part = P_BODY_CHUNKLEN;\n            goto parse_again;\n         }\n         response->pos += newlen;\n         response->len -= newlen;\n      }\n   }\n   else\n   {\n      response->pos += newlen;\n\n      if (response->pos > response->len)\n         return false;\n      else if (response->pos == response->len)\n      {\n         response->part = P_DONE;\n         if (response->buflen != response->len && response->len > 0)\n         {\n            char *tmp = (char*)realloc(response->data, response->len);\n            if (!tmp)\n            {\n               state->err = true;\n               return false;\n            }\n            response->data = tmp;\n         }\n         return true;\n      }\n   }\n\n   if (response->pos >= response->buflen)\n   {\n      char *tmp;\n      response->buflen *= 2;\n      tmp               = (char*)realloc(response->data, response->buflen);\n      if (!tmp)\n      {\n         state->err = true;\n         return false;\n      }\n      response->data    = tmp;\n   }\n   return true;\n}\n\nstatic bool net_http_redirect(struct http_t *state, const char *location)\n{\n   /* This reinitializes state based on the new location.  Every\n    * allocation below is checked; on any failure state->err is\n    * set and we return true (the dispatch loop reads that as\n    * \"transfer finished with an error\"), leaving the state in a\n    * safe-to-delete shape. */\n\n   /* URL may be absolute or relative to the current URL */\n   char *new_domain = NULL;\n   char *new_path   = NULL;\n   char *tmp;\n   bool absolute = (!strncmp(location, \"http://\", sizeof(\"http://\")-1)\n                 || !strncmp(location, \"https://\", sizeof(\"https://\")-1));\n\n   if (absolute)\n   {\n      /* this block is a little wasteful, memory-wise */\n      struct http_connection_t *new_url = net_http_connection_new(\n      location, NULL, NULL);\n      net_http_connection_iterate(new_url);\n      if (!net_http_connection_done(new_url))\n      {\n         net_http_connection_free(new_url);\n         state->err = true;\n         return true;\n      }\n      new_domain = strdup(new_url->domain);\n      new_path   = strdup(new_url->path);\n      if (!new_domain || !new_path)\n      {\n         free(new_domain);\n         free(new_path);\n         net_http_connection_free(new_url);\n         state->err = true;\n         return true;\n      }\n      state->ssl  = new_url->ssl;\n      state->request.port = new_url->port;\n      if (state->request.domain)\n         free(state->request.domain);\n      state->request.domain = new_domain;\n      if (state->request.path)\n         free(state->request.path);\n      state->request.path = new_path;\n      net_http_connection_free(new_url);\n   }\n   else\n   {\n      if (*location == '/')\n      {\n         new_path = strdup(location);\n         if (!new_path)\n         {\n            state->err = true;\n            return true;\n         }\n         if (state->request.path)\n            free(state->request.path);\n         state->request.path = new_path;\n      }\n      else\n      {\n         new_path = (char*)malloc(PATH_MAX_LENGTH);\n         if (!new_path)\n         {\n            state->err = true;\n            return true;\n         }\n         fill_pathname_resolve_relative(new_path, state->request.path,\n         location, PATH_MAX_LENGTH);\n         free(state->request.path);\n         state->request.path = new_path;\n      }\n   }\n   state->request_sent       = false;\n   state->response.part      = P_HEADER_TOP;\n   state->response.status    = -1;\n   /* Start with larger buffer to reduce reallocations */\n   state->response.buflen    = 64 * 1024;\n   tmp = (char*)realloc(state->response.data, state->response.buflen);\n   if (!tmp)\n   {\n      /* Keep the existing buffer; state->data is still valid.\n       * Mark the transfer as errored so the dispatch loop tears\n       * it down. */\n      state->err = true;\n      return true;\n   }\n   state->response.data      = tmp;\n   state->response.pos       = 0;\n   state->response.len       = 0;\n   state->response.bodytype  = T_FULL;\n   /* after this, assume location is invalid */\n   string_list_deinitialize(state->response.headers);\n   string_list_initialize(state->response.headers);\n   /* keep going */\n   return false;\n}\n\n/**\n * net_http_update:\n *\n * @return true if it's done, or if something broke.\n * @total will be 0 if it's not known.\n **/\nbool net_http_update(struct http_t *state, size_t* progress, size_t* total)\n{\n   struct response *response;\n   ssize_t _len = 0;\n\n   if (!state || state->err)\n      return true;\n\n   if (!state->conn)\n   {\n      state->conn = net_http_conn_pool_find(state->request.domain, state->request.port);\n      if (!state->conn)\n      {\n         if (!net_http_new_socket(state))\n            state->err = true;\n         return state->err;\n      }\n   }\n\n   if (!state->conn->connected)\n   {\n      if (!net_http_connect(state))\n         state->err = true;\n      return state->err;\n   }\n\n   if (!state->request_sent)\n      return net_http_send_request(state);\n\n   response = (struct response*)&state->response;\n\n#ifdef HAVE_SSL\n   if (state->ssl && state->conn->ssl_ctx)\n      _len = ssl_socket_receive_all_nonblocking(state->conn->ssl_ctx, &state->err,\n            (uint8_t*)response->data + response->pos,\n            response->buflen - response->pos);\n   else\n#endif\n      _len = socket_receive_all_nonblocking(state->conn->fd, &state->err,\n            (uint8_t*)response->data + response->pos,\n            response->buflen - response->pos);\n\n   if (response->part < P_BODY)\n   {\n      if (_len < 0 || state->err)\n      {\n         net_http_log_transport_state(state, \"receive_header_failed\", _len);\n         net_http_conn_pool_remove(state->conn);\n         state->conn      = NULL;\n         state->err       = true;\n         response->part   = P_DONE;\n         response->status = -1;\n         return true;\n      }\n      _len = net_http_receive_header(state, _len);\n   }\n\n   if (response->part >= P_BODY && response->part < P_DONE)\n   {\n      if (!net_http_receive_body(state, _len))\n      {\n         net_http_log_transport_state(state, \"receive_body_failed\", _len);\n         net_http_conn_pool_remove(state->conn);\n         state->conn      = NULL;\n         state->err       = true;\n         response->part   = P_DONE;\n         response->status = -1;\n         return true;\n      }\n   }\n\n   if (progress)\n      *progress = response->pos;\n\n   if (total)\n   {\n      if (response->bodytype == T_LEN)\n         *total = response->len;\n      else\n         *total = 0;\n   }\n\n   if (response->part != P_DONE)\n      return false;\n\n   for (_len = 0; (size_t)_len < response->headers->size; _len++)\n   {\n      if (string_is_equal_case_insensitive(response->headers->elems[_len].data, \"connection: close\"))\n      {\n         net_http_conn_pool_remove(state->conn);\n         state->conn = NULL;\n         break;\n      }\n   }\n\n   if (state->conn)\n      state->conn->in_use = false;\n   state->conn = NULL;\n\n   if (response->status >= 300 && response->status < 400)\n   {\n      for (_len = 0; (size_t)_len < response->headers->size; _len++)\n      {\n         if (string_starts_with_case_insensitive(response->headers->elems[_len].data, \"Location: \"))\n            return net_http_redirect(state, response->headers->elems[_len].data + (sizeof(\"Location: \")-1));\n      }\n   }\n\n   return true;\n}\n\n/**\n * net_http_status:\n *\n * Report HTTP status. 200, 404, or whatever.\n *\n * Leaf function.\n *\n * @return HTTP status code.\n **/\nint net_http_status(struct http_t *state)\n{\n   if (!state)\n      return -1;\n   return state->response.status;\n}\n\n/**\n * net_http_headers:\n *\n * Leaf function.\n *\n * @return the response headers. The returned buffer is owned by the\n * caller of net_http_new; it is not freed by net_http_delete().\n * On a transport error, NULL is returned unless accept_err is true.\n * Headers are returned for any response that was parsed successfully,\n * including HTTP error statuses such as 401 (needed for auth challenges).\n **/\nstruct string_list *net_http_headers_ex(struct http_t *state, bool accept_err)\n{\n   if (!state)\n      return NULL;\n   if (!accept_err && state->err)\n      return NULL;\n   return state->response.headers;\n}\n\nstruct string_list *net_http_headers(struct http_t *state)\n{\n   return net_http_headers_ex(state, false);\n}\n\n/**\n * net_http_data:\n *\n * Leaf function.\n *\n * @return the downloaded data. The returned buffer is owned by the\n * HTTP handler; it's freed by net_http_delete().\n * If the status is not 20x and accept_err is false, it returns NULL.\n **/\nuint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_err)\n{\n   if (!state)\n      return NULL;\n\n   if (!accept_err && (state->err || state->response.status < 200 || state->response.status > 299))\n   {\n      if (len)\n         *len = 0;\n      return NULL;\n   }\n\n   if (len)\n      *len    = state->response.len;\n\n   return (uint8_t*)state->response.data;\n}\n\n/**\n * net_http_delete:\n *\n * Cleans up all memory.\n **/\nvoid net_http_delete(struct http_t *state)\n{\n   if (!state)\n      return;\n\n   if (state->conn)\n      net_http_conn_pool_remove(state->conn);\n   if (state->request.domain)\n      free(state->request.domain);\n   if (state->request.path)\n      free(state->request.path);\n   if (state->request.method)\n      free(state->request.method);\n   if (state->request.contenttype)\n      free(state->request.contenttype);\n   if (state->request.postdata)\n      free(state->request.postdata);\n   if (state->request.useragent)\n      free(state->request.useragent);\n   if (state->request.headers)\n      free(state->request.headers);\n   free(state);\n}\n\n/**\n * net_http_error:\n *\n * Leaf function\n **/\nbool net_http_error(struct http_t *state)\n{\n   return (state->err || state->response.status < 200 || state->response.status > 299);\n}\n"
  },
  {
    "path": "net/net_http_parse.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_http_parse.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <compat/strcasestr.h>\n\n/**\n * string_parse_html_anchor:\n * @line               : Buffer where the <a> tag is stored\n * @link               : Buffer to store the link URL in\n * @name               : Buffer to store the link URL in\n * @link_size          : Size of the link buffer including the NUL-terminator\n * @name_size          : Size of the name buffer including the NUL-terminator\n *\n * Parses an HTML anchor link stored in @line in the form of: <a href=\"/path/to/url\">Title</a>\n * The buffer pointed to by @link is filled with the URL path the link points to,\n * and @name is filled with the title portion of the link.\n *\n * @return 0 if URL was parsed completely, otherwise 1.\n **/\nint string_parse_html_anchor(const char *line, char *link, char *name,\n      size_t link_size, size_t name_size)\n{\n   if (!line || !link || !name)\n      return 1;\n\n   memset(link, 0, link_size);\n   memset(name, 0, name_size);\n\n   line = strcasestr(line, \"<a href=\\\"\");\n\n   if (!line)\n      return 1;\n\n   line += 9;\n\n   if (line && *line)\n   {\n      if (!*link)\n      {\n         const char *end = strstr(line, \"\\\"\");\n         size_t _len;\n\n         if (!end)\n            return 1;\n\n         /* Bound the href length against the caller's buffer.\n          * Pre-patch the memcpy was unbounded and a long href\n          * would overflow link[].  Keep room for the NUL. */\n         _len = (size_t)(end - line);\n         if (_len >= link_size)\n            _len = (link_size > 0) ? link_size - 1 : 0;\n\n         memcpy(link, line, _len);\n         link[_len] = '\\0';\n         line += end - line;\n      }\n\n      if (!*name)\n      {\n         const char *start = strstr(line, \"\\\">\");\n         const char *end   = start ? strstr(start, \"</a>\") : NULL;\n         size_t _len;\n\n         if (!start || !end)\n            return 1;\n\n         /* Same bounding for the anchor text. */\n         _len = (size_t)(end - start - 2);\n         if (_len >= name_size)\n            _len = (name_size > 0) ? name_size - 1 : 0;\n\n         memcpy(name, start + 2, _len);\n         name[_len] = '\\0';\n      }\n   }\n\n   return 0;\n}\n"
  },
  {
    "path": "net/net_ifinfo.c",
    "content": "/* Copyright  (C) 2010-2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_ifinfo.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <string/stdstring.h>\n#include <net/net_compat.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#ifdef _MSC_VER\n#pragma comment(lib, \"Iphlpapi\")\n#endif\n\n#include <iphlpapi.h>\n\n#elif !defined(VITA) && !defined(GEKKO)\n#if defined(WANT_IFADDRS)\n#include <compat/ifaddrs.h>\n#elif !defined(HAVE_LIBNX) && !defined(_3DS)\n#include <ifaddrs.h>\n#ifndef WIIU\n#include <net/if.h>\n#endif\n#endif\n#endif\n\n#include <net/net_ifinfo.h>\n\nbool net_ifinfo_new(net_ifinfo_t *list)\n{\n#if defined(_WIN32) && !defined(_XBOX)\n   /* Microsoft docs recommend doing it this way. */\n   char buf[512];\n   ULONG ret;\n   PIP_ADAPTER_ADDRESSES addr;\n   struct net_ifinfo_entry *entry;\n   size_t                interfaces = 0;\n   ULONG                 flags      = GAA_FLAG_SKIP_ANYCAST\n                                    | GAA_FLAG_SKIP_MULTICAST\n                                    | GAA_FLAG_SKIP_DNS_SERVER;\n   ULONG                 len        = 15 * 1024;\n   PIP_ADAPTER_ADDRESSES addresses  = (PIP_ADAPTER_ADDRESSES)calloc(1, len);\n\n   list->entries                    = NULL;\n\n   if (!addresses)\n      goto failure;\n\n   ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addresses, &len);\n   if (ret == ERROR_BUFFER_OVERFLOW)\n   {\n      PIP_ADAPTER_ADDRESSES new_addresses =\n         (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);\n\n      if (new_addresses)\n      {\n         memset(new_addresses, 0, len);\n\n         addresses = new_addresses;\n         ret       = GetAdaptersAddresses(AF_UNSPEC, flags, NULL,\n            addresses, &len);\n      }\n   }\n   if (ret != ERROR_SUCCESS)\n      goto failure;\n\n   /* Count the number of valid interfaces first. */\n   addr = addresses;\n\n   do\n   {\n      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;\n\n      if (!unicast_addr)\n         continue;\n      if (addr->OperStatus != IfOperStatusUp)\n         continue;\n\n      do\n      {\n         interfaces++;\n      } while ((unicast_addr = unicast_addr->Next));\n   } while ((addr = addr->Next));\n\n   if (!interfaces)\n      goto failure;\n\n   if (!(list->entries =\n      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries))))\n      goto failure;\n\n   list->size    = 0;\n   /* Now create the entries. */\n   addr          = addresses;\n   entry         = list->entries;\n\n   do\n   {\n      PIP_ADAPTER_UNICAST_ADDRESS unicast_addr = addr->FirstUnicastAddress;\n\n      if (!unicast_addr)\n         continue;\n      if (addr->OperStatus != IfOperStatusUp)\n         continue;\n\n      buf[0] = '\\0';\n      if (addr->FriendlyName)\n      {\n         if (!WideCharToMultiByte(CP_UTF8, 0, addr->FriendlyName, -1,\n               buf, sizeof(buf), NULL, NULL))\n            buf[0] = '\\0'; /* Empty name on conversion failure. */\n      }\n\n      do\n      {\n         if (getnameinfo_retro(unicast_addr->Address.lpSockaddr,\n               unicast_addr->Address.iSockaddrLength,\n               entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))\n            continue;\n\n         strlcpy(entry->name, buf, sizeof(entry->name));\n\n         if (++list->size >= interfaces)\n            break;\n\n         entry++;\n      } while ((unicast_addr = unicast_addr->Next));\n\n      if (list->size >= interfaces)\n         break;\n   } while ((addr = addr->Next));\n\n   free(addresses);\n\n   return true;\n\nfailure:\n   free(addresses);\n   net_ifinfo_free(list);\n\n   return false;\n#elif defined(VITA)\n   SceNetCtlInfo info;\n   if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))\n   {\n      list->size = 0;\n      return false;\n   }\n\n   strlcpy(list->entries[0].name, \"lo\",        sizeof(list->entries[0].name));\n   strlcpy(list->entries[0].host, \"127.0.0.1\", sizeof(list->entries[0].host));\n   list->size = 1;\n\n   if (!sceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info))\n   {\n      strlcpy(list->entries[1].name, \"wlan\", sizeof(list->entries[1].name));\n      strlcpy(list->entries[1].host, info.ip_address,\n         sizeof(list->entries[1].host));\n      list->size++;\n   }\n\n   return true;\n#elif defined(HAVE_LIBNX) || defined(_3DS) || defined(GEKKO)\n   uint32_t addr = 0;\n   if (!(list->entries = (struct net_ifinfo_entry*)calloc(2, sizeof(*list->entries))))\n   {\n      list->size = 0;\n      return false;\n   }\n\n   strlcpy(list->entries[0].name, \"lo\", sizeof(list->entries[0].name));\n   strlcpy(list->entries[0].host, \"127.0.0.1\", sizeof(list->entries[0].host));\n   list->size = 1;\n\n#if defined(HAVE_LIBNX)\n   {\n      Result rc = nifmGetCurrentIpAddress(&addr);\n\n      if (!R_SUCCEEDED(rc))\n         return true;\n   }\n#elif defined(_3DS)\n   addr = gethostid();\n#else\n   addr = net_gethostip();\n#endif\n   if (addr)\n   {\n      uint8_t *addr8 = (uint8_t*)&addr;\n      strlcpy(list->entries[1].name,\n#if defined(HAVE_LIBNX)\n         \"switch\"\n#elif defined(_3DS)\n         \"wlan\"\n#else\n         \"gekko\"\n#endif\n      , sizeof(list->entries[1].name));\n      snprintf(list->entries[1].host, sizeof(list->entries[1].host),\n         \"%d.%d.%d.%d\",\n         (int)addr8[0], (int)addr8[1], (int)addr8[2], (int)addr8[3]);\n      list->size++;\n   }\n\n   return true;\n#else\n   struct ifaddrs *addr;\n   struct net_ifinfo_entry *entry;\n   size_t         interfaces = 0;\n   struct ifaddrs *addresses = NULL;\n\n   list->entries             = NULL;\n\n   if (getifaddrs(&addresses) || !addresses)\n      goto failure;\n\n   /* Count the number of valid interfaces first. */\n   addr                      = addresses;\n\n   do\n   {\n      if (!addr->ifa_addr)\n         continue;\n#ifndef WIIU\n      if (!(addr->ifa_flags & IFF_UP))\n         continue;\n#endif\n\n      switch (addr->ifa_addr->sa_family)\n      {\n         case AF_INET:\n#ifdef HAVE_INET6\n         case AF_INET6:\n#endif\n            interfaces++;\n            break;\n         default:\n            break;\n      }\n   } while ((addr = addr->ifa_next));\n\n   if (!interfaces)\n      goto failure;\n\n   list->entries =\n      (struct net_ifinfo_entry*)calloc(interfaces, sizeof(*list->entries));\n   if (!list->entries)\n      goto failure;\n   list->size    = 0;\n\n   /* Now create the entries. */\n   addr  = addresses;\n   entry = list->entries;\n\n   do\n   {\n      socklen_t addrlen;\n\n      if (!addr->ifa_addr)\n         continue;\n#ifndef WIIU\n      if (!(addr->ifa_flags & IFF_UP))\n         continue;\n#endif\n\n      switch (addr->ifa_addr->sa_family)\n      {\n         case AF_INET:\n            addrlen = sizeof(struct sockaddr_in);\n            break;\n#ifdef HAVE_INET6\n         case AF_INET6:\n            addrlen = sizeof(struct sockaddr_in6);\n            break;\n#endif\n         default:\n            continue;\n      }\n\n      if (getnameinfo_retro(addr->ifa_addr, addrlen,\n            entry->host, sizeof(entry->host), NULL, 0, NI_NUMERICHOST))\n         continue;\n\n      if (addr->ifa_name)\n         strlcpy(entry->name, addr->ifa_name, sizeof(entry->name));\n\n      if (++list->size >= interfaces)\n         break;\n\n      entry++;\n   } while ((addr = addr->ifa_next));\n\n   freeifaddrs(addresses);\n\n   return true;\n\nfailure:\n   freeifaddrs(addresses);\n   net_ifinfo_free(list);\n\n   return false;\n#endif\n}\n\nvoid net_ifinfo_free(net_ifinfo_t *list)\n{\n   free(list->entries);\n\n   list->entries = NULL;\n   list->size    = 0;\n}\n\nbool net_ifinfo_best(const char *dst, void *src, bool ipv6)\n{\n/* TODO/FIXME: Implement for other platforms, if necessary. */\n#if defined(_WIN32) && !defined(_XBOX)\n   if (!ipv6)\n   {\n      /* Courtesy of MiniUPnP: https://github.com/miniupnp/miniupnp */\n      DWORD index;\n#ifdef __WINRT__\n      struct sockaddr_in dst_addr = {0};\n#endif\n      ULONG dst_ip               = (ULONG)inet_addr(dst);\n\n      if (!src)\n         return false;\n      if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY)\n         return false;\n\n#ifdef __WINRT__\n      dst_addr.sin_family      = AF_INET;\n      dst_addr.sin_addr.s_addr = dst_ip;\n      if (GetBestInterfaceEx((struct sockaddr*)&dst_addr, &index) == NO_ERROR)\n#else\n      if (GetBestInterface(dst_ip, &index) == NO_ERROR)\n#endif\n      {\n         /* Microsoft docs recommend doing it this way. */\n         ULONG                 len       = 15 * 1024;\n         PIP_ADAPTER_ADDRESSES addresses =\n            (PIP_ADAPTER_ADDRESSES)calloc(1, len);\n\n         if (addresses)\n         {\n            ULONG flags  = GAA_FLAG_SKIP_ANYCAST    | GAA_FLAG_SKIP_MULTICAST\n                         | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;\n            ULONG ret    = GetAdaptersAddresses(AF_INET, flags, NULL,\n               addresses, &len);\n\n            if (ret == ERROR_BUFFER_OVERFLOW)\n            {\n               PIP_ADAPTER_ADDRESSES new_addresses =\n                  (PIP_ADAPTER_ADDRESSES)realloc(addresses, len);\n\n               if (new_addresses)\n               {\n                  memset(new_addresses, 0, len);\n\n                  addresses = new_addresses;\n                  ret       = GetAdaptersAddresses(AF_INET, flags, NULL,\n                     addresses, &len);\n               }\n            }\n\n            if (ret == NO_ERROR)\n            {\n               bool found = false;\n               PIP_ADAPTER_ADDRESSES addr = addresses;\n\n               do\n               {\n                  if (addr->IfIndex == index)\n                  {\n                     if (addr->FirstUnicastAddress)\n                     {\n                        struct sockaddr_in *addr_unicast =\n                           (struct sockaddr_in*)\n                              addr->FirstUnicastAddress->Address.lpSockaddr;\n\n                        memcpy(src, &addr_unicast->sin_addr,\n                           sizeof(addr_unicast->sin_addr));\n\n                        found = true;\n                     }\n\n                     break;\n                  }\n               } while ((addr = addr->Next));\n               return found;\n            }\n\n            free(addresses);\n         }\n      }\n   }\n#endif\n   return false;\n}\n"
  },
  {
    "path": "net/net_socket.c",
    "content": "/* Copyright  (C) 2010-2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_socket.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#ifdef _MSC_VER\n#include <compat/msvc.h>\n#endif\n\n#include <features/features_cpu.h>\n\n#include <net/net_socket.h>\n\nint socket_init(void **address, uint16_t port, const char *server,\n      enum socket_type type, int family)\n{\n   char port_buf[6];\n   struct addrinfo hints      = {0};\n   struct addrinfo **addrinfo = (struct addrinfo**)address;\n   struct addrinfo *addr      = NULL;\n\n   if (!family)\n#if defined(HAVE_SOCKET_LEGACY) || defined(WIIU)\n      family = AF_INET;\n#else\n      family = AF_UNSPEC;\n#endif\n\n   hints.ai_family = family;\n\n   switch (type)\n   {\n      case SOCKET_TYPE_DATAGRAM:\n         hints.ai_socktype = SOCK_DGRAM;\n         break;\n      case SOCKET_TYPE_STREAM:\n         hints.ai_socktype = SOCK_STREAM;\n         break;\n      default:\n         return -1;\n   }\n\n   if (!server)\n      hints.ai_flags = AI_PASSIVE;\n\n   if (!network_init())\n      return -1;\n\n   snprintf(port_buf, sizeof(port_buf), \"%hu\", (unsigned short)port);\n   hints.ai_flags |= AI_NUMERICSERV;\n\n   if (getaddrinfo_retro(server, port_buf, &hints, addrinfo))\n      return -1;\n\n   addr = *addrinfo;\n   if (!addr)\n      return -1;\n\n   return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);\n}\n\nint socket_next(void **address)\n{\n   struct addrinfo **addrinfo = (struct addrinfo**)address;\n   struct addrinfo *addr      = *addrinfo;\n\n   if ((*addrinfo = addr = addr->ai_next))\n      return socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);\n\n   return -1;\n}\n\nssize_t socket_receive_all_nonblocking(int fd, bool *err,\n      void *data_, size_t len)\n{\n   ssize_t ret = recv(fd, (char*)data_, len, 0);\n   if (ret > 0)\n      return ret;\n   if (ret < 0 && isagain((int)ret))\n      return 0;\n   *err = true;\n   return -1;\n}\n\nbool socket_receive_all_blocking(int fd, void *data_, size_t len)\n{\n   const uint8_t *data = (const uint8_t*)data_;\n\n   while (len)\n   {\n      ssize_t ret = recv(fd, (char*)data, len, 0);\n\n      if (!ret)\n         return false;\n\n      if (ret < 0)\n      {\n         if (!isagain((int)ret))\n            return false;\n      }\n      else\n      {\n         data += ret;\n         len  -= ret;\n      }\n   }\n\n   return true;\n}\n\nbool socket_receive_all_blocking_with_timeout(int fd,\n      void *data_, size_t len, int timeout)\n{\n   const uint8_t *data    = (const uint8_t*)data_;\n   retro_time_t  deadline = cpu_features_get_time_usec();\n\n   if (timeout > 0)\n      deadline += (retro_time_t)timeout * 1000;\n   else\n      deadline += 5000000;\n\n   while (len)\n   {\n      ssize_t ret = recv(fd, (char*)data, len, 0);\n\n      if (!ret)\n         return false;\n\n      if (ret < 0)\n      {\n         int _timeout;\n         bool ready = true;\n\n         if (!isagain((int)ret))\n            return false;\n\n         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);\n         if (_timeout <= 0)\n            return false;\n\n         if (!socket_wait(fd, &ready, NULL, _timeout) || !ready)\n            return false;\n      }\n      else\n      {\n         data += ret;\n         len  -= ret;\n      }\n   }\n\n   return true;\n}\n\nbool socket_set_block(int fd, bool block)\n{\n#if defined(_WIN32)\n   u_long i = !block;\n\n   return !ioctlsocket(fd, FIONBIO, &i);\n#elif defined(__PS3__) || defined(VITA) || defined(WIIU)\n   int i = !block;\n\n   return !setsockopt(fd, SOL_SOCKET, SO_NBIO, &i, sizeof(i));\n#elif defined(GEKKO)\n   u32 i = !block;\n\n   return !net_ioctl(fd, FIONBIO, &i);\n#else\n   int flags = fcntl(fd, F_GETFL);\n\n   if (block)\n      flags &= ~O_NONBLOCK;\n   else\n      flags |= O_NONBLOCK;\n\n   return !fcntl(fd, F_SETFL, flags);\n#endif\n}\n\nbool socket_nonblock(int fd)\n{\n   return socket_set_block(fd, false);\n}\n\nint socket_close(int fd)\n{\n#if defined(_WIN32) && !defined(_XBOX360)\n   /* WinSock has headers from the stone age. */\n   return closesocket(fd);\n#elif defined(__PS3__) || defined(WIIU)\n   return socketclose(fd);\n#elif defined(VITA)\n   return sceNetSocketClose(fd);\n#else\n   return close(fd);\n#endif\n}\n\nint socket_select(int nfds, fd_set *readfds, fd_set *writefds,\n      fd_set *err_fds, struct timeval *timeout)\n{\n#if defined(__PS3__)\n   return socketselect(nfds, readfds, writefds, err_fds, timeout);\n#elif defined(VITA)\n   int i, j;\n   fd_set rfds, wfds, efds;\n   int epoll_fd;\n   SceNetEpollEvent *events     = NULL;\n   int              event_count = 0;\n   int              timeout_us  = -1;\n   int              ret         = -1;\n\n   if (nfds < 0 || nfds > 1024)\n      return SCE_NET_ERROR_EINVAL;\n   if (timeout && (timeout->tv_sec < 0 || timeout->tv_usec < 0))\n      return SCE_NET_ERROR_EINVAL;\n\n   epoll_fd = sceNetEpollCreate(\"socket_select\", 0);\n   if (epoll_fd < 0)\n      return SCE_NET_ERROR_ENOMEM;\n\n   FD_ZERO(&rfds);\n   FD_ZERO(&wfds);\n   FD_ZERO(&efds);\n\n   for (i = 0; i < nfds; i++)\n   {\n      if (readfds && FD_ISSET(i, readfds))\n         event_count++;\n      else if (writefds && FD_ISSET(i, writefds))\n         event_count++;\n      else if (err_fds && FD_ISSET(i, err_fds))\n         event_count++;\n   }\n\n#define ALLOC_EVENTS(count) \\\n   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \\\n   if (!events) \\\n   { \\\n      ret = SCE_NET_ERROR_ENOMEM; \\\n      goto done; \\\n   }\n\n   if (event_count)\n   {\n      ALLOC_EVENTS(event_count)\n\n      for (i = 0, j = 0; i < nfds && j < event_count; i++)\n      {\n         SceNetEpollEvent *event = &events[j];\n\n         if (readfds && FD_ISSET(i, readfds))\n            event->events |= SCE_NET_EPOLLIN;\n         if (writefds && FD_ISSET(i, writefds))\n            event->events |= SCE_NET_EPOLLOUT;\n\n         if (event->events || (err_fds && FD_ISSET(i, err_fds)))\n         {\n            event->data.fd = i;\n\n            ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,\n               i, event);\n            if (ret < 0)\n            {\n               switch (ret)\n               {\n                  case SCE_NET_ERROR_EBADF:\n                  case SCE_NET_ERROR_ENOMEM:\n                     break;\n                  default:\n                     ret = SCE_NET_ERROR_EBADF;\n                     break;\n               }\n               goto done;\n            }\n\n            j++;\n         }\n      }\n\n      memset(events, 0, event_count * sizeof(*events));\n\n      /* Keep a copy of the original sets for lookup later. */\n      if (readfds)\n         memcpy(&rfds, readfds, sizeof(rfds));\n      if (writefds)\n         memcpy(&wfds, writefds, sizeof(wfds));\n      if (err_fds)\n         memcpy(&efds, err_fds, sizeof(efds));\n   }\n   else\n   {\n      /* Necessary to work with epoll wait. */\n      event_count = 1;\n      ALLOC_EVENTS(1)\n   }\n\n#undef ALLOC_EVENTS\n\n   if (readfds)\n      FD_ZERO(readfds);\n   if (writefds)\n      FD_ZERO(writefds);\n   if (err_fds)\n      FD_ZERO(err_fds);\n\n   /* Vita's epoll takes a microsecond timeout parameter. */\n   if (timeout)\n      timeout_us = (int)(timeout->tv_usec + (timeout->tv_sec * 1000000));\n\n   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout_us);\n   if (ret <= 0)\n      goto done;\n\n#define EPOLL_FD_SET(op, in_set, out_set) \\\n   if ((event->events & (op)) && FD_ISSET(event->data.fd, (in_set))) \\\n   { \\\n      FD_SET(event->data.fd, (out_set)); \\\n      j++; \\\n   }\n\n   for (i = 0, j = 0; i < ret; i++)\n   {\n      SceNetEpollEvent *event = &events[i];\n\n      /* Sanity check */\n      if (event->data.fd < 0 || event->data.fd >= nfds)\n         continue;\n\n      EPOLL_FD_SET(SCE_NET_EPOLLIN,  &rfds, readfds)\n      EPOLL_FD_SET(SCE_NET_EPOLLOUT, &wfds, writefds)\n      EPOLL_FD_SET(SCE_NET_EPOLLERR, &efds, err_fds)\n   }\n\n   ret = j;\n\n#undef EPOLL_FD_SET\n\ndone:\n   free(events);\n   sceNetEpollDestroy(epoll_fd);\n\n   return ret;\n#else\n   return select(nfds, readfds, writefds, err_fds, timeout);\n#endif\n}\n\n#ifdef NETWORK_HAVE_POLL\nint socket_poll(struct pollfd *fds, unsigned nfds, int timeout)\n{\n#if defined(_WIN32)\n   return WSAPoll(fds, nfds, timeout);\n#elif defined(VITA)\n   int i, j;\n   int epoll_fd;\n   SceNetEpollEvent *events     = NULL;\n   int              event_count = (int)nfds;\n   int              ret         = -1;\n\n   if (event_count < 0)\n      return SCE_NET_ERROR_EINVAL;\n\n   epoll_fd = sceNetEpollCreate(\"socket_poll\", 0);\n   if (epoll_fd < 0)\n      return SCE_NET_ERROR_ENOMEM;\n\n#define ALLOC_EVENTS(count) \\\n   events = (SceNetEpollEvent*)calloc((count), sizeof(*events)); \\\n   if (!events) \\\n   { \\\n      ret = SCE_NET_ERROR_ENOMEM; \\\n      goto done; \\\n   }\n\n   if (event_count)\n   {\n      ALLOC_EVENTS(event_count)\n\n      for (i = 0; i < event_count; i++)\n      {\n         struct pollfd    *fd    = &fds[i];\n         SceNetEpollEvent *event = &events[i];\n\n         fd->revents = 0;\n\n         if (fd->fd < 0)\n            continue;\n\n         event->events  = fd->events;\n         event->data.fd = fd->fd;\n\n         ret = sceNetEpollControl(epoll_fd, SCE_NET_EPOLL_CTL_ADD,\n            fd->fd, event);\n         if (ret < 0)\n            goto done;\n      }\n\n      memset(events, 0, event_count * sizeof(*events));\n   }\n   else\n   {\n      /* Necessary to work with epoll wait. */\n      event_count = 1;\n      ALLOC_EVENTS(1)\n   }\n\n#undef ALLOC_EVENTS\n\n   /* Vita's epoll takes a microsecond timeout parameter. */\n   if (timeout > 0)\n      timeout *= 1000;\n\n   ret = sceNetEpollWait(epoll_fd, events, event_count, timeout);\n   if (ret <= 0)\n      goto done;\n\n   for (i = 0, j = 0; i < ret; i++)\n   {\n      unsigned k;\n      SceNetEpollEvent *event = &events[i];\n\n      /* Sanity check */\n      if (event->data.fd < 0)\n         continue;\n\n      for (k = 0; k < nfds; k++)\n      {\n         struct pollfd *fd = &fds[k];\n\n         if (fd->fd == event->data.fd)\n         {\n            fd->revents = event->events;\n            j++;\n            break;\n         }\n      }\n   }\n\n   ret = j;\n\ndone:\n   free(events);\n   sceNetEpollDestroy(epoll_fd);\n\n   return ret;\n#elif defined(_3DS)\n   int i;\n   int timeout_quotient;\n   int timeout_remainder;\n   int ret = -1;\n\n#define TIMEOUT_DIVISOR 100\n   if (timeout <= TIMEOUT_DIVISOR)\n      return poll(fds, nfds, timeout);\n\n   timeout_quotient = timeout / TIMEOUT_DIVISOR;\n   for (i = 0; i < timeout_quotient; i++)\n   {\n      ret = poll(fds, nfds, TIMEOUT_DIVISOR);\n      /* Success or error. */\n      if (ret)\n         return ret;\n   }\n\n   timeout_remainder = timeout % TIMEOUT_DIVISOR;\n   if (timeout_remainder)\n      ret = poll(fds, nfds, timeout_remainder);\n\n   return ret;\n#undef TIMEOUT_DIVISOR\n\n#elif defined(GEKKO)\n   return net_poll(fds, nfds, timeout);\n#else\n   return poll(fds, nfds, timeout);\n#endif\n}\n#endif\n\nbool socket_wait(int fd, bool *rd, bool *wr, int timeout)\n{\n#ifdef NETWORK_HAVE_POLL\n   struct pollfd fds = {0};\n\n   NET_POLL_FD(fd, &fds);\n\n   if (rd && *rd)\n   {\n      NET_POLL_EVENT(POLLIN, &fds);\n      *rd = false;\n   }\n   if (wr && *wr)\n   {\n      NET_POLL_EVENT(POLLOUT, &fds);\n      *wr = false;\n   }\n\n   if (socket_poll(&fds, 1, timeout) < 0)\n      return false;\n\n   if (rd && NET_POLL_HAS_EVENT(POLLIN, &fds))\n      *rd = true;\n   if (wr && NET_POLL_HAS_EVENT(POLLOUT, &fds))\n      *wr = true;\n\n   return !NET_POLL_HAS_EVENT((POLLERR | POLLNVAL), &fds);\n#else\n   fd_set rfd, wfd, efd;\n   struct timeval tv, *ptv = NULL;\n\n   FD_ZERO(&rfd);\n   FD_ZERO(&wfd);\n   FD_ZERO(&efd);\n\n   if (rd && *rd)\n   {\n      FD_SET(fd, &rfd);\n      *rd = false;\n   }\n   if (wr && *wr)\n   {\n      FD_SET(fd, &wfd);\n      *wr = false;\n   }\n   FD_SET(fd, &efd);\n\n   if (timeout >= 0)\n   {\n      tv.tv_sec  = (unsigned)timeout / 1000;\n      tv.tv_usec = ((unsigned)timeout % 1000) * 1000;\n      ptv = &tv;\n   }\n\n   if (socket_select(fd + 1, &rfd, &wfd, &efd, ptv) < 0)\n      return false;\n\n   if (rd && FD_ISSET(fd, &rfd))\n      *rd = true;\n   if (wr && FD_ISSET(fd, &wfd))\n      *wr = true;\n\n   return !FD_ISSET(fd, &efd);\n#endif\n}\n\nbool socket_send_all_blocking(int fd, const void *data_, size_t len,\n      bool no_signal)\n{\n   const uint8_t *data = (const uint8_t*)data_;\n   int           flags = no_signal ? MSG_NOSIGNAL : 0;\n\n   while (len)\n   {\n      ssize_t ret = send(fd, (const char*)data, len, flags);\n\n      if (!ret)\n         continue;\n\n      if (ret < 0)\n      {\n         if (!isagain((int)ret))\n            return false;\n      }\n      else\n      {\n         data += ret;\n         len  -= ret;\n      }\n   }\n\n   return true;\n}\n\nbool socket_send_all_blocking_with_timeout(int fd,\n      const void *data_, size_t len,\n      int timeout, bool no_signal)\n{\n   const uint8_t *data    = (const uint8_t*)data_;\n   int           flags    = no_signal ? MSG_NOSIGNAL : 0;\n   retro_time_t  deadline = cpu_features_get_time_usec();\n\n   if (timeout > 0)\n      deadline += (retro_time_t)timeout * 1000;\n   else\n      deadline += 5000000;\n\n   while (len)\n   {\n      ssize_t ret = send(fd, (const char*)data, len, flags);\n\n      if (!ret)\n         continue;\n\n      if (ret < 0)\n      {\n         int _timeout;\n         bool ready = true;\n\n         if (!isagain((int)ret))\n            return false;\n\n         _timeout = (int)((deadline - cpu_features_get_time_usec()) / 1000);\n         if (_timeout <= 0)\n            return false;\n\n         if (!socket_wait(fd, NULL, &ready, _timeout) || !ready)\n            return false;\n      }\n      else\n      {\n         data += ret;\n         len  -= ret;\n      }\n   }\n\n   return true;\n}\n\nssize_t socket_send_all_nonblocking(int fd, const void *data_, size_t len,\n      bool no_signal)\n{\n   const uint8_t *data = (const uint8_t*)data_;\n   int           flags = no_signal ? MSG_NOSIGNAL : 0;\n\n   while (len)\n   {\n      ssize_t ret = send(fd, (const char*)data, len, flags);\n\n      if (!ret)\n         break;\n\n      if (ret < 0)\n      {\n         if (isagain((int)ret))\n            break;\n\n         return -1;\n      }\n      else\n      {\n         data += ret;\n         len  -= ret;\n      }\n   }\n\n   return (ssize_t)((size_t)data - (size_t)data_);\n}\n\nbool socket_bind(int fd, void *data)\n{\n   struct addrinfo *addr = (struct addrinfo*)data;\n\n   {\n      int on = 1;\n\n      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,\n         (char*)&on, sizeof(on));\n   }\n\n   return !bind(fd, addr->ai_addr, addr->ai_addrlen);\n}\n\nint socket_connect(int fd, void *data)\n{\n   struct addrinfo *addr = (struct addrinfo*)data;\n\n#ifdef WIIU\n   {\n      int op = 1;\n\n      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));\n\n      if (addr->ai_socktype == SOCK_STREAM)\n      {\n         int recvsz = WIIU_RCVBUF;\n         int sendsz = WIIU_SNDBUF;\n\n         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));\n         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &op, sizeof(op));\n         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));\n         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));\n      }\n   }\n#endif\n\n   return connect(fd, addr->ai_addr, addr->ai_addrlen);\n}\n\nbool socket_connect_with_timeout(int fd, void *data, int timeout)\n{\n   int res;\n   struct addrinfo *addr = (struct addrinfo*)data;\n\n   if (!socket_nonblock(fd))\n      return false;\n\n#ifdef WIIU\n   {\n      int op = 1;\n\n      setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op));\n\n      if (addr->ai_socktype == SOCK_STREAM)\n      {\n         int recvsz = WIIU_RCVBUF;\n         int sendsz = WIIU_SNDBUF;\n\n         setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op));\n         setsockopt(fd, SOL_SOCKET, SO_RUSRBUF, &op, sizeof(op));\n         setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz));\n         setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz));\n      }\n   }\n#endif\n\n   res = connect(fd, addr->ai_addr, addr->ai_addrlen);\n   if (res)\n   {\n      bool ready = true;\n\n      if (!isinprogress(res) && !isagain(res))\n         return false;\n\n      if (timeout <= 0)\n         timeout = 5000;\n\n      if (!socket_wait(fd, NULL, &ready, timeout) || !ready)\n         return false;\n   }\n\n#if defined(GEKKO)\n   /* libogc does not have getsockopt implemented */\n   res = connect(fd, addr->ai_addr, addr->ai_addrlen);\n   if (res < 0 && -res != EISCONN)\n      return false;\n#elif defined(_3DS)\n   /* libctru getsockopt does not return expected value */\n   if ((connect(fd, addr->ai_addr, addr->ai_addrlen) < 0) && errno != EISCONN)\n      return false;\n#elif defined(WIIU)\n   /* On WiiU, getsockopt() returns -1 and sets lastsocketerr() (Wii's\n    * equivalent to errno) to 16. */\n   if ((connect(fd, addr->ai_addr, addr->ai_addrlen) == -1)\n         && socketlasterr() != SO_EISCONN)\n      return false;\n#else\n   {\n      int       err = -1;\n      socklen_t errsz = sizeof(err);\n\n      getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&err, &errsz);\n      if (err)\n         return false;\n   }\n#endif\n\n   return true;\n}\n\nint socket_create(\n      const char *name,\n      enum socket_domain   domain_type,\n      enum socket_type     socket_type,\n      enum socket_protocol protocol_type)\n{\n   int domain   = 0;\n   int type     = 0;\n   int protocol = 0;\n\n   switch (domain_type)\n   {\n      case SOCKET_DOMAIN_INET:\n         domain = AF_INET;\n         break;\n      default:\n         break;\n   }\n\n   switch (socket_type)\n   {\n      case SOCKET_TYPE_DATAGRAM:\n         type = SOCK_DGRAM;\n         break;\n      case SOCKET_TYPE_STREAM:\n         type = SOCK_STREAM;\n         break;\n      case SOCKET_TYPE_SEQPACKET:\n      default:\n         /* TODO/FIXME - implement */\n         break;\n   }\n\n   switch (protocol_type)\n   {\n      case SOCKET_PROTOCOL_TCP:\n         protocol = IPPROTO_TCP;\n         break;\n      case SOCKET_PROTOCOL_UDP:\n         protocol = IPPROTO_UDP;\n         break;\n      case SOCKET_PROTOCOL_NONE:\n      default:\n         break;\n   }\n\n#ifdef VITA\n   return sceNetSocket(name, domain, type, protocol);\n#else\n   return socket(domain, type, protocol);\n#endif\n}\n\nvoid socket_set_target(void *data, socket_target_t *in_addr)\n{\n   struct sockaddr_in *out_target = (struct sockaddr_in*)data;\n\n#ifdef GEKKO\n   out_target->sin_len          = 8;\n#endif\n   switch (in_addr->domain)\n   {\n      case SOCKET_DOMAIN_INET:\n         out_target->sin_family = AF_INET;\n         break;\n      default:\n         out_target->sin_family = 0;\n         break;\n   }\n   out_target->sin_port         = htons(in_addr->port);\n   inet_pton(AF_INET, in_addr->server, &out_target->sin_addr);\n}\n"
  },
  {
    "path": "net/net_socket_ssl_bear.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_socket.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <net/net_socket_ssl.h>\n#include <net/net_socket.h>\n#include <encodings/base64.h>\n#include <streams/file_stream.h>\n#include <string/stdstring.h>\n\n#include \"../../deps/bearssl-0.6/inc/bearssl.h\"\n\nstruct ssl_state\n{\n   int fd;\n   br_ssl_client_context sc;\n   br_x509_minimal_context xc;\n   uint8_t iobuf[BR_SSL_BUFSIZE_BIDI];\n};\n\n/* TODO/FIXME - static global variables */\nstatic br_x509_trust_anchor TAs[500] = {};\nstatic size_t TAs_NUM = 0;\n\nstatic uint8_t* current_vdn;\nstatic size_t current_vdn_size;\n/* Set by vdn_append when a realloc() fails during DN accumulation.\n * BearSSL's x509 decoder drives vdn_append as a void-returning\n * callback, so we have no failure channel to hand back mid-decode;\n * instead we latch this flag, skip further appends, and let\n * append_cert_x509 observe it after the decoder returns. */\nstatic bool current_vdn_failed;\n\nstatic uint8_t* blobdup(const void * src, size_t len)\n{\n   uint8_t *ret = (uint8_t*)malloc(len);\n   /* Pre-patch: no NULL check, so the next line memcpy'd into NULL\n    * on OOM and crashed.  Return NULL and make it the caller's\n    * problem - all three call sites below now propagate the NULL\n    * back out of append_cert_x509. */\n   if (!ret)\n      return NULL;\n   memcpy(ret, src, len);\n   return ret;\n}\nstatic void vdn_append(void* dest_ctx, const void * src, size_t len)\n{\n   uint8_t *tmp;\n   if (current_vdn_failed)\n      return;\n   /* Use a tmp pointer: the pre-patch form\n    *     current_vdn = (uint8_t*)realloc(current_vdn, ...)\n    * overwrote current_vdn with NULL on realloc failure, leaking\n    * the original buffer, and the subsequent memcpy then\n    * dereferenced NULL.  The callback signature is 'void' so we\n    * cannot signal to the decoder to stop - we just latch the\n    * flag and short-circuit subsequent invocations. */\n   if (!(tmp = (uint8_t*)realloc(current_vdn, current_vdn_size + len)))\n   {\n      current_vdn_failed = true;\n      return;\n   }\n   current_vdn = tmp;\n   memcpy(current_vdn + current_vdn_size, src, len);\n   current_vdn_size += len;\n}\n\nstatic bool append_cert_x509(void* x509, size_t len)\n{\n   br_x509_pkey* pk;\n   br_x509_decoder_context dc;\n   br_x509_trust_anchor* ta = &TAs[TAs_NUM];\n\n   current_vdn              = NULL;\n   current_vdn_size         = 0;\n   current_vdn_failed       = false;\n\n   br_x509_decoder_init(&dc, vdn_append, NULL);\n   br_x509_decoder_push(&dc, x509, len);\n\n   /* If any vdn_append realloc failed during decoding, whatever\n    * bytes we did accumulate in current_vdn are incomplete; drop\n    * the DN buffer and abandon this trust anchor. */\n   if (current_vdn_failed)\n   {\n      free(current_vdn);\n      return false;\n   }\n\n   pk                       = br_x509_decoder_get_pkey(&dc);\n   if (!pk || !br_x509_decoder_isCA(&dc))\n   {\n      /* Pre-existing leak: the original code returned here without\n       * freeing current_vdn.  Ownership had not yet been transferred\n       * to ta->dn.data, so the buffer was orphaned. */\n      free(current_vdn);\n      return false;\n   }\n\n   ta->dn.len               = current_vdn_size;\n   ta->dn.data              = current_vdn;\n   ta->flags                = BR_X509_TA_CA;\n\n   switch (pk->key_type)\n   {\n      case BR_KEYTYPE_RSA:\n         ta->pkey.key_type     = BR_KEYTYPE_RSA;\n         ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;\n         ta->pkey.key.rsa.n    = blobdup(pk->key.rsa.n, pk->key.rsa.nlen);\n         ta->pkey.key.rsa.elen = pk->key.rsa.elen;\n         ta->pkey.key.rsa.e    = blobdup(pk->key.rsa.e, pk->key.rsa.elen);\n         /* If either blobdup OOM'd, we cannot install a half-built\n          * trust anchor - BearSSL dereferences ta->pkey during\n          * every handshake against a cert that chains to this TA,\n          * and a NULL .n or .e is a crash. */\n         if (!ta->pkey.key.rsa.n || !ta->pkey.key.rsa.e)\n         {\n            free(ta->pkey.key.rsa.n);\n            free(ta->pkey.key.rsa.e);\n            free(current_vdn);\n            ta->pkey.key.rsa.n = NULL;\n            ta->pkey.key.rsa.e = NULL;\n            ta->dn.data        = NULL;\n            return false;\n         }\n         break;\n      case BR_KEYTYPE_EC:\n         ta->pkey.key_type     = BR_KEYTYPE_EC;\n         ta->pkey.key.ec.curve = pk->key.ec.curve;\n         ta->pkey.key.ec.qlen  = pk->key.ec.qlen;\n         ta->pkey.key.ec.q     = blobdup(pk->key.ec.q, pk->key.ec.qlen);\n         if (!ta->pkey.key.ec.q)\n         {\n            free(current_vdn);\n            ta->dn.data = NULL;\n            return false;\n         }\n         break;\n      default:\n         /* Pre-existing leak: same pattern as the '!pk || !isCA'\n          * early return above.  current_vdn was orphaned. */\n         free(current_vdn);\n         ta->dn.data = NULL;\n         return false;\n   }\n\n   TAs_NUM++;\n   return true;\n}\n\nstatic char* delete_linebreaks(char* in)\n{\n   char* iter_in;\n   char* iter_out;\n   while (*in == '\\n')\n      in++;\n\n   iter_in = in;\n\n   while (*iter_in != '\\n' && *iter_in != '\\0')\n      iter_in++;\n   iter_out = iter_in;\n   while (*iter_in != '\\0')\n   {\n      while (*iter_in == '\\n')\n         iter_in++;\n      *iter_out++ = *iter_in++;\n   }\n\n   return in;\n}\n\n/* this rearranges its input, it's easier to implement\n * that way and caller doesn't need it anymore anyways */\nstatic void append_certs_pem_x509(char * certs_pem)\n{\n   void * cert_bin;\n   int cert_bin_len;\n   char *cert     = certs_pem;\n   char *cert_end = certs_pem;\n\n   for (;;)\n   {\n      cert      = strstr(cert_end, \"-----BEGIN CERTIFICATE-----\");\n      if (!cert)\n         break;\n      cert     += STRLEN_CONST(\"-----BEGIN CERTIFICATE-----\");\n      cert_end  = strstr(cert, \"-----END CERTIFICATE-----\");\n\n      *cert_end = '\\0';\n      cert      = delete_linebreaks(cert);\n\n      cert_bin  = unbase64(cert, cert_end-cert, &cert_bin_len);\n      append_cert_x509(cert_bin, cert_bin_len);\n      free(cert_bin);\n\n      cert_end++; /* skip the NUL we just added */\n   }\n}\n\n/* TODO: not thread safe, rthreads doesn't provide any\n * statically allocatable mutex/etc */\nstatic void initialize(void)\n{\n   void* certs_pem;\n   if (TAs_NUM)\n      return;\n   /* filestream_read_file appends a NUL */\n   filestream_read_file(\"/etc/ssl/certs/ca-certificates.crt\", &certs_pem, NULL);\n   append_certs_pem_x509((char*)certs_pem);\n   free(certs_pem);\n}\n\nvoid* ssl_socket_init(int fd, const char *domain)\n{\n   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));\n\n   /* NULL-check before any of the br_ssl_* calls below dereference\n    * state.  The pre-patch form segfaulted on OOM at the first\n    * br_ssl_client_init_full(&state->sc, ...) call.  Caller\n    * (net_http.c line 1030) already NULL-checks our return. */\n   if (!state)\n      return NULL;\n\n   initialize();\n\n   br_ssl_client_init_full(&state->sc, &state->xc, TAs, TAs_NUM);\n   br_ssl_engine_set_buffer(&state->sc.eng,\n         state->iobuf, sizeof(state->iobuf), true);\n   br_ssl_client_reset(&state->sc, domain, false);\n\n   state->fd = fd;\n   return state;\n}\n\nstatic bool process_inner(struct ssl_state *state, bool blocking)\n{\n   bool dummy;\n   size_t buflen;\n   ssize_t bytes;\n   uint8_t *buf = br_ssl_engine_sendrec_buf(&state->sc.eng, &buflen);\n\n   if (buflen)\n   {\n      if (blocking)\n         bytes = (socket_send_all_blocking(state->fd, buf, buflen, true)\n               ? buflen\n               : -1);\n      else\n         bytes = socket_send_all_nonblocking(state->fd, buf, buflen, true);\n\n      if (bytes > 0)\n         br_ssl_engine_sendrec_ack(&state->sc.eng, bytes);\n      if (bytes < 0)\n         return false;\n      /* if we did something, return immediately so we\n       * don't try to read if Bear still wants to send */\n      return true;\n   }\n\n   buf = br_ssl_engine_recvrec_buf(&state->sc.eng, &buflen);\n   if (buflen)\n   {\n      /* if the socket is blocking, socket_receive_all_nonblocking blocks,\n       * but only to read at least 1 byte which is exactly what we want */\n      bytes = socket_receive_all_nonblocking(state->fd, &dummy, buf, buflen);\n      if (bytes > 0)\n         br_ssl_engine_recvrec_ack(&state->sc.eng, bytes);\n      if (bytes < 0)\n         return false;\n   }\n\n   return true;\n}\n\nint ssl_socket_connect(void *state_data,\n      void *data, bool timeout_enable, bool nonblock)\n{\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   unsigned bearstate;\n\n   if (timeout_enable)\n   {\n      if (!socket_connect_with_timeout(state->fd, data, 5000))\n         return -1;\n      /* socket_connect_with_timeout makes the socket non-blocking. */\n      if (!socket_set_block(state->fd, true))\n         return -1;\n   }\n   else\n   {\n      if (socket_connect(state->fd, data))\n         return -1;\n   }\n\n   for (;;)\n   {\n      if (!process_inner(state, true))\n         return -1;\n\n      bearstate = br_ssl_engine_current_state(&state->sc.eng);\n      if (bearstate & BR_SSL_SENDAPP)\n         break; /* handshake done */\n      if (bearstate & BR_SSL_CLOSED)\n         return -1; /* failed */\n   }\n\n   return 1;\n}\n\nssize_t ssl_socket_receive_all_nonblocking(void *state_data,\n      bool *err, void *data_, size_t len)\n{\n   size_t __len;\n   uint8_t *bear_data;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   socket_set_block(state->fd, false);\n   if (!process_inner(state, false))\n   {\n      *err = true;\n      return -1;\n   }\n   bear_data = br_ssl_engine_recvapp_buf(&state->sc.eng, &__len);\n   if (__len > len)\n      __len = len;\n   memcpy(data_, bear_data, __len);\n   if (__len)\n      br_ssl_engine_recvapp_ack(&state->sc.eng, __len);\n   return __len;\n}\n\nint ssl_socket_receive_all_blocking(void *state_data,\n      void *data_, size_t len)\n{\n   size_t __len;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   uint8_t           *data = (uint8_t*)data_;\n   uint8_t *         bear_data;\n\n   socket_set_block(state->fd, true);\n\n   for (;;)\n   {\n      bear_data = br_ssl_engine_recvapp_buf(&state->sc.eng, &__len);\n      if (__len > len)\n         __len = len;\n      memcpy(data, bear_data, __len);\n      if (__len)\n         br_ssl_engine_recvapp_ack(&state->sc.eng, __len);\n      data += __len;\n      len -= __len;\n\n      if (len)\n         process_inner(state, true);\n      else\n         break;\n   }\n   return 1;\n}\n\nint ssl_socket_send_all_blocking(void *state_data,\n      const void *data_, size_t len, bool no_signal)\n{\n   size_t __len;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   const     uint8_t *data = (const uint8_t*)data_;\n   uint8_t *         bear_data;\n\n   socket_set_block(state->fd, true);\n\n   for (;;)\n   {\n      bear_data = br_ssl_engine_sendapp_buf(&state->sc.eng, &__len);\n      if (__len > len)\n         __len = len;\n      memcpy(bear_data, data_, __len);\n      if (__len)\n         br_ssl_engine_sendapp_ack(&state->sc.eng, __len);\n      data += __len;\n      len  -= __len;\n\n      if (len)\n         process_inner(state, true);\n      else\n         break;\n   }\n\n   br_ssl_engine_flush(&state->sc.eng, false);\n   process_inner(state, false);\n   return 1;\n}\n\nssize_t ssl_socket_send_all_nonblocking(void *state_data,\n      const void *data_, size_t len, bool no_signal)\n{\n   size_t __len;\n   uint8_t *bear_data;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n\n   socket_set_block(state->fd, false);\n   bear_data = br_ssl_engine_sendapp_buf(&state->sc.eng, &__len);\n   if (__len > len)\n      __len = len;\n   memcpy(bear_data, data_, __len);\n   if (__len)\n   {\n      br_ssl_engine_sendapp_ack(&state->sc.eng, __len);\n      br_ssl_engine_flush(&state->sc.eng, false);\n   }\n   if (!process_inner(state, false))\n      return -1;\n   return __len;\n}\n\nvoid ssl_socket_close(void *state_data)\n{\n   struct ssl_state *state = (struct ssl_state*)state_data;\n\n   br_ssl_engine_close(&state->sc.eng);\n   process_inner(state, false); /* send close notification */\n   socket_close(state->fd);     /* but immediately close socket\n                                   and don't worry about recipient\n                                   getting our message */\n}\n\nvoid ssl_socket_free(void *state_data)\n{\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   /* BearSSL does zero allocations of its own,\n    * so other than this struct, there is nothing to free */\n   free(state);\n}\n"
  },
  {
    "path": "net/net_socket_ssl_mbed.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_socket.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n#include <net/net_compat.h>\n#include <net/net_socket.h>\n#include <net/net_socket_ssl.h>\n\n#ifdef _3DS\n#include <3ds/types.h>\n#include <3ds/services/ps.h>\n#endif\n\n#if defined(HAVE_BUILTINMBEDTLS)\n#include \"../../deps/mbedtls/mbedtls/config.h\"\n#include \"../../deps/mbedtls/mbedtls/certs.h\"\n#include \"../../deps/mbedtls/mbedtls/debug.h\"\n#include \"../../deps/mbedtls/mbedtls/platform.h\"\n#include \"../../deps/mbedtls/mbedtls/net_sockets.h\"\n#include \"../../deps/mbedtls/mbedtls/ssl.h\"\n#include \"../../deps/mbedtls/mbedtls/ctr_drbg.h\"\n#include \"../../deps/mbedtls/mbedtls/entropy.h\"\n#else\n#include <mbedtls/version.h>\n#if MBEDTLS_VERSION_MAJOR < 3\n#include <mbedtls/config.h>\n#include <mbedtls/certs.h>\n#else\n#include <mbedtls/build_info.h>\n#endif\n#include <mbedtls/debug.h>\n#include <mbedtls/platform.h>\n#include <mbedtls/net_sockets.h>\n#include <mbedtls/ssl.h>\n#include <mbedtls/ctr_drbg.h>\n#include <mbedtls/entropy.h>\n#endif\n\n/* Not part of the mbedtls upstream source */\n#include \"cacert.h\"\n\n#define DEBUG_LEVEL 0\n\nstruct ssl_state\n{\n   mbedtls_net_context net_ctx;\n   mbedtls_ssl_context ctx;\n   mbedtls_entropy_context entropy;\n   mbedtls_ctr_drbg_context ctr_drbg;\n   mbedtls_ssl_config conf;\n#if defined(MBEDTLS_X509_CRT_PARSE_C)\n   mbedtls_x509_crt ca;\n#endif\n  const char *domain;\n};\n\nstatic void ssl_debug(void *ctx, int level,\n      const char *file, int line,\n      const char *str)\n{\n   fprintf((FILE*)ctx, \"%s:%04d: %s\", file, line, str);\n   fflush((FILE*)ctx);\n}\n\n#ifdef _3DS\nint ctr_entropy_func(void *data, unsigned char *s, size_t len)\n{\n   (void)data;\n   PS_GenerateRandomBytes(s, len);\n   return 0;\n}\n#endif\n\nvoid* ssl_socket_init(int fd, const char *domain)\n{\n   static const char *pers = \"libretro\";\n   struct ssl_state *state = (struct ssl_state*)calloc(1, sizeof(*state));\n\n   /* NULL-check before 'state->domain = domain' on the next line\n    * dereferences state.  Sibling bug in net_socket_ssl_bear.c's\n    * ssl_socket_init was fixed in the previous commit; applying\n    * the same fix here. */\n   if (!state)\n      return NULL;\n\n   state->domain           = domain;\n\n#if defined(MBEDTLS_DEBUG_C)\n   mbedtls_debug_set_threshold(DEBUG_LEVEL);\n#endif\n\n   mbedtls_net_init(&state->net_ctx);\n   mbedtls_ssl_init(&state->ctx);\n   mbedtls_ssl_config_init(&state->conf);\n#if defined(MBEDTLS_X509_CRT_PARSE_C)\n   mbedtls_x509_crt_init(&state->ca);\n#endif\n   mbedtls_ctr_drbg_init(&state->ctr_drbg);\n   mbedtls_entropy_init(&state->entropy);\n\n   state->net_ctx.fd = fd;\n\n   if (mbedtls_ctr_drbg_seed(&state->ctr_drbg,\n#ifdef _3DS\n      ctr_entropy_func,\n#else\n      mbedtls_entropy_func,\n#endif\n      &state->entropy, (const unsigned char*)pers, strlen(pers)) != 0)\n      goto error;\n\n#if defined(MBEDTLS_X509_CRT_PARSE_C)\n   if (mbedtls_x509_crt_parse(&state->ca, (const unsigned char*)cacert_pem, sizeof(cacert_pem) / sizeof(cacert_pem[0])) < 0)\n      goto error;\n#endif\n\n   return state;\n\nerror:\n   /* Pair each non-trivial _init call above (lines 112-118) with\n    * its matching _free.  Pre-patch only free(state) was called,\n    * leaking the five mbedtls sub-context heap allocations that\n    * the _init / _free functions internally manage (entropy\n    * pool buffers, DRBG state buffers, SSL context buffers,\n    * config buffers, X509 chain).\n    *\n    * Mirrors the normal-teardown path in ssl_socket_free below\n    * (lines 355-361) in reverse of init order.  mbedtls_net_free\n    * is intentionally not called for net_ctx (line 111):\n    *   - init sets state->net_ctx.fd from the caller's fd\n    *     parameter at line 120, and the caller still owns that\n    *     fd on this error exit.\n    *   - ssl_socket_free similarly never calls mbedtls_net_free;\n    *     it just socket_close's the fd via ssl_socket_close at\n    *     line 345.\n    *\n    * The if (state) guard is redundant - the state calloc is\n    * NULL-checked at line 102 so we can't reach this label with\n    * state == NULL - but leave it to keep the diff minimal. */\n   if (state)\n   {\n      mbedtls_entropy_free(&state->entropy);\n      mbedtls_ctr_drbg_free(&state->ctr_drbg);\n#if defined(MBEDTLS_X509_CRT_PARSE_C)\n      mbedtls_x509_crt_free(&state->ca);\n#endif\n      mbedtls_ssl_config_free(&state->conf);\n      mbedtls_ssl_free(&state->ctx);\n      free(state);\n   }\n   return NULL;\n}\n\nint ssl_socket_connect(void *state_data,\n      void *data, bool timeout_enable, bool nonblock)\n{\n   int ret, flags;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n\n   if (timeout_enable)\n   {\n      if (!socket_connect_with_timeout(state->net_ctx.fd, data, 5000))\n         return -1;\n      /* socket_connect_with_timeout makes the socket non-blocking. */\n      if (!socket_set_block(state->net_ctx.fd, true))\n         return -1;\n   }\n   else\n   {\n      if (socket_connect(state->net_ctx.fd, data))\n         return -1;\n   }\n\n   if (mbedtls_ssl_config_defaults(&state->conf,\n               MBEDTLS_SSL_IS_CLIENT,\n               MBEDTLS_SSL_TRANSPORT_STREAM,\n               MBEDTLS_SSL_PRESET_DEFAULT) != 0)\n      return -1;\n\n   mbedtls_ssl_conf_authmode(&state->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);\n   mbedtls_ssl_conf_ca_chain(&state->conf, &state->ca, NULL);\n   mbedtls_ssl_conf_rng(&state->conf, mbedtls_ctr_drbg_random, &state->ctr_drbg);\n   mbedtls_ssl_conf_dbg(&state->conf, ssl_debug, stderr);\n\n   if (mbedtls_ssl_setup(&state->ctx, &state->conf) != 0)\n      return -1;\n\n#if defined(MBEDTLS_X509_CRT_PARSE_C)\n   if (mbedtls_ssl_set_hostname(&state->ctx, state->domain) != 0)\n      return -1;\n#endif\n\n   mbedtls_ssl_set_bio(&state->ctx, &state->net_ctx, mbedtls_net_send, mbedtls_net_recv, NULL);\n\n   while ((ret = mbedtls_ssl_handshake(&state->ctx)) != 0)\n   {\n      if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)\n         return -1;\n   }\n\n   if ((flags = mbedtls_ssl_get_verify_result(&state->ctx)) != 0)\n   {\n      char vrfy_buf[512];\n      mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), \"  ! \", flags);\n   }\n\n   return state->net_ctx.fd;\n}\n\nssize_t ssl_socket_receive_all_nonblocking(void *state_data,\n      bool *err, void *data_, size_t len)\n{\n   ssize_t ret;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   unsigned char     *data = (unsigned char*)data_;\n   size_t       total_read = 0;\n   int      max_iterations = 8;  /* Limit iterations to prevent infinite loops */\n\n   mbedtls_net_set_nonblock(&state->net_ctx);\n\n   /* Keep reading while we get data without blocking, up to max iterations\n    * This allows us to read multiple TLS records (16KB each) in one call */\n   while (len > 0 && max_iterations-- > 0)\n   {\n      ret = mbedtls_ssl_read(&state->ctx, data, len);\n\n      if (ret > 0)\n      {\n         total_read += ret;\n         data += ret;\n         len -= ret;\n\n         /* If we read less than requested, there's likely no more data available\n          * But check if there's buffered data we can read without blocking */\n         if ((size_t)ret < len)\n         {\n            size_t bytes_avail = mbedtls_ssl_get_bytes_avail(&state->ctx);\n            if (bytes_avail == 0)\n\n               break;  /* No more buffered data, don't risk blocking */\n         }\n         /* Continue looping to read more records */\n      }\n      else if (ret == 0)\n      {\n         /* Socket closed */\n         if (total_read > 0)\n            return total_read;  /* Return what we got before close */\n         *err = true;\n         return -1;\n      }\n      else if (isagain((int)ret) || ret == MBEDTLS_ERR_SSL_WANT_READ)\n      {\n         /* Would block - return what we have so far */\n         if (total_read > 0)\n            return total_read;\n         return 0;  /* No data available yet */\n      }\n      else\n      {\n         /* Error */\n         if (total_read > 0)\n            return total_read;  /* Return what we got before error */\n         *err = true;\n         return -1;\n      }\n   }\n\n   return total_read;\n}\n\nint ssl_socket_receive_all_blocking(void *state_data,\n      void *data_, size_t len)\n{\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   const uint8_t     *data = (const uint8_t*)data_;\n\n   mbedtls_net_set_block(&state->net_ctx);\n\n   for (;;)\n   {\n      /* mbedtls_ssl_read wants non-const data but it only reads it,\n       * so this cast is safe */\n      int ret = mbedtls_ssl_read(&state->ctx, (unsigned char*)data, len);\n\n      if (     ret == MBEDTLS_ERR_SSL_WANT_READ\n            || ret == MBEDTLS_ERR_SSL_WANT_WRITE)\n         continue;\n\n      if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)\n         break;\n\n      if (ret == 0)\n         break; /* normal EOF */\n\n      if (ret < 0)\n         return -1;\n   }\n\n   return 1;\n}\n\nint ssl_socket_send_all_blocking(void *state_data,\n      const void *data_, size_t len, bool no_signal)\n{\n   int ret;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   const     uint8_t *data = (const uint8_t*)data_;\n\n   mbedtls_net_set_block(&state->net_ctx);\n\n   while (len)\n   {\n      ret = mbedtls_ssl_write(&state->ctx, data, len);\n\n      if (!ret)\n         continue;\n\n      if (ret < 0)\n      {\n         if (  ret != MBEDTLS_ERR_SSL_WANT_READ &&\n              ret != MBEDTLS_ERR_SSL_WANT_WRITE)\n            return false;\n      }\n      else\n      {\n          data += ret;\n          len  -= ret;\n      }\n   }\n\n   return true;\n}\n\nssize_t ssl_socket_send_all_nonblocking(void *state_data,\n      const void *data_, size_t len, bool no_signal)\n{\n   int ret;\n   ssize_t __len = len;\n   struct ssl_state *state = (struct ssl_state*)state_data;\n   const uint8_t     *data = (const uint8_t*)data_;\n   mbedtls_net_set_nonblock(&state->net_ctx);\n   ret = mbedtls_ssl_write(&state->ctx, data, len);\n   if (ret <= 0)\n      return -1;\n   return __len;\n}\n\nvoid ssl_socket_close(void *state_data)\n{\n   struct ssl_state *state = (struct ssl_state*)state_data;\n\n   mbedtls_ssl_close_notify(&state->ctx);\n\n   socket_close(state->net_ctx.fd);\n}\n\nvoid ssl_socket_free(void *state_data)\n{\n   struct ssl_state *state = (struct ssl_state*)state_data;\n\n   if (!state)\n      return;\n\n   mbedtls_ssl_free(&state->ctx);\n   mbedtls_ssl_config_free(&state->conf);\n   mbedtls_ctr_drbg_free(&state->ctr_drbg);\n   mbedtls_entropy_free(&state->entropy);\n#if defined(MBEDTLS_X509_CRT_PARSE_C)\n   mbedtls_x509_crt_free(&state->ca);\n#endif\n\n   free(state);\n}\n"
  },
  {
    "path": "playlists/label_sanitization.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (label_sanitization.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n\n#include <compat/strl.h>\n#include <retro_miscellaneous.h>\n#include <playlists/label_sanitization.h>\n\n#define DISC_STRINGS_LENGTH   5\n#define REGION_STRINGS_LENGTH 20\n\nconst char *disc_strings[DISC_STRINGS_LENGTH] = {\n   \"(CD\",\n   \"(Disc\",\n   \"(Disk\",\n   \"(Side\",\n   \"(Tape\"\n};\n\n/*\n * We'll use the standard No-Intro regions for now.\n */\nconst char *region_strings[REGION_STRINGS_LENGTH] = {\n   \"(Australia)\", /* Don’t use with Europe */\n   \"(Brazil)\",\n   \"(Canada)\",    /* Don’t use with USA */\n   \"(China)\",\n   \"(France)\",\n   \"(Germany)\",\n   \"(Hong Kong)\",\n   \"(Italy)\",\n   \"(Japan)\",\n   \"(Korea)\",\n   \"(Netherlands)\",\n   \"(Spain)\",\n   \"(Sweden)\",\n   \"(USA)\",       /* Includes Canada */\n   \"(World)\",\n   \"(Europe)\",    /* Includes Australia */\n   \"(Asia)\",\n   \"(Japan, USA)\",\n   \"(Japan, Europe)\",\n   \"(USA, Europe)\"\n};\n\n/**\n * label_sanitize:\n *\n * NOTE: Does not work with nested blocks.\n **/\nvoid label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*))\n{\n   bool copy = true;\n   int rindex = 0;\n   int lindex = 0;\n   char new_label[PATH_MAX_LENGTH];\n\n   for (; lindex < PATH_MAX_LENGTH && label[lindex] != '\\0'; lindex++)\n   {\n      if (copy)\n      {\n         /* check for the start of the range */\n         if ((*left)(&label[lindex]))\n            copy                = false;\n         else\n         {\n            const bool whitespace = label[lindex] == ' ' && (rindex == 0 || new_label[rindex - 1] == ' ');\n\n            /* Simplify consecutive whitespaces */\n            if (!whitespace)\n               new_label[rindex++] = label[lindex];\n         }\n      }\n      else if ((*right)(&label[lindex]))\n         copy = true;\n   }\n\n   /* Trim trailing whitespace */\n   if (rindex > 0 && new_label[rindex - 1] == ' ')\n      new_label[rindex - 1] = '\\0';\n   else\n      new_label[rindex] = '\\0';\n\n   strlcpy(label, new_label, PATH_MAX_LENGTH);\n}\n\nstatic bool left_parens(char *left)\n{\n   return left[0] == '(';\n}\n\nstatic bool right_parens(char *right)\n{\n   return right[0] == ')';\n}\n\nstatic bool left_brackets(char *left)\n{\n   return left[0] == '[';\n}\n\nstatic bool right_brackets(char *right)\n{\n   return right[0] == ']';\n}\n\nstatic bool left_parens_or_brackets(char *left)\n{\n   return left[0] == '(' || left[0] == '[';\n}\n\nstatic bool right_parens_or_brackets(char *right)\n{\n   return right[0] == ')' || right[0] == ']';\n}\n\nstatic bool left_exclusion(char *left,\n      const char **strings, const size_t strings_count)\n{\n   unsigned i;\n   for (i = 0; i < (unsigned)strings_count; i++)\n   {\n      if (left && strings[i]\n            && !strncasecmp(left, strings[i], strlen(strings[i])))\n         return true;\n   }\n   return false;\n}\n\nstatic bool left_parens_or_brackets_excluding_region(char *left)\n{\n   return left_parens_or_brackets(left)\n      && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH);\n}\n\nstatic bool left_parens_or_brackets_excluding_disc(char *left)\n{\n   return left_parens_or_brackets(left)\n      && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);\n}\n\nstatic bool left_parens_or_brackets_excluding_region_or_disc(char *left)\n{\n   return left_parens_or_brackets(left)\n      && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH)\n      && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);\n}\n\nvoid label_remove_parens(char *label)\n{\n   label_sanitize(label, left_parens, right_parens);\n}\n\nvoid label_remove_brackets(char *label)\n{\n   label_sanitize(label, left_brackets, right_brackets);\n}\n\nvoid label_remove_parens_and_brackets(char *label)\n{\n   label_sanitize(label, left_parens_or_brackets,\n         right_parens_or_brackets);\n}\n\nvoid label_keep_region(char *label)\n{\n   label_sanitize(label, left_parens_or_brackets_excluding_region,\n         right_parens_or_brackets);\n}\n\nvoid label_keep_disc(char *label)\n{\n   label_sanitize(label, left_parens_or_brackets_excluding_disc,\n         right_parens_or_brackets);\n}\n\nvoid label_keep_region_and_disc(char *label)\n{\n   label_sanitize(label, left_parens_or_brackets_excluding_region_or_disc,\n         right_parens_or_brackets);\n}\n"
  },
  {
    "path": "queues/fifo_queue.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fifo_queue.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_common_api.h>\n#include <retro_inline.h>\n#include <boolean.h>\n\n#include <queues/fifo_queue.h>\n\nstatic bool fifo_initialize_internal(fifo_buffer_t *buf, size_t len)\n{\n   uint8_t *buffer    = (uint8_t*)calloc(1, len + 1);\n\n   if (!buffer)\n      return false;\n\n   buf->buffer        = buffer;\n   buf->size          = len + 1;\n   buf->first         = 0;\n   buf->end           = 0;\n\n   return true;\n}\n\nbool fifo_initialize(fifo_buffer_t *buf, size_t len)\n{\n   return (buf && fifo_initialize_internal(buf, len));\n}\n\nvoid fifo_free(fifo_buffer_t *buffer)\n{\n   if (!buffer)\n      return;\n\n   free(buffer->buffer);\n   free(buffer);\n}\n\nbool fifo_deinitialize(fifo_buffer_t *buffer)\n{\n   if (!buffer)\n      return false;\n\n   if (buffer->buffer)\n      free(buffer->buffer);\n   buffer->buffer = NULL;\n   buffer->size   = 0;\n   buffer->first  = 0;\n   buffer->end    = 0;\n\n   return true;\n}\n\nfifo_buffer_t *fifo_new(size_t len)\n{\n   fifo_buffer_t *buf = (fifo_buffer_t*)malloc(sizeof(*buf));\n\n   if (!buf)\n      return NULL;\n\n   if (!fifo_initialize_internal(buf, len))\n   {\n      free(buf);\n      return NULL;\n   }\n\n   return buf;\n}\n\nvoid fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t len)\n{\n   size_t first_write = len;\n   size_t rest_write  = 0;\n\n   if (buffer->end + len > buffer->size)\n   {\n      first_write = buffer->size - buffer->end;\n      rest_write  = len - first_write;\n   }\n\n   memcpy(buffer->buffer + buffer->end, in_buf, first_write);\n   if (rest_write > 0)\n      memcpy(buffer->buffer, (const uint8_t*)in_buf + first_write, rest_write);\n\n   buffer->end = (buffer->end + len) % buffer->size;\n}\n\nvoid fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t len)\n{\n   size_t first_read = len;\n   size_t rest_read  = 0;\n\n   if (buffer->first + len > buffer->size)\n   {\n      first_read = buffer->size - buffer->first;\n      rest_read  = len - first_read;\n   }\n\n   memcpy(in_buf, (const uint8_t*)buffer->buffer + buffer->first, first_read);\n   if (rest_read > 0)\n      memcpy((uint8_t*)in_buf + first_read, buffer->buffer, rest_read);\n\n   buffer->first = (buffer->first + len) % buffer->size;\n}\n"
  },
  {
    "path": "queues/generic_queue.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (generic_queue.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <boolean.h>\n#include <stddef.h>\n#include <stdlib.h>\n\n#include <queues/generic_queue.h>\n\nstruct generic_queue_item_t\n{\n   void *value;\n   struct generic_queue_item_t *previous;\n   struct generic_queue_item_t *next;\n};\n\nstruct generic_queue\n{\n   struct generic_queue_item_t *first_item;\n   struct generic_queue_item_t *last_item;\n   size_t length;\n};\n\nstruct generic_queue_iterator\n{\n   generic_queue_t *queue;\n   struct generic_queue_item_t *item;\n   bool forward;\n};\n\ngeneric_queue_t *generic_queue_new(void)\n{\n   return (generic_queue_t *)calloc(1, sizeof(generic_queue_t));\n}\n\nvoid generic_queue_free(generic_queue_t *queue, void (*free_value)(void *value))\n{\n   struct generic_queue_item_t *next_item;\n\n   if (!queue)\n      return;\n\n   while (queue->first_item)\n   {\n      if (free_value)\n         free_value(queue->first_item->value);\n\n      next_item = queue->first_item->next;\n      free(queue->first_item);\n      queue->first_item = next_item;\n   }\n\n   free(queue);\n}\n\nvoid generic_queue_push(generic_queue_t *queue, void *value)\n{\n   struct generic_queue_item_t *new_item;\n\n   /* NULL-check queue: the sibling generic_queue_shift does this\n    * too, but _push was missing it.  new_item->previous = queue->\n    * last_item on a NULL queue would segfault. */\n   if (!queue)\n      return;\n\n   /* NULL-check calloc: the subsequent new_item->value / ->previous\n    * / ->next assignments would all segfault on OOM.  The function\n    * returns void, so we can't signal failure to the caller; a\n    * silent no-op on OOM is the only option.  length stays\n    * unchanged, which keeps the length/first_item/last_item\n    * invariant consistent. */\n   if (!(new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t))))\n      return;\n\n   new_item->value = value;\n   new_item->previous = queue->last_item;\n   new_item->next = NULL;\n\n   queue->last_item = new_item;\n   queue->length++;\n\n   if (!queue->first_item)\n      queue->first_item = new_item;\n   else\n      new_item->previous->next = new_item;\n}\n\nvoid *generic_queue_pop(generic_queue_t *queue)\n{\n   void *value;\n   struct generic_queue_item_t *item;\n\n   if (!queue || !queue->last_item)\n      return NULL;\n\n   item = queue->last_item;\n   queue->last_item = queue->last_item->previous;\n   queue->length--;\n\n   if (queue->length == 0)\n      queue->first_item = NULL;\n\n   value = item->value;\n   free(item);\n\n   return value;\n}\n\nvoid *generic_queue_peek(generic_queue_t *queue)\n{\n   if (!queue || !queue->last_item)\n      return NULL;\n\n   return queue->last_item->value;\n}\n\nvoid *generic_queue_peek_first(generic_queue_t *queue)\n{\n   if (!queue || !queue->first_item)\n      return NULL;\n\n   return queue->first_item->value;\n}\n\nvoid generic_queue_shift(generic_queue_t *queue, void *value)\n{\n   struct generic_queue_item_t *new_item;\n\n   if (!queue)\n      return;\n\n   /* NULL-check calloc: the subsequent field writes would all\n    * segfault on OOM.  Same silent-no-op-on-OOM approach as\n    * generic_queue_push.  length and the first_item/last_item\n    * invariant stay consistent because we return before touching\n    * either. */\n   if (!(new_item = (struct generic_queue_item_t *)calloc(1, sizeof(struct generic_queue_item_t))))\n      return;\n\n   new_item->value = value;\n   new_item->previous = NULL;\n   new_item->next = queue->first_item;\n\n   queue->first_item = new_item;\n   queue->length++;\n\n   if (!queue->last_item)\n      queue->last_item = new_item;\n   else\n      new_item->next->previous = new_item;\n}\n\nvoid *generic_queue_unshift(generic_queue_t *queue)\n{\n   void *value;\n   struct generic_queue_item_t *item;\n\n   if (!queue || !queue->first_item)\n      return NULL;\n\n   item = queue->first_item;\n   queue->first_item = queue->first_item->next;\n   queue->length--;\n\n   if (queue->length == 0)\n      queue->last_item = NULL;\n\n   value = item->value;\n   free(item);\n\n   return value;\n}\n\nsize_t generic_queue_length(generic_queue_t *queue)\n{\n   if (queue)\n      return queue->length;\n\n   return 0;\n}\n\nvoid *generic_queue_remove(generic_queue_t *queue, void *value)\n{\n   struct generic_queue_item_t *item;\n\n   if (!queue)\n      return NULL;\n\n   for (item = queue->first_item; item; item = item->next)\n   {\n      if (item->value == value)\n      {\n         if (item->previous)\n            item->previous->next = item->next;\n         else\n            queue->first_item = item->next;\n\n         if (item->next)\n            item->next->previous = item->previous;\n         else\n            queue->last_item = item->previous;\n\n         free(item);\n         queue->length--;\n\n         return value;\n      }\n   }\n\n   return NULL;\n}\n\ngeneric_queue_iterator_t *generic_queue_iterator(generic_queue_t *queue, bool forward)\n{\n   if (queue && queue->first_item)\n   {\n      generic_queue_iterator_t *iterator;\n\n      /* NULL-check malloc: the three field writes below would\n       * segfault on OOM.  The function already returns NULL for\n       * the empty-queue / NULL-queue case below, so returning\n       * NULL on OOM is consistent with the existing contract. */\n      if (!(iterator = (generic_queue_iterator_t *)malloc(sizeof(generic_queue_iterator_t))))\n         return NULL;\n\n      iterator->queue = queue;\n      iterator->item = forward ? queue->first_item : queue->last_item;\n      iterator->forward = forward;\n\n      return iterator;\n   }\n\n   return NULL;\n}\n\ngeneric_queue_iterator_t *generic_queue_iterator_next(generic_queue_iterator_t *iterator)\n{\n   if (iterator)\n   {\n      struct generic_queue_item_t *item;\n\n      item = iterator->forward ? iterator->item->next : iterator->item->previous;\n      if (item)\n      {\n         iterator->item = item;\n         return iterator;\n      } else\n      {\n         free(iterator);\n         return NULL;\n      }\n   }\n\n   return NULL;\n}\n\nvoid *generic_queue_iterator_value(generic_queue_iterator_t *iterator)\n{\n   if (iterator)\n      return iterator->item->value;\n\n   return NULL;\n}\n\ngeneric_queue_iterator_t *generic_queue_iterator_remove(generic_queue_iterator_t *iterator)\n{\n   struct generic_queue_item_t *item;\n\n   if (!iterator)\n      return NULL;\n\n   item = iterator->forward ? iterator->queue->first_item : iterator->queue->last_item;\n   while (item)\n   {\n      if (iterator->item == item)\n      {\n         if (iterator->queue->first_item == item)\n            iterator->queue->first_item = item->next;\n         else\n            item->previous->next = item->next;\n\n         if (iterator->queue->last_item == item)\n            iterator->queue->last_item = item->previous;\n         else\n            item->next->previous = item->previous;\n\n         iterator->queue->length--;\n\n         iterator->item = iterator->forward ? item->next : item->previous;\n         free(item);\n         if (iterator->item)\n            return iterator;\n         free(iterator);\n         return NULL;\n      }\n\n      item = iterator->forward ? item->next : item->previous;\n   }\n\n   return iterator;\n}\n\nvoid generic_queue_iterator_free(generic_queue_iterator_t *iterator)\n{\n   if (iterator)\n      free(iterator);\n}\n"
  },
  {
    "path": "queues/message_queue.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (message_queue.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <boolean.h>\n#include <queues/message_queue.h>\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n\nbool msg_queue_initialize(msg_queue_t *queue, size_t len)\n{\n   struct queue_elem **elems = NULL;\n\n   if (!queue)\n      return false;\n\n   if (!(elems = (struct queue_elem**)\n            calloc(len + 1, sizeof(struct queue_elem*))))\n      return false;\n\n   queue->tmp_msg            = NULL;\n   queue->elems              = elems;\n   queue->ptr                = 1;\n   queue->size               = len + 1;\n\n   return true;\n}\n\n/**\n * msg_queue_new:\n * @len              : maximum size of message\n *\n * Creates a message queue with maximum size different messages.\n *\n * Returns: NULL if allocation error, pointer to a message queue\n * if successful. Has to be freed manually.\n **/\nmsg_queue_t *msg_queue_new(size_t len)\n{\n   msg_queue_t *queue = (msg_queue_t*)malloc(sizeof(*queue));\n\n   if (!msg_queue_initialize(queue, len))\n   {\n      if (queue)\n         free(queue);\n      return NULL;\n   }\n\n   return queue;\n}\n\n/**\n * msg_queue_free:\n * @queue             : pointer to queue object\n *\n * Frees message queue..\n **/\nvoid msg_queue_free(msg_queue_t *queue)\n{\n   if (!queue)\n      return;\n   msg_queue_clear(queue);\n   free(queue->elems);\n   free(queue);\n}\n\nbool msg_queue_deinitialize(msg_queue_t *queue)\n{\n   if (!queue)\n      return false;\n   msg_queue_clear(queue);\n   free(queue->elems);\n   queue->elems   = NULL;\n   queue->tmp_msg = NULL;\n   queue->ptr     = 0;\n   queue->size    = 0;\n   return true;\n}\n\n/**\n * msg_queue_push:\n * @queue             : pointer to queue object\n * @msg               : message to add to the queue\n * @prio              : priority level of the message\n * @duration          : how many times the message can be pulled\n *                      before it vanishes (E.g. show a message for\n *                      3 seconds @ 60fps = 180 duration).\n *\n * Push a new message onto the queue.\n **/\nvoid msg_queue_push(msg_queue_t *queue, const char *msg,\n      unsigned prio, unsigned duration,\n      char *title,\n      enum message_queue_icon icon, enum message_queue_category category)\n{\n   size_t tmp_ptr = 0;\n   struct queue_elem *new_elem = NULL;\n\n   if (!queue || queue->ptr >= queue->size)\n      return;\n\n   if (!(new_elem = (struct queue_elem*)malloc(sizeof(struct queue_elem))))\n      return;\n\n   new_elem->duration            = duration;\n   new_elem->prio                = prio;\n   new_elem->msg                 = msg   ? strdup(msg)   : NULL;\n   new_elem->title               = title ? strdup(title) : NULL;\n   new_elem->icon                = icon;\n   new_elem->category            = category;\n\n   queue->elems[queue->ptr]      = new_elem;\n\n   tmp_ptr                       = queue->ptr++;\n\n   while (tmp_ptr > 1)\n   {\n      struct queue_elem *parent  = queue->elems[tmp_ptr >> 1];\n      struct queue_elem *child   = queue->elems[tmp_ptr];\n\n      if (child->prio <= parent->prio)\n         break;\n\n      queue->elems[tmp_ptr >> 1] = child;\n      queue->elems[tmp_ptr]      = parent;\n\n      tmp_ptr >>= 1;\n   }\n}\n\n/**\n * msg_queue_clear:\n * @queue             : pointer to queue object\n *\n * Clears out everything in the queue.\n **/\nvoid msg_queue_clear(msg_queue_t *queue)\n{\n   size_t i;\n\n   if (!queue)\n      return;\n\n   for (i = 1; i < queue->ptr; i++)\n   {\n      if (queue->elems[i])\n      {\n         free(queue->elems[i]->msg);\n         free(queue->elems[i]->title);\n         free(queue->elems[i]);\n         queue->elems[i] = NULL;\n      }\n   }\n   queue->ptr     = 1;\n   free(queue->tmp_msg);\n   queue->tmp_msg = NULL;\n}\n\n/**\n * msg_queue_pull:\n * @queue             : pointer to queue object\n *\n * Pulls highest priority message in queue.\n *\n * Returns: NULL if no message in queue, otherwise a string\n * containing the message.\n **/\nconst char *msg_queue_pull(msg_queue_t *queue)\n{\n   struct queue_elem *front  = NULL, *last = NULL;\n   size_t tmp_ptr = 1;\n\n   /* Nothing in queue. */\n   if (!queue || queue->ptr == 1)\n      return NULL;\n\n   front = (struct queue_elem*)queue->elems[1];\n   front->duration--;\n   if (front->duration > 0)\n      return front->msg;\n\n   free(queue->tmp_msg);\n   queue->tmp_msg = front->msg;\n   front->msg = NULL;\n\n   last  = (struct queue_elem*)queue->elems[--queue->ptr];\n   queue->elems[1] = last;\n   free(front->title);\n   free(front);\n\n   for (;;)\n   {\n      struct queue_elem *parent = NULL;\n      struct queue_elem *child  = NULL;\n      size_t switch_index       = tmp_ptr;\n      bool left                 = (tmp_ptr * 2 <= queue->ptr)\n         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);\n      bool right                = (tmp_ptr * 2 + 1 <= queue->ptr)\n         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);\n\n      if (!left && !right)\n         break;\n\n      if (left && !right)\n         switch_index <<= 1;\n      else if (right && !left)\n         switch_index += switch_index + 1;\n      else\n      {\n         if (queue->elems[tmp_ptr * 2]\n               >= queue->elems[tmp_ptr * 2 + 1])\n            switch_index <<= 1;\n         else\n            switch_index += switch_index + 1;\n      }\n\n      parent = (struct queue_elem*)queue->elems[tmp_ptr];\n      child  = (struct queue_elem*)queue->elems[switch_index];\n      queue->elems[tmp_ptr]      = child;\n      queue->elems[switch_index] = parent;\n      tmp_ptr                    = switch_index;\n   }\n\n   return queue->tmp_msg;\n}\n\n/**\n * msg_queue_extract:\n * @queue             : pointer to queue object\n * @queue_entry       : pointer to external queue entry struct\n *\n * Removes highest priority message from queue, copying\n * contents into queue_entry struct.\n *\n * Returns: false if no messages in queue, otherwise true\n **/\nbool msg_queue_extract(msg_queue_t *queue, msg_queue_entry_t *queue_entry)\n{\n   struct queue_elem *front  = NULL, *last = NULL;\n   size_t tmp_ptr = 1;\n\n   /* Ensure arguments are valid and queue is not\n    * empty */\n   if (!queue || queue->ptr == 1 || !queue_entry)\n      return false;\n\n   front = (struct queue_elem*)queue->elems[1];\n   last  = (struct queue_elem*)queue->elems[--queue->ptr];\n   queue->elems[1] = last;\n\n   /* Copy element parameters */\n   queue_entry->duration = front->duration;\n   queue_entry->prio     = front->prio;\n   queue_entry->icon     = front->icon;\n   queue_entry->category = front->category;\n   queue_entry->msg[0]   = '\\0';\n   queue_entry->title[0] = '\\0';\n\n   if (front->msg)\n      strlcpy(queue_entry->msg, front->msg, sizeof(queue_entry->msg));\n\n   if (front->title)\n      strlcpy(queue_entry->title, front->title, sizeof(queue_entry->title));\n\n   /* Delete element */\n   free(front->msg);\n   free(front->title);\n   free(front);\n\n   for (;;)\n   {\n      struct queue_elem *parent = NULL;\n      struct queue_elem *child  = NULL;\n      size_t switch_index       = tmp_ptr;\n      bool left                 = (tmp_ptr * 2 <= queue->ptr)\n         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2]);\n      bool right                = (tmp_ptr * 2 + 1 <= queue->ptr)\n         && (queue->elems[tmp_ptr] < queue->elems[tmp_ptr * 2 + 1]);\n\n      if (!left && !right)\n         break;\n\n      if (left && !right)\n         switch_index <<= 1;\n      else if (right && !left)\n         switch_index += switch_index + 1;\n      else\n      {\n         if (queue->elems[tmp_ptr * 2]\n               >= queue->elems[tmp_ptr * 2 + 1])\n            switch_index <<= 1;\n         else\n            switch_index += switch_index + 1;\n      }\n\n      parent = (struct queue_elem*)queue->elems[tmp_ptr];\n      child  = (struct queue_elem*)queue->elems[switch_index];\n      queue->elems[tmp_ptr]      = child;\n      queue->elems[switch_index] = parent;\n      tmp_ptr                    = switch_index;\n   }\n\n   return true;\n}\n\n/**\n * msg_queue_size:\n * @queue             : pointer to queue object\n *\n * Fetches number of messages in queue.\n *\n * Returns: Number of messages in queue.\n **/\nsize_t msg_queue_size(msg_queue_t *queue)\n{\n   if (!queue || queue->ptr <= 1)\n      return 0;\n\n   return queue->ptr - 1;\n}\n"
  },
  {
    "path": "queues/retro_spsc.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_spsc.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <retro_spsc.h>\n\n/* Round @v up to the next power of 2.  Returns 0 if @v == 0 or if\n * the next power of 2 would overflow (caller checks @v <= SIZE_MAX/2). */\nstatic size_t spsc_round_up_pow2(size_t v)\n{\n   size_t r;\n   if (v == 0)\n      return 0;\n   /* If already a power of 2, return as-is. */\n   if ((v & (v - 1)) == 0)\n      return v;\n   /* Round up.  Loop terminates because v <= SIZE_MAX/2 means r\n    * cannot overflow. */\n   r = 1;\n   while (r < v)\n      r <<= 1;\n   return r;\n}\n\nbool retro_spsc_init(retro_spsc_t *q, size_t min_capacity)\n{\n   size_t cap;\n\n   if (!q || min_capacity == 0 || min_capacity > (SIZE_MAX / 2))\n      return false;\n\n   cap = spsc_round_up_pow2(min_capacity);\n   if (cap == 0 || cap > (SIZE_MAX / 2))\n      return false;\n\n   q->buffer = (uint8_t*)malloc(cap);\n   if (!q->buffer)\n      return false;\n\n   q->capacity = cap;\n   retro_atomic_size_init(&q->head, 0);\n   retro_atomic_size_init(&q->tail, 0);\n   return true;\n}\n\nvoid retro_spsc_free(retro_spsc_t *q)\n{\n   if (!q)\n      return;\n   if (q->buffer)\n   {\n      free(q->buffer);\n      q->buffer = NULL;\n   }\n   q->capacity = 0;\n}\n\nvoid retro_spsc_clear(retro_spsc_t *q)\n{\n   if (!q)\n      return;\n   /* Quiescence is the caller's responsibility (documented).\n    * Under that assumption, no other thread is touching head or\n    * tail, so plain init is correct here -- and necessary, because\n    * plain assignment to a retro_atomic_size_t is illegal under\n    * the C11 stdatomic backend. */\n   retro_atomic_size_init(&q->head, 0);\n   retro_atomic_size_init(&q->tail, 0);\n}\n\nsize_t retro_spsc_write_avail(const retro_spsc_t *q)\n{\n   /* Producer query.  We read our own head (which we wrote) and the\n    * consumer's tail (which they wrote with a release-store).\n    * acquire-load on tail so any reads we do based on the freed\n    * space are ordered after the consumer's tail publication.\n    *\n    * We can read our own head without an acquire because we are the\n    * only writer to it; but retro_atomic.h does not expose relaxed\n    * loads, so use acquire.  Cost is one extra fence on weak-memory\n    * targets, which is negligible compared to the actual work\n    * surrounding this query. */\n   size_t head = retro_atomic_load_acquire_size(\n         (retro_atomic_size_t*)&q->head);\n   size_t tail = retro_atomic_load_acquire_size(\n         (retro_atomic_size_t*)&q->tail);\n   /* head - tail is well-defined modular arithmetic on size_t.\n    * Invariant: 0 <= head - tail <= capacity. */\n   return q->capacity - (head - tail);\n}\n\nsize_t retro_spsc_read_avail(const retro_spsc_t *q)\n{\n   /* Consumer query.  acquire-load on head pairs with the producer's\n    * release-store on head, so the data writes that preceded the\n    * release are visible by the time we read them. */\n   size_t head = retro_atomic_load_acquire_size(\n         (retro_atomic_size_t*)&q->head);\n   size_t tail = retro_atomic_load_acquire_size(\n         (retro_atomic_size_t*)&q->tail);\n   return head - tail;\n}\n\nsize_t retro_spsc_write(retro_spsc_t *q, const void *data, size_t bytes)\n{\n   size_t mask, head_idx, first;\n   const uint8_t *src = (const uint8_t*)data;\n   /* read tail first to know how much room there is */\n   size_t head  = retro_atomic_load_acquire_size(&q->head);\n   size_t tail  = retro_atomic_load_acquire_size(&q->tail);\n   size_t avail = q->capacity - (head - tail);\n   if (bytes > avail)\n      bytes = avail;\n   if (bytes == 0)\n      return 0;\n\n   mask     = q->capacity - 1;\n   head_idx = head & mask;\n\n   /* first = bytes from head_idx to end-of-buffer */\n   first = q->capacity - head_idx;\n   if (first > bytes)\n      first = bytes;\n\n   memcpy(q->buffer + head_idx, src, first);\n   memcpy(q->buffer, src + first, bytes - first);\n\n   /* Publish: release-store ensures the memcpys above are globally\n    * visible before the consumer observes the new head. */\n   retro_atomic_store_release_size(&q->head, head + bytes);\n   return bytes;\n}\n\nsize_t retro_spsc_read(retro_spsc_t *q, void *data, size_t bytes)\n{\n   size_t mask, tail_idx, first;\n   uint8_t *dst = (uint8_t*)data;\n   /* acquire on head pairs with producer's release-store; this is\n    * what makes the subsequent memcpys safe to read. */\n   size_t head  = retro_atomic_load_acquire_size(&q->head);\n   size_t tail  = retro_atomic_load_acquire_size(&q->tail);\n   size_t avail = head - tail;\n   if (bytes > avail)\n      bytes = avail;\n   if (bytes == 0)\n      return 0;\n\n   mask     = q->capacity - 1;\n   tail_idx = tail & mask;\n\n   first = q->capacity - tail_idx;\n   if (first > bytes)\n      first = bytes;\n\n   memcpy(dst, q->buffer + tail_idx, first);\n   memcpy(dst + first, q->buffer, bytes - first);\n\n   /* Publish: release-store so the producer can re-use this space. */\n   retro_atomic_store_release_size(&q->tail, tail + bytes);\n   return bytes;\n}\n\nsize_t retro_spsc_peek(const retro_spsc_t *q, void *data, size_t bytes)\n{\n   size_t mask, tail_idx, first;\n   uint8_t *dst = (uint8_t*)data;\n   size_t head  = retro_atomic_load_acquire_size(\n         (retro_atomic_size_t*)&q->head);\n   size_t tail = retro_atomic_load_acquire_size(\n         (retro_atomic_size_t*)&q->tail);\n   size_t avail = head - tail;\n   if (bytes > avail)\n      bytes = avail;\n   if (bytes == 0)\n      return 0;\n\n   mask     = q->capacity - 1;\n   tail_idx = tail & mask;\n\n   first    = q->capacity - tail_idx;\n   if (first > bytes)\n      first = bytes;\n\n   memcpy(dst, q->buffer + tail_idx, first);\n   memcpy(dst + first, q->buffer, bytes - first);\n   /* No tail update: peek does not consume. */\n   return bytes;\n}\n"
  },
  {
    "path": "queues/task_queue.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (task_queue.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n\n#include <queues/task_queue.h>\n\n#include <features/features_cpu.h>\n\n#if defined(HAVE_GCD) && !defined(HAVE_THREADS)\n#error \"gcd uses threads, what are you doing\"\n#endif\n\n#ifdef HAVE_THREADS\n#include <rthreads/rthreads.h>\n#endif\n#if defined(EMSCRIPTEN) || defined(_3DS)\n#include <retro_timers.h>\n#endif\n#ifdef HAVE_GCD\n#include <dispatch/dispatch.h>\n#endif\n\ntypedef struct\n{\n   retro_task_t *front;\n   retro_task_t *back;\n} task_queue_t;\n\nstruct retro_task_impl\n{\n   retro_task_queue_msg_t msg_push;\n   void (*push_running)(retro_task_t *);\n   void (*cancel)(void *);\n   void (*reset)(void);\n   void (*wait)(retro_task_condition_fn_t, void *);\n   void (*gather)(void);\n   bool (*find)(retro_task_finder_t, void*);\n   void (*retrieve)(task_retriever_data_t *data);\n   void (*init)(void);\n   void (*deinit)(void);\n};\n\n/* TODO/FIXME - static globals */\nstatic retro_task_queue_msg_t msg_push_bak  = NULL;\nstatic task_queue_t tasks_running           = {NULL, NULL};\nstatic task_queue_t tasks_finished          = {NULL, NULL};\n\nstatic struct retro_task_impl *impl_current = NULL;\nstatic bool task_threaded_enable            = false;\n\n#ifdef HAVE_THREADS\nstatic uintptr_t main_thread_id             = 0;\nstatic slock_t *running_lock                = NULL;\nstatic slock_t *finished_lock               = NULL;\nstatic slock_t *property_lock               = NULL;\nstatic slock_t *queue_lock                  = NULL;\nstatic scond_t *worker_cond                 = NULL;\nstatic sthread_t *worker_thread             = NULL;\nstatic bool worker_continue                 = true;\n/* use running_lock when touching it */\n#endif\n\n#ifdef HAVE_GCD\nstatic unsigned gcd_queue_count             = 0;\n#endif\n\nstatic void task_queue_msg_push(retro_task_t *task,\n      unsigned prio, unsigned duration,\n      bool flush, const char *fmt, ...)\n{\n   char buf[1024];\n   va_list ap;\n\n   buf[0] = '\\0';\n\n   va_start(ap, fmt);\n   vsnprintf(buf, sizeof(buf), fmt, ap);\n   va_end(ap);\n\n   if (impl_current->msg_push)\n      impl_current->msg_push(task, buf, prio, duration, flush);\n}\n\nstatic void task_queue_push_progress(retro_task_t *task)\n{\n#ifdef HAVE_THREADS\n   /* msg_push callback interacts directly with the task properties (particularly title).\n    * make sure another thread doesn't modify them while rendering\n    */\n   slock_lock(property_lock);\n#endif\n\n   if (task->title && (!((task->flags & RETRO_TASK_FLG_MUTE) > 0)))\n   {\n      if ((task->flags & RETRO_TASK_FLG_FINISHED) > 0)\n      {\n         if (task->error)\n            task_queue_msg_push(task, 1, 60, true, \"%s: %s\",\n               \"Task failed\", task->title);\n         else\n            task_queue_msg_push(task, 1, 60, false, \"100%%: %s\", task->title);\n      }\n      else\n      {\n         if (task->progress >= 0 && task->progress <= 100)\n            task_queue_msg_push(task, 1, 60, true, \"%i%%: %s\",\n                  task->progress, task->title);\n         else\n            task_queue_msg_push(task, 1, 60, false, \"%s...\", task->title);\n      }\n\n      if (task->progress_cb)\n         task->progress_cb(task);\n   }\n\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nstatic void task_queue_put(task_queue_t *queue, retro_task_t *task)\n{\n   task->next                   = NULL;\n\n   if (queue->front)\n   {\n      /* Make sure to insert in order - the queue is\n       * sorted by 'when' so items that aren't scheduled\n       * to run immediately are at the back of the queue.\n       * Items with the same 'when' are inserted after\n       * all the other items with the same 'when'.\n       * This primarily affects items with a 'when' of 0.\n       */\n      if (queue->back)\n      {\n         if (queue->back->when > task->when)\n         {\n            retro_task_t** prev = &queue->front;\n            while (*prev && (*prev)->when <= task->when)\n               prev             = &((*prev)->next);\n\n            task->next          = *prev;\n            *prev               = task;\n            return;\n         }\n\n         queue->back->next      = task;\n      }\n   }\n   else\n      queue->front              = task;\n\n   queue->back                  = task;\n}\n\nstatic retro_task_t *task_queue_get(task_queue_t *queue)\n{\n   retro_task_t *task = queue->front;\n\n   if (task)\n   {\n      queue->front = task->next;\n      task->next   = NULL;\n   }\n\n   return task;\n}\n\nstatic void retro_task_internal_gather(void)\n{\n   retro_task_t *task = NULL;\n   while ((task = task_queue_get(&tasks_finished)))\n   {\n      task_queue_push_progress(task);\n\n      if (task->callback)\n         task->callback(task, task->task_data, task->user_data, task->error);\n\n      if (task->cleanup)\n          task->cleanup(task);\n\n#ifdef HAVE_THREADS\n      slock_lock(property_lock);\n#endif\n      if (task->error)\n      {\n         free(task->error);\n         task->error = NULL;\n      }\n\n      if (task->title)\n      {\n         free(task->title);\n         task->title = NULL;\n      }\n#ifdef HAVE_THREADS\n      slock_unlock(property_lock);\n#endif\n\n      free(task);\n   }\n}\n\nstatic void retro_task_regular_push_running(retro_task_t *task)\n{\n   task_queue_put(&tasks_running, task);\n}\n\nstatic void retro_task_regular_cancel(void *task)\n{\n   retro_task_t *t = (retro_task_t*)task;\n   t->flags       |= RETRO_TASK_FLG_CANCELLED;\n}\n\nstatic void retro_task_regular_gather(void)\n{\n   retro_task_t *task  = NULL;\n   retro_task_t *queue = NULL;\n   retro_task_t *next  = NULL;\n\n   while ((task = task_queue_get(&tasks_running)))\n   {\n      task->next = queue;\n      queue = task;\n   }\n\n   for (task = queue; task; task = next)\n   {\n      next = task->next;\n\n      if (!task->when || task->when < cpu_features_get_time_usec())\n      {\n         task->handler(task);\n\n         task_queue_push_progress(task);\n      }\n\n      if ((task->flags & RETRO_TASK_FLG_FINISHED) > 0)\n         task_queue_put(&tasks_finished, task);\n      else\n         task_queue_put(&tasks_running, task);\n   }\n\n   retro_task_internal_gather();\n}\n\nstatic void retro_task_regular_wait(retro_task_condition_fn_t cond, void* data)\n{\n   while ((tasks_running.front && !tasks_running.front->when) && (!cond || cond(data)))\n      retro_task_regular_gather();\n}\n\nstatic void retro_task_regular_reset(void)\n{\n   retro_task_t *task = tasks_running.front;\n\n   for (; task; task = task->next)\n      task->flags |= RETRO_TASK_FLG_CANCELLED;\n}\n\nstatic void retro_task_regular_init(void) { }\nstatic void retro_task_regular_deinit(void) { }\n\nstatic bool retro_task_regular_find(retro_task_finder_t func, void *user_data)\n{\n   retro_task_t *task = tasks_running.front;\n\n   for (; task; task = task->next)\n   {\n      if (func(task, user_data))\n         return true;\n   }\n\n   return false;\n}\n\nstatic void retro_task_regular_retrieve(task_retriever_data_t *data)\n{\n   retro_task_t *task          = NULL;\n   task_retriever_info_t *tail = NULL;\n\n   /* Parse all running tasks and handle matching handlers */\n   for (task = tasks_running.front; task != NULL; task = task->next)\n   {\n      task_retriever_info_t *info = NULL;\n      if (task->handler != data->handler)\n         continue;\n\n      /* Create new link.  NULL-check both allocations: the previous\n       * form dereferenced info on the very next line, and passed\n       * info->data (potentially NULL from the second malloc) into\n       * data->func which is free to dereference it.  On OOM just\n       * skip this task - the retriever already tolerates tasks\n       * being absent from the result list (data->func returning\n       * false is the documented 'skip' signal). */\n      if (!(info = (task_retriever_info_t*)\n            malloc(sizeof(task_retriever_info_t))))\n         continue;\n      if (!(info->data = malloc(data->element_size)))\n      {\n         free(info);\n         continue;\n      }\n      info->next = NULL;\n\n      /* Call retriever function and fill info-specific data */\n      if (!data->func(task, info->data))\n      {\n         free(info->data);\n         free(info);\n         continue;\n      }\n\n      /* Add link to list */\n      if (data->list)\n      {\n         if (tail)\n         {\n            tail->next = info;\n            tail       = tail->next;\n         }\n         else\n            tail       = info;\n      }\n      else\n      {\n         data->list    = info;\n         tail          = data->list;\n      }\n   }\n}\n\nstatic struct retro_task_impl impl_regular = {\n   NULL,\n   retro_task_regular_push_running,\n   retro_task_regular_cancel,\n   retro_task_regular_reset,\n   retro_task_regular_wait,\n   retro_task_regular_gather,\n   retro_task_regular_find,\n   retro_task_regular_retrieve,\n   retro_task_regular_init,\n   retro_task_regular_deinit\n};\n\n#ifdef HAVE_THREADS\n\n/* 'queue_lock' must be held for the duration of this function */\nstatic void task_queue_remove(task_queue_t *queue, retro_task_t *task)\n{\n   retro_task_t     *t = NULL;\n   retro_task_t *front = queue->front;\n \n   /* Remove first element if needed */\n   if (task == front)\n   {\n      queue->front     = task->next;\n      if (queue->back == task) /* if only element, also update back */\n         queue->back   = NULL;\n      task->next       = NULL;\n      return;\n   }\n \n   /* Parse queue */\n   t = front;\n \n   while (t && t->next)\n   {\n      /* Remove task and update queue */\n      if (t->next == task)\n      {\n         t->next    = task->next;\n         task->next = NULL;\n \n         /* When removing the tail of the queue, update the tail pointer */\n         if (queue->back == task)\n            queue->back = t;\n         break;\n      }\n \n      /* Update iterator */\n      t = t->next;\n   }\n}\n\nstatic void retro_task_threaded_push_running(retro_task_t *task)\n{\n   slock_lock(running_lock);\n   slock_lock(queue_lock);\n   task_queue_put(&tasks_running, task);\n   scond_signal(worker_cond);\n   slock_unlock(queue_lock);\n   slock_unlock(running_lock);\n}\n\nstatic void retro_task_threaded_cancel(void *task)\n{\n   retro_task_t *t;\n\n   slock_lock(running_lock);\n\n   for (t = tasks_running.front; t; t = t->next)\n   {\n      if (t == task)\n      {\n        t->flags |= RETRO_TASK_FLG_CANCELLED;\n        break;\n      }\n   }\n\n   slock_unlock(running_lock);\n}\n\nstatic void retro_task_threaded_gather(void)\n{\n   retro_task_t *task = NULL;\n\n   slock_lock(running_lock);\n   for (task = tasks_running.front; task; task = task->next)\n      task_queue_push_progress(task);\n   slock_unlock(running_lock);\n\n   slock_lock(finished_lock);\n   retro_task_internal_gather();\n   slock_unlock(finished_lock);\n}\n\nstatic void retro_task_threaded_wait(retro_task_condition_fn_t cond, void* data)\n{\n   bool wait = false;\n\n   do\n   {\n      retro_task_threaded_gather();\n\n      slock_lock(running_lock);\n      wait = (tasks_running.front && !tasks_running.front->when);\n      slock_unlock(running_lock);\n\n      if (!wait)\n      {\n         slock_lock(finished_lock);\n         wait = (tasks_finished.front && !tasks_finished.front->when);\n         slock_unlock(finished_lock);\n      }\n   } while (wait && (!cond || cond(data)));\n}\n\nstatic void retro_task_threaded_reset(void)\n{\n   retro_task_t *task = NULL;\n\n   slock_lock(running_lock);\n   for (task = tasks_running.front; task; task = task->next)\n      task->flags |= RETRO_TASK_FLG_CANCELLED;\n   slock_unlock(running_lock);\n}\n\nstatic bool retro_task_threaded_find(\n      retro_task_finder_t func, void *user_data)\n{\n   retro_task_t *task = NULL;\n   bool ret = false;\n\n   slock_lock(running_lock);\n   for (task = tasks_running.front; task; task = task->next)\n   {\n      if (func(task, user_data))\n      {\n         ret = true;\n         break;\n      }\n   }\n   slock_unlock(running_lock);\n\n   return ret;\n}\n\nstatic void retro_task_threaded_retrieve(task_retriever_data_t *data)\n{\n   /* Protect access to running tasks */\n   slock_lock(running_lock);\n   /* Call regular retrieve function */\n   retro_task_regular_retrieve(data);\n   /* Release access to running tasks */\n   slock_unlock(running_lock);\n}\n\nstatic void threaded_worker(void *userdata)\n{\n   for (;;)\n   {\n      retro_task_t *task  = NULL;\n      bool       finished = false;\n\n      slock_lock(running_lock);\n\n      if (!worker_continue)\n      {\n         slock_unlock(running_lock);\n         break; /* should we keep running until all tasks finished? */\n      }\n\n      /* Get first task to run */\n      if (!(task = tasks_running.front))\n      {\n         scond_wait(worker_cond, running_lock);\n         slock_unlock(running_lock);\n         continue;\n      }\n\n      if (task->when)\n      {\n         retro_time_t now   = cpu_features_get_time_usec();\n         retro_time_t delay = task->when - now - 500; /* allow half a millisecond for context switching */\n         if (delay > 0)\n         {\n            scond_wait_timeout(worker_cond, running_lock, delay);\n            slock_unlock(running_lock);\n            continue;\n         }\n      }\n\n      slock_unlock(running_lock);\n      task->handler(task);\n#if defined(EMSCRIPTEN) || defined(_3DS)\n      /* Workaround emscripten pthread bug where not parking the\n         thread will prevent other important stuff from\n         happening. Maybe due to lack of signals implementation in\n         emscripten's pthreads?  */\n      retro_sleep(1);\n#endif\n\n      slock_lock(property_lock);\n      finished = ((task->flags & RETRO_TASK_FLG_FINISHED) > 0) ? true : false;\n      slock_unlock(property_lock);\n\n      /* Update queue */\n      if (!finished)\n      {\n         /* Move the task to the back of the queue */\n         /* mimics retro_task_threaded_push_running,\n          * but also includes a task_queue_remove */\n         slock_lock(running_lock);\n         slock_lock(queue_lock);\n\n         /* do nothing if only item in queue */\n         if (task->next)\n         {\n            task_queue_remove(&tasks_running, task);\n            task_queue_put(&tasks_running, task);\n            scond_signal(worker_cond);\n         }\n         slock_unlock(queue_lock);\n         slock_unlock(running_lock);\n      }\n      else\n      {\n         /* Remove task from running queue */\n         slock_lock(running_lock);\n         slock_lock(queue_lock);\n         task_queue_remove(&tasks_running, task);\n         slock_unlock(queue_lock);\n         slock_unlock(running_lock);\n\n         /* Add task to finished queue */\n         slock_lock(finished_lock);\n         task_queue_put(&tasks_finished, task);\n         slock_unlock(finished_lock);\n      }\n   }\n}\n\nstatic void retro_task_threaded_init(void)\n{\n   running_lock    = slock_new();\n   finished_lock   = slock_new();\n   property_lock   = slock_new();\n   queue_lock      = slock_new();\n   worker_cond     = scond_new();\n\n   slock_lock(running_lock);\n   worker_continue = true;\n   slock_unlock(running_lock);\n\n   worker_thread   = sthread_create(threaded_worker, NULL);\n}\n\nstatic void retro_task_threaded_deinit(void)\n{\n   slock_lock(running_lock);\n   worker_continue = false;\n   scond_signal(worker_cond);\n   slock_unlock(running_lock);\n\n   sthread_join(worker_thread);\n\n   scond_free(worker_cond);\n   slock_free(running_lock);\n   slock_free(finished_lock);\n   slock_free(property_lock);\n   slock_free(queue_lock);\n\n   worker_thread   = NULL;\n   worker_cond     = NULL;\n   running_lock    = NULL;\n   finished_lock   = NULL;\n   property_lock   = NULL;\n   queue_lock      = NULL;\n}\n\nstatic struct retro_task_impl impl_threaded = {\n   NULL,\n   retro_task_threaded_push_running,\n   retro_task_threaded_cancel,\n   retro_task_threaded_reset,\n   retro_task_threaded_wait,\n   retro_task_threaded_gather,\n   retro_task_threaded_find,\n   retro_task_threaded_retrieve,\n   retro_task_threaded_init,\n   retro_task_threaded_deinit\n};\n#endif\n\n#ifdef HAVE_GCD\n\nstatic void gcd_worker(retro_task_t *task)\n{\n   bool       finished = false;\n   slock_lock(running_lock);\n\n   if (!worker_continue)\n   {\n      gcd_queue_count--;\n      if (!gcd_queue_count)\n         scond_signal(worker_cond);\n      slock_unlock(running_lock);\n      return;\n   }\n\n   if (task->when)\n   {\n      retro_time_t now   = cpu_features_get_time_usec();\n      retro_time_t delay = task->when - now - 500;\n      if (delay > 0)\n      {\n         dispatch_time_t after = dispatch_time(DISPATCH_TIME_NOW, delay);\n         dispatch_after(after, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),\n                        ^{ gcd_worker(task); });\n         slock_unlock(running_lock);\n         return;\n      }\n   }\n\n   slock_unlock(running_lock);\n\n   task->handler(task);\n\n   slock_lock(property_lock);\n   finished = ((task->flags & RETRO_TASK_FLG_FINISHED) > 0) ? true : false;\n   slock_unlock(property_lock);\n\n   if (!finished)\n      dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),\n                     ^{ gcd_worker(task); });\n   else\n   {\n      /* Remove task from running queue */\n      slock_lock(running_lock);\n      slock_lock(queue_lock);\n      gcd_queue_count--;\n      if (!gcd_queue_count)\n         scond_signal(worker_cond);\n      task_queue_remove(&tasks_running, task);\n      slock_unlock(queue_lock);\n      slock_unlock(running_lock);\n\n      /* Add task to finished queue */\n      slock_lock(finished_lock);\n      task_queue_put(&tasks_finished, task);\n      slock_unlock(finished_lock);\n   }\n}\n\nstatic void retro_task_gcd_push_running(retro_task_t *task)\n{\n   slock_lock(running_lock);\n   slock_lock(queue_lock);\n   task_queue_put(&tasks_running, task);\n   gcd_queue_count++;\n   dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),\n                  ^{ gcd_worker(task); });\n   slock_unlock(queue_lock);\n   slock_unlock(running_lock);\n}\n\nstatic void retro_task_gcd_wait(retro_task_condition_fn_t cond, void* data)\n{\n   bool wait = false;\n\n   do\n   {\n      retro_task_t *task = NULL;\n      retro_task_threaded_gather();\n\n      slock_lock(running_lock);\n      wait = false;\n      /* can't just look at the first task like threaded, they're not sorted by when */\n      for (task = tasks_running.front; !wait && task; task = task->next)\n         wait |= !task->when;\n      slock_unlock(running_lock);\n\n      if (!wait)\n      {\n         slock_lock(finished_lock);\n         for (task = tasks_finished.front; !wait && task; task = task->next)\n            wait |= !task->when;\n         slock_unlock(finished_lock);\n      }\n   } while (wait && (!cond || cond(data)));\n}\n\nstatic void retro_task_gcd_init(void)\n{\n   retro_task_t *task = NULL;\n\n   running_lock    = slock_new();\n   finished_lock   = slock_new();\n   property_lock   = slock_new();\n   queue_lock      = slock_new();\n   worker_cond     = scond_new();\n\n   slock_lock(running_lock);\n   worker_continue = true;\n   for (task = tasks_running.front; task; task = task->next)\n   {\n      gcd_queue_count++;\n      dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),\n                     ^{ gcd_worker(task); });\n   };\n   slock_unlock(running_lock);\n}\n\nstatic void retro_task_gcd_deinit(void)\n{\n   slock_lock(running_lock);\n   worker_continue = false;\n   if (gcd_queue_count)\n      scond_wait(worker_cond, running_lock);\n   slock_unlock(running_lock);\n\n   scond_free(worker_cond);\n   slock_free(running_lock);\n   slock_free(finished_lock);\n   slock_free(property_lock);\n   slock_free(queue_lock);\n\n   worker_cond     = NULL;\n   running_lock    = NULL;\n   finished_lock   = NULL;\n   property_lock   = NULL;\n   queue_lock      = NULL;\n}\n\nstatic struct retro_task_impl impl_gcd = {\n   NULL,\n   retro_task_gcd_push_running,\n   retro_task_threaded_cancel,\n   retro_task_threaded_reset,\n   retro_task_gcd_wait,\n   retro_task_threaded_gather,\n   retro_task_threaded_find,\n   retro_task_threaded_retrieve,\n   retro_task_gcd_init,\n   retro_task_gcd_deinit\n};\n#endif\n\n/* Deinitializes the task system.\n * This deinitializes the task system.\n * The tasks that are running at\n * the moment will stay on hold */\nvoid task_queue_deinit(void)\n{\n   if (impl_current)\n      impl_current->deinit();\n   impl_current = NULL;\n}\n\nvoid task_queue_init(bool threaded, retro_task_queue_msg_t msg_push)\n{\n   impl_current   = &impl_regular;\n#ifdef HAVE_THREADS\n   main_thread_id = sthread_get_current_thread_id();\n   if (threaded)\n   {\n      task_threaded_enable = true;\n#ifdef HAVE_GCD\n      impl_current         = &impl_gcd;\n#else\n      impl_current         = &impl_threaded;\n#endif\n   }\n#endif\n\n   msg_push_bak            = msg_push;\n\n   impl_current->msg_push  = msg_push;\n   impl_current->init();\n}\n\nvoid task_queue_set_threaded(void)\n{\n   task_threaded_enable = true;\n}\n\nvoid task_queue_unset_threaded(void)\n{\n   task_threaded_enable = false;\n}\n\nbool task_queue_is_threaded(void)\n{\n   return task_threaded_enable;\n}\n\nbool task_queue_find(task_finder_data_t *find_data)\n{\n   return impl_current->find(find_data->func, find_data->userdata);\n}\n\nvoid task_queue_retrieve(task_retriever_data_t *data)\n{\n   impl_current->retrieve(data);\n}\n\nvoid task_queue_check(void)\n{\n#ifdef HAVE_THREADS\n   bool current_threaded = (impl_current != &impl_regular);\n   bool want_threaded    = task_threaded_enable;\n\n   if (want_threaded != current_threaded)\n      task_queue_deinit();\n\n   if (!impl_current)\n      task_queue_init(want_threaded, msg_push_bak);\n#endif\n\n   impl_current->gather();\n}\n\nbool task_queue_push(retro_task_t *task)\n{\n   /* Ignore this task if a related one is already running */\n   if (task->type == TASK_TYPE_BLOCKING)\n   {\n      retro_task_t *running = NULL;\n      bool            found = false;\n\n#ifdef HAVE_THREADS\n      slock_lock(queue_lock);\n#endif\n      running = tasks_running.front;\n\n      for (; running; running = running->next)\n      {\n         if (running->type == TASK_TYPE_BLOCKING)\n         {\n            found = true;\n            break;\n         }\n      }\n\n#ifdef HAVE_THREADS\n      slock_unlock(queue_lock);\n#endif\n\n      /* skip this task, user must try again later */\n      if (found)\n         return false;\n   }\n\n   /* The lack of NULL checks in the following functions\n    * is proposital to ensure correct control flow by the users. */\n   impl_current->push_running(task);\n\n   return true;\n}\n\nvoid task_queue_wait(retro_task_condition_fn_t cond, void* data)\n{\n   impl_current->wait(cond, data);\n}\n\nvoid task_queue_reset(void)\n{\n   impl_current->reset();\n}\n\n/**\n * Signals a task to end without waiting for\n * it to complete. */\nvoid task_queue_cancel_task(void *task)\n{\n   impl_current->cancel(task);\n}\n\nvoid *task_queue_retriever_info_next(task_retriever_info_t **link)\n{\n   void *data = NULL;\n\n   /* Grab data from current link, then advance */\n   if (*link)\n   {\n      data  = (*link)->data;\n      *link = (*link)->next;\n   }\n\n   return data;\n}\n\nvoid task_queue_retriever_info_free(task_retriever_info_t *list)\n{\n   task_retriever_info_t *info;\n\n   /* Free links including retriever-specific data */\n   while (list)\n   {\n      info = list->next;\n      free(list->data);\n      free(list);\n      list = info;\n   }\n}\n\nbool task_is_on_main_thread(void)\n{\n#ifdef HAVE_THREADS\n   return sthread_get_current_thread_id() == main_thread_id;\n#else\n   return true;\n#endif\n}\n\nvoid task_set_error(retro_task_t *task, char *err)\n{\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   task->error = err;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nvoid task_set_progress(retro_task_t *task, int8_t progress)\n{\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   task->progress = progress;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nvoid task_set_title(retro_task_t *task, char *title)\n{\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   task->title = title;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nvoid task_set_data(retro_task_t *task, void *data)\n{\n#ifdef HAVE_THREADS\n   slock_lock(running_lock);\n#endif\n   task->task_data = data;\n#ifdef HAVE_THREADS\n   slock_unlock(running_lock);\n#endif\n}\n\nvoid task_free_title(retro_task_t *task)\n{\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   if (task->title)\n      free(task->title);\n   task->title = NULL;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nvoid task_free_error(retro_task_t *task)\n{\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   if (task->error)\n      free(task->error);\n   task->error = NULL;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nvoid* task_get_data(retro_task_t *task)\n{\n   void *data = NULL;\n\n#ifdef HAVE_THREADS\n   slock_lock(running_lock);\n#endif\n   data = task->task_data;\n#ifdef HAVE_THREADS\n   slock_unlock(running_lock);\n#endif\n\n   return data;\n}\n\nvoid task_set_flags(retro_task_t *task, uint8_t flags, bool set)\n{\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   if (set)\n      task->flags |=  (flags);\n   else\n      task->flags &= ~(flags);\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n}\n\nuint8_t task_get_flags(retro_task_t *task)\n{\n   uint8_t _flags = 0;\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   _flags = task->flags;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n   return _flags;\n}\n\nchar* task_get_error(retro_task_t *task)\n{\n   char *s = NULL;\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   s = task->error;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n   return s;\n}\n\nint8_t task_get_progress(retro_task_t *task)\n{\n   int8_t progress = 0;\n\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   progress = task->progress;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n\n   return progress;\n}\n\nchar* task_get_title(retro_task_t *task)\n{\n   char *title = NULL;\n\n#ifdef HAVE_THREADS\n   slock_lock(property_lock);\n#endif\n   title = task->title;\n#ifdef HAVE_THREADS\n   slock_unlock(property_lock);\n#endif\n\n   return title;\n}\n\nretro_task_t *task_init(void)\n{\n   /* TODO/FIXME - static local global */\n   static uint32_t task_count = 0;\n   retro_task_t *task         = (retro_task_t*)malloc(sizeof(*task));\n\n   if (!task)\n      return NULL;\n\n   task->handler           = NULL;\n   task->callback          = NULL;\n   task->cleanup           = NULL;\n   task->flags             = 0;\n   task->task_data         = NULL;\n   task->user_data         = NULL;\n   task->state             = NULL;\n   task->error             = NULL;\n   task->progress          = 0;\n   task->progress_cb       = NULL;\n   task->title             = NULL;\n   task->type              = TASK_TYPE_NONE;\n   task->style             = TASK_STYLE_NONE;\n   task->ident             = task_count++;\n   task->frontend_userdata = NULL;\n   task->next              = NULL;\n   task->when              = 0;\n\n   return task;\n}\n"
  },
  {
    "path": "rthreads/ctr_pthread.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (gx_pthread.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _CTR_PTHREAD_WRAP_CTR_\n#define _CTR_PTHREAD_WRAP_CTR_\n\n#include <3ds/thread.h>\n#include <3ds/synchronization.h>\n#include <3ds/svc.h>\n#include <3ds/services/apt.h>\n#include <sys/time.h>\n#include <time.h>\n#include <errno.h>\n#include <retro_inline.h>\n\n#define STACKSIZE (32 * 1024)\n\n#ifndef PTHREAD_SCOPE_PROCESS\n/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */\n\ntypedef Thread     pthread_t;\ntypedef LightLock  pthread_mutex_t;\ntypedef void*      pthread_mutexattr_t;\ntypedef int        pthread_attr_t;\ntypedef uint32_t   pthread_cond_t;\ntypedef int        pthread_condattr_t;\n#endif\n\n#ifndef USE_CTRULIB_2\n/* Backported CondVar API from libctru 2.0, and under its license:\n   https://github.com/devkitPro/libctru\n   Slightly modified for compatibility with older libctru. */\n\ntypedef s32 CondVar;\n\nstatic INLINE Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)\n{\n   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, 0);\n}\n\nstatic INLINE Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)\n{\n   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, timeout_ns);\n}\n\nstatic INLINE void __dmb(void)\n{\n\t__asm__ __volatile__(\"mcr p15, 0, %[val], c7, c10, 5\" :: [val] \"r\" (0) : \"memory\");\n}\n\nstatic INLINE void CondVar_BeginWait(CondVar* cv, LightLock* lock)\n{\n\ts32 val;\n\tdo\n\t\tval = __ldrex(cv) - 1;\n\twhile (__strex(cv, val));\n\tLightLock_Unlock(lock);\n}\n\nstatic INLINE bool CondVar_EndWait(CondVar* cv, s32 num_threads)\n{\n\tbool hasWaiters;\n\ts32 val;\n\n\tdo {\n\t\tval = __ldrex(cv);\n\t\thasWaiters = val < 0;\n\t\tif (hasWaiters)\n\t\t{\n\t\t\tif (num_threads < 0)\n\t\t\t\tval = 0;\n\t\t\telse if (val <= -num_threads)\n\t\t\t\tval += num_threads;\n\t\t\telse\n\t\t\t\tval = 0;\n\t\t}\n\t} while (__strex(cv, val));\n\n\treturn hasWaiters;\n}\n\nstatic INLINE void CondVar_Init(CondVar* cv)\n{\n\t*cv = 0;\n}\n\nstatic INLINE void CondVar_Wait(CondVar* cv, LightLock* lock)\n{\n\tCondVar_BeginWait(cv, lock);\n\tsyncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);\n\tLightLock_Lock(lock);\n}\n\nstatic INLINE int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)\n{\n\tCondVar_BeginWait(cv, lock);\n\n\tbool timedOut = false;\n\tResult rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);\n\tif (R_DESCRIPTION(rc) == RD_TIMEOUT)\n\t{\n\t\ttimedOut = CondVar_EndWait(cv, 1);\n\t\t__dmb();\n\t}\n\n\tLightLock_Lock(lock);\n\treturn timedOut;\n}\n\nstatic INLINE void CondVar_WakeUp(CondVar* cv, s32 num_threads)\n{\n\t__dmb();\n\tif (CondVar_EndWait(cv, num_threads))\n\t\tsyncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);\n\telse\n\t\t__dmb();\n}\n\nstatic INLINE void CondVar_Signal(CondVar* cv)\n{\n\tCondVar_WakeUp(cv, 1);\n}\n\nstatic INLINE void CondVar_Broadcast(CondVar* cv)\n{\n\tCondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);\n}\n/* End libctru 2.0 backport */\n#endif\n\n/* libctru threads return void but pthreads return void pointer */\nstatic bool mutex_inited = false;\nstatic LightLock safe_double_thread_launch;\nstatic void *(*start_routine_jump)(void*);\n\nstatic void ctr_thread_launcher(void* data)\n{\n\tvoid *(*start_routine_jump_safe)(void*) = start_routine_jump;\n\tLightLock_Unlock(&safe_double_thread_launch);\n\tstart_routine_jump_safe(data);\n}\n\nstatic INLINE int pthread_create(pthread_t *thread,\n      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)\n{\n   s32 prio = 0;\n   Thread new_ctr_thread;\n   int procnum = -2; /* use default cpu */\n   bool isNew3DS;\n\n   APT_CheckNew3DS(&isNew3DS);\n\n   if (isNew3DS)\n      procnum = 2;\n\n   if (!mutex_inited)\n   {\n      LightLock_Init(&safe_double_thread_launch);\n      mutex_inited = true;\n   }\n\n   /* Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/\n   while (LightLock_TryLock(&safe_double_thread_launch) != 0);\n\n   svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);\n\n   start_routine_jump = start_routine;\n   new_ctr_thread     = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, false);\n\n   if (!new_ctr_thread)\n   {\n      LightLock_Unlock(&safe_double_thread_launch);\n      return EAGAIN;\n   }\n\n   *thread = (pthread_t)new_ctr_thread;\n   return 0;\n}\n\nstatic INLINE pthread_t pthread_self(void)\n{\n   return (pthread_t)threadGetCurrent();\n}\n\nstatic INLINE int pthread_mutex_init(pthread_mutex_t *mutex,\n      const pthread_mutexattr_t *attr)\n{\n   LightLock_Init((LightLock *)mutex);\n   return 0;\n}\n\nstatic INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)\n{\n   /*Nothing to destroy*/\n   return 0;\n}\n\nstatic INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)\n{\n   LightLock_Lock((LightLock *)mutex);\n   return 0;\n}\n\nstatic INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)\n{\n   LightLock_Unlock((LightLock *)mutex);\n   return 0;\n}\n\nstatic INLINE void pthread_exit(void *retval)\n{\n   /*Yes the pointer to int cast is not ideal*/\n   /*threadExit((int)retval);*/\n   (void)retval;\n\n   threadExit(0);\n}\n\nstatic INLINE int pthread_detach(pthread_t thread)\n{\n   threadDetach((Thread)thread);\n   return 0;\n}\n\nstatic INLINE int pthread_join(pthread_t thread, void **retval)\n{\n   /*retval is ignored*/\n   if (threadJoin((Thread)thread, INT64_MAX))\n      return -1;\n\n   threadFree((Thread)thread);\n\n   return 0;\n}\n\nstatic INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)\n{\n   return LightLock_TryLock((LightLock *)mutex);\n}\n\nstatic INLINE int pthread_cond_wait(pthread_cond_t *cond,\n      pthread_mutex_t *mutex)\n{\n   CondVar_Wait((CondVar *)cond, (LightLock *)mutex);\n   return 0;\n}\n\nstatic INLINE int pthread_cond_timedwait(pthread_cond_t *cond,\n      pthread_mutex_t *mutex, const struct timespec *abstime)\n{\n   /* Missing clock_gettime*/\n   struct timespec now;\n   struct timeval tm;\n   int retval = 0;\n\n   do\n   {\n      s64 timeout;\n      gettimeofday(&tm, NULL);\n      now.tv_sec  = tm.tv_sec;\n      now.tv_nsec = tm.tv_usec * 1000;\n\n      if ((timeout = (abstime->tv_sec - now.tv_sec) * 1000000000 +\n(abstime->tv_nsec - now.tv_nsec)) < 0)\n      {\n         retval = ETIMEDOUT;\n         break;\n      }\n\n      if (!CondVar_WaitTimeout((CondVar *)cond, (LightLock *)mutex, timeout))\n         break;\n   } while (1);\n\n   return retval;\n}\n\nstatic INLINE int pthread_cond_init(pthread_cond_t *cond,\n      const pthread_condattr_t *attr)\n{\n   CondVar_Init((CondVar *)cond);\n   return 0;\n}\n\nstatic INLINE int pthread_cond_signal(pthread_cond_t *cond)\n{\n   CondVar_Signal((CondVar *)cond);\n   return 0;\n}\n\nstatic INLINE int pthread_cond_broadcast(pthread_cond_t *cond)\n{\n   CondVar_Broadcast((CondVar *)cond);\n   return 0;\n}\n\nstatic INLINE int pthread_cond_destroy(pthread_cond_t *cond)\n{\n   /*Nothing to destroy*/\n   return 0;\n}\n\nstatic INLINE int pthread_equal(pthread_t t1, pthread_t t2)\n{\n\tif (threadGetHandle((Thread)t1) == threadGetHandle((Thread)t2))\n\t\treturn 1;\n\treturn 0;\n}\n\n#endif\n"
  },
  {
    "path": "rthreads/gx_pthread.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (gx_pthread.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef _GX_PTHREAD_WRAP_GX_\n#define _GX_PTHREAD_WRAP_GX_\n\n#include <ogcsys.h>\n#include <gccore.h>\n#include <ogc/cond.h>\n#include <retro_inline.h>\n\n#ifndef OSThread\n#define OSThread lwp_t\n#endif\n\n#ifndef OSCond\n#define OSCond lwpq_t\n#endif\n\n#ifndef OSThreadQueue\n#define OSThreadQueue lwpq_t\n#endif\n\n#ifndef OSInitMutex\n#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)\n#endif\n\n#ifndef OSLockMutex\n#define OSLockMutex(mutex) LWP_MutexLock(mutex)\n#endif\n\n#ifndef OSUnlockMutex\n#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)\n#endif\n\n#ifndef OSTryLockMutex\n#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)\n#endif\n\n#ifndef OSInitCond\n#define OSInitCond(cond) LWP_CondInit(cond)\n#endif\n\n#ifndef OSWaitCond\n#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)\n#endif\n\n#ifndef OSInitThreadQueue\n#define OSInitThreadQueue(queue) LWP_InitQueue(queue)\n#endif\n\n#ifndef OSSleepThread\n#define OSSleepThread(queue) LWP_ThreadSleep(queue)\n#endif\n\n#ifndef OSJoinThread\n#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)\n#endif\n\n#ifndef OSCreateThread\n#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)\n#endif\n\n#define STACKSIZE (8 * 1024)\n\ntypedef OSThread pthread_t;\ntypedef mutex_t pthread_mutex_t;\ntypedef OSCond pthread_cond_t;\n\n#if defined(GX_PTHREAD_LEGACY)\ntypedef void* pthread_mutexattr_t;\ntypedef int pthread_attr_t;\ntypedef OSCond pthread_condattr_t;\n#endif\n\nstatic INLINE int pthread_create(pthread_t *thread,\n      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)\n{\n   *thread = 0;\n   return OSCreateThread(thread, start_routine, 0 /* unused */, arg,\n         0, STACKSIZE, 64, 0 /* unused */);\n}\n\nstatic INLINE pthread_t pthread_self(void)\n{\n   /* zero 20-mar-2016: untested */\n   return LWP_GetSelf();\n}\n\nstatic INLINE int pthread_mutex_init(pthread_mutex_t *mutex,\n      const pthread_mutexattr_t *attr)\n{\n   return OSInitMutex(mutex);\n}\n\nstatic INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)\n{\n   return LWP_MutexDestroy(*mutex);\n}\n\nstatic INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)\n{\n   return OSLockMutex(*mutex);\n}\n\nstatic INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)\n{\n   return OSUnlockMutex(*mutex);\n}\n\nstatic INLINE void pthread_exit(void *retval)\n{\n   /* FIXME: No LWP equivalent for this? */\n   (void)retval;\n}\n\nstatic INLINE int pthread_detach(pthread_t thread)\n{\n   /* FIXME: pthread_detach equivalent missing? */\n   (void)thread;\n   return 0;\n}\n\nstatic INLINE int pthread_join(pthread_t thread, void **retval)\n{\n   return OSJoinThread(thread, retval);\n}\n\nstatic INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)\n{\n   return OSTryLockMutex(*mutex);\n}\n\nstatic INLINE int pthread_cond_wait(pthread_cond_t *cond,\n      pthread_mutex_t *mutex)\n{\n   return OSWaitCond(*cond, *mutex);\n}\n\nstatic INLINE int pthread_cond_timedwait(pthread_cond_t *cond,\n      pthread_mutex_t *mutex, const struct timespec *abstime)\n{\n   return LWP_CondTimedWait(*cond, *mutex, abstime);\n}\n\nstatic INLINE int pthread_cond_init(pthread_cond_t *cond,\n      const pthread_condattr_t *attr)\n{\n   return OSInitCond(cond);\n}\n\nstatic INLINE int pthread_cond_signal(pthread_cond_t *cond)\n{\n   return LWP_CondSignal(*cond);\n}\n\nstatic INLINE int pthread_cond_broadcast(pthread_cond_t *cond)\n{\n   return LWP_CondBroadcast(*cond);\n}\n\nstatic INLINE int pthread_cond_destroy(pthread_cond_t *cond)\n{\n   return LWP_CondDestroy(*cond);\n}\n\n#endif\n"
  },
  {
    "path": "rthreads/psp_pthread.h",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (psp_pthread.h).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */\n#ifndef _PSP_PTHREAD_WRAP__\n#define _PSP_PTHREAD_WRAP__\n\n#ifdef VITA\n#include <psp2/kernel/threadmgr.h>\n#include <sys/time.h>\n#else\n#include <pspkernel.h>\n#include <pspthreadman.h>\n#include <pspthreadman_kernel.h>\n#endif\n#include <stdio.h>\n#include <retro_inline.h>\n\n#define STACKSIZE (8 * 1024)\n\ntypedef SceUID pthread_t;\ntypedef SceUID pthread_mutex_t;\ntypedef void* pthread_mutexattr_t;\ntypedef int pthread_attr_t;\n\ntypedef struct\n{\n\tSceUID mutex;\n\tSceUID sema;\n\tint waiting;\n} pthread_cond_t;\n\ntypedef SceUID pthread_condattr_t;\n\n/* Use pointer values to create unique names for threads/mutexes */\nchar name_buffer[256];\n\ntypedef void* (*sthreadEntry)(void *argp);\n\ntypedef struct\n{\n   void* arg;\n   sthreadEntry start_routine;\n} sthread_args_struct;\n\nstatic int psp_thread_wrap(SceSize args, void *argp)\n{\n   sthread_args_struct* sthread_args = (sthread_args_struct*)argp;\n\n   return (int)sthread_args->start_routine(sthread_args->arg);\n}\n\nstatic INLINE int pthread_create(pthread_t *thread,\n      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)\n{\n   snprintf(name_buffer, sizeof(name_buffer), \"0x%08X\", (unsigned int) thread);\n\n#ifdef VITA\n   *thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,\n         0x10000100, 0x10000, 0, 0, NULL);\n#else\n   *thread = sceKernelCreateThread(name_buffer,\n         psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);\n#endif\n\n   sthread_args_struct sthread_args;\n   sthread_args.arg = arg;\n   sthread_args.start_routine = start_routine;\n\n   return sceKernelStartThread(*thread, sizeof(sthread_args), &sthread_args);\n}\n\nstatic INLINE int pthread_mutex_init(pthread_mutex_t *mutex,\n      const pthread_mutexattr_t *attr)\n{\n   snprintf(name_buffer, sizeof(name_buffer), \"0x%08X\", (unsigned int) mutex);\n\n#ifdef VITA\n   *mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);\n\t if (*mutex<0)\n\t \t\treturn *mutex;\n\t return 0;\n#else\n   return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);\n#endif\n}\n\nstatic INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)\n{\n#ifdef VITA\n   return sceKernelDeleteMutex(*mutex);\n#else\n   return sceKernelDeleteSema(*mutex);\n#endif\n}\n\nstatic INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)\n{\n#ifdef VITA\n\t int ret = sceKernelLockMutex(*mutex, 1, 0);\n\t return ret;\n\n#else\n   /* FIXME: stub */\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)\n{\n#ifdef VITA\n\tint ret = sceKernelUnlockMutex(*mutex, 1);\n\treturn ret;\n#else\n   /* FIXME: stub */\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_join(pthread_t thread, void **retval)\n{\n#ifdef VITA\n   int res = sceKernelWaitThreadEnd(thread, 0, 0);\n   if (res < 0)\n      return res;\n   return sceKernelDeleteThread(thread);\n#else\n   SceUInt timeout = (SceUInt)-1;\n   sceKernelWaitThreadEnd(thread, &timeout);\n   exit_status = sceKernelGetThreadExitStatus(thread);\n   sceKernelDeleteThread(thread);\n   return exit_status;\n#endif\n}\n\nstatic INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)\n{\n#ifdef VITA\n   return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);\n#else\n   /* FIXME: stub */\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_cond_wait(pthread_cond_t *cond,\n      pthread_mutex_t *mutex)\n{\n#ifdef VITA\n   int ret = pthread_mutex_lock(&cond->mutex);\n   if (ret < 0)\n      return ret;\n   ++cond->waiting;\n   pthread_mutex_unlock(mutex);\n   pthread_mutex_unlock(&cond->mutex);\n\n   ret = sceKernelWaitSema(cond->sema, 1, 0);\n   if (ret < 0)\n      sceClibPrintf(\"Premature wakeup: %08X\", ret);\n   pthread_mutex_lock(mutex);\n   return ret;\n#else\n   /* FIXME: stub */\n   sceKernelDelayThread(10000);\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_cond_timedwait(pthread_cond_t *cond,\n      pthread_mutex_t *mutex, const struct timespec *abstime)\n{\n#ifdef VITA\n   int ret = pthread_mutex_lock(&cond->mutex);\n   if (ret < 0)\n      return ret;\n   ++cond->waiting;\n   pthread_mutex_unlock(mutex);\n   pthread_mutex_unlock(&cond->mutex);\n\n   SceUInt timeout = 0;\n\n   timeout  = abstime->tv_sec;\n   timeout += abstime->tv_nsec / 1.0e6;\n\n   ret = sceKernelWaitSema(cond->sema, 1, &timeout);\n   if (ret < 0)\n      sceClibPrintf(\"Premature wakeup: %08X\", ret);\n   pthread_mutex_lock(mutex);\n   return ret;\n\n#else\n   /* FIXME: stub */\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_cond_init(pthread_cond_t *cond,\n      const pthread_condattr_t *attr)\n{\n#ifdef VITA\n\n   pthread_mutex_init(&cond->mutex,NULL);\n\n   if (cond->mutex<0)\n      return cond->mutex;\n\n   snprintf(name_buffer, sizeof(name_buffer), \"0x%08X\", (unsigned int) cond);\n   cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);\n\n   if (cond->sema < 0)\n   {\n      pthread_mutex_destroy(&cond->mutex);\n      return cond->sema;\n   }\n\n   cond->waiting = 0;\n\n   return 0;\n\n#else\n   /* FIXME: stub */\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_cond_signal(pthread_cond_t *cond)\n{\n#ifdef VITA\n\tpthread_mutex_lock(&cond->mutex);\n\tif (cond->waiting)\n   {\n\t\t--cond->waiting;\n\t\tsceKernelSignalSema(cond->sema, 1);\n\t}\n\tpthread_mutex_unlock(&cond->mutex);\n\treturn 0;\n#else\n   /* FIXME: stub */\n   return 1;\n#endif\n}\n\nstatic INLINE int pthread_cond_broadcast(pthread_cond_t *cond)\n{\n   /* FIXME: stub */\n   return 1;\n}\n\nstatic INLINE int pthread_cond_destroy(pthread_cond_t *cond)\n{\n#ifdef VITA\n   int ret = sceKernelDeleteSema(cond->sema);\n   if (ret < 0)\n    return ret;\n\n   return sceKernelDeleteMutex(cond->mutex);\n#else\n  /* FIXME: stub */\n  return 1;\n#endif\n}\n\nstatic INLINE int pthread_detach(pthread_t thread)\n{\n   return 0;\n}\n\nstatic INLINE void pthread_exit(void *retval)\n{\n#ifdef VITA\n   sceKernelExitDeleteThread(sceKernelGetThreadId());\n#endif\n}\n\nstatic INLINE pthread_t pthread_self(void)\n{\n   /* zero 20-mar-2016: untested */\n   return sceKernelGetThreadId();\n}\n\nstatic INLINE int pthread_equal(pthread_t t1, pthread_t t2)\n{\n\t return t1 == t2;\n}\n\n#endif /* _PSP_PTHREAD_WRAP__ */\n"
  },
  {
    "path": "rthreads/rthreads.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rthreads.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifdef __unix__\n#ifndef __sun__\n#ifndef _POSIX_C_SOURCE\n#define _POSIX_C_SOURCE 199309\n#endif\n#endif\n#endif\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <boolean.h>\n#include <rthreads/rthreads.h>\n\n/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32.\n * Maybe only supported in MSVC>=2005 */\n\n#if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)\n#define USE_WIN32_THREADS\n#ifdef _XBOX\n#include <xtl.h>\n#else\n#define WIN32_LEAN_AND_MEAN\n#ifndef _WIN32_WINNT\n#define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */\n#endif\n#include <windows.h>\n#include <mmsystem.h>\n#endif\n#elif defined(GEKKO)\n#include <ogc/lwp_watchdog.h>\n#include \"gx_pthread.h\"\n#elif defined(_3DS)\n#include \"ctr_pthread.h\"\n#else\n#include <pthread.h>\n#include <time.h>\n#endif\n\n#if defined(VITA) || defined(BSD) || defined(ORBIS) || defined(__mips__) || defined(_3DS)\n#include <sys/time.h>\n#endif\n\n#if defined(PS2)\n#include <ps2sdkapi.h>\n#endif\n\n#if defined(__MACH__) && defined(__APPLE__)\n#include <mach/clock.h>\n#include <mach/mach.h>\n#endif\n\nstruct thread_data\n{\n   void (*func)(void*);\n   void *userdata;\n};\n\nstruct sthread\n{\n#ifdef USE_WIN32_THREADS\n   HANDLE thread;\n   DWORD id;\n#else\n   pthread_t id;\n#endif\n};\n\nstruct slock\n{\n#ifdef USE_WIN32_THREADS\n   CRITICAL_SECTION lock;\n#else\n   pthread_mutex_t lock;\n#endif\n};\n\n#ifdef USE_WIN32_THREADS\n/* This will be used as a linked list implementing a queue of waiting threads */\nstruct queue_entry\n{\n   struct queue_entry *next;\n};\n#endif\n\nstruct scond\n{\n#ifdef USE_WIN32_THREADS\n   /* With this implementation of scond, we don't have any way of waking\n    * (or even identifying) specific threads.\n    * But we need to wake them in the order indicated by the queue.\n    * This potato token will get passed around every waiter.\n    * The bearer can test whether he's next, and hold onto the potato if he is.\n    * When he's done he can then put it back into play to progress\n    * the queue further. */\n   HANDLE hot_potato;\n\n   /* The primary signalled event. Hot potatoes are passed until this is set. */\n   HANDLE event;\n\n   /* the head of the queue; NULL if queue is empty */\n   struct queue_entry *head;\n\n   /* equivalent to the queue length */\n   int waiters;\n\n   /* how many waiters in the queue have been conceptually wakened by signals\n    * (even if we haven't managed to actually wake them yet) */\n   int wakens;\n\n   /* used to control access to this scond, in case the user fails */\n   CRITICAL_SECTION cs;\n\n#else\n   pthread_cond_t cond;\n#endif\n};\n\n#ifdef USE_WIN32_THREADS\nstatic DWORD CALLBACK thread_wrap(void *data_)\n#else\nstatic void *thread_wrap(void *data_)\n#endif\n{\n   struct thread_data *data = (struct thread_data*)data_;\n   if (!data)\n      return 0;\n   data->func(data->userdata);\n   free(data);\n   return 0;\n}\n\nsthread_t *sthread_create(void (*thread_func)(void*), void *userdata)\n{\n   return sthread_create_with_priority(thread_func, userdata, 0);\n}\n\n/* TODO/FIXME - this needs to be implemented for Switch/3DS */\n#if !defined(SWITCH) && !defined(USE_WIN32_THREADS) && !defined(_3DS) && !defined(GEKKO) && !defined(__HAIKU__) && !defined(EMSCRIPTEN)\n#define HAVE_THREAD_ATTR\n#endif\n\nsthread_t *sthread_create_with_priority(void (*thread_func)(void*), void *userdata, int thread_priority)\n{\n#ifdef HAVE_THREAD_ATTR\n   pthread_attr_t thread_attr;\n   bool thread_attr_needed  = false;\n#endif\n   bool thread_created      = false;\n   struct thread_data *data = NULL;\n   sthread_t *thread        = (sthread_t*)malloc(sizeof(*thread));\n\n   if (!thread)\n      return NULL;\n\n   if (!(data = (struct thread_data*)malloc(sizeof(*data))))\n   {\n      free(thread);\n      return NULL;\n   }\n\n   data->func               = thread_func;\n   data->userdata           = userdata;\n\n   thread->id               = 0;\n#ifdef USE_WIN32_THREADS\n   thread->thread           = CreateThread(NULL, 0, thread_wrap,\n         data, 0, &thread->id);\n   thread_created           = !!thread->thread;\n#else\n#ifdef HAVE_THREAD_ATTR\n   pthread_attr_init(&thread_attr);\n\n   if ((thread_priority >= 1) && (thread_priority <= 100))\n   {\n      struct sched_param sp;\n      memset(&sp, 0, sizeof(struct sched_param));\n      sp.sched_priority = thread_priority;\n      pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);\n      pthread_attr_setschedparam(&thread_attr, &sp);\n\n      thread_attr_needed = true;\n   }\n\n#if defined(VITA)\n   pthread_attr_setstacksize(&thread_attr , 0x10000 );\n   thread_attr_needed = true;\n#elif defined(__APPLE__)\n   /* Default stack size on Apple is 512Kb;\n    * for PS2 disc scanning and other reasons, we'd like 2MB. */\n   pthread_attr_setstacksize(&thread_attr , 0x200000 );\n   thread_attr_needed = true;\n#endif\n\n   if (thread_attr_needed)\n      thread_created = pthread_create(&thread->id, &thread_attr, thread_wrap, data) == 0;\n   else\n      thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;\n\n   pthread_attr_destroy(&thread_attr);\n#else\n   thread_created    = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;\n#endif\n\n#endif\n\n   if (thread_created)\n      return thread;\n   free(data);\n   free(thread);\n   return NULL;\n}\n\nint sthread_detach(sthread_t *thread)\n{\n#ifdef USE_WIN32_THREADS\n   if (!thread)\n      return 0;\n   CloseHandle(thread->thread);\n   free(thread);\n   return 0;\n#else\n   int ret;\n   if (!thread)\n      return 0;\n   ret = pthread_detach(thread->id);\n   free(thread);\n   return ret;\n#endif\n}\n\nvoid sthread_join(sthread_t *thread)\n{\n   if (!thread)\n      return;\n#ifdef USE_WIN32_THREADS\n   WaitForSingleObject(thread->thread, INFINITE);\n   CloseHandle(thread->thread);\n#else\n   pthread_join(thread->id, NULL);\n#endif\n   free(thread);\n}\n\n#if !defined(GEKKO)\nbool sthread_isself(sthread_t *thread)\n{\n#ifdef USE_WIN32_THREADS\n   return thread ? GetCurrentThreadId() == thread->id        : false;\n#else\n   return thread ? pthread_equal(pthread_self(), thread->id) : false;\n#endif\n}\n#endif\n\nslock_t *slock_new(void)\n{\n   slock_t      *lock = (slock_t*)calloc(1, sizeof(*lock));\n   if (!lock)\n      return NULL;\n#ifdef USE_WIN32_THREADS\n   InitializeCriticalSection(&lock->lock);\n#else\n   if (pthread_mutex_init(&lock->lock, NULL) != 0)\n   {\n      free(lock);\n      return NULL;\n   }\n#endif\n   return lock;\n}\n\nvoid slock_free(slock_t *lock)\n{\n   if (!lock)\n      return;\n\n#ifdef USE_WIN32_THREADS\n   DeleteCriticalSection(&lock->lock);\n#else\n   pthread_mutex_destroy(&lock->lock);\n#endif\n   free(lock);\n}\n\nvoid slock_lock(slock_t *lock)\n{\n   if (!lock)\n      return;\n#ifdef USE_WIN32_THREADS\n   EnterCriticalSection(&lock->lock);\n#else\n   pthread_mutex_lock(&lock->lock);\n#endif\n}\n\nbool slock_try_lock(slock_t *lock)\n{\n#ifdef USE_WIN32_THREADS\n   return lock && TryEnterCriticalSection(&lock->lock);\n#else\n   return lock && (pthread_mutex_trylock(&lock->lock) == 0);\n#endif\n}\n\nvoid slock_unlock(slock_t *lock)\n{\n   if (!lock)\n      return;\n#ifdef USE_WIN32_THREADS\n   LeaveCriticalSection(&lock->lock);\n#else\n   pthread_mutex_unlock(&lock->lock);\n#endif\n}\n\nscond_t *scond_new(void)\n{\n   scond_t      *cond = (scond_t*)calloc(1, sizeof(*cond));\n\n   if (!cond)\n      return NULL;\n\n#ifdef USE_WIN32_THREADS\n   /* This is very complex because recreating condition variable semantics\n    * with Win32 parts is not easy.\n    *\n    * The main problem is that a condition variable can't be used to\n    * \"pre-wake\" a thread (it will get wakened only after it's waited).\n    *\n    * Whereas a win32 event can pre-wake a thread (the event will be set\n    * in advance, so a 'waiter' won't even have to wait on it).\n    *\n    * Keep in mind a condition variable can apparently pre-wake a thread,\n    * insofar as spurious wakeups are always possible,\n    * but nobody will be expecting this and it does not need to be simulated.\n    *\n    * Moreover, we won't be doing this, because it counts as a spurious wakeup\n    * -- someone else with a genuine claim must get wakened, in any case.\n    *\n    * Therefore we choose to wake only one of the correct waiting threads.\n    * So at the very least, we need to do something clever. But there's\n    * bigger problems.\n    * We don't even have a straightforward way in win32 to satisfy\n    * pthread_cond_wait's atomicity requirement. The bulk of this\n    * algorithm is solving that.\n    *\n    * Note: We might could simplify this using vista+ condition variables,\n    * but we wanted an XP compatible solution. */\n   if (!(cond->event = CreateEvent(NULL, FALSE, FALSE, NULL)))\n   {\n      free(cond);\n      return NULL;\n   }\n   if (!(cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL)))\n   {\n      CloseHandle(cond->event);\n      free(cond);\n      return NULL;\n   }\n\n   InitializeCriticalSection(&cond->cs);\n#else\n   if (pthread_cond_init(&cond->cond, NULL) != 0)\n   {\n      free(cond);\n      return NULL;\n   }\n#endif\n\n   return cond;\n}\n\nvoid scond_free(scond_t *cond)\n{\n   if (!cond)\n      return;\n\n#ifdef USE_WIN32_THREADS\n   CloseHandle(cond->event);\n   CloseHandle(cond->hot_potato);\n   DeleteCriticalSection(&cond->cs);\n#else\n   pthread_cond_destroy(&cond->cond);\n#endif\n   free(cond);\n}\n\n#ifdef USE_WIN32_THREADS\n\n#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)\nstatic LARGE_INTEGER scond_perf_freq;\nstatic bool scond_perf_freq_inited = false;\n\nstatic void scond_init_perf_freq(void)\n{\n   if (!scond_perf_freq_inited)\n   {\n      QueryPerformanceFrequency(&scond_perf_freq);\n      scond_perf_freq_inited = true;\n   }\n}\n#else\nstatic bool scond_begin_period_done = false;\n\nstatic void scond_init_timer_period(void)\n{\n   if (!scond_begin_period_done)\n   {\n      scond_begin_period_done = true;\n      timeBeginPeriod(1);\n   }\n}\n#endif\n\nstatic bool scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds)\n{\n   struct queue_entry myentry;\n   struct queue_entry **ptr;\n\n#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)\n   LARGE_INTEGER tsBegin;\n#else\n   DWORD tsBegin;\n#endif\n   DWORD waitResult;\n   DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head,\n                                             we don't do the hot potato stuff,\n                                             so this timeout needs presetting. */\n\n   /* Reminder: `lock` is held before this is called. */\n   /* however, someone else may have called scond_signal without the lock. soo... */\n   EnterCriticalSection(&cond->cs);\n\n   /* since this library is meant for realtime game software\n    * I have no problem setting this to 1 and forgetting about it. */\n#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)\n   scond_init_perf_freq();\n#else\n   scond_init_timer_period();\n#endif\n\n   /* Now we can take a good timestamp for use in faking the timeout ourselves. */\n   /* But don't bother unless we need to (to save a little time) */\n   if (dwMilliseconds != INFINITE)\n#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)\n      QueryPerformanceCounter(&tsBegin);\n#else\n      tsBegin = timeGetTime();\n#endif\n\n   /* add ourselves to a queue of waiting threads */\n   ptr = &cond->head;\n\n   /* walk to the end of the linked list */\n   while (*ptr)\n      ptr       = &((*ptr)->next);\n\n   *ptr         = &myentry;\n   myentry.next = NULL;\n\n   cond->waiters++;\n\n   /* now the conceptual lock release and condition block are supposed to be atomic.\n    * we can't do that in Windows, but we can simulate the effects by using\n    * the queue, by the following analysis:\n    * What happens if they aren't atomic?\n    *\n    * 1. a signaller can rush in and signal, expecting a waiter to get it;\n    * but the waiter wouldn't, because he isn't blocked yet.\n    * Solution: Win32 events make this easy. The event will sit there enabled\n    *\n    * 2. a signaller can rush in and signal, and then turn right around and wait.\n    * Solution: the signaller will get queued behind the waiter, who's\n    * enqueued before he releases the mutex. */\n\n   /* It's my turn if I'm the head of the queue.\n    * Check to see if it's my turn. */\n   while (cond->head != &myentry)\n   {\n      /* It isn't my turn: */\n      DWORD timeout = INFINITE;\n\n      /* As long as someone is even going to be able to wake up\n       * when they receive the potato, keep it going round. */\n      if (cond->wakens > 0)\n         SetEvent(cond->hot_potato);\n\n      /* Assess the remaining timeout time */\n      if (dwMilliseconds != INFINITE)\n      {\n#if _WIN32_WINNT >= 0x0500 || defined(_XBOX)\n         LARGE_INTEGER now;\n         LONGLONG elapsed;\n\n         QueryPerformanceCounter(&now);\n         elapsed  = now.QuadPart - tsBegin.QuadPart;\n         elapsed *= 1000;\n         elapsed /= scond_perf_freq.QuadPart;\n#else\n         DWORD now     = timeGetTime();\n         DWORD elapsed = now - tsBegin;\n#endif\n\n         /* Try one last time with a zero timeout (keeps the code simpler) */\n         if (elapsed > dwMilliseconds)\n            elapsed = dwMilliseconds;\n\n         timeout = dwMilliseconds - elapsed;\n      }\n\n      /* Let someone else go */\n      LeaveCriticalSection(&lock->lock);\n      LeaveCriticalSection(&cond->cs);\n\n      /* Wait a while to catch the hot potato..\n       * someone else should get a chance to go */\n      /* After all, it isn't my turn (and it must be someone else's) */\n      Sleep(0);\n      waitResult = WaitForSingleObject(cond->hot_potato, timeout);\n\n      /* I should come out of here with the main lock taken */\n      EnterCriticalSection(&lock->lock);\n      EnterCriticalSection(&cond->cs);\n\n      if (waitResult == WAIT_TIMEOUT)\n      {\n         /* Out of time! Now, let's think about this. I do have the potato now--\n          * maybe it's my turn, and I have the event?\n          * If that's the case, I could proceed right now without aborting\n          * due to timeout.\n          *\n          * However.. I DID wait a real long time. The caller was willing\n          * to wait that long.\n          *\n          * I choose to give him one last chance with a zero timeout\n          * in the next step\n          */\n         if (cond->head == &myentry)\n         {\n            dwFinalTimeout = 0;\n            break;\n         }\n         else\n         {\n            /* It's not our turn and we're out of time. Give up.\n             * Remove ourself from the queue and bail. */\n            struct queue_entry *curr = cond->head;\n\n            while (curr->next != &myentry)\n               curr = curr->next;\n            curr->next = myentry.next;\n            cond->waiters--;\n            LeaveCriticalSection(&cond->cs);\n            return false;\n         }\n      }\n\n   }\n\n   /* It's my turn now -- and I hold the potato */\n\n   /* I still have the main lock, in any case */\n   /* I need to release it so that someone can set the event */\n   LeaveCriticalSection(&lock->lock);\n   LeaveCriticalSection(&cond->cs);\n\n   /* Wait for someone to actually signal this condition */\n   /* We're the only waiter waiting on the event right now -- everyone else\n    * is waiting on something different */\n   waitResult = WaitForSingleObject(cond->event, dwFinalTimeout);\n\n   /* Take the main lock so we can do work. Nobody else waits on this lock\n    * for very long, so even though it's GO TIME we won't have to wait long */\n   EnterCriticalSection(&lock->lock);\n   EnterCriticalSection(&cond->cs);\n\n   /* Remove ourselves from the queue */\n   cond->head = myentry.next;\n   cond->waiters--;\n\n   if (waitResult == WAIT_TIMEOUT)\n   {\n      /* Oops! ran out of time in the final wait. Just bail. */\n      LeaveCriticalSection(&cond->cs);\n      return false;\n   }\n\n   /* If any other wakenings are pending, go ahead and set it up  */\n   /* There may actually be no waiters. That's OK. The first waiter will come in,\n    * find it's his turn, and immediately get the signaled event */\n   cond->wakens--;\n   if (cond->wakens > 0)\n   {\n      SetEvent(cond->event);\n\n      /* Progress the queue: Put the hot potato back into play. It'll be\n       * tossed around until next in line gets it */\n      SetEvent(cond->hot_potato);\n   }\n\n   LeaveCriticalSection(&cond->cs);\n   return true;\n}\n#endif\n\nvoid scond_wait(scond_t *cond, slock_t *lock)\n{\n#ifdef USE_WIN32_THREADS\n   scond_wait_win32(cond, lock, INFINITE);\n#else\n   pthread_cond_wait(&cond->cond, &lock->lock);\n#endif\n}\n\nint scond_broadcast(scond_t *cond)\n{\n#ifdef USE_WIN32_THREADS\n   EnterCriticalSection(&cond->cs);\n   if (cond->waiters != 0)\n   {\n      /* Awaken everything which is currently queued up */\n      if (cond->wakens == 0)\n         SetEvent(cond->event);\n      cond->wakens = cond->waiters;\n\n      /* Since there is now at least one pending waken, the potato must be in play */\n      SetEvent(cond->hot_potato);\n   }\n   LeaveCriticalSection(&cond->cs);\n   return 0;\n#else\n   return pthread_cond_broadcast(&cond->cond);\n#endif\n}\n\nvoid scond_signal(scond_t *cond)\n{\n#ifdef USE_WIN32_THREADS\n\n   /* Unfortunately, pthread_cond_signal does not require that the\n    * lock be held in advance */\n   /* To avoid stomping on the condvar from other threads, we need\n    * to control access to it with this */\n   EnterCriticalSection(&cond->cs);\n\n   if (cond->waiters == 0)\n   {\n      LeaveCriticalSection(&cond->cs);\n      return;\n   }\n\n   /* wake up the next thing in the queue */\n   if (cond->wakens == 0)\n      SetEvent(cond->event);\n\n   cond->wakens++;\n\n   /* The data structure is done being modified.. I think we can leave the CS now.\n    * This would prevent some other thread from receiving the hot potato and then\n    * immediately stalling for the critical section.\n    * But remember, we were trying to replicate a semantic where this entire\n    * scond_signal call was controlled (by the user) by a lock.\n    * So in case there's trouble with this, we can move it after SetEvent() */\n   LeaveCriticalSection(&cond->cs);\n\n   /* Since there is now at least one pending waken, the potato must be in play */\n   SetEvent(cond->hot_potato);\n\n#else\n   pthread_cond_signal(&cond->cond);\n#endif\n}\n\nbool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)\n{\n#ifdef USE_WIN32_THREADS\n   /* How to convert a microsecond (us) timeout to millisecond (ms)?\n    *\n    * Someone asking for a 0 timeout clearly wants immediate timeout.\n    * Someone asking for a 1 timeout clearly wants an actual timeout\n    * of the minimum length */\n   /* The implementation of a 0 timeout here with pthreads is sketchy.\n    * It isn't clear what happens if pthread_cond_timedwait is called with NOW.\n    * Moreover, it is possible that this thread gets preempted after the\n    * clock_gettime but before the pthread_cond_timedwait.\n    * In order to help smoke out problems caused by this strange usage,\n    * let's treat a 0 timeout as always timing out.\n    */\n   if (timeout_us == 0)\n      return false;\n   else if (timeout_us < 1000)\n      return scond_wait_win32(cond, lock, 1);\n   /* Someone asking for 1000 or 1001 timeout shouldn't\n    * accidentally get 2ms. */\n   return scond_wait_win32(cond, lock, timeout_us / 1000);\n#else\n   int64_t seconds, remainder;\n   struct timespec now;\n#if defined(__MACH__) && defined(__APPLE__)\n   /* OSX doesn't have clock_gettime. */\n   clock_serv_t cclock;\n   mach_timespec_t mts;\n   host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);\n   clock_get_time(cclock, &mts);\n   mach_port_deallocate(mach_task_self(), cclock);\n   now.tv_sec = mts.tv_sec;\n   now.tv_nsec = mts.tv_nsec;\n#elif !defined(__PSL1GHT__) && defined(__PS3__)\n   sys_time_sec_t s;\n   sys_time_nsec_t n;\n   sys_time_get_current_time(&s, &n);\n   now.tv_sec            = s;\n   now.tv_nsec           = n;\n#elif defined(PS2)\n   {\n      int tickms            = ps2_clock();\n      now.tv_sec            = tickms / 1000;\n      now.tv_nsec           = (long)(tickms % 1000) * 1000000L;\n   }\n#elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS))\n   {\n      struct timeval tm;\n      gettimeofday(&tm, NULL);\n      now.tv_sec            = tm.tv_sec;\n      now.tv_nsec           = tm.tv_usec * 1000;\n   }\n#elif defined(RETRO_WIN32_USE_PTHREADS)\n   _ftime64_s(&now);\n#elif defined(GEKKO)\n   {\n      const uint64_t tickms = gettime() / TB_TIMER_CLOCK;\n      now.tv_sec            = tickms / 1000;\n      now.tv_nsec           = (long)(tickms % 1000) * 1000000L;\n   }\n#else\n   clock_gettime(CLOCK_REALTIME, &now);\n#endif\n\n   seconds              = timeout_us / INT64_C(1000000);\n   remainder            = timeout_us % INT64_C(1000000);\n\n   now.tv_sec          += seconds;\n   now.tv_nsec         += remainder * INT64_C(1000);\n\n   if (now.tv_nsec >= 1000000000)\n   {\n      now.tv_nsec      -= 1000000000;\n      now.tv_sec       += 1;\n   }\n\n   return (pthread_cond_timedwait(&cond->cond, &lock->lock, &now) == 0);\n#endif\n}\n\n#ifdef HAVE_THREAD_STORAGE\nbool sthread_tls_create(sthread_tls_t *tls)\n{\n#ifdef USE_WIN32_THREADS\n   return (*tls = TlsAlloc()) != TLS_OUT_OF_INDEXES;\n#else\n   return pthread_key_create((pthread_key_t*)tls, NULL) == 0;\n#endif\n}\n\nbool sthread_tls_delete(sthread_tls_t *tls)\n{\n#ifdef USE_WIN32_THREADS\n   return TlsFree(*tls) != 0;\n#else\n   return pthread_key_delete(*tls) == 0;\n#endif\n}\n\nvoid *sthread_tls_get(sthread_tls_t *tls)\n{\n#ifdef USE_WIN32_THREADS\n   return TlsGetValue(*tls);\n#else\n   return pthread_getspecific(*tls);\n#endif\n}\n\nbool sthread_tls_set(sthread_tls_t *tls, const void *data)\n{\n#ifdef USE_WIN32_THREADS\n   return TlsSetValue(*tls, (void*)data) != 0;\n#else\n   return pthread_setspecific(*tls, data) == 0;\n#endif\n}\n#endif\n\nuintptr_t sthread_get_thread_id(sthread_t *thread)\n{\n   if (thread)\n      return (uintptr_t)thread->id;\n   return 0;\n}\n\nuintptr_t sthread_get_current_thread_id(void)\n{\n#ifdef USE_WIN32_THREADS\n   return (uintptr_t)GetCurrentThreadId();\n#else\n   return (uintptr_t)pthread_self();\n#endif\n}\n"
  },
  {
    "path": "rthreads/tpool.c",
    "content": "/*\n * Copyright (c) 2010-2020 The RetroArch team\n * Copyright (c) 2017 John Schember <john@nachtimwald.com>\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (tpool.c).\n * ---------------------------------------------------------------------------------------\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE\n */\n\n#include <stdlib.h>\n#include <boolean.h>\n\n#include <rthreads/rthreads.h>\n#include <rthreads/tpool.h>\n\n/* Work object which will sit in a queue\n * waiting for the pool to process it.\n *\n * It is a singly linked list acting as a FIFO queue. */\nstruct tpool_work\n{\n   thread_func_t      func;  /* Function to be called. */\n   void              *arg;   /* Data to be passed to func. */\n   struct tpool_work *next;  /* Next work item in the queue. */\n};\ntypedef struct tpool_work tpool_work_t;\n\nstruct tpool\n{\n   tpool_work_t    *work_first;   /* First work item in the work queue. */\n   tpool_work_t    *work_last;    /* Last work item in the work queue. */\n   slock_t         *work_mutex;   /* Mutex protecting inserting and removing work from the work queue. */\n   scond_t         *work_cond;    /* Conditional to signal when there is work to process. */\n   scond_t         *working_cond; /* Conditional to signal when there is no work processing.\n                                       This will also signal when there are no threads running. */\n   size_t           working_cnt;  /* The number of threads processing work (Not waiting for work). */\n   size_t           thread_cnt;   /* Total number of threads within the pool. */\n   bool             stop;         /* Marker to tell the work threads to exit. */\n};\n\nstatic tpool_work_t *tpool_work_create(thread_func_t func, void *arg)\n{\n   tpool_work_t *work;\n\n   if (!func)\n      return NULL;\n\n   work       = (tpool_work_t*)calloc(1, sizeof(*work));\n   if (!work)\n      return NULL;\n   work->func = func;\n   work->arg  = arg;\n   work->next = NULL;\n   return work;\n}\n\nstatic void tpool_work_destroy(tpool_work_t *work)\n{\n   free(work);\n}\n\n/* Pull the first work item out of the queue. */\nstatic tpool_work_t *tpool_work_get(tpool_t *tp)\n{\n   tpool_work_t *work;\n\n   if (!tp)\n      return NULL;\n\n   work = tp->work_first;\n   if (!work)\n      return NULL;\n\n   if (!work->next)\n   {\n      tp->work_first = NULL;\n      tp->work_last  = NULL;\n   }\n   else\n      tp->work_first = work->next;\n\n   return work;\n}\n\nstatic void tpool_worker(void *arg)\n{\n   tpool_work_t *work = NULL;\n   tpool_t      *tp   = (tpool_t*)arg;\n\n   for (;;)\n   {\n      slock_lock(tp->work_mutex);\n\n      /* Wait until there is work available or we are told to stop.\n       * Loop handles spurious wakeups. */\n      while (!tp->work_first && !tp->stop)\n         scond_wait(tp->work_cond, tp->work_mutex);\n\n      /* Re-check stop after waking from the conditional. */\n      if (tp->stop)\n         break;\n\n      /* Try to pull work from the queue. */\n      work = tpool_work_get(tp);\n      if (work)\n         tp->working_cnt++;\n      slock_unlock(tp->work_mutex);\n\n      /* Call the work function and let it process. */\n      if (work)\n      {\n         work->func(work->arg);\n         tpool_work_destroy(work);\n\n         slock_lock(tp->work_mutex);\n         tp->working_cnt--;\n         /* Since we're in a lock no work can be added or removed from the queue.\n          * Also, the working_cnt can't be changed (except the thread holding the lock).\n          * At this point if there isn't any work processing and if there is no work\n          * signal this is the case. */\n         if (!tp->stop && tp->working_cnt == 0 && !tp->work_first)\n            scond_signal(tp->working_cond);\n         slock_unlock(tp->work_mutex);\n      }\n   }\n\n   tp->thread_cnt--;\n   if (tp->thread_cnt == 0)\n      scond_signal(tp->working_cond);\n   slock_unlock(tp->work_mutex);\n}\n\ntpool_t *tpool_create(size_t num)\n{\n   tpool_t   *tp;\n   sthread_t *thread;\n   size_t     i;\n\n   if (num == 0)\n      num = 2;\n\n   tp               = (tpool_t*)calloc(1, sizeof(*tp));\n   if (!tp)\n      return NULL;\n\n   tp->thread_cnt   = num;\n\n   tp->work_mutex   = slock_new();\n   tp->work_cond    = scond_new();\n   tp->working_cond = scond_new();\n\n   if (!tp->work_mutex || !tp->work_cond || !tp->working_cond)\n   {\n      if (tp->work_mutex)\n         slock_free(tp->work_mutex);\n      if (tp->work_cond)\n         scond_free(tp->work_cond);\n      if (tp->working_cond)\n         scond_free(tp->working_cond);\n      free(tp);\n      return NULL;\n   }\n\n   tp->work_first   = NULL;\n   tp->work_last    = NULL;\n\n   /* Create the requested number of threads and detach them. */\n   tp->thread_cnt   = 0;\n   for (i = 0; i < num; i++)\n   {\n      thread = sthread_create(tpool_worker, tp);\n      if (!thread)\n         continue;\n      tp->thread_cnt++;\n      sthread_detach(thread);\n   }\n\n   /* If no threads were created, clean up and fail. */\n   if (tp->thread_cnt == 0)\n   {\n      slock_free(tp->work_mutex);\n      scond_free(tp->work_cond);\n      scond_free(tp->working_cond);\n      free(tp);\n      return NULL;\n   }\n\n   return tp;\n}\n\nvoid tpool_destroy(tpool_t *tp)\n{\n   tpool_work_t *work;\n   tpool_work_t *work2;\n\n   if (!tp)\n      return;\n\n   /* Take all work out of the queue and destroy it. */\n   slock_lock(tp->work_mutex);\n   work = tp->work_first;\n   while (work)\n   {\n      work2 = work->next;\n      tpool_work_destroy(work);\n      work = work2;\n   }\n   tp->work_first = NULL;\n   tp->work_last  = NULL;\n\n   /* Tell the worker threads to stop. */\n   tp->stop = true;\n   scond_broadcast(tp->work_cond);\n   slock_unlock(tp->work_mutex);\n\n   /* Wait for all threads to stop. */\n   tpool_wait(tp);\n\n   slock_free(tp->work_mutex);\n   scond_free(tp->work_cond);\n   scond_free(tp->working_cond);\n\n   free(tp);\n}\n\nbool tpool_add_work(tpool_t *tp, thread_func_t func, void *arg)\n{\n   tpool_work_t *work;\n\n   if (!tp)\n      return false;\n\n   work = tpool_work_create(func, arg);\n   if (!work)\n      return false;\n\n   slock_lock(tp->work_mutex);\n   if (!tp->work_first)\n   {\n      tp->work_first      = work;\n      tp->work_last       = tp->work_first;\n   }\n   else\n   {\n      tp->work_last->next = work;\n      tp->work_last       = work;\n   }\n\n   scond_signal(tp->work_cond);\n   slock_unlock(tp->work_mutex);\n\n   return true;\n}\n\nvoid tpool_wait(tpool_t *tp)\n{\n   if (!tp)\n      return;\n\n   slock_lock(tp->work_mutex);\n\n   for (;;)\n   {\n      /* working_cond is dual use. It signals when we're not stopping but the\n       * working_cnt is 0 indicating there isn't any work processing. If we\n       * are stopping it will trigger when there aren't any threads running.\n       *\n       * The non-stopping branch must also wait while work_first is non-NULL:\n       * a tpool_wait racing tpool_add_work would otherwise return before any\n       * worker has dequeued the just-added work (working_cnt still 0).  The\n       * worker's completion path signals working_cond only when both\n       * working_cnt == 0 and work_first == NULL, so this predicate matches\n       * the signal exactly. */\n      if ((!tp->stop && (tp->work_first || tp->working_cnt != 0)) || (tp->stop && tp->thread_cnt != 0))\n         scond_wait(tp->working_cond, tp->work_mutex);\n      else\n         break;\n   }\n\n   slock_unlock(tp->work_mutex);\n}\n"
  },
  {
    "path": "rthreads/xenon_sdl_threads.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (xenon_sdl_threads.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;) */\n\n#include \"SDL_thread.h\"\n#include \"SDL_mutex.h\"\n#include <stdlib.h>\n#include <boolean.h>\n\nSDL_cond *SDL_CreateCond(void)\n{\n   bool *sleeping = calloc(1, sizeof(*sleeping));\n   return (SDL_cond*)sleeping;\n}\n\nvoid SDL_DestroyCond(SDL_cond *sleeping)\n{\n   free(sleeping);\n}\n\nint SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)\n{\n   (void)lock;\n   volatile bool *sleeping = (volatile bool*)cond;\n\n   SDL_mutexV(lock);\n   *sleeping = true;\n   while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */\n   SDL_mutexP(lock);\n\n   return 0;\n}\n\nint SDL_CondSignal(SDL_cond *cond)\n{\n   *(volatile bool*)cond = false;\n   return 0;\n}\n"
  },
  {
    "path": "samples/atomic/retro_atomic_extern_c_linkage/Makefile",
    "content": "TARGET      := retro_atomic_extern_c_linkage_test\nTARGET_TEST := retro_atomic_extern_c_linkage_test_cxx\n\nLIBRETRO_COMM_DIR := ../../..\n\n# Two binaries from one source.  The source mirrors ui_qt.cpp's pattern\n# of wrapping a RetroArch header include in extern \"C\" { ... }, gated\n# on !CXX_BUILD.  We build it once each way:\n#\n#   $(TARGET)      : non-unity / separate-TU build (extern \"C\" wrap is\n#                    active).  This is the configuration that triggered\n#                    the original \"template with C linkage\" failure on\n#                    g++ before the retro_common_api.h fix.\n#\n#   $(TARGET_TEST) : unity / griffin build (CXX_BUILD defined, extern\n#                    \"C\" wrappers compile out).  Validates that the\n#                    fix did not regress the unity-build path.\n#\n# Both must compile and pass.  Build failure on $(TARGET) is the\n# regression signal for the original bug.\n\nSOURCE := retro_atomic_extern_c_linkage_test.cpp\n\n# C++11 is the minimum that engages retro_atomic.h's CXX11 backend.\n# -Wall -Wextra to catch any incidental warning the test's macro\n# expansions might produce on a future toolchain.\nCXXFLAGS += -Wall -Wextra -pedantic -std=c++11 -g -O0 \\\n            -I$(LIBRETRO_COMM_DIR)/include\n\nifneq ($(SANITIZER),)\n   CXXFLAGS := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CXXFLAGS)\n   LDFLAGS  := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\n# The unity-build target gets CXX_BUILD defined, exactly as\n# Makefile.griffin does for griffin_cpp.cpp's TUs.\n$(TARGET_TEST): CXXFLAGS += -DCXX_BUILD\n\nall: $(TARGET) $(TARGET_TEST)\n\n$(TARGET): $(SOURCE)\n\t$(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS)\n\n$(TARGET_TEST): $(SOURCE)\n\t$(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(TARGET_TEST)\n\n.PHONY: all clean\n"
  },
  {
    "path": "samples/atomic/retro_atomic_extern_c_linkage/retro_atomic_extern_c_linkage_test.cpp",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (retro_atomic_extern_c_linkage_test.cpp).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression test for the linkage hazard in\n * libretro-common/include/retro_atomic.h's C++11 backend.\n *\n * Background\n * ----------\n * Several C++ TUs in RetroArch wrap their includes of in-tree C\n * headers in extern \"C\" { ... } when CXX_BUILD is not defined.  The\n * canonical example is ui/drivers/ui_qt.cpp:\n *\n *     #ifndef CXX_BUILD\n *     extern \"C\" {\n *     #endif\n *     #include \"../../menu/menu_driver.h\"   // pulls in retro_atomic.h\n *     ...\n *     #ifndef CXX_BUILD\n *     }\n *     #endif\n *\n * On a C++11+ build this chain reaches retro_atomic.h's CXX11 backend,\n * which #include's <atomic>.  libstdc++'s <atomic> declares dozens of\n * templates and template specializations; under C linkage every one of\n * them is rejected with\n *\n *     error: template with C linkage\n *\n * yielding ~80 errors on a single TU.  See the build log on master at\n * the time of the original report; same failure on g++ 9 through 13.\n *\n * Fix\n * ---\n * retro_common_api.h gained RETRO_BEGIN_DECLS_CXX / RETRO_END_DECLS_CXX\n * macros that expand to extern \"C++\" { ... } in C++ mode (with\n * CXX_BUILD off) and to nothing otherwise.  retro_atomic.h's C++11\n * backend wraps its <atomic> / <cstddef> include in those macros, so\n * the standard headers parse at C++ linkage regardless of any\n * extern \"C\" the caller imposes.\n *\n * What this test asserts\n * ----------------------\n *  1. Compile-time: a C++ TU that wraps #include <retro_atomic.h>\n *     in extern \"C\" { ... } compiles without error.  The include\n *     pattern below is a faithful mirror of ui_qt.cpp's; if the\n *     header's linkage shield breaks, this file fails to compile\n *     and that is the regression signal.\n *\n *  2. Runtime: the macro expansions inside the extern \"C\" wrap still\n *     produce live std::atomic<T> objects whose load_acquire /\n *     store_release / fetch_add / fetch_sub / inc / dec round-trip\n *     correctly.  This guards against a future \"fix\" that papered\n *     over the compile error by, say, falling back to a non-atomic\n *     plain-int typedef under C linkage.  exit(0) on success,\n *     exit(1) on any property failure.\n *\n *  3. Both build configurations exercise the same source with no\n *     code-level difference (see Makefile).  The Makefile builds\n *     two targets:\n *       retro_atomic_extern_c_linkage_test       -- !CXX_BUILD path\n *       retro_atomic_extern_c_linkage_test_cxx   -- CXX_BUILD path\n *     The second one defines CXX_BUILD before including any\n *     RetroArch headers, which makes the in-tree extern \"C\" wrappers\n *     compile out (because RETRO_BEGIN_DECLS / RETRO_END_DECLS expand\n *     to nothing).  Both must build and pass.\n *\n * What this test does NOT assert\n * ------------------------------\n * It does not exercise weakly-ordered SMP correctness or thread\n * safety -- those are covered by retro_atomic_test (single-thread\n * property + SPSC stress) and retro_spsc_test (lock-free SPSC) in\n * neighbouring sample directories, and by the cross-arch qemu lane\n * in .github/workflows/Linux-libretro-common-samples.yml.  This\n * test's job is purely to police the include-from-C++ hazard.\n *\n * Build standalone\n * ----------------\n *   make clean all\n *   ./retro_atomic_extern_c_linkage_test\n *   ./retro_atomic_extern_c_linkage_test_cxx\n *\n * Both binaries exit 0 on success.  A pre-fix retro_atomic.h would\n * fail at the build step rather than at runtime.\n */\n\n/* Mirror of ui_qt.cpp's include guard pattern.  retro_common_api.h\n * (transitively included from retro_atomic.h) keys on this:\n *\n *   #ifdef CXX_BUILD\n *     -- no extern \"C\" wrappers anywhere in libretro-common headers --\n *   #else\n *     -- normal RETRO_BEGIN_DECLS = extern \"C\" { wrapping --\n *   #endif\n *\n * The Makefile builds this file twice, once with CXX_BUILD undefined\n * (the non-unity build path that triggered the original bug) and once\n * with CXX_BUILD defined (the griffin/unity-build path).  Both must\n * compile and pass the runtime checks. */\n\n#include <cstdio>\n#include <cstddef>\n\n/* This is the regression's trigger pattern: a C++ TU includes a\n * RetroArch header from inside its own extern \"C\" block.  On a stock\n * (broken) retro_atomic.h, the transitive #include <atomic> here would\n * be parsed at C linkage and the build would die. */\n#ifndef CXX_BUILD\nextern \"C\" {\n#endif\n\n#include <retro_atomic.h>\n\n#ifndef CXX_BUILD\n}\n#endif\n\n/* Capability flags must be set after the include succeeds.  If a\n * future refactor accidentally compiles the header out under\n * extern \"C\", these gates fire at preprocessing time with a clearer\n * message than the libstdc++ template avalanche. */\n#if !defined(HAVE_RETRO_ATOMIC)\n# error \"retro_atomic.h: HAVE_RETRO_ATOMIC not set after include\"\n#endif\n#if !defined(RETRO_ATOMIC_BACKEND_NAME)\n# error \"retro_atomic.h: RETRO_ATOMIC_BACKEND_NAME not set after include\"\n#endif\n\n/* On a C++11+ host the CXX11 backend is the expected selection.  If\n * something promotes a different backend in this TU we want to know;\n * the whole point of the test is to police the C++11 path. */\n#if !defined(RETRO_ATOMIC_BACKEND_CXX11)\n# error \"retro_atomic_extern_c_linkage_test: expected the C++11 <atomic> backend; if a different backend is intentional, update this gate\"\n#endif\n\n/* ---- Single-threaded property checks --------------------------------- */\n/* Each returns 0 on success, 1 on failure.  Identical in shape to\n * retro_atomic_test.c so a regression in either test points at the\n * same place. */\n\nstatic int check_init(void)\n{\n   retro_atomic_int_t  ai; retro_atomic_int_init (&ai, 7);\n   retro_atomic_size_t as; retro_atomic_size_init(&as, (std::size_t)9);\n\n   if (retro_atomic_load_acquire_int (&ai) != 7) return 1;\n   if (retro_atomic_load_acquire_size(&as) != (std::size_t)9) return 1;\n   return 0;\n}\n\nstatic int check_store_release_load_acquire(void)\n{\n   retro_atomic_int_t  ai; retro_atomic_int_init (&ai, 0);\n   retro_atomic_size_t as; retro_atomic_size_init(&as, 0);\n\n   retro_atomic_store_release_int (&ai, 42);\n   retro_atomic_store_release_size(&as, (std::size_t)42);\n\n   if (retro_atomic_load_acquire_int (&ai) != 42) return 1;\n   if (retro_atomic_load_acquire_size(&as) != (std::size_t)42) return 1;\n   return 0;\n}\n\nstatic int check_fetch_add_sub_returns_previous(void)\n{\n   retro_atomic_int_t  ai; retro_atomic_int_init (&ai, 10);\n   retro_atomic_size_t as; retro_atomic_size_init(&as, (std::size_t)10);\n\n   /* fetch_add returns the previous value (POSIX convention). */\n   if (retro_atomic_fetch_add_int (&ai, 5) != 10) return 1;\n   if (retro_atomic_fetch_add_size(&as, 5) != (std::size_t)10) return 1;\n\n   if (retro_atomic_load_acquire_int (&ai) != 15) return 1;\n   if (retro_atomic_load_acquire_size(&as) != (std::size_t)15) return 1;\n\n   if (retro_atomic_fetch_sub_int (&ai, 5) != 15) return 1;\n   if (retro_atomic_fetch_sub_size(&as, 5) != (std::size_t)15) return 1;\n\n   if (retro_atomic_load_acquire_int (&ai) != 10) return 1;\n   if (retro_atomic_load_acquire_size(&as) != (std::size_t)10) return 1;\n   return 0;\n}\n\nint main(void)\n{\n   int fails = 0;\n\n   std::printf(\"backend: %s\\n\", RETRO_ATOMIC_BACKEND_NAME);\n#ifdef CXX_BUILD\n   std::puts(\"config:  CXX_BUILD defined (griffin/unity-build path)\");\n#else\n   std::puts(\"config:  CXX_BUILD undefined (separate-TU path, ui_qt.cpp shape)\");\n#endif\n\n   fails += check_init();\n   fails += check_store_release_load_acquire();\n   fails += check_fetch_add_sub_returns_previous();\n\n   if (fails)\n   {\n      std::printf(\"FAIL: %d check(s) failed\\n\", fails);\n      return 1;\n   }\n   std::puts(\"ALL OK\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/atomic/retro_atomic_test/Makefile",
    "content": "TARGET := retro_atomic_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# retro_atomic.h is a header-only primitive (no .c counterpart) so the\n# test only needs rthreads.c when the SPSC stress check is enabled.\n# Build with HAVE_THREADS for real coverage; without HAVE_THREADS the\n# header-only checks still run, validating the macros' single-thread\n# behaviour on platforms where threading is not available.\nHAVE_THREADS ?= 1\n\nSOURCES := retro_atomic_test.c\n\nCFLAGS  += -Wall -pedantic -std=gnu99 -g -O0 -I$(LIBRETRO_COMM_DIR)/include\n\nifeq ($(HAVE_THREADS),1)\n   CFLAGS  += -DHAVE_THREADS\n   SOURCES += $(LIBRETRO_COMM_DIR)/rthreads/rthreads.c\n   LDFLAGS += -lpthread\n   # rthreads.c uses clock_gettime + CLOCK_REALTIME on Linux glibc; on\n   # older glibc those live in -lrt.  Harmless on newer glibc.\n   LDFLAGS += -lrt\nendif\n\nOBJS := $(SOURCES:.c=.o)\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/atomic/retro_atomic_test/retro_atomic_test.c",
    "content": "/* Regression test for libretro-common/include/retro_atomic.h.\n *\n * Background\n * ----------\n * retro_atomic.h consolidates the ad-hoc atomic shims that were\n * previously duplicated in audio/drivers/{coreaudio,coreaudio3,xaudio,\n * opensl}.c, audio/common/mmdevice_common.c and gfx/gfx_thumbnail.c.\n * It exposes a narrow surface (load/store with acquire/release\n * ordering, fetch_add, fetch_sub, plus inc/dec wrappers) on int and\n * size_t, with seven selectable backends:\n *\n *   1. C11 <stdatomic.h>          - modern toolchains\n *   2. C++11 <atomic>             - C++ TUs with __cplusplus >= 201103L\n *   3. GCC __atomic_*             - GCC 4.7+ / Clang 3.1+\n *   4. MSVC Win32 Interlocked*    - VS2003+, OG Xbox, Xbox 360 XDK\n *   5. Apple OSAtomic*            - PPC / pre-10.7\n *   6. GCC __sync_*               - GCC 4.1-4.6\n *   7. volatile fallback          - single-core / x86 TSO\n *\n * The header's correctness rests on each backend exposing the same\n * sequential behaviour through the macros, so this test exercises the\n * single-threaded behaviour exhaustively (any backend gets it wrong\n * and we see it) and runs an SPSC stress test under one of the\n * threading-capable backends to exercise the release/acquire pairing.\n *\n * What this test asserts\n * ----------------------\n *  1. The capability flags HAVE_RETRO_ATOMIC, RETRO_ATOMIC_BACKEND_NAME\n *     and RETRO_ATOMIC_LOCK_FREE are defined consistently with the\n *     selected backend (compile-time #error checks; a real-backend\n *     selection must imply RETRO_ATOMIC_LOCK_FREE, and the volatile\n *     fallback must NOT define RETRO_ATOMIC_LOCK_FREE).\n *  2. Initialisers seed the slot to the requested value.\n *  3. store_release publishes a value visible to load_acquire on the\n *     same thread (single-thread observability).\n *  4. fetch_add and fetch_sub return the previous value (POSIX-style)\n *     and update the storage in place.\n *  5. inc / dec wrappers map to fetch_add(1) / fetch_sub(1).\n *  6. SPSC stress (HAVE_THREADS only): a producer running fetch_add\n *     1..N and a release-store flag, paired with a consumer doing\n *     load_acquire on the counter and the flag, sees a strictly\n *     monotonically non-decreasing counter sequence and a final value\n *     of exactly N.  This is the property the SPSC fifo design relies\n *     on.  A backend that releases without ordering would be flagged\n *     by a counter going backwards or by the consumer seeing the flag\n *     before the writes that should have preceded it.\n *  7. The test prints which backend was selected and whether\n *     RETRO_ATOMIC_LOCK_FREE is defined, so a CI diff makes accidental\n *     backend regressions obvious.\n *\n * What this test does NOT assert\n * ------------------------------\n * It does not validate hardware ordering on weakly-ordered SMP from\n * a single host run on x86_64 (TSO masks most reordering bugs).  For\n * the GCC backend, AArch64 / ARMv7 cross-compile + qemu user-mode\n * has been verified locally: the test passes and the emitted asm\n * contains real ldar/stlr instructions and ldadd*_acq_rel libcalls.\n * The existing Switch (libnx), Wii U, PSVita, 3DS and Android CI\n * workflows compile-test the rest of the tree on real ARM toolchains,\n * which would catch any backend-selection regression at build time.\n * MSVC ARM64 is the path we have not been able to validate from a\n * Linux CI host; its correctness rests on the *Acquire / *Release\n * Win32 forms emitting dmb (Microsoft-documented behaviour) and on\n * the explicit __dmb brackets we add around the plain RMW path.\n *\n * It does not exercise compare-and-exchange or thread fences -- those\n * are deliberately not in the API surface, since no caller in the tree\n * needs them today.  Add them (and tests) only when motivated by a\n * real caller.\n *\n * How a regression is caught\n * --------------------------\n * Each property check returns 1 on failure; main() sums them and\n * exits non-zero if any tripped.  CI runs the binary with ASan +\n * UBSan (the workflow's default), so any UB from torn writes or\n * mistyped casts inside the macros is caught at the same time.\n */\n\n#include <stdio.h>\n#include <stddef.h>\n\n#include <retro_atomic.h>\n\n#ifdef HAVE_THREADS\n#include <rthreads/rthreads.h>\n#endif\n\n/* ---- Capability flag sanity checks (compile-time) -------------------- */\n\n/* The header must always define HAVE_RETRO_ATOMIC after a successful\n * include.  A regression that drops it (or makes it conditional) would\n * silently break callers that gate on it -- this static check catches it. */\n#if !defined(HAVE_RETRO_ATOMIC)\n#error \"retro_atomic.h was included but HAVE_RETRO_ATOMIC is not defined\"\n#endif\n\n/* RETRO_ATOMIC_BACKEND_NAME is documented as always available. */\n#if !defined(RETRO_ATOMIC_BACKEND_NAME)\n#error \"retro_atomic.h was included but RETRO_ATOMIC_BACKEND_NAME is not defined\"\n#endif\n\n/* RETRO_ATOMIC_LOCK_FREE must be defined if and only if a real backend\n * was selected.  We can't test the disjunction directly in the\n * preprocessor, but we can assert the obvious half: every named real\n * backend implies RETRO_ATOMIC_LOCK_FREE. */\n#if (defined(RETRO_ATOMIC_BACKEND_C11)     \\\n  || defined(RETRO_ATOMIC_BACKEND_CXX11)   \\\n  || defined(RETRO_ATOMIC_BACKEND_GCC_NEW) \\\n  || defined(RETRO_ATOMIC_BACKEND_MSVC)    \\\n  || defined(RETRO_ATOMIC_BACKEND_APPLE)   \\\n  || defined(RETRO_ATOMIC_BACKEND_SYNC))   \\\n   && !defined(RETRO_ATOMIC_LOCK_FREE)\n#error \"a real atomic backend was selected but RETRO_ATOMIC_LOCK_FREE is not defined\"\n#endif\n\n#if defined(RETRO_ATOMIC_BACKEND_VOLATILE) && defined(RETRO_ATOMIC_LOCK_FREE)\n#error \"the volatile fallback was selected but RETRO_ATOMIC_LOCK_FREE was set anyway\"\n#endif\n\n/* ---- Backend tag (printed once at start of run) ----------------------- */\n\nstatic const char *backend_name(void)\n{\n   return RETRO_ATOMIC_BACKEND_NAME;\n}\n\n/* ---- Single-threaded property checks --------------------------------- */\n\nstatic int check_init(void)\n{\n   retro_atomic_int_t  vi;\n   retro_atomic_size_t vs;\n\n   retro_atomic_int_init(&vi, 7);\n   retro_atomic_size_init(&vs, 99);\n\n   if (retro_atomic_load_acquire_int(&vi) != 7)\n   {\n      fprintf(stderr, \"FAIL init_int: expected 7\\n\");\n      return 1;\n   }\n   if ((size_t)retro_atomic_load_acquire_size(&vs) != 99)\n   {\n      fprintf(stderr, \"FAIL init_size: expected 99\\n\");\n      return 1;\n   }\n   return 0;\n}\n\nstatic int check_store_load(void)\n{\n   retro_atomic_int_t  vi;\n   retro_atomic_size_t vs;\n\n   retro_atomic_int_init(&vi, 0);\n   retro_atomic_size_init(&vs, 0);\n\n   retro_atomic_store_release_int(&vi, 42);\n   retro_atomic_store_release_size(&vs, (size_t)123456);\n\n   if (retro_atomic_load_acquire_int(&vi) != 42)\n   {\n      fprintf(stderr, \"FAIL store_load_int\\n\");\n      return 1;\n   }\n   if ((size_t)retro_atomic_load_acquire_size(&vs) != 123456)\n   {\n      fprintf(stderr, \"FAIL store_load_size\\n\");\n      return 1;\n   }\n   return 0;\n}\n\nstatic int check_fetch_add_returns_previous(void)\n{\n   retro_atomic_int_t  vi;\n   retro_atomic_size_t vs;\n   int    prev_i;\n   size_t prev_s;\n\n   retro_atomic_int_init(&vi, 100);\n   retro_atomic_size_init(&vs, 1000);\n\n   prev_i = retro_atomic_fetch_add_int(&vi, 5);\n   prev_s = (size_t)retro_atomic_fetch_add_size(&vs, 50);\n\n   if (prev_i != 100)\n   {\n      fprintf(stderr, \"FAIL fetch_add_int returned %d, expected 100\\n\", prev_i);\n      return 1;\n   }\n   if (prev_s != 1000)\n   {\n      fprintf(stderr, \"FAIL fetch_add_size returned %zu, expected 1000\\n\", prev_s);\n      return 1;\n   }\n   if (retro_atomic_load_acquire_int(&vi) != 105)\n   {\n      fprintf(stderr, \"FAIL fetch_add_int post-state\\n\");\n      return 1;\n   }\n   if ((size_t)retro_atomic_load_acquire_size(&vs) != 1050)\n   {\n      fprintf(stderr, \"FAIL fetch_add_size post-state\\n\");\n      return 1;\n   }\n   return 0;\n}\n\nstatic int check_fetch_sub_returns_previous(void)\n{\n   retro_atomic_int_t  vi;\n   retro_atomic_size_t vs;\n   int    prev_i;\n   size_t prev_s;\n\n   retro_atomic_int_init(&vi, 50);\n   retro_atomic_size_init(&vs, 500);\n\n   prev_i = retro_atomic_fetch_sub_int(&vi, 3);\n   prev_s = (size_t)retro_atomic_fetch_sub_size(&vs, 30);\n\n   if (prev_i != 50)\n   {\n      fprintf(stderr, \"FAIL fetch_sub_int returned %d, expected 50\\n\", prev_i);\n      return 1;\n   }\n   if (prev_s != 500)\n   {\n      fprintf(stderr, \"FAIL fetch_sub_size returned %zu, expected 500\\n\", prev_s);\n      return 1;\n   }\n   if (retro_atomic_load_acquire_int(&vi) != 47)\n   {\n      fprintf(stderr, \"FAIL fetch_sub_int post-state\\n\");\n      return 1;\n   }\n   if ((size_t)retro_atomic_load_acquire_size(&vs) != 470)\n   {\n      fprintf(stderr, \"FAIL fetch_sub_size post-state\\n\");\n      return 1;\n   }\n   return 0;\n}\n\nstatic int check_inc_dec_wrappers(void)\n{\n   retro_atomic_int_t  vi;\n   retro_atomic_size_t vs;\n   int i;\n\n   retro_atomic_int_init(&vi, 0);\n   retro_atomic_size_init(&vs, 0);\n\n   for (i = 0; i < 100; i++)\n      retro_atomic_inc_int(&vi);\n   for (i = 0; i < 30; i++)\n      retro_atomic_dec_int(&vi);\n\n   for (i = 0; i < 100; i++)\n      retro_atomic_inc_size(&vs);\n   for (i = 0; i < 30; i++)\n      retro_atomic_dec_size(&vs);\n\n   if (retro_atomic_load_acquire_int(&vi) != 70)\n   {\n      fprintf(stderr, \"FAIL inc/dec int\\n\");\n      return 1;\n   }\n   if ((size_t)retro_atomic_load_acquire_size(&vs) != 70)\n   {\n      fprintf(stderr, \"FAIL inc/dec size\\n\");\n      return 1;\n   }\n   return 0;\n}\n\n/* ---- SPSC stress test (HAVE_THREADS only) ---------------------------- */\n\n#ifdef HAVE_THREADS\n\n#define SPSC_N 1000000\n\ntypedef struct\n{\n   retro_atomic_size_t counter;\n   retro_atomic_int_t  done;\n   /* Filled in by the consumer; checked by main. */\n   int counter_went_backwards;\n   int final_mismatch;\n   size_t final_seen;\n   int reader_runaway;\n} spsc_state_t;\n\nstatic void spsc_writer(void *userdata)\n{\n   spsc_state_t *st = (spsc_state_t*)userdata;\n   int i;\n   for (i = 1; i <= SPSC_N; i++)\n      retro_atomic_fetch_add_size(&st->counter, 1);\n   /* Publish the done flag *after* the counter writes; pairs with the\n    * consumer's load_acquire on `done`. */\n   retro_atomic_store_release_int(&st->done, 1);\n}\n\nstatic void spsc_reader(void *userdata)\n{\n   spsc_state_t *st = (spsc_state_t*)userdata;\n   size_t last  = 0;\n   int saw_done = 0;\n   /* Bound on iterations to keep CI from hanging if a backend is\n    * silently broken; SPSC_N is 1e6, the loop should converge well\n    * inside 1e8. */\n   unsigned long long loops = 0;\n\n   for (;;)\n   {\n      size_t cur = (size_t)retro_atomic_load_acquire_size(&st->counter);\n\n      if (cur < last)\n      {\n         st->counter_went_backwards = 1;\n         return;\n      }\n      last = cur;\n\n      if (!saw_done && retro_atomic_load_acquire_int(&st->done))\n         saw_done = 1;\n\n      if (saw_done && cur >= (size_t)SPSC_N)\n         break;\n\n      if (++loops > 100000000ull)\n      {\n         st->reader_runaway = 1;\n         return;\n      }\n   }\n\n   st->final_seen = last;\n   if (last != (size_t)SPSC_N)\n      st->final_mismatch = 1;\n}\n\nstatic int check_spsc_stress(void)\n{\n   spsc_state_t st;\n   sthread_t *tw, *tr;\n\n   retro_atomic_size_init(&st.counter, 0);\n   retro_atomic_int_init(&st.done, 0);\n   st.counter_went_backwards = 0;\n   st.final_mismatch         = 0;\n   st.final_seen             = 0;\n   st.reader_runaway         = 0;\n\n   tw = sthread_create(spsc_writer, &st);\n   tr = sthread_create(spsc_reader, &st);\n   if (!tw || !tr)\n   {\n      fprintf(stderr, \"FAIL spsc: sthread_create returned NULL\\n\");\n      return 1;\n   }\n   sthread_join(tw);\n   sthread_join(tr);\n\n   if (st.counter_went_backwards)\n   {\n      fprintf(stderr, \"FAIL spsc: counter observed going backwards\\n\");\n      return 1;\n   }\n   if (st.reader_runaway)\n   {\n      fprintf(stderr, \"FAIL spsc: reader exceeded loop bound\\n\");\n      return 1;\n   }\n   if (st.final_mismatch)\n   {\n      fprintf(stderr, \"FAIL spsc: final counter %zu != %d\\n\",\n            st.final_seen, SPSC_N);\n      return 1;\n   }\n   return 0;\n}\n\n#endif /* HAVE_THREADS */\n\nint main(void)\n{\n   int fails = 0;\n\n   printf(\"retro_atomic backend: %s\\n\", backend_name());\n#if defined(RETRO_ATOMIC_LOCK_FREE)\n   printf(\"retro_atomic lock-free: yes\\n\");\n#else\n   printf(\"retro_atomic lock-free: NO (volatile fallback; SMP-unsafe)\\n\");\n#endif\n\n   fails += check_init();\n   fails += check_store_load();\n   fails += check_fetch_add_returns_previous();\n   fails += check_fetch_sub_returns_previous();\n   fails += check_inc_dec_wrappers();\n\n#ifdef HAVE_THREADS\n   fails += check_spsc_stress();\n#else\n   printf(\"[skip] SPSC stress test (HAVE_THREADS not defined)\\n\");\n#endif\n\n   if (fails == 0)\n   {\n      printf(\"ALL OK\\n\");\n      return 0;\n   }\n   printf(\"%d FAILURE(S)\\n\", fails);\n   return 1;\n}\n"
  },
  {
    "path": "samples/compat/fnmatch/Makefile",
    "content": "TARGET := compat_fnmatch_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\tcompat_fnmatch_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/compat/fnmatch/compat_fnmatch_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (compat_fnmatch_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <assert.h>\n#include <stddef.h>\n\n#include <compat/fnmatch.h>\n\nint main(void)\n{\n   assert(rl_fnmatch(\"TEST\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE?T\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE[Ssa]T\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE[Ssda]T\", \"TEsT\", 0) == 0);\n   assert(rl_fnmatch(\"TE[Ssda]T\", \"TEdT\", 0) == 0);\n   assert(rl_fnmatch(\"TE[Ssda]T\", \"TEaT\", 0) == 0);\n   assert(rl_fnmatch(\"TEST*\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TEST**\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE*ST*\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE**ST*\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE**ST*\", \"TExST\", 0) == 0);\n   assert(rl_fnmatch(\"TE**ST\", \"TEST\", 0) == 0);\n   assert(rl_fnmatch(\"TE**ST\", \"TExST\", 0) == 0);\n   assert(rl_fnmatch(\"TE\\\\**ST\", \"TE*xST\", 0) == 0);\n   assert(rl_fnmatch(\"*.*\", \"test.jpg\", 0) == 0);\n   assert(rl_fnmatch(\"*.jpg\", \"test.jpg\", 0) == 0);\n   assert(rl_fnmatch(\"*.[Jj][Pp][Gg]\", \"test.jPg\", 0) == 0);\n   assert(rl_fnmatch(\"*.[Jj]*[Gg]\", \"test.jPg\", 0) == 0);\n   assert(rl_fnmatch(\"TEST?\", \"TEST\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TES[asd\", \"TEST\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TEST\\\\\", \"TEST\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TEST*S\", \"TEST\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TE**ST\", \"TExT\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TE\\\\*T\", \"TExT\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TES?\", \"TES\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TE\", \"TEST\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"TEST!\", \"TEST\", 0) == FNM_NOMATCH);\n   assert(rl_fnmatch(\"DSAD\", \"TEST\", 0) == FNM_NOMATCH);\n}\n"
  },
  {
    "path": "samples/compat/snprintf/Makefile",
    "content": "TARGET := snprintf\n\nCORE_DIR          := .\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES_C := \t\\\n\t$(CORE_DIR)/snprintf_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_snprintf.c\n\nOBJS := $(SOURCES_C:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/compat/snprintf/snprintf_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (snprintf_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#include <compat/strl.h>\n\nint main(int argc, char *argv[])\n{\n   char s[128];\n   char *variable      = \"test1\";\n   char *variable2     = \"test2\";\n   char *variable3     = \"test3\";\n   char *variable4     = \"test4\";\n   char *variable5     = \"test5\";\n   char *variable6     = \"test6\";\n   int ret             = snprintf(s,\n         sizeof(s), \"%s%s%s%s%s%s%s%s%s%s%s\", variable,\n         \" : \", variable2,\n         \" : \", variable3,\n         \" : \", variable4,\n         \" : \", variable5,\n         \" : \", variable6\n         );\n\n   fprintf(stderr, \"[%d], %s\\n\", ret, s);\n\n   return 0;\n}\n"
  },
  {
    "path": "samples/core_options/README.md",
    "content": "## Adding 'enhanced' core options to a core\n\nThe basic steps for updating a core to support core options v1 are as follows:\n\n- Copy `example_default/libretro_core_options.h` to the same directory as `libretro.c/.cpp`\n\n- Copy `example_default/libretro_core_options_intl.h` to the same directory as `libretro.c/.cpp`\n\n- Add `#include \"libretro_core_options.h\"` to `libretro.c/.cpp`\n\n- Replace any existing calls of `RETRO_ENVIRONMENT_SET_VARIABLES` with `libretro_set_core_options(retro_environment_t environ_cb)`  \n  (Note: `libretro_set_core_options()` should be called as early as possible - preferably in `retro_set_environment()`  \n  and no later than `retro_load_game()`)\n\n- Open `libretro_core_options.h` and replace the contents of the existing `option_defs_us` struct array with all required core option parameters.  \n\n## Adding core option translations\n\nTo add a translation, simply:\n\n- 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\n\n- Translate all human-readable strings\n\n- Add the new struct array to the appropriate location in the `option_defs_intl` array inside `libretro_core_options.h`\n\nThis 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.\n\nNOTE: 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.\n\n## Disabling core options on unsupported frontends\n\nSometimes it is desirable to only show a particular core option if the frontend supports the new core options v1 API. For example:\n\n- The API v1 allows cores to hide options dynamically\n\n- We can therefore create a specific 'toggle display' option to hide or show a number of other options (e.g. advanced settings)\n\n- On frontends that do not support API v1, this 'toggle display' option will have no function - it should therefore be omitted\n\nThis 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`:\n\n- Here, a `mycore_show_speedhacks` option is added to `option_defs_us`\n\n- On line 227, the following comparison allows the option to be skipped:  \n  (Note that another `strcmp()` may be added for each option to be omitted)\n\n```c\nif (strcmp(key, \"mycore_show_speedhacks\") == 0)\n\tcontinue;\n```\n\nFor 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`\n\n## Adding core option categories\n\nCore 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.\n\nA 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).\n"
  },
  {
    "path": "samples/core_options/example_categories/conversion_scripts/core_option_regex.py",
    "content": "import re\n\n# 0: full struct; 1: up to & including first []; 2: content between first {}\np_struct = re.compile(r'(struct\\s*[a-zA-Z0-9_\\s]+\\[])\\s*'\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+)\\s*)*'\n                      r'=\\s*'  # =\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+)\\s*)*'\n                      r'{((?:.|[\\r\\n])*?)\\{\\s*NULL,\\s*NULL,\\s*NULL\\s*(?:.|[\\r\\n])*?},?(?:.|[\\r\\n])*?};')  # captures full struct, it's beginning and it's content\n# 0: type name[]; 1: type; 2: name\np_type_name = re.compile(r'(retro_core_option_[a-zA-Z0-9_]+)\\s*'\n                         r'(option_cats[a-z_]{0,8}|option_defs([a-z_]{0,8}))\\s*\\[]')\n# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs\np_option = re.compile(r'{\\s*'  # opening braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(\\\".*?\\\"|'  # key start; group 1\n                      r'[a-zA-Z0-9_]+\\s*\\((?:.|[\\r\\n])*?\\)|'\n                      r'[a-zA-Z0-9_]+\\s*\\[(?:.|[\\r\\n])*?]|'\n                      r'[a-zA-Z0-9_]+\\s*\\\".*?\\\")\\s*'  # key end\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(\\\".*?\\\")\\s*'  # description; group 2\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'((?:'  # group 3\n                      r'(?:NULL|\\\"(?:.|[\\r\\n])*?\\\")\\s*'  # description in category, info, info in category, category\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r')+)'\n                      r'(?:'  # defs only start\n                      r'{\\s*'  # opening braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'((?:'  # key/value pairs start; group 4\n                      r'{\\s*'  # opening braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(?:NULL|\\\".*?\\\")\\s*'  # option key\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(?:NULL|\\\".*?\\\")\\s*'  # option value\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'}\\s*'  # closing braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r')*)'  # key/value pairs end\n                      r'}\\s*'  # closing braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(?:'  # defaults start\n                      r'(?:NULL|\\\".*?\\\")\\s*'  # default value\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r')*'  # defaults end\n                      r')?'  # defs only end\n                      r'},')  # closing braces\n# analyse option group 3\np_info = re.compile(r'(NULL|\\\"(?:.|[\\r\\n])*?\\\")\\s*'  # description in category, info, info in category, category\n                    r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                    r',\\s*'  # comma\n                    r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*')\n# analyse option group 4\np_key_value = re.compile(r'{\\s*'  # opening braces\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r'(NULL|\\\".*?\\\")\\s*'  # option key; 1\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r',\\s*'  # comma\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r'(NULL|\\\".*?\\\")\\s*'  # option value; 2\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r'}\\s*'  # closing braces\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r',?\\s*'  # comma\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*')\n\np_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\\s*(\\\"(?:\"\\s*\"|\\\\\\s*|.)*\\\")')\n"
  },
  {
    "path": "samples/core_options/example_categories/conversion_scripts/v1_to_v2_converter.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"Core options v1 to v2 converter\n\nJust copy 'libretro_core_options.h' & 'libretro_core_options_intl.h' into the same folder as this script\nand run it! The original files will be preserved as *.v1\n\"\"\"\nimport core_option_regex as cor\nimport os\nimport sys\n\nif os.name == 'nt':\n    joiner = '\\\\'\nelse:\n    joiner = '/'\ndir_path = os.path.dirname(os.path.realpath(__file__))\nh_filename = joiner.join((dir_path, 'libretro_core_options.h'))\nintl_filename = joiner.join((dir_path, 'libretro_core_options_intl.h'))\n\n\ndef create_v2_code_file(struct_text, file_name):\n    def replace_option(option_match):\n        _offset = option_match.start(0)\n\n        if option_match.group(3):\n            res = option_match.group(0)[:option_match.end(2) - _offset] + ',\\n      NULL' + \\\n                  option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \\\n                  'NULL,\\n      NULL,\\n      ' + option_match.group(0)[option_match.end(3) - _offset:]\n        else:\n            return option_match.group(0)\n\n        return res\n\n    comment_v1 = '/*\\n' \\\n                 ' ********************************\\n' \\\n                 ' * VERSION: 1.3\\n' \\\n                 ' ********************************\\n' \\\n                 ' *\\n' \\\n                 ' * - 1.3: Move translations to libretro_core_options_intl.h\\n' \\\n                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\\n' \\\n                 ' *          fix for MSVC 2010-2013\\n' \\\n                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\\n' \\\n                 ' *          on platforms/compilers without BOM support\\n' \\\n                 ' * - 1.2: Use core options v1 interface when\\n' \\\n                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\\n' \\\n                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\\n' \\\n                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\\n' \\\n                 ' *        arrays containing options with a single value\\n' \\\n                 ' * - 1.0: First commit\\n' \\\n                 '*/\\n'\n\n    comment_v2 = '/*\\n' \\\n                 ' ********************************\\n' \\\n                 ' * VERSION: 2.0\\n' \\\n                 ' ********************************\\n' \\\n                 ' *\\n' \\\n                 ' * - 2.0: Add support for core options v2 interface\\n' \\\n                 ' * - 1.3: Move translations to libretro_core_options_intl.h\\n' \\\n                 ' *        - libretro_core_options_intl.h includes BOM and utf-8\\n' \\\n                 ' *          fix for MSVC 2010-2013\\n' \\\n                 ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\\n' \\\n                 ' *          on platforms/compilers without BOM support\\n' \\\n                 ' * - 1.2: Use core options v1 interface when\\n' \\\n                 ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\\n' \\\n                 ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\\n' \\\n                 ' * - 1.1: Support generation of core options v0 retro_core_option_value\\n' \\\n                 ' *        arrays containing options with a single value\\n' \\\n                 ' * - 1.0: First commit\\n' \\\n                 '*/\\n'\n\n    p_intl = cor.re.compile(r'(struct retro_core_option_definition \\*option_defs_intl\\[RETRO_LANGUAGE_LAST]) = {'\n                            r'((?:.|[\\r\\n])*?)};')\n    p_set = cor.re.compile(r'static INLINE void libretro_set_core_options\\(retro_environment_t environ_cb\\)'\n                           r'(?:.|[\\r\\n])*?};?\\s*#ifdef __cplusplus\\s*}\\s*#endif')\n    new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\\n' \\\n              '      bool *categories_supported)\\n' \\\n              '{\\n' \\\n              '   unsigned version  = 0;\\n' \\\n              '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n              '   unsigned language = 0;\\n' \\\n              '#endif\\n' \\\n              '\\n' \\\n              '   if (!environ_cb || !categories_supported)\\n' \\\n              '      return;\\n' \\\n              '\\n' \\\n              '   *categories_supported = false;\\n' \\\n              '\\n' \\\n              '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\\n' \\\n              '      version = 0;\\n' \\\n              '\\n' \\\n              '   if (version >= 2)\\n' \\\n              '   {\\n' \\\n              '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n              '      struct retro_core_options_v2_intl core_options_intl;\\n' \\\n              '\\n' \\\n              '      core_options_intl.us    = &options_us;\\n' \\\n              '      core_options_intl.local = NULL;\\n' \\\n              '\\n' \\\n              '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\\n' \\\n              '          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\\n' \\\n              '         core_options_intl.local = options_intl[language];\\n' \\\n              '\\n' \\\n              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\\n' \\\n              '            &core_options_intl);\\n' \\\n              '#else\\n' \\\n              '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\\n' \\\n              '            &options_us);\\n' \\\n              '#endif\\n' \\\n              '   }\\n' \\\n              '   else\\n' \\\n              '   {\\n' \\\n              '      size_t i, j;\\n' \\\n              '      size_t option_index              = 0;\\n' \\\n              '      size_t num_options               = 0;\\n' \\\n              '      struct retro_core_option_definition\\n' \\\n              '            *option_v1_defs_us         = NULL;\\n' \\\n              '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n              '      size_t num_options_intl          = 0;\\n' \\\n              '      struct retro_core_option_v2_definition\\n' \\\n              '            *option_defs_intl          = NULL;\\n' \\\n              '      struct retro_core_option_definition\\n' \\\n              '            *option_v1_defs_intl       = NULL;\\n' \\\n              '      struct retro_core_options_intl\\n' \\\n              '            core_options_v1_intl;\\n' \\\n              '#endif\\n' \\\n              '      struct retro_variable *variables = NULL;\\n' \\\n              '      char **values_buf                = NULL;\\n' \\\n              '\\n' \\\n              '      /* Determine total number of options */\\n' \\\n              '      while (true)\\n' \\\n              '      {\\n' \\\n              '         if (option_defs_us[num_options].key)\\n' \\\n              '            num_options++;\\n' \\\n              '         else\\n' \\\n              '            break;\\n' \\\n              '      }\\n' \\\n              '\\n' \\\n              '      if (version >= 1)\\n' \\\n              '      {\\n' \\\n              '         /* Allocate US array */\\n' \\\n              '         option_v1_defs_us = (struct retro_core_option_definition *)\\n' \\\n              '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\\n' \\\n              '\\n' \\\n              '         /* Copy parameters from option_defs_us array */\\n' \\\n              '         for (i = 0; i < num_options; i++)\\n' \\\n              '         {\\n' \\\n              '            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\\n' \\\n              '            struct retro_core_option_value *option_values         = option_def_us->values;\\n' \\\n              '            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\\n' \\\n              '            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;\\n' \\\n              '\\n' \\\n              '            option_v1_def_us->key           = option_def_us->key;\\n' \\\n              '            option_v1_def_us->desc          = option_def_us->desc;\\n' \\\n              '            option_v1_def_us->info          = option_def_us->info;\\n' \\\n              '            option_v1_def_us->default_value = option_def_us->default_value;\\n' \\\n              '\\n' \\\n              '            /* Values must be copied individually... */\\n' \\\n              '            while (option_values->value)\\n' \\\n              '            {\\n' \\\n              '               option_v1_values->value = option_values->value;\\n' \\\n              '               option_v1_values->label = option_values->label;\\n' \\\n              '\\n' \\\n              '               option_values++;\\n' \\\n              '               option_v1_values++;\\n' \\\n              '            }\\n' \\\n              '         }\\n' \\\n              '\\n' \\\n              '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n              '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\\n' \\\n              '             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\\n' \\\n              '             options_intl[language])\\n' \\\n              '            option_defs_intl = options_intl[language]->definitions;\\n' \\\n              '\\n' \\\n              '         if (option_defs_intl)\\n' \\\n              '         {\\n' \\\n              '            /* Determine number of intl options */\\n' \\\n              '            while (true)\\n' \\\n              '            {\\n' \\\n              '               if (option_defs_intl[num_options_intl].key)\\n' \\\n              '                  num_options_intl++;\\n' \\\n              '               else\\n' \\\n              '                  break;\\n' \\\n              '            }\\n' \\\n              '\\n' \\\n              '            /* Allocate intl array */\\n' \\\n              '            option_v1_defs_intl = (struct retro_core_option_definition *)\\n' \\\n              '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\\n' \\\n              '\\n' \\\n              '            /* Copy parameters from option_defs_intl array */\\n' \\\n              '            for (i = 0; i < num_options_intl; i++)\\n' \\\n              '            {\\n' \\\n              '               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\\n' \\\n              '               struct retro_core_option_value *option_values           = option_def_intl->values;\\n' \\\n              '               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\\n' \\\n              '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;\\n' \\\n              '\\n' \\\n              '               option_v1_def_intl->key           = option_def_intl->key;\\n' \\\n              '               option_v1_def_intl->desc          = option_def_intl->desc;\\n' \\\n              '               option_v1_def_intl->info          = option_def_intl->info;\\n' \\\n              '               option_v1_def_intl->default_value = option_def_intl->default_value;\\n' \\\n              '\\n' \\\n              '               /* Values must be copied individually... */\\n' \\\n              '               while (option_values->value)\\n' \\\n              '               {\\n' \\\n              '                  option_v1_values->value = option_values->value;\\n' \\\n              '                  option_v1_values->label = option_values->label;\\n' \\\n              '\\n' \\\n              '                  option_values++;\\n' \\\n              '                  option_v1_values++;\\n' \\\n              '               }\\n' \\\n              '            }\\n' \\\n              '         }\\n' \\\n              '\\n' \\\n              '         core_options_v1_intl.us    = option_v1_defs_us;\\n' \\\n              '         core_options_v1_intl.local = option_v1_defs_intl;\\n' \\\n              '\\n' \\\n              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\\n' \\\n              '#else\\n' \\\n              '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\\n' \\\n              '#endif\\n' \\\n              '      }\\n' \\\n              '      else\\n' \\\n              '      {\\n' \\\n              '         /* Allocate arrays */\\n' \\\n              '         variables  = (struct retro_variable *)calloc(num_options + 1,\\n' \\\n              '               sizeof(struct retro_variable));\\n' \\\n              '         values_buf = (char **)calloc(num_options, sizeof(char *));\\n' \\\n              '\\n' \\\n              '         if (!variables || !values_buf)\\n' \\\n              '            goto error;\\n' \\\n              '\\n' \\\n              '         /* Copy parameters from option_defs_us array */\\n' \\\n              '         for (i = 0; i < num_options; i++)\\n' \\\n              '         {\\n' \\\n              '            const char *key                        = option_defs_us[i].key;\\n' \\\n              '            const char *desc                       = option_defs_us[i].desc;\\n' \\\n              '            const char *default_value              = option_defs_us[i].default_value;\\n' \\\n              '            struct retro_core_option_value *values = option_defs_us[i].values;\\n' \\\n              '            size_t buf_len                         = 3;\\n' \\\n              '            size_t default_index                   = 0;\\n' \\\n              '\\n' \\\n              '            values_buf[i] = NULL;\\n' \\\n              '\\n' \\\n              '            if (desc)\\n' \\\n              '            {\\n' \\\n              '               size_t num_values = 0;\\n' \\\n              '\\n' \\\n              '               /* Determine number of values */\\n' \\\n              '               while (true)\\n' \\\n              '               {\\n' \\\n              '                  if (values[num_values].value)\\n' \\\n              '                  {\\n' \\\n              '                     /* Check if this is the default value */\\n' \\\n              '                     if (default_value)\\n' \\\n              '                        if (strcmp(values[num_values].value, default_value) == 0)\\n' \\\n              '                           default_index = num_values;\\n' \\\n              '\\n' \\\n              '                     buf_len += strlen(values[num_values].value);\\n' \\\n              '                     num_values++;\\n' \\\n              '                  }\\n' \\\n              '                  else\\n' \\\n              '                     break;\\n' \\\n              '               }\\n' \\\n              '\\n' \\\n              '               /* Build values string */\\n' \\\n              '               if (num_values > 0)\\n' \\\n              '               {\\n' \\\n              '                  buf_len += num_values - 1;\\n' \\\n              '                  buf_len += strlen(desc);\\n' \\\n              '\\n' \\\n              '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\\n' \\\n              '                  if (!values_buf[i])\\n' \\\n              '                     goto error;\\n' \\\n              '\\n' \\\n              '                  strcpy(values_buf[i], desc);\\n' \\\n              '                  strcat(values_buf[i], \"; \");\\n' \\\n              '\\n' \\\n              '                  /* Default value goes first */\\n' \\\n              '                  strcat(values_buf[i], values[default_index].value);\\n' \\\n              '\\n' \\\n              '                  /* Add remaining values */\\n' \\\n              '                  for (j = 0; j < num_values; j++)\\n' \\\n              '                  {\\n' \\\n              '                     if (j != default_index)\\n' \\\n              '                     {\\n' \\\n              '                        strcat(values_buf[i], \"|\");\\n' \\\n              '                        strcat(values_buf[i], values[j].value);\\n' \\\n              '                     }\\n' \\\n              '                  }\\n' \\\n              '               }\\n' \\\n              '            }\\n' \\\n              '\\n' \\\n              '            variables[option_index].key   = key;\\n' \\\n              '            variables[option_index].value = values_buf[i];\\n' \\\n              '            option_index++;\\n' \\\n              '         }\\n' \\\n              '\\n' \\\n              '         /* Set variables */\\n' \\\n              '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\\n' \\\n              '      }\\n' \\\n              '\\n' \\\n              'error:\\n' \\\n              '      /* Clean up */\\n' \\\n              '\\n' \\\n              '      if (option_v1_defs_us)\\n' \\\n              '      {\\n' \\\n              '         free(option_v1_defs_us);\\n' \\\n              '         option_v1_defs_us = NULL;\\n' \\\n              '      }\\n' \\\n              '\\n' \\\n              '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n              '      if (option_v1_defs_intl)\\n' \\\n              '      {\\n' \\\n              '         free(option_v1_defs_intl);\\n' \\\n              '         option_v1_defs_intl = NULL;\\n' \\\n              '      }\\n' \\\n              '#endif\\n' \\\n              '\\n' \\\n              '      if (values_buf)\\n' \\\n              '      {\\n' \\\n              '         for (i = 0; i < num_options; i++)\\n' \\\n              '         {\\n' \\\n              '            if (values_buf[i])\\n' \\\n              '            {\\n' \\\n              '               free(values_buf[i]);\\n' \\\n              '               values_buf[i] = NULL;\\n' \\\n              '            }\\n' \\\n              '         }\\n' \\\n              '\\n' \\\n              '         free(values_buf);\\n' \\\n              '         values_buf = NULL;\\n' \\\n              '      }\\n' \\\n              '\\n' \\\n              '      if (variables)\\n' \\\n              '      {\\n' \\\n              '         free(variables);\\n' \\\n              '         variables = NULL;\\n' \\\n              '      }\\n' \\\n              '   }\\n' \\\n              '}\\n' \\\n              '\\n' \\\n              '#ifdef __cplusplus\\n' \\\n              '}\\n' \\\n              '#endif'\n\n    struct_groups = cor.p_struct.finditer(struct_text)\n    out_text = struct_text\n\n    for construct in struct_groups:\n        repl_text = ''\n        declaration = construct.group(1)\n        struct_match = cor.p_type_name.search(declaration)\n        if struct_match:\n            struct_type_name = struct_match.group(1, 2)\n        else:\n            return -1\n\n        if 'retro_core_option_definition' == struct_type_name[0]:\n            import shutil\n            shutil.copy(file_name, file_name + '.v1')\n            new_declaration = f'\\nstruct retro_core_option_v2_category option_cats_{struct_match.group(3)}[] = ' \\\n                              '{\\n   { NULL, NULL, NULL },\\n' \\\n                              '};\\n\\n' \\\n                              + declaration[:struct_match.start(1)] + \\\n                              'retro_core_option_v2_definition' \\\n                              + declaration[struct_match.end(1):]\n            offset = construct.start(0)\n            repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,\n                                               construct.group(0)[:construct.start(2) - offset])\n            content = construct.group(2)\n            new_content = cor.p_option.sub(replace_option, content)\n\n            repl_text = repl_text + new_content + cor.re.sub(r'{\\s*NULL,\\s*NULL,\\s*NULL,\\s*{\\{0}},\\s*NULL\\s*},\\s*};',\n                                                             '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\\n};'\n                                                             '\\n\\nstruct retro_core_options_v2 options_' +\n                                                             struct_match.group(3) + ' = {\\n'\n                                                             f'   option_cats_{struct_match.group(3)},\\n'\n                                                             f'   option_defs_{struct_match.group(3)}\\n'\n                                                             '};',\n                                                             construct.group(0)[construct.end(2) - offset:])\n            out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, out_text)\n        else:\n            return -2\n    with open(file_name, 'w', encoding='utf-8') as code_file:\n        out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)\n        intl = p_intl.search(out_text)\n        if intl:\n            new_intl = out_text[:intl.start(1)] \\\n                       + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \\\n                       + out_text[intl.end(1):intl.start(2)] + cor.re.sub(r'option_defs_', '&options_', intl.group(2)) \\\n                       + out_text[intl.end(2):]\n            out_text = p_set.sub(new_set, new_intl)\n        else:\n            out_text = p_set.sub(new_set, out_text)\n        code_file.write(out_text)\n\n    return 1\n\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n    try:\n        for file in (h_filename, intl_filename):\n            if os.path.isfile(file):\n                with open(file, 'r+', encoding='utf-8') as h_file:\n                    text = h_file.read()\n                    test = create_v2_code_file(text, file)\n                    if -1 > test:\n                        print('Your file looks like it already is v2? (' + file + ')')\n                        continue\n                    if 0 > test:\n                        print('An error occurred! Please make sure to use the complete v1 struct! (' + file + ')')\n                        continue\n            else:\n                print(file + ' not found.')\n    except EnvironmentError:\n        print('Something went wrong with reading or writing files!')\n        sys.exit(1)\n"
  },
  {
    "path": "samples/core_options/example_categories/libretro_core_options.h",
    "content": "#ifndef LIBRETRO_CORE_OPTIONS_H__\n#define LIBRETRO_CORE_OPTIONS_H__\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <libretro.h>\n#include <retro_inline.h>\n\n#ifndef HAVE_NO_LANGEXTRA\n#include \"libretro_core_options_intl.h\"\n#endif\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_ENGLISH */\n\n/* Default language:\n * - All other languages must include the same keys and values\n * - Will be used as a fallback in the event that frontend language\n *   is not available\n * - Will be used as a fallback for any missing entries in\n *   frontend language definition */\n\nstruct retro_core_option_v2_category option_cats_us[] = {\n   {\n      \"video\",                     /* key (category name) */\n      \"Video\",                     /* category description (label) */\n      \"Configure display options.\" /* category sublabel */\n   },\n   {\n      \"hacks\",\n      \"Advanced\",\n      \"Options affecting low-level emulation performance and accuracy.\"\n   },\n   { NULL, NULL, NULL },\n};\n\nstruct retro_core_option_v2_definition option_defs_us[] = {\n   {\n      \"mycore_region\",                            /* key (option name) */\n      \"Console Region\",                           /* description (label) */\n      NULL,                                       /* 'categorised' description (used instead of\n                                                   * 'description' if frontend has category\n                                                   * support; if NULL or empty, regular\n                                                   * description is always used */\n      \"Specify which region the system is from.\", /* sublabel */\n      NULL,                                       /* 'categorised' sublabel (used instead of\n                                                   * 'sublabel' if frontend has category\n                                                   * support; if NULL or empty, regular\n                                                   * sublabel is always used */\n      NULL,                                       /* category key (must match an entry in\n                                                   * option_cats_us; if NULL or empty,\n                                                   * option is uncategorised */\n      {\n         { \"auto\",   \"Auto\" },                    /* value_1, value_1_label */\n         { \"ntsc-j\", \"Japan\" },                   /* value_2, value_2_label */\n         { \"ntsc-u\", \"America\" },                 /* value_3, value_3_label */\n         { \"pal\",    \"Europe\" },                  /* value_4, value_4_label */\n         { NULL, NULL },\n      },\n      \"auto\"                                      /* default_value */\n   },\n   {\n      \"mycore_video_scale\",\n      \"Video > Scale\",   /* description: here a 'Video >' prefix is used to\n                          * signify a category on frontends without explicit\n                          * category support */\n      \"Scale\",           /* 'categorised' description: will be displayed inside\n                          * the 'Video' submenu */\n      \"Set internal video scale factor.\",\n      NULL,\n      \"video\",           /* category key */\n      {\n         { \"1x\", NULL }, /* If value itself is human-readable (e.g. a number)  */\n         { \"2x\", NULL }, /* and can displayed directly, the value_label should */\n         { \"3x\", NULL }, /* be set to NULL                                     */\n         { \"4x\", NULL },\n         { NULL, NULL },\n      },\n      \"3x\"\n   },\n   {\n      \"mycore_overclock\",\n      \"Advanced > Reduce Slowdown\",\n      \"Reduce Slowdown\",\n      \"Enabling 'Advanced > Reduce Slowdown' will reduce accuracy.\", /* sublabel */\n      \"Enabling 'Reduce Slowdown' will reduce accuracy.\",            /* 'categorised' sublabel:\n                               * will be displayed inside the 'Advanced' submenu; note that\n                               * 'Advanced > Reduce Slowdown' is replaced with 'Reduce Slowdown' */\n      \"hacks\",\n      {\n         { \"enabled\",  NULL }, /* If value is equal to 'enabled' or 'disabled', */\n         { \"disabled\", NULL }, /* value_label should be set to NULL             */\n         { NULL, NULL },\n      },\n      \"disabled\"\n   },\n   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};\n\nstruct retro_core_options_v2 options_us = {\n   option_cats_us,\n   option_defs_us\n};\n\n/*\n ********************************\n * Language Mapping\n ********************************\n*/\n\n#ifndef HAVE_NO_LANGEXTRA\nstruct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {\n   &options_us, /* RETRO_LANGUAGE_ENGLISH */\n   NULL,        /* RETRO_LANGUAGE_JAPANESE */\n   &options_fr, /* RETRO_LANGUAGE_FRENCH */\n   NULL,        /* RETRO_LANGUAGE_SPANISH */\n   NULL,        /* RETRO_LANGUAGE_GERMAN */\n   NULL,        /* RETRO_LANGUAGE_ITALIAN */\n   NULL,        /* RETRO_LANGUAGE_DUTCH */\n   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n   NULL,        /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n   NULL,        /* RETRO_LANGUAGE_RUSSIAN */\n   NULL,        /* RETRO_LANGUAGE_KOREAN */\n   NULL,        /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n   NULL,        /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n   NULL,        /* RETRO_LANGUAGE_ESPERANTO */\n   NULL,        /* RETRO_LANGUAGE_POLISH */\n   NULL,        /* RETRO_LANGUAGE_VIETNAMESE */\n   NULL,        /* RETRO_LANGUAGE_ARABIC */\n   NULL,        /* RETRO_LANGUAGE_GREEK */\n   NULL,        /* RETRO_LANGUAGE_TURKISH */\n   NULL,        /* RETRO_LANGUAGE_SLOVAK */\n   NULL,        /* RETRO_LANGUAGE_PERSIAN */\n   NULL,        /* RETRO_LANGUAGE_HEBREW */\n   NULL,        /* RETRO_LANGUAGE_ASTURIAN */\n   NULL,        /* RETRO_LANGUAGE_FINNISH */\n   NULL,        /* RETRO_LANGUAGE_INDONESIAN */\n   NULL,        /* RETRO_LANGUAGE_SWEDISH */\n   NULL,        /* RETRO_LANGUAGE_UKRAINIAN */\n   NULL,        /* RETRO_LANGUAGE_CZECH */\n   NULL,        /* RETRO_LANGUAGE_CATALAN_VALENCIA */\n   NULL,        /* RETRO_LANGUAGE_CATALAN */\n   NULL,        /* RETRO_LANGUAGE_BRITISH_ENGLISH */\n   NULL,        /* RETRO_LANGUAGE_HUNGARIAN */\n   NULL,        /* RETRO_LANGUAGE_BELARUSIAN */\n   NULL,        /* RETRO_LANGUAGE_GALICIAN */\n   NULL,        /* RETRO_LANGUAGE_NORWEGIAN */\n};\n#endif\n\n/*\n ********************************\n * Functions\n ********************************\n*/\n\n/* Handles configuration/setting of core options.\n * Should be called as early as possible - ideally inside\n * retro_set_environment(), and no later than retro_load_game()\n * > We place the function body in the header to avoid the\n *   necessity of adding more .c files (i.e. want this to\n *   be as painless as possible for core devs)\n */\n\nstatic 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\nerror:\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\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_categories/libretro_core_options_intl.h",
    "content": "﻿#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__\n#define LIBRETRO_CORE_OPTIONS_INTL_H__\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)\n/* https://support.microsoft.com/en-us/kb/980263 */\n#pragma execution_character_set(\"utf-8\")\n#pragma warning(disable:4566)\n#endif\n\n#include <libretro.h>\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_JAPANESE */\n\n/* RETRO_LANGUAGE_FRENCH */\n\nstruct retro_core_option_v2_category option_cats_fr[] = {\n   {\n      \"video\",                              /* key must match option_cats_us entry */\n      \"Vidéo\",                              /* translated category description */\n      \"Configurez les options d'affichage.\" /* translated category sublabel */\n   },\n   {\n      \"hacks\",\n      \"Avancée\",\n      \"Options affectant les performances et la précision de l'émulation de bas niveau.\"\n   },\n   { NULL, NULL, NULL },\n};\n\nstruct retro_core_option_v2_definition option_defs_fr[] = {\n   {\n      \"mycore_region\",                             /* key must match option_defs_us entry */\n      \"Région de la console\",                      /* translated description */\n      NULL,\n      \"Spécifiez la région d'origine du système.\", /* translated sublabel */\n      NULL,\n      NULL,                                        /* category key is taken from option_defs_us\n                                                    * -> can set to NULL here */\n      {\n         { \"auto\",   \"Auto\" },                     /* value must match option_defs_us entry   */\n         { \"ntsc-j\", \"Japon\" },                    /* > only value_label should be translated */\n         { \"ntsc-u\", \"Amérique\" },\n         { \"pal\",    \"L'Europe\" },\n         { NULL, NULL },\n      },\n      NULL                                         /* default_value is taken from option_defs_us\n                                                    * -> can set to NULL here */\n   },\n   {\n      \"mycore_video_scale\",\n      \"Vidéo > Échelle\", /* translated description */\n      \"Échelle\",         /* translated 'categorised' description */\n      \"Définir le facteur d'échelle vidéo interne.\",\n      NULL,\n      NULL,\n      {\n         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */\n      },\n      NULL\n   },\n   {\n      \"mycore_overclock\",\n      \"Avancé > Réduire le ralentissement\",\n      \"Réduire le ralentissement\",\n      \"L'activation de « Avancé > Réduire le ralentissement » réduira la précision.\", /* translated sublabel */\n      \"L'activation de « Réduire le ralentissement » réduira la précision.\",          /* translated 'categorised'\n                                                                                       * sublabel */\n      NULL,\n      {\n         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */\n      },\n      NULL\n   },\n   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};\n\nstruct retro_core_options_v2 options_fr = {\n   option_cats_fr,\n   option_defs_fr\n};\n\n/* RETRO_LANGUAGE_SPANISH */\n\n/* RETRO_LANGUAGE_GERMAN */\n\n/* RETRO_LANGUAGE_ITALIAN */\n\n/* RETRO_LANGUAGE_DUTCH */\n\n/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n\n/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n\n/* RETRO_LANGUAGE_RUSSIAN */\n\n/* RETRO_LANGUAGE_KOREAN */\n\n/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n\n/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n\n/* RETRO_LANGUAGE_ESPERANTO */\n\n/* RETRO_LANGUAGE_POLISH */\n\n/* RETRO_LANGUAGE_VIETNAMESE */\n\n/* RETRO_LANGUAGE_ARABIC */\n\n/* RETRO_LANGUAGE_GREEK */\n\n/* RETRO_LANGUAGE_TURKISH */\n\n/* RETRO_LANGUAGE_SLOVAK */\n\n/* RETRO_LANGUAGE_PERSIAN */\n\n/* RETRO_LANGUAGE_HEBREW */\n\n/* RETRO_LANGUAGE_ASTURIAN */\n\n/* RETRO_LANGUAGE_FINNISH */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_default/libretro_core_options.h",
    "content": "#ifndef LIBRETRO_CORE_OPTIONS_H__\n#define LIBRETRO_CORE_OPTIONS_H__\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <libretro.h>\n#include <retro_inline.h>\n\n#ifndef HAVE_NO_LANGEXTRA\n#include \"libretro_core_options_intl.h\"\n#endif\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_ENGLISH */\n\n/* Default language:\n * - All other languages must include the same keys and values\n * - Will be used as a fallback in the event that frontend language\n *   is not available\n * - Will be used as a fallback for any missing entries in\n *   frontend language definition */\n\nstruct retro_core_option_definition option_defs_us[] = {\n   {\n      \"mycore_region\",                            /* key (option name) */\n      \"Console Region\",                           /* description (label) */\n      \"Specify which region the system is from.\", /* sublabel */\n      {\n         { \"auto\",   \"Auto\" },                    /* value_1, value_1_label */\n         { \"ntsc-j\", \"Japan\" },                   /* value_2, value_2_label */\n         { \"ntsc-u\", \"America\" },                 /* value_3, value_3_label */\n         { \"pal\",    \"Europe\" },                  /* value_4, value_4_label */\n         { NULL, NULL },\n      },\n      \"auto\"                                      /* default_value */\n   },\n   {\n      \"mycore_video_scale\",\n      \"Video Scale\",\n      \"Set internal video scale factor.\",\n      {\n         { \"1x\", NULL }, /* If value itself is human-readable (e.g. a number)  */\n         { \"2x\", NULL }, /* and can displayed directly, the value_label should */\n         { \"3x\", NULL }, /* be set to NULL                                     */\n         { \"4x\", NULL },\n         { NULL, NULL },\n      },\n      \"3x\"\n   },\n   {\n      \"mycore_overclock\",\n      \"Reduce Slowdown\",\n      \"Enable CPU overclock (unsafe).\",\n      {\n         { \"enabled\",  NULL }, /* If value is equal to 'enabled' or 'disabled', */\n         { \"disabled\", NULL }, /* value_label should be set to NULL             */\n         { NULL, NULL },\n      },\n      \"disabled\"\n   },\n   { NULL, NULL, NULL, {{0}}, NULL },\n};\n\n/*\n ********************************\n * Language Mapping\n ********************************\n*/\n\n#ifndef HAVE_NO_LANGEXTRA\nstruct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {\n   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */\n   NULL,           /* RETRO_LANGUAGE_JAPANESE */\n   NULL,           /* RETRO_LANGUAGE_FRENCH */\n   NULL,           /* RETRO_LANGUAGE_SPANISH */\n   NULL,           /* RETRO_LANGUAGE_GERMAN */\n   NULL,           /* RETRO_LANGUAGE_ITALIAN */\n   NULL,           /* RETRO_LANGUAGE_DUTCH */\n   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n   NULL,           /* RETRO_LANGUAGE_RUSSIAN */\n   NULL,           /* RETRO_LANGUAGE_KOREAN */\n   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n   NULL,           /* RETRO_LANGUAGE_ESPERANTO */\n   NULL,           /* RETRO_LANGUAGE_POLISH */\n   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */\n   NULL,           /* RETRO_LANGUAGE_ARABIC */\n   NULL,           /* RETRO_LANGUAGE_GREEK */\n   NULL,           /* RETRO_LANGUAGE_TURKISH */\n   NULL,           /* RETRO_LANGUAGE_SLOVAK */\n   NULL,           /* RETRO_LANGUAGE_PERSIAN */\n   NULL,           /* RETRO_LANGUAGE_HEBREW */\n   NULL,           /* RETRO_LANGUAGE_ASTURIAN */\n   NULL,           /* RETRO_LANGUAGE_FINNISH */\n   NULL,           /* RETRO_LANGUAGE_INDONESIAN */\n   NULL,           /* RETRO_LANGUAGE_SWEDISH */\n   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */\n   NULL,           /* RETRO_LANGUAGE_CZECH */\n   NULL,           /* RETRO_LANGUAGE_CATALAN_VALENCIA */\n   NULL,           /* RETRO_LANGUAGE_CATALAN */\n   NULL,           /* RETRO_LANGUAGE_BRITISH_ENGLISH */\n   NULL,           /* RETRO_LANGUAGE_HUNGARIAN */\n   NULL,           /* RETRO_LANGUAGE_BELARUSIAN */\n   NULL,           /* RETRO_LANGUAGE_GALICIAN */\n   NULL,           /* RETRO_LANGUAGE_NORWEGIAN */\n   NULL,           /* RETRO_LANGUAGE_THAI */\n};\n#endif\n\n/*\n ********************************\n * Functions\n ********************************\n*/\n\n/* Handles configuration/setting of core options.\n * Should be called as early as possible - ideally inside\n * retro_set_environment(), and no later than retro_load_game()\n * > We place the function body in the header to avoid the\n *   necessity of adding more .c files (i.e. want this to\n *   be as painless as possible for core devs)\n */\n\nstatic INLINE void libretro_set_core_options(retro_environment_t environ_cb)\n{\n   unsigned version = 0;\n\n   if (!environ_cb)\n      return;\n\n   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))\n   {\n#ifndef HAVE_NO_LANGEXTRA\n      struct retro_core_options_intl core_options_intl;\n      unsigned language = 0;\n\n      core_options_intl.us    = option_defs_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 = option_defs_intl[language];\n\n      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);\n#else\n      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);\n#endif\n   }\n   else\n   {\n      size_t i;\n      size_t num_options               = 0;\n      struct retro_variable *variables = NULL;\n      char **values_buf                = NULL;\n\n      /* Determine number of options */\n      for (;;)\n      {\n         if (!option_defs_us[num_options].key)\n            break;\n         num_options++;\n      }\n\n      /* Allocate arrays */\n      variables  = (struct retro_variable *)calloc(num_options + 1, 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            for (;;)\n            {\n               if (!values[num_values].value)\n                  break;\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\n            /* Build values string */\n            if (num_values > 0)\n            {\n               size_t j;\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[i].key   = key;\n         variables[i].value = values_buf[i];\n      }\n\n      /* Set variables */\n      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\n\nerror:\n\n      /* Clean up */\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\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_default/libretro_core_options_intl.h",
    "content": "﻿#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__\n#define LIBRETRO_CORE_OPTIONS_INTL_H__\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)\n/* https://support.microsoft.com/en-us/kb/980263 */\n#pragma execution_character_set(\"utf-8\")\n#pragma warning(disable:4566)\n#endif\n\n#include <libretro.h>\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_JAPANESE */\n\n/* RETRO_LANGUAGE_FRENCH */\n\n/* RETRO_LANGUAGE_SPANISH */\n\n/* RETRO_LANGUAGE_GERMAN */\n\n/* RETRO_LANGUAGE_ITALIAN */\n\n/* RETRO_LANGUAGE_DUTCH */\n\n/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n\n/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n\n/* RETRO_LANGUAGE_RUSSIAN */\n\n/* RETRO_LANGUAGE_KOREAN */\n\n/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n\n/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n\n/* RETRO_LANGUAGE_ESPERANTO */\n\n/* RETRO_LANGUAGE_POLISH */\n\n/* RETRO_LANGUAGE_VIETNAMESE */\n\n/* RETRO_LANGUAGE_ARABIC */\n\n/* RETRO_LANGUAGE_GREEK */\n\n/* RETRO_LANGUAGE_TURKISH */\n\n/* RETRO_LANGUAGE_SLOVAK */\n\n/* RETRO_LANGUAGE_PERSIAN */\n\n/* RETRO_LANGUAGE_HEBREW */\n\n/* RETRO_LANGUAGE_ASTURIAN */\n\n/* RETRO_LANGUAGE_FINNISH */\n\n/* RETRO_LANGUAGE_THAI */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_hide_option/libretro_core_options.h",
    "content": "#ifndef LIBRETRO_CORE_OPTIONS_H__\n#define LIBRETRO_CORE_OPTIONS_H__\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <libretro.h>\n#include <retro_inline.h>\n\n#ifndef HAVE_NO_LANGEXTRA\n#include \"libretro_core_options_intl.h\"\n#endif\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_ENGLISH */\n\n/* Default language:\n * - All other languages must include the same keys and values\n * - Will be used as a fallback in the event that frontend language\n *   is not available\n * - Will be used as a fallback for any missing entries in\n *   frontend language definition */\n\nstruct retro_core_option_definition option_defs_us[] = {\n   {\n      \"mycore_region\",                            /* key (option name) */\n      \"Console Region\",                           /* description (label) */\n      \"Specify which region the system is from.\", /* sublabel */\n      {\n         { \"auto\",   \"Auto\" },                    /* value_1, value_1_label */\n         { \"ntsc-j\", \"Japan\" },                   /* value_2, value_2_label */\n         { \"ntsc-u\", \"America\" },                 /* value_3, value_3_label */\n         { \"pal\",    \"Europe\" },                  /* value_4, value_4_label */\n         { NULL, NULL },\n      },\n      \"auto\"                                      /* default_value */\n   },\n   {\n      \"mycore_video_scale\",\n      \"Video Scale\",\n      \"Set internal video scale factor.\",\n      {\n         { \"1x\", NULL }, /* If value itself is human-readable (e.g. a number)  */\n         { \"2x\", NULL }, /* and can displayed directly, the value_label should */\n         { \"3x\", NULL }, /* be set to NULL                                     */\n         { \"4x\", NULL },\n         { NULL, NULL },\n      },\n      \"3x\"\n   },\n   /* This 'mycore_show_speedhacks' option will only be shown\n    * if the frontend supports core options API v1.\n    * It will be hidden on older frontends.\n    * See line 227 */\n   {\n      \"mycore_show_speedhacks\",\n      \"Show Unsafe Settings\",\n      \"Enable configuration of emulation speed hacks.\",\n      {\n         { \"enabled\",  NULL },\n         { \"disabled\", NULL },\n         { NULL, NULL},\n      },\n      \"disabled\"\n   },\n   {\n      \"mycore_overclock\",\n      \"Reduce Slowdown\",\n      \"Enable CPU overclock (unsafe).\",\n      {\n         { \"enabled\",  NULL }, /* If value is equal to 'enabled' or 'disabled', */\n         { \"disabled\", NULL }, /* value_label should be set to NULL             */\n         { NULL, NULL },\n      },\n      \"disabled\"\n   },\n   { NULL, NULL, NULL, {{0}}, NULL },\n};\n\n/*\n ********************************\n * Language Mapping\n ********************************\n*/\n\n#ifndef HAVE_NO_LANGEXTRA\nstruct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {\n   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */\n   NULL,           /* RETRO_LANGUAGE_JAPANESE */\n   NULL,           /* RETRO_LANGUAGE_FRENCH */\n   NULL,           /* RETRO_LANGUAGE_SPANISH */\n   NULL,           /* RETRO_LANGUAGE_GERMAN */\n   NULL,           /* RETRO_LANGUAGE_ITALIAN */\n   NULL,           /* RETRO_LANGUAGE_DUTCH */\n   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n   NULL,           /* RETRO_LANGUAGE_RUSSIAN */\n   NULL,           /* RETRO_LANGUAGE_KOREAN */\n   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n   NULL,           /* RETRO_LANGUAGE_ESPERANTO */\n   NULL,           /* RETRO_LANGUAGE_POLISH */\n   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */\n   NULL,           /* RETRO_LANGUAGE_ARABIC */\n   NULL,           /* RETRO_LANGUAGE_GREEK */\n   NULL,           /* RETRO_LANGUAGE_TURKISH */\n   NULL,           /* RETRO_LANGUAGE_SLOVAK */\n   NULL,           /* RETRO_LANGUAGE_PERSIAN */\n   NULL,           /* RETRO_LANGUAGE_HEBREW */\n   NULL,           /* RETRO_LANGUAGE_ASTURIAN */\n   NULL,           /* RETRO_LANGUAGE_FINNISH */\n   NULL,           /* RETRO_LANGUAGE_INDONESIAN */\n   NULL,           /* RETRO_LANGUAGE_SWEDISH */\n   NULL,           /* RETRO_LANGUAGE_UKRAINIAN */\n   NULL,           /* RETRO_LANGUAGE_CZECH */\n   NULL,           /* RETRO_LANGUAGE_CATALAN_VALENCIA */\n   NULL,           /* RETRO_LANGUAGE_CATALAN */\n   NULL,           /* RETRO_LANGUAGE_BRITISH_ENGLISH */\n   NULL,           /* RETRO_LANGUAGE_HUNGARIAN */\n   NULL,           /* RETRO_LANGUAGE_BELARUSIAN */\n   NULL,           /* RETRO_LANGUAGE_GALICIAN */\n   NULL,           /* RETRO_LANGUAGE_NORWEGIAN */\n   NULL,           /* RETRO_LANGUAGE_THAI */\n};\n#endif\n\n/*\n ********************************\n * Functions\n ********************************\n*/\n\n/* Handles configuration/setting of core options.\n * Should be called as early as possible - ideally inside\n * retro_set_environment(), and no later than retro_load_game()\n * > We place the function body in the header to avoid the\n *   necessity of adding more .c files (i.e. want this to\n *   be as painless as possible for core devs)\n */\n\nstatic INLINE void libretro_set_core_options(retro_environment_t environ_cb)\n{\n   unsigned version = 0;\n\n   if (!environ_cb)\n      return;\n\n   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))\n   {\n#ifndef HAVE_NO_LANGEXTRA\n      struct retro_core_options_intl core_options_intl;\n      unsigned language = 0;\n\n      core_options_intl.us    = option_defs_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 = option_defs_intl[language];\n\n      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);\n#else\n      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);\n#endif\n   }\n   else\n   {\n      size_t i;\n      size_t option_index              = 0;\n      size_t num_options               = 0;\n      struct retro_variable *variables = NULL;\n      char **values_buf                = NULL;\n\n      /* Determine number of options\n       * > Note: We are going to skip a number of irrelevant\n       *   core options when building the retro_variable array,\n       *   but we'll allocate space for all of them. The difference\n       *   in resource usage is negligible, and this allows us to\n       *   keep the code 'cleaner' */\n      for (;;)\n      {\n         if (!option_defs_us[num_options].key)\n            break;\n         num_options++;\n      }\n\n      /* Allocate arrays */\n      variables  = (struct retro_variable *)calloc(num_options + 1, 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         /* Skip options that are irrelevant when using the\n          * old style core options interface */\n         if (strcmp(key, \"mycore_show_speedhacks\") == 0)\n            continue;\n\n         if (desc)\n         {\n            size_t num_values = 0;\n\n            /* Determine number of values */\n            for (;;)\n            {\n               if (!values[num_values].value)\n                  break;\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\n            /* Build values string */\n            if (num_values > 0)\n            {\n               size_t j;\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\nerror:\n\n      /* Clean up */\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\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_hide_option/libretro_core_options_intl.h",
    "content": "﻿#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__\n#define LIBRETRO_CORE_OPTIONS_INTL_H__\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)\n/* https://support.microsoft.com/en-us/kb/980263 */\n#pragma execution_character_set(\"utf-8\")\n#pragma warning(disable:4566)\n#endif\n\n#include <libretro.h>\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_JAPANESE */\n\n/* RETRO_LANGUAGE_FRENCH */\n\n/* RETRO_LANGUAGE_SPANISH */\n\n/* RETRO_LANGUAGE_GERMAN */\n\n/* RETRO_LANGUAGE_ITALIAN */\n\n/* RETRO_LANGUAGE_DUTCH */\n\n/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n\n/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n\n/* RETRO_LANGUAGE_RUSSIAN */\n\n/* RETRO_LANGUAGE_KOREAN */\n\n/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n\n/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n\n/* RETRO_LANGUAGE_ESPERANTO */\n\n/* RETRO_LANGUAGE_POLISH */\n\n/* RETRO_LANGUAGE_VIETNAMESE */\n\n/* RETRO_LANGUAGE_ARABIC */\n\n/* RETRO_LANGUAGE_GREEK */\n\n/* RETRO_LANGUAGE_TURKISH */\n\n/* RETRO_LANGUAGE_SLOVAK */\n\n/* RETRO_LANGUAGE_PERSIAN */\n\n/* RETRO_LANGUAGE_HEBREW */\n\n/* RETRO_LANGUAGE_ASTURIAN */\n\n/* RETRO_LANGUAGE_FINNISH */\n\n/* RETRO_LANGUAGE_THAI */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_translation/.github/workflows/crowdin_initial_setup.yml",
    "content": "# Uploads source texts and any present translations to Crowdin.\n\nname: Crowdin Translations Initial Setup\n\n# On manual run only.\non:\n  workflow_dispatch\n\njobs:\n  upload_source_file:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup Java JDK\n        uses: actions/setup-java@v4\n        with:\n          java-version: 18\n          distribution: zulu\n\n      - name: Setup Python\n        uses: actions/setup-python@v4\n        with:\n          python-version: '3.10'\n\n      - name: Checkout\n        uses: actions/checkout@v3\n\n      - name: Initial synchroniation\n        shell: bash\n        env:\n          CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}\n        run: |\n          python3 intl/initial_sync.py $CROWDIN_API_KEY \"<CORE_NAME>\" \"<PATH/TO>/libretro_core_options.h\"\n"
  },
  {
    "path": "samples/core_options/example_translation/.github/workflows/crowdin_source_upload.yml",
    "content": "# Prepare source texts & upload them to Crowdin\n\nname: Crowdin Source Texts Upload\n\n# on change to the English texts\non:\n  workflow_dispatch\n  push:\n    branches:\n      - master\n    paths:\n      - '<PATH/TO>/libretro_core_options.h'\n\njobs:\n  upload_source_file:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup Java JDK\n        uses: actions/setup-java@v4\n        with:\n          java-version: 18\n          distribution: zulu\n\n      - name: Setup Python\n        uses: actions/setup-python@v4\n        with:\n          python-version: '3.10'\n\n      - name: Checkout\n        uses: actions/checkout@v3\n\n      - name: Upload Source\n        shell: bash\n        env:\n          CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}\n        run: |\n          python3 intl/upload_workflow.py $CROWDIN_API_KEY \"<CORE_NAME>\" \"<PATH/TO>/libretro_core_options.h\"\n"
  },
  {
    "path": "samples/core_options/example_translation/.github/workflows/crowdin_translation_sync.yml",
    "content": "# Download translations form Crowdin & Recreate libretro_core_options_intl.h\n\nname: Crowdin Translation Sync\n\non:\n  workflow_dispatch\n  schedule:\n  # please choose a random time & weekday to avoid all repos synching at the same time\n    - cron: '<0-59> <0-23> * * 5'  # Fridays at , UTC\n\njobs:\n  create_intl_file:\n    permissions:\n      contents: write           # 'write' access to repository contents\n      pull-requests: write      # 'write' access to pull requests\n\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup Java JDK\n        uses: actions/setup-java@v4\n        with:\n          java-version: 18\n          distribution: zulu\n\n      - name: Setup Python\n        uses: actions/setup-python@v4\n        with:\n          python-version: '3.10'\n\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.\n          fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.\n\n      - name: Create intl file\n        shell: bash\n        env:\n          CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}\n        run: |\n          python3 intl/download_workflow.py $CROWDIN_API_KEY \"<CORE_NAME>\" \"<PATH/TO>/libretro_core_options_intl.h\"\n\n      - name: Commit files\n        run: |\n          git config --local user.email \"github-actions@github.com\"\n          git config --local user.name \"github-actions[bot]\"\n          git add intl/*_workflow.py \"<PATH/TO>/libretro_core_options_intl.h\"\n          git commit -m \"Fetch translations & Recreate libretro_core_options_intl.h\"\n\n      - name: GitHub Push\n        uses: ad-m/github-push-action@v0.8.0\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          branch: ${{ github.ref }}\n\n"
  },
  {
    "path": "samples/core_options/example_translation/instructions.txt",
    "content": "## Requirements\n\nMake sure the core is libretro conformant:\nboth `libretro_core_options.h`, containing the English texts, and\n`libretro_core_options_intl.h`, containing all already existing\ntranslations, if any, must be present in the same directory.\n\n> Please note: `libretro_core_options_intl.h` does not need to contain\nanything, if no translations exist or none of them should be preserved.\n\nThe scripts are not compatible with text filled in by macros or during run time.\nThe procedure should not fail - but those texts will not be made translatable.\n\nAlso, please verify the existence and correct use of\n\n   `#ifdef HAVE_LANGEXTRA`\n   \nand/or\n   \n   `#ifndef NAVE_NO_LANGEXTRA`\n   \npre-compiler instructions in `libretro_core_options.h` to remove any\nreferences to additional languages on platforms which cannot handle them,\ne.g. due to limited RAM.\nFor an example, refer to an up-to-date core, like [gambatte-libretro](https://github.com/libretro/gambatte-libretro/blob/master/libgambatte/libretro/libretro_core_options.h).\n\n> Make sure `options_intl` in `libretro_core_options.h` correctly references the `intl` options, or the translations will not be applied!\n\n## Adding automatic Crowdin sync\n\nPlace the `intl` and `.github` folders, including content, into the root\nof the repository.\n\nIn `.github/workflows` are two files:\n`crowdin_prep.yml` & `crowdin_translate.yml`.\nIn each of those are placeholders, which need to be replaced.\n\nFor convenience, one can run `intl/activate.py`, which will try to find\nthe `libretro_core_options.h` file as well as identify the core name to\nfill those placeholders with.\n\nEven then, one should still check, if it produced the correct result:\n\nFor `crowdin_prep.yml`:\n> **NOTE:** Please verify, that this workflow watches the correct branch!\nUploads happen, whenever `libretro_core_options.h` of that branch is changed.\n\n- <PATH/TO/libretro_core_options.h FILE> (x2)\n\t- replace with the full path from the root of the repo to the\n           `libretro_core_options.h` file\n\n- <CORE_NAME>\n\t- the name of the core (or repo)\n\nAnd for crowdin_translate.yml:\n- <0-59> <0-23>\n\t- Minute and hour at which the sync will happen.\n      The script will generate a random time for this, to avoid\n      stressing GitHub & Crowdin with many simultaneous runs.\n\n- <CORE_NAME>\n    - same as above\n\n- <PATH/TO/libretro_core_options_intl.h FILE> (x2)\n    - replace with the full path from the root of the repo to the\n      'libretro_core_options_intl.h' file\n\nCreate a Pull Request and ask a Crowdin project manager, either on [Crowdin](https://crowdin.com/project/retroarch) or, preferably, on [discord](https://discord.gg/xuMbcVuF) in the `retroarch-translations` channel, to provide you with an access key. Create an Actions repository secret on GitHub named CROWDIN_API_KEY for this access token.\n\n<!-- TODO: set correct permissions https://github.com/marketplace/actions/github-push --> \nWhen everything is ready, run the \"Crowdin Translations Initial Setup\" workflow manually to upload the source texts and any translations to Crowdin.\n\n> You may either disable the initial workflow or even remove it from your repository. Running it more than once is very much discouraged! That may mess with the newest translations, which are usually not yet incorporated into the repository.\n\nFinally, it is recommended to run the \"Crowdin Translation Sync\" workflow manually once. If a \"Permission to \\<repository> denied\" error occurs, you might need to configure the GITHUB_TOKEN with the appropriate access rights, [see here](https://github.com/marketplace/actions/github-push#requirements-and-prerequisites).\n\n## (For Crowdin project managers) Creating an access token\n\nTo create an access token, navigate to the account settings via your profile picture in the top right. Change to the API tab. Here you should find a `New Token` button.\n\nName the token after the core/repository, which will receive it. The following permissions should be set:\n\n- Projects\n  - read\n- Source files & strings\n  - read & write\n- Translations\n  - read & write\n- (optional) Translation status\n  - read\n\n> Please provide these access tokens to the core developers in a private message and delete those after successful setup. Do not share tokens publicly or store them in plain text long term!"
  },
  {
    "path": "samples/core_options/example_translation/intl/.gitignore",
    "content": "__pycache__\ncrowdin-cli.jar\n*.h\n*.json\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/activate.py",
    "content": "#!/usr/bin/env python3\n\nimport os\nimport glob\nimport random as r\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n   DIR_PATH = os.path.dirname(os.path.realpath(__file__))\n   if os.path.basename(DIR_PATH) != \"intl\":\n      raise RuntimeError(\"Script is not in intl folder!\")\n\n   BASE_PATH = os.path.dirname(DIR_PATH)\n   WORKFLOW_PATH = os.path.join(BASE_PATH, \".github\", \"workflows\")\n   PREP_WF = os.path.join(WORKFLOW_PATH, \"crowdin_prep.yml\")\n   TRANSLATE_WF = os.path.join(WORKFLOW_PATH, \"crowdin_translate.yml\")\n   CORE_NAME = os.path.basename(BASE_PATH)\n   CORE_OP_FILE = os.path.join(BASE_PATH, \"**\", \"libretro_core_options.h\")\n\n   core_options_hits = glob.glob(CORE_OP_FILE, recursive=True)\n\n   if len(core_options_hits) == 0:\n      raise RuntimeError(\"libretro_core_options.h not found!\")\n   elif len(core_options_hits) > 1:\n      print(\"More than one libretro_core_options.h file found:\\n\\n\")\n      for i, file in enumerate(core_options_hits):\n         print(f\"{i} {file}\\n\")\n\n      while True:\n         user_choice = input(\"Please choose one ('q' will exit): \")\n         if user_choice == 'q':\n            exit(0)\n         elif user_choice.isdigit():\n            core_op_file = core_options_hits[int(user_choice)]\n            break\n         else:\n            print(\"Please make a valid choice!\\n\\n\")\n   else:\n      core_op_file = core_options_hits[0]\n\n   core_intl_file = os.path.join(os.path.dirname(core_op_file.replace(BASE_PATH, ''))[1:],\n                                 'libretro_core_options_intl.h')\n   core_op_file   = os.path.join(os.path.dirname(core_op_file.replace(BASE_PATH, ''))[1:],\n                                 'libretro_core_options.h')\n   minutes = r.randrange(0, 59, 5)\n   hour = r.randrange(0, 23)\n\n   with open(PREP_WF, 'r') as wf_file:\n      prep_txt = wf_file.read()\n\n   prep_txt = prep_txt.replace(\"<CORE_NAME>\", CORE_NAME)\n   prep_txt = prep_txt.replace(\"<PATH/TO>/libretro_core_options.h\",\n                               core_op_file)\n   with open(PREP_WF, 'w') as wf_file:\n      wf_file.write(prep_txt)\n\n\n   with open(TRANSLATE_WF, 'r') as wf_file:\n      translate_txt = wf_file.read()\n\n   translate_txt = translate_txt.replace('<0-59>', f\"{minutes}\")\n   translate_txt = translate_txt.replace('<0-23>', f\"{hour}\")\n   translate_txt = translate_txt.replace('# Fridays at , UTC',\n                                         f\"# Fridays at {hour%12}:{minutes if minutes > 9 else '0' + str(minutes)} {'AM' if hour < 12 else 'PM'}, UTC\")\n   translate_txt = translate_txt.replace(\"<CORE_NAME>\", CORE_NAME)\n   translate_txt = translate_txt.replace('<PATH/TO>/libretro_core_options_intl.h',\n                                         core_intl_file)\n   with open(TRANSLATE_WF, 'w') as wf_file:\n      wf_file.write(translate_txt)\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/core_option_regex.py",
    "content": "import re\n\n# 0: full struct; 1: up to & including first []; 2 & 3: comments; 4: content between first {}\np_struct = re.compile(r'(\\bstruct\\b\\s*[a-zA-Z0-9_\\s]+\\[])\\s*'  # 1st capturing group\n                      r'(?:(?=(\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+))\\2\\s*)*'  # 2nd capturing group\n                      r'=\\s*'  # =\n                      r'(?:(?=(\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+))\\3\\s*)*'  # 3rd capturing group\n                      r'{((?:.|[\\r\\n])*?)\\{\\s*NULL,\\s*NULL,\\s*NULL\\s*(?:.|[\\r\\n])*?},?(?:.|[\\r\\n])*?};')  # captures full struct, it's beginning and it's content\n# 0: type name[]; 1: type; 2: name\np_type_name = re.compile(r'(\\bretro_core_option_[a-zA-Z0-9_]+)\\s*'\n                         r'(\\boption_cats([a-z_]{0,8})|\\boption_defs([a-z_]*))\\s*\\[]')\n# 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs\np_option = re.compile(r'{\\s*'  # opening braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(\\\".*?\\\"|'  # key start; group 1\n                      r'[a-zA-Z0-9_]+\\s*\\((?:.|[\\r\\n])*?\\)|'\n                      r'[a-zA-Z0-9_]+\\s*\\[(?:.|[\\r\\n])*?]|'\n                      r'[a-zA-Z0-9_]+\\s*\\\".*?\\\")\\s*'  # key end\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(\\\".*?\\\")\\s*'  # description; group 2\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'((?:'  # group 3\n                      r'(?:NULL|\\\"(?:.|[\\r\\n])*?\\\")\\s*'  # description in category, info, info in category, category\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r')+)'\n                      r'(?:'  # defs only start\n                      r'{\\s*'  # opening braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'((?:'  # key/value pairs start; group 4\n                      r'{\\s*'  # opening braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(?:NULL|\\\".*?\\\")\\s*'  # option key\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(?:NULL|\\\".*?\\\")\\s*'  # option value\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'}\\s*'  # closing braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r')*)'  # key/value pairs end\n                      r'}\\s*'  # closing braces\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r'(?:'  # defaults start\n                      r'(?:NULL|\\\".*?\\\")\\s*'  # default value\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r',?\\s*'  # comma\n                      r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                      r')*'  # defaults end\n                      r')?'  # defs only end\n                      r'},')  # closing braces\n# analyse option group 3\np_info = re.compile(r'(NULL|\\\"(?:.|[\\r\\n])*?\\\")\\s*'  # description in category, info, info in category, category\n                    r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                    r',')\np_info_cat = re.compile(r'(NULL|\\\"(?:.|[\\r\\n])*?\\\")')\n# analyse option group 4\np_key_value = re.compile(r'{\\s*'  # opening braces\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r'(NULL|\\\".*?\\\")\\s*'  # option key; 1\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r',\\s*'  # comma\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r'(NULL|\\\".*?\\\")\\s*'  # option value; 2\n                         r'(?:(?:\\/\\*(?:.|[\\r\\n])*?\\*\\/|\\/\\/.*[\\r\\n]+|#.*[\\r\\n]+)\\s*)*'\n                         r'}')\n\np_masked = re.compile(r'([A-Z_][A-Z0-9_]+)\\s*(\\\"(?:\"\\s*\"|\\\\\\s*|.)*\\\")')\n\np_intl = re.compile(r'(\\bstruct retro_core_option_definition \\*option_defs_intl\\[RETRO_LANGUAGE_LAST]) = {'\n                    r'((?:.|[\\r\\n])*?)};')\np_set = re.compile(r'\\bstatic INLINE void libretro_set_core_options\\(retro_environment_t environ_cb\\)'\n                   r'(?:.|[\\r\\n])*?};?\\s*#ifdef __cplusplus\\s*}\\s*#endif')\n\np_yaml = re.compile(r'\"project_id\": \"[0-9]+\".*\\s*'\n                    r'\"api_token\": \"([a-zA-Z0-9]+)\".*\\s*'\n                    r'\"base_path\": \"\\./intl\".*\\s*'\n                    r'\"base_url\": \"https://api\\.crowdin\\.com\".*\\s*'\n                    r'\"preserve_hierarchy\": true.*\\s*'\n                    r'\"files\": \\[\\s*'\n                    r'\\{\\s*'\n                    r'\"source\": \"/_us/\\*\\.json\",.*\\s*'\n                    r'\"translation\": \"/_%two_letters_code%/%original_file_name%\",.*\\s*'\n                    r'\"skip_untranslated_strings\": true.*\\s*'\n                    r'},\\s*'\n                    r']')\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/core_option_translation.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"Core options text extractor\n\nThe purpose of this script is to set up & provide functions for automatic generation of 'libretro_core_options_intl.h'\nfrom 'libretro_core_options.h' using translations from Crowdin.\n\nBoth v1 and v2 structs are supported. It is, however, recommended to convert v1 files to v2 using the included\n'v1_to_v2_converter.py'.\n\nUsage:\npython3 path/to/core_option_translation.py \"path/to/where/libretro_core_options.h & libretro_core_options_intl.h/are\" \"core_name\"\n\nThis script will:\n1.) create key words for & extract the texts from libretro_core_options.h & save them into intl/_us/core_options.h\n2.) do the same for any present translations in libretro_core_options_intl.h, saving those in their respective folder\n\"\"\"\nimport core_option_regex as cor\nimport re\nimport os\nimport sys\nimport json\nimport urllib.request as req\nimport shutil\n\n# LANG_CODE_TO_R_LANG = {'_ar': 'RETRO_LANGUAGE_ARABIC',\n#                        '_ast': 'RETRO_LANGUAGE_ASTURIAN',\n#                        '_chs': 'RETRO_LANGUAGE_CHINESE_SIMPLIFIED',\n#                        '_cht': 'RETRO_LANGUAGE_CHINESE_TRADITIONAL',\n#                        '_cs': 'RETRO_LANGUAGE_CZECH',\n#                        '_cy': 'RETRO_LANGUAGE_WELSH',\n#                        '_da': 'RETRO_LANGUAGE_DANISH',\n#                        '_de': 'RETRO_LANGUAGE_GERMAN',\n#                        '_el': 'RETRO_LANGUAGE_GREEK',\n#                        '_eo': 'RETRO_LANGUAGE_ESPERANTO',\n#                        '_es': 'RETRO_LANGUAGE_SPANISH',\n#                        '_fa': 'RETRO_LANGUAGE_PERSIAN',\n#                        '_fi': 'RETRO_LANGUAGE_FINNISH',\n#                        '_fr': 'RETRO_LANGUAGE_FRENCH',\n#                        '_gl': 'RETRO_LANGUAGE_GALICIAN',\n#                        '_he': 'RETRO_LANGUAGE_HEBREW',\n#                        '_hu': 'RETRO_LANGUAGE_HUNGARIAN',\n#                        '_id': 'RETRO_LANGUAGE_INDONESIAN',\n#                        '_it': 'RETRO_LANGUAGE_ITALIAN',\n#                        '_ja': 'RETRO_LANGUAGE_JAPANESE',\n#                        '_ko': 'RETRO_LANGUAGE_KOREAN',\n#                        '_nl': 'RETRO_LANGUAGE_DUTCH',\n#                        '_oc': 'RETRO_LANGUAGE_OCCITAN',\n#                        '_pl': 'RETRO_LANGUAGE_POLISH',\n#                        '_pt_br': 'RETRO_LANGUAGE_PORTUGUESE_BRAZIL',\n#                        '_pt_pt': 'RETRO_LANGUAGE_PORTUGUESE_PORTUGAL',\n#                        '_ru': 'RETRO_LANGUAGE_RUSSIAN',\n#                        '_sk': 'RETRO_LANGUAGE_SLOVAK',\n#                        '_sv': 'RETRO_LANGUAGE_SWEDISH',\n#                        '_tr': 'RETRO_LANGUAGE_TURKISH',\n#                        '_uk': 'RETRO_LANGUAGE_UKRAINIAN',\n#                        '_us': 'RETRO_LANGUAGE_ENGLISH',\n#                        '_vn': 'RETRO_LANGUAGE_VIETNAMESE'}\n\n# these are handled by RetroArch directly - no need to include them in core translations\nON_OFFS = {'\"enabled\"', '\"disabled\"', '\"true\"', '\"false\"', '\"on\"', '\"off\"'}\n\n\ndef remove_special_chars(text: str, char_set=0, allow_non_ascii=False) -> str:\n   \"\"\"Removes special characters from a text.\n\n   :param text: String to be cleaned.\n   :param char_set: 0 -> remove all ASCII special chars except for '_' & 'space' (default)\n                    1 -> remove invalid chars from file names\n   :param allow_non_ascii: False -> all non-ascii characters will be removed (default)\n                           True -> non-ascii characters will be passed through\n   :return: Clean text.\n   \"\"\"\n   command_chars = [chr(unicode) for unicode in tuple(range(0, 32)) + (127,)]\n   special_chars = ([chr(unicode) for unicode in tuple(range(33, 48)) + tuple(range(58, 65)) + tuple(range(91, 95))\n                     + (96,) + tuple(range(123, 127))],\n                    ('\\\\', '/', ':', '*', '?', '\"', '<', '>', '|', '#', '%',\n                     '&', '{', '}', '$', '!', '¸', \"'\", '@', '+', '='))\n   res = text if allow_non_ascii \\\n      else text.encode('ascii', errors='ignore').decode('unicode-escape')\n\n   for cm in command_chars:\n      res = res.replace(cm, '_')\n   for sp in special_chars[char_set]:\n      res = res.replace(sp, '_')\n   while res.startswith('_'):\n      res = res[1:]\n   while res.endswith('_'):\n      res = res[:-1]\n   return res\n\n\ndef clean_file_name(file_name: str) -> str:\n   \"\"\"Removes characters which might make file_name inappropriate for files on some OS.\n\n   :param file_name: File name to be cleaned.\n   :return: The clean file name.\n   \"\"\"\n   file_name = remove_special_chars(file_name, 1)\n   file_name = re.sub(r'__+', '_', file_name.replace(' ', '_'))\n   return file_name\n\n\ndef get_struct_type_name(decl: str) -> tuple:\n   \"\"\" Returns relevant parts of the struct declaration:\n   type, name of the struct and the language appendix, if present.\n   :param decl: The struct declaration matched by cor.p_type_name.\n   :return: Tuple, e.g.: ('retro_core_option_definition', 'option_defs_us', '_us')\n   \"\"\"\n   struct_match = cor.p_type_name.search(decl)\n   if struct_match:\n      if struct_match.group(3):\n         struct_type_name = struct_match.group(1, 2, 3)\n         return struct_type_name\n      elif struct_match.group(4):\n         struct_type_name = struct_match.group(1, 2, 4)\n         return struct_type_name\n      else:\n         struct_type_name = struct_match.group(1, 2)\n         return struct_type_name\n   else:\n      raise ValueError(f'No or incomplete struct declaration: {decl}!\\n'\n                       'Please make sure all structs are complete, including the type and name declaration.')\n\n\ndef is_viable_non_dupe(text: str, comparison) -> bool:\n   \"\"\"text must be longer than 2 ('\"\"'), not 'NULL' and not in comparison.\n\n   :param text: String to be tested.\n   :param comparison: Dictionary or set to search for text in.\n   :return: bool\n   \"\"\"\n   return 2 < len(text) and text != 'NULL' and text not in comparison\n\n\ndef is_viable_value(text: str) -> bool:\n   \"\"\"text must be longer than 2 ('\"\"') and not 'NULL'.\n\n   :param text: String to be tested.\n   :return: bool\n   \"\"\"\n   return 2 < len(text) and text != 'NULL'\n\n\ndef create_non_dupe(base_name: str, opt_num: int, comparison) -> str:\n   \"\"\"Makes sure base_name is not in comparison, and if it is it's renamed.\n\n   :param base_name: Name to check/make unique.\n   :param opt_num: Number of the option base_name belongs to, used in making it unique.\n   :param comparison: Dictionary or set to search for base_name in.\n   :return: Unique name.\n   \"\"\"\n   h = base_name\n   if h in comparison:\n      n = 0\n      h = h + '_O' + str(opt_num)\n      h_end = len(h)\n      while h in comparison:\n         h = h[:h_end] + '_' + str(n)\n         n += 1\n   return h\n\n\ndef get_texts(text: str) -> dict:\n   \"\"\"Extracts the strings, which are to be translated/are the translations,\n   from text and creates macro names for them.\n\n   :param text: The string to be parsed.\n   :return: Dictionary of the form { '_<lang>': { 'macro': 'string', ... }, ... }.\n   \"\"\"\n   # all structs: group(0) full struct, group(1) beginning, group(2) content\n   structs = cor.p_struct.finditer(text)\n   hash_n_string = {}\n   just_string = {}\n   for struct in structs:\n      struct_declaration = struct.group(1)\n      struct_type_name = get_struct_type_name(struct_declaration)\n      if 3 > len(struct_type_name):\n         lang = '_us'\n      else:\n         lang = struct_type_name[2]\n      if lang not in just_string:\n         hash_n_string[lang] = {}\n         just_string[lang] = set()\n      is_v2_definition = 'retro_core_option_v2_definition' == struct_type_name[0]\n      pre_name = ''\n      # info texts format\n      p = cor.p_info\n      if 'retro_core_option_v2_category' == struct_type_name[0]:\n         # prepend category labels, as they can be the same as option labels\n         pre_name = 'CATEGORY_'\n         # categories have different info texts format\n         p = cor.p_info_cat\n\n      struct_content = struct.group(4)\n      # 0: full option; 1: key; 2: description; 3: additional info; 4: key/value pairs\n      struct_options = cor.p_option.finditer(struct_content)\n      for opt, option in enumerate(struct_options):\n         # group 1: key\n         if option.group(1):\n            opt_name = pre_name + option.group(1)\n            # no special chars allowed in key\n            opt_name = remove_special_chars(opt_name).upper().replace(' ', '_')\n         else:\n            raise ValueError(f'No option name (key) found in struct {struct_type_name[1]} option {opt}!')\n\n         # group 2: description0\n         if option.group(2):\n            desc0 = option.group(2)\n            if is_viable_non_dupe(desc0, just_string[lang]):\n               just_string[lang].add(desc0)\n               m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL'), opt, hash_n_string[lang])\n               hash_n_string[lang][m_h] = desc0\n         else:\n            raise ValueError(f'No label found in struct {struct_type_name[1]} option {option.group(1)}!')\n\n         # group 3: desc1, info0, info1, category\n         if option.group(3):\n            infos = option.group(3)\n            option_info = p.finditer(infos)\n            if is_v2_definition:\n               desc1 = next(option_info).group(1)\n               if is_viable_non_dupe(desc1, just_string[lang]):\n                  just_string[lang].add(desc1)\n                  m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_LABEL_CAT'), opt, hash_n_string[lang])\n                  hash_n_string[lang][m_h] = desc1\n               last = None\n               m_h = None\n               for j, info in enumerate(option_info):\n                  last = info.group(1)\n                  if is_viable_non_dupe(last, just_string[lang]):\n                     just_string[lang].add(last)\n                     m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,\n                                           hash_n_string[lang])\n                     hash_n_string[lang][m_h] = last\n               if last in just_string[lang]:  # category key should not be translated\n                  hash_n_string[lang].pop(m_h)\n                  just_string[lang].remove(last)\n            else:\n               for j, info in enumerate(option_info):\n                  gr1 = info.group(1)\n                  if is_viable_non_dupe(gr1, just_string[lang]):\n                     just_string[lang].add(gr1)\n                     m_h = create_non_dupe(re.sub(r'__+', '_', f'{opt_name}_INFO_{j}'), opt,\n                                           hash_n_string[lang])\n                     hash_n_string[lang][m_h] = gr1\n         else:\n            raise ValueError(f'Too few arguments in struct {struct_type_name[1]} option {option.group(1)}!')\n\n         # group 4: key/value pairs\n         if option.group(4):\n            for j, kv_set in enumerate(cor.p_key_value.finditer(option.group(4))):\n               set_key, set_value = kv_set.group(1, 2)\n               if not is_viable_value(set_value):\n                  # use the key if value not available\n                  set_value = set_key\n                  if not is_viable_value(set_value):\n                     continue\n               # re.fullmatch(r'(?:[+-][0-9]+)+', value[1:-1])\n\n               # add only if non-dupe, not translated by RetroArch directly & not purely numeric\n               if set_value not in just_string[lang]\\\n                  and set_value.lower() not in ON_OFFS\\\n                  and not re.sub(r'[+-]', '', set_value[1:-1]).isdigit():\n                  clean_key = set_key[1:-1]\n                  clean_key = remove_special_chars(clean_key).upper().replace(' ', '_')\n                  m_h = create_non_dupe(re.sub(r'__+', '_', f\"OPTION_VAL_{clean_key}\"), opt, hash_n_string[lang])\n                  hash_n_string[lang][m_h] = set_value\n                  just_string[lang].add(set_value)\n   return hash_n_string\n\n\ndef create_msg_hash(intl_dir_path: str, core_name: str, keyword_string_dict: dict) -> dict:\n   \"\"\"Creates '<core_name>.h' files in 'intl/_<lang>/' containing the macro name & string combinations.\n\n   :param intl_dir_path: Path to the intl directory.\n   :param core_name: Name of the core, used for the files' paths.\n   :param keyword_string_dict: Dictionary of the form { '_<lang>': { 'macro': 'string', ... }, ... }.\n   :return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.\n   \"\"\"\n   files = {}\n   for localisation in keyword_string_dict:\n      path = os.path.join(intl_dir_path, core_name)  # intl/<core_name>/\n      files[localisation] = os.path.join(path, localisation + '.h')  # intl/<core_name>/_<lang>.h\n      if not os.path.exists(path):\n         os.makedirs(path)\n      with open(files[localisation], 'w', encoding='utf-8') as crowdin_file:\n         out_text = ''\n         for keyword in keyword_string_dict[localisation]:\n            out_text = f'{out_text}{keyword} {keyword_string_dict[localisation][keyword]}\\n'\n         crowdin_file.write(out_text)\n   return files\n\n\ndef h2json(file_paths: dict) -> dict:\n   \"\"\"Converts .h files pointed to by file_paths into .jsons.\n\n   :param file_paths: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.h)', ... }.\n   :return: Dictionary of the form { '_<lang>': 'path/to/file (./intl/_<lang>/<core_name>.json)', ... }.\n   \"\"\"\n   jsons = {}\n   for file_lang in file_paths:\n      if not os.path.isfile(file_paths[file_lang]):\n         continue\n      file_path = file_paths[file_lang]\n      try:\n         jsons[file_lang] = file_path[:file_path.rindex('.')] + '.json'\n      except ValueError:\n         print(f\"File {file_path} has incorrect format! File ending missing?\")\n         continue\n\n      p = cor.p_masked\n\n      with open(file_paths[file_lang], 'r+', encoding='utf-8') as h_file:\n         text = h_file.read()\n         result = p.finditer(text)\n         messages = {}\n         for msg in result:\n            key, val = msg.group(1, 2)\n            if key not in messages:\n               if key and val:\n                  # unescape & remove \"\\n\"\n                  messages[key] = re.sub(r'\"\\s*(?:(?:/\\*(?:.|[\\r\\n])*?\\*/|//.*[\\r\\n]+)\\s*)*\"',\n                                         '\\\\\\n', val[1:-1].replace('\\\\\\\"', '\"'))\n            else:\n               print(f\"DUPLICATE KEY in {file_paths[file_lang]}: {key}\")\n         with open(jsons[file_lang], 'w', encoding='utf-8') as json_file:\n            json.dump(messages, json_file, indent=2)\n\n   return jsons\n\n\ndef json2h(intl_dir_path: str, file_list) -> None:\n   \"\"\"Converts .json file in json_file_path into an .h ready to be included in C code.\n\n   :param intl_dir_path: Path to the intl/<core_name> directory.\n   :param file_list: Iterator of os.DirEntry objects. Contains localisation files to convert.\n   :return: None\n   \"\"\"\n\n   p = cor.p_masked\n\n   def update(s_messages, s_template, s_source_messages, file_name):\n      translation = ''\n      template_messages = p.finditer(s_template)\n      for tp_msg in template_messages:\n         old_key = tp_msg.group(1)\n         if old_key in s_messages and s_messages[old_key] != s_source_messages[old_key]:\n            tl_msg_val = s_messages[old_key]\n            tl_msg_val = tl_msg_val.replace('\"', '\\\\\\\"').replace('\\n', '')  # escape\n            translation = ''.join((translation, '#define ', old_key, file_name.upper(), f' \"{tl_msg_val}\"\\n'))\n\n         else:  # Remove English duplicates and non-translatable strings\n            translation = ''.join((translation, '#define ', old_key, file_name.upper(), ' NULL\\n'))\n      return translation\n\n   us_h = os.path.join(intl_dir_path, '_us.h')\n   us_json = os.path.join(intl_dir_path, '_us.json')\n\n   with open(us_h, 'r', encoding='utf-8') as template_file:\n      template = template_file.read()\n   with open(us_json, 'r+', encoding='utf-8') as source_json_file:\n      source_messages = json.load(source_json_file)\n\n   for file in file_list:\n      if file.name.lower().startswith('_us') \\\n         or file.name.lower().endswith('.h') \\\n         or file.is_dir():\n         continue\n\n      with open(file.path, 'r+', encoding='utf-8') as json_file:\n         messages = json.load(json_file)\n         new_translation = update(messages, template, source_messages, os.path.splitext(file.name)[0])\n      with open(os.path.splitext(file.path)[0] + '.h', 'w', encoding='utf-8') as h_file:\n         h_file.seek(0)\n         h_file.write(new_translation)\n         h_file.truncate()\n   return\n\n\ndef get_crowdin_client(dir_path: str) -> str:\n   \"\"\"Makes sure the Crowdin CLI client is present. If it isn't, it is fetched & extracted.\n\n   :return: The path to 'crowdin-cli.jar'.\n   \"\"\"\n   jar_name = 'crowdin-cli.jar'\n   jar_path = os.path.join(dir_path, jar_name)\n\n   if not os.path.isfile(jar_path):\n      print('Downloading crowdin-cli.jar')\n      crowdin_cli_file = os.path.join(dir_path, 'crowdin-cli.zip')\n      crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/crowdin-cli.zip'\n      req.urlretrieve(crowdin_cli_url, crowdin_cli_file)\n      import zipfile\n      with zipfile.ZipFile(crowdin_cli_file, 'r') as zip_ref:\n         jar_dir = zip_ref.namelist()[0]\n         for file in zip_ref.namelist():\n            if file.endswith(jar_name):\n               jar_file = file\n               break\n         zip_ref.extract(jar_file)\n         os.rename(jar_file, jar_path)\n         os.remove(crowdin_cli_file)\n         shutil.rmtree(jar_dir)\n   return jar_path\n\n\ndef create_intl_file(intl_file_path: str, localisations_path: str, text: str, file_path: str) -> None:\n   \"\"\"Creates 'libretro_core_options_intl.h' from Crowdin translations.\n\n   :param intl_file_path: Path to 'libretro_core_options_intl.h'\n   :param localisations_path: Path to the intl/<core_name> directory.\n   :param text: Content of the 'libretro_core_options.h' being translated.\n   :param file_path: Path to the '_us.h' file, containing the original English texts.\n   :return: None\n   \"\"\"\n   msg_dict = {}\n   lang_up = ''\n\n   def replace_pair(pair_match):\n      \"\"\"Replaces a key-value-pair of an option with the macros corresponding to the language.\n\n      :param pair_match: The re match object representing the key-value-pair block.\n      :return: Replacement string.\n      \"\"\"\n      offset = pair_match.start(0)\n      if pair_match.group(1):  # key\n         if pair_match.group(2) in msg_dict:  # value\n            val = msg_dict[pair_match.group(2)] + lang_up\n         elif pair_match.group(1) in msg_dict:  # use key if value not viable (e.g. NULL)\n            val = msg_dict[pair_match.group(1)] + lang_up\n         else:\n            return pair_match.group(0)\n      else:\n         return pair_match.group(0)\n      res = pair_match.group(0)[:pair_match.start(2) - offset] + val \\\n            + pair_match.group(0)[pair_match.end(2) - offset:]\n      return res\n\n   def replace_info(info_match):\n      \"\"\"Replaces the 'additional strings' of an option with the macros corresponding to the language.\n\n      :param info_match: The re match object representing the 'additional strings' block.\n      :return: Replacement string.\n      \"\"\"\n      offset = info_match.start(0)\n      if info_match.group(1) in msg_dict:\n         res = info_match.group(0)[:info_match.start(1) - offset] + \\\n               msg_dict[info_match.group(1)] + lang_up + \\\n               info_match.group(0)[info_match.end(1) - offset:]\n         return res\n      else:\n         return info_match.group(0)\n\n   def replace_option(option_match):\n      \"\"\"Replaces strings within an option\n      '{ \"opt_key\", \"label\", \"additional strings\", ..., { {\"key\", \"value\"}, ... }, ... }'\n      within a struct with the macros corresponding to the language:\n      '{ \"opt_key\", MACRO_LABEL, MACRO_STRINGS, ..., { {\"key\", MACRO_VALUE}, ... }, ... }'\n\n      :param option_match: The re match object representing the option.\n      :return: Replacement string.\n      \"\"\"\n      # label\n      offset = option_match.start(0)\n      if option_match.group(2):\n         res = option_match.group(0)[:option_match.start(2) - offset] + msg_dict[option_match.group(2)] + lang_up\n      else:\n         return option_match.group(0)\n      # additional block\n      if option_match.group(3):\n         res = res + option_match.group(0)[option_match.end(2) - offset:option_match.start(3) - offset]\n         new_info = p.sub(replace_info, option_match.group(3))\n         res = res + new_info\n      else:\n         return res + option_match.group(0)[option_match.end(2) - offset:]\n      # key-value-pairs\n      if option_match.group(4):\n         res = res + option_match.group(0)[option_match.end(3) - offset:option_match.start(4) - offset]\n         new_pairs = cor.p_key_value.sub(replace_pair, option_match.group(4))\n         res = res + new_pairs + option_match.group(0)[option_match.end(4) - offset:]\n      else:\n         res = res + option_match.group(0)[option_match.end(3) - offset:]\n\n      return res\n\n   # ------------------------------------------------------------------------------------\n\n   with open(file_path, 'r+', encoding='utf-8') as template:  # intl/<core_name>/_us.h\n      masked_msgs = cor.p_masked.finditer(template.read())\n\n   for msg in masked_msgs:\n      msg_dict[msg.group(2)] = msg.group(1)\n\n   # top of the file - in case there is no file to copy it from\n   out_txt = \"﻿#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__\\n\" \\\n             \"#define LIBRETRO_CORE_OPTIONS_INTL_H__\\n\\n\" \\\n             \"#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)\\n\" \\\n             \"/* https://support.microsoft.com/en-us/kb/980263 */\\n\" \\\n             '#pragma execution_character_set(\"utf-8\")\\n' \\\n             \"#pragma warning(disable:4566)\\n\" \\\n             \"#endif\\n\\n\" \\\n             \"#include <libretro.h>\\n\\n\" \\\n             '#ifdef __cplusplus\\n' \\\n             'extern \"C\" {\\n' \\\n             '#endif\\n'\n\n   if os.path.isfile(intl_file_path):\n      # copy top of the file for re-use\n      with open(intl_file_path, 'r', encoding='utf-8') as intl:  # libretro_core_options_intl.h\n         in_text = intl.read()\n         # attempt 1: find the distinct comment header\n         intl_start = re.search(re.escape('/*\\n'\n                                          ' ********************************\\n'\n                                          ' * Core Option Definitions\\n'\n                                          ' ********************************\\n'\n                                          '*/\\n'), in_text)\n         if intl_start:\n            out_txt = in_text[:intl_start.end(0)]\n         else:\n            # attempt 2: if no comment header present, find c++ compiler instruction (it is kind of a must)\n            intl_start = re.search(re.escape('#ifdef __cplusplus\\n'\n                                             'extern \"C\" {\\n'\n                                             '#endif\\n'), in_text)\n            if intl_start:\n               out_txt = in_text[:intl_start.end(0)]\n            # if all attempts fail, use default from above\n\n   # only write to file, if there is anything worthwhile to write!\n   overwrite = False\n\n   # iterate through localisation files\n   files = {}\n   for file in os.scandir(localisations_path):\n      files[file.name] = {'is_file': file.is_file(), 'path': file.path}\n\n   for file in sorted(files):  # intl/<core_name>/_*\n      if files[file]['is_file'] \\\n         and file.startswith('_') \\\n         and file.endswith('.h') \\\n         and not file.startswith('_us'):\n         translation_path = files[file]['path']  # <core_name>_<lang>.h\n         # all structs: group(0) full struct, group(1) beginning, group(2) content\n         struct_groups = cor.p_struct.finditer(text)\n         lang_low = os.path.splitext(file)[0].lower()\n         lang_up = lang_low.upper()\n         # mark each language's section with a comment, for readability\n         out_txt = out_txt + f'/* RETRO_LANGUAGE{lang_up} */\\n\\n'  # /* RETRO_LANGUAGE_NM */\n\n         # copy adjusted translations (makros)\n         with open(translation_path, 'r+', encoding='utf-8') as f_in:  # <core name>.h\n            out_txt = out_txt + f_in.read() + '\\n'\n         # replace English texts with makros\n         for construct in struct_groups:\n            declaration = construct.group(1)\n            struct_type_name = get_struct_type_name(declaration)\n            if 3 > len(struct_type_name):  # no language specifier\n               new_decl = re.sub(re.escape(struct_type_name[1]), struct_type_name[1] + lang_low, declaration)\n            else:\n               if '_us' != struct_type_name[2]:\n                  # only use _us constructs - other languages present in the source file are not important\n                  continue\n               new_decl = re.sub(re.escape(struct_type_name[2]), lang_low, declaration)\n\n            p = (cor.p_info_cat if 'retro_core_option_v2_category' == struct_type_name[0] else cor.p_info)\n            offset_construct = construct.start(0)\n            # append localised construct name and ' = {'\n            start = construct.end(1) - offset_construct\n            end = construct.start(4) - offset_construct\n            out_txt = out_txt + new_decl + construct.group(0)[start:end]\n            # insert macros\n            content = construct.group(4)\n            new_content = cor.p_option.sub(replace_option, content)\n            start = construct.end(4) - offset_construct\n            # append macro-filled content and close the construct\n            out_txt = out_txt + new_content + construct.group(0)[start:] + '\\n'\n\n            # for v2\n            if 'retro_core_option_v2_definition' == struct_type_name[0]:\n               out_txt = out_txt + f'struct retro_core_options_v2 options{lang_low}' \\\n                                   ' = {\\n' \\\n                                   f'   option_cats{lang_low},\\n' \\\n                                   f'   option_defs{lang_low}\\n' \\\n                                   '};\\n\\n'\n         # if it got this far, we've got something to write\n         overwrite = True\n\n   # only write to file, if there is anything worthwhile to write!\n   if overwrite:\n      with open(intl_file_path, 'w', encoding='utf-8') as intl:\n         intl.write(out_txt + '\\n#ifdef __cplusplus\\n'\n                              '}\\n#endif\\n'\n                              '\\n#endif')\n   return\n\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n   try:\n      if os.path.isfile(sys.argv[1]) or sys.argv[1].endswith('.h'):\n         _temp = os.path.dirname(sys.argv[1])\n      else:\n         _temp = sys.argv[1]\n      while _temp.endswith('/') or _temp.endswith('\\\\'):\n         _temp = _temp[:-1]\n      TARGET_DIR_PATH = _temp\n   except IndexError:\n      TARGET_DIR_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))\n      print(\"No path provided, assuming parent directory:\\n\" + TARGET_DIR_PATH)\n\n   CORE_NAME = clean_file_name(sys.argv[2])\n\n   DIR_PATH = os.path.dirname(os.path.realpath(__file__))\n   H_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')\n   INTL_FILE_PATH = os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')\n\n   print('Getting texts from libretro_core_options.h')\n   with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:\n      _main_text = _h_file.read()\n   _hash_n_str = get_texts(_main_text)\n   _files = create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str)\n   _source_jsons = h2json(_files)\n\n   print('Getting texts from libretro_core_options_intl.h')\n   if os.path.isfile(INTL_FILE_PATH):\n      with open(INTL_FILE_PATH, 'r+', encoding='utf-8') as _intl_file:\n         _intl_text = _intl_file.read()\n         _hash_n_str_intl = get_texts(_intl_text)\n         _intl_files = create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str_intl)\n         _intl_jsons = h2json(_intl_files)\n\n   print('\\nAll done!')\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/crowdin.yaml",
    "content": "\"project_id\": \"380544\"\n\"api_token\": \"_secret_\"\n\"base_url\": \"https://api.crowdin.com\"\n\"preserve_hierarchy\": true\n\n\"files\":\n  [\n    {\n      \"source\": \"/_core_name_/_us.json\",\n      \"dest\": \"/_core_name_/_core_name_.json\",\n      \"translation\": \"/_core_name_/_%two_letters_code%.json\",\n    },\n  ]\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/crowdin_prep.py",
    "content": "#!/usr/bin/env python3\n\nimport core_option_translation as t\n\nif __name__ == '__main__':\n   try:\n      if t.os.path.isfile(t.sys.argv[1]) or t.sys.argv[1].endswith('.h'):\n         _temp = t.os.path.dirname(t.sys.argv[1])\n      else:\n         _temp = t.sys.argv[1]\n      while _temp.endswith('/') or _temp.endswith('\\\\'):\n         _temp = _temp[:-1]\n      TARGET_DIR_PATH = _temp\n   except IndexError:\n      TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))\n      print(\"No path provided, assuming parent directory:\\n\" + TARGET_DIR_PATH)\n\n   CORE_NAME = t.clean_file_name(t.sys.argv[2])\n   DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))\n   H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')\n\n   print('Getting texts from libretro_core_options.h')\n   with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:\n      _main_text = _h_file.read()\n   _hash_n_str = t.get_texts(_main_text)\n   _files = t.create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str)\n\n   _source_jsons = t.h2json(_files)\n\n   print('\\nAll done!')\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/crowdin_source_upload.py",
    "content": "#!/usr/bin/env python3\n\nimport re\nimport os\nimport shutil\nimport subprocess\nimport sys\nimport urllib.request\nimport zipfile\nimport core_option_translation as t\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n   # Check Crowdin API Token and core name\n   try:\n      API_KEY = sys.argv[1]\n      CORE_NAME = t.clean_file_name(sys.argv[2])\n   except IndexError as e:\n      print('Please provide Crowdin API Token and core name!')\n      raise e\n\n   DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))\n   YAML_PATH = t.os.path.join(DIR_PATH, 'crowdin.yaml')\n\n   # Apply Crowdin API Key\n   with open(YAML_PATH, 'r') as crowdin_config_file:\n      crowdin_config = crowdin_config_file.read()\n   crowdin_config = re.sub(r'\"api_token\": \"_secret_\"',\n                           f'\"api_token\": \"{API_KEY}\"',\n                           crowdin_config, 1)\n   crowdin_config = re.sub(r'/_core_name_',\n                           f'/{CORE_NAME}'\n                           , crowdin_config)\n   with open(YAML_PATH, 'w') as crowdin_config_file:\n      crowdin_config_file.write(crowdin_config)\n\n   try:\n      # Download Crowdin CLI\n      jar_name = 'crowdin-cli.jar'\n      jar_path = t.os.path.join(DIR_PATH, jar_name)\n      crowdin_cli_file = 'crowdin-cli.zip'\n      crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file\n      crowdin_cli_path = t.os.path.join(DIR_PATH, crowdin_cli_file)\n\n      if not os.path.isfile(t.os.path.join(DIR_PATH, jar_name)):\n         print('download crowdin-cli.jar')\n         urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path)\n         with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref:\n            jar_dir = t.os.path.join(DIR_PATH, zip_ref.namelist()[0])\n            for file in zip_ref.namelist():\n               if file.endswith(jar_name):\n                  jar_file = file\n                  break\n            zip_ref.extract(jar_file, path=DIR_PATH)\n            os.rename(t.os.path.join(DIR_PATH, jar_file), jar_path)\n            os.remove(crowdin_cli_path)\n            shutil.rmtree(jar_dir)\n\n      print('upload source *.json')\n      subprocess.run(['java', '-jar', jar_path, 'upload', 'sources', '--config', YAML_PATH])\n\n      # Reset Crowdin API Key\n      with open(YAML_PATH, 'r') as crowdin_config_file:\n         crowdin_config = crowdin_config_file.read()\n      crowdin_config = re.sub(r'\"api_token\": \".*?\"',\n                              '\"api_token\": \"_secret_\"',\n                              crowdin_config, 1)\n\n      # TODO this is NOT safe!\n      crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'),\n                              '/_core_name_',\n                              crowdin_config)\n\n      with open(YAML_PATH, 'w') as crowdin_config_file:\n         crowdin_config_file.write(crowdin_config)\n\n   except Exception as e:\n      # Try really hard to reset Crowdin API Key\n      with open(YAML_PATH, 'r') as crowdin_config_file:\n         crowdin_config = crowdin_config_file.read()\n      crowdin_config = re.sub(r'\"api_token\": \".*?\"',\n                              '\"api_token\": \"_secret_\"',\n                              crowdin_config, 1)\n\n      # TODO this is NOT safe!\n      crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'),\n                              '/_core_name_',\n                              crowdin_config)\n\n      with open(YAML_PATH, 'w') as crowdin_config_file:\n         crowdin_config_file.write(crowdin_config)\n      raise e\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/crowdin_translate.py",
    "content": "#!/usr/bin/env python3\n\nimport core_option_translation as t\n\nif __name__ == '__main__':\n   try:\n      if t.os.path.isfile(t.sys.argv[1]) or t.sys.argv[1].endswith('.h'):\n         _temp = t.os.path.dirname(t.sys.argv[1])\n      else:\n         _temp = t.sys.argv[1]\n      while _temp.endswith('/') or _temp.endswith('\\\\'):\n         _temp = _temp[:-1]\n      TARGET_DIR_PATH = _temp\n   except IndexError:\n      TARGET_DIR_PATH = t.os.path.dirname(t.os.path.dirname(t.os.path.realpath(__file__)))\n      print(\"No path provided, assuming parent directory:\\n\" + TARGET_DIR_PATH)\n\n   CORE_NAME = t.clean_file_name(t.sys.argv[2])\n   DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))\n   LOCALISATIONS_PATH = t.os.path.join(DIR_PATH, CORE_NAME)\n   US_FILE_PATH = t.os.path.join(LOCALISATIONS_PATH, '_us.h')\n   H_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options.h')\n   INTL_FILE_PATH = t.os.path.join(TARGET_DIR_PATH, 'libretro_core_options_intl.h')\n\n   print('Getting texts from libretro_core_options.h')\n   with open(H_FILE_PATH, 'r+', encoding='utf-8') as _h_file:\n      _main_text = _h_file.read()\n   _hash_n_str = t.get_texts(_main_text)\n   _files = t.create_msg_hash(DIR_PATH, CORE_NAME, _hash_n_str)\n   _source_jsons = t.h2json(_files)\n\n   print('Converting translations *.json to *.h:')\n   localisation_files = t.os.scandir(LOCALISATIONS_PATH)\n   t.json2h(LOCALISATIONS_PATH, localisation_files)\n\n   print('Constructing libretro_core_options_intl.h')\n   t.create_intl_file(INTL_FILE_PATH, LOCALISATIONS_PATH, _main_text, _files[\"_us\"])\n\n   print('\\nAll done!')\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/crowdin_translation_download.py",
    "content": "#!/usr/bin/env python3\n\nimport re\nimport os\nimport shutil\nimport subprocess\nimport sys\nimport urllib.request\nimport zipfile\nimport core_option_translation as t\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n   # Check Crowdin API Token and core name\n   try:\n      API_KEY = sys.argv[1]\n      CORE_NAME = t.clean_file_name(sys.argv[2])\n   except IndexError as e:\n      print('Please provide Crowdin API Token and core name!')\n      raise e\n\n   DIR_PATH = t.os.path.dirname(t.os.path.realpath(__file__))\n   YAML_PATH = t.os.path.join(DIR_PATH, 'crowdin.yaml')\n\n   # Apply Crowdin API Key\n   with open(YAML_PATH, 'r') as crowdin_config_file:\n      crowdin_config = crowdin_config_file.read()\n   crowdin_config = re.sub(r'\"api_token\": \"_secret_\"',\n                           f'\"api_token\": \"{API_KEY}\"',\n                           crowdin_config, 1)\n   crowdin_config = re.sub(r'/_core_name_',\n                           f'/{CORE_NAME}'\n                           , crowdin_config)\n   with open(YAML_PATH, 'w') as crowdin_config_file:\n      crowdin_config_file.write(crowdin_config)\n\n   try:\n      # Download Crowdin CLI\n      jar_name = 'crowdin-cli.jar'\n      jar_path = t.os.path.join(DIR_PATH, jar_name)\n      crowdin_cli_file = 'crowdin-cli.zip'\n      crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file\n      crowdin_cli_path = t.os.path.join(DIR_PATH, crowdin_cli_file)\n\n      if not os.path.isfile(t.os.path.join(DIR_PATH, jar_name)):\n         print('download crowdin-cli.jar')\n         urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path)\n         with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref:\n            jar_dir = t.os.path.join(DIR_PATH, zip_ref.namelist()[0])\n            for file in zip_ref.namelist():\n               if file.endswith(jar_name):\n                  jar_file = file\n                  break\n            zip_ref.extract(jar_file, path=DIR_PATH)\n            os.rename(t.os.path.join(DIR_PATH, jar_file), jar_path)\n            os.remove(crowdin_cli_path)\n            shutil.rmtree(jar_dir)\n\n      print('download translation *.json')\n      subprocess.run(['java', '-jar', jar_path, 'download', '--config', YAML_PATH])\n\n      # Reset Crowdin API Key\n      with open(YAML_PATH, 'r') as crowdin_config_file:\n         crowdin_config = crowdin_config_file.read()\n      crowdin_config = re.sub(r'\"api_token\": \".*?\"',\n                              '\"api_token\": \"_secret_\"',\n                              crowdin_config, 1)\n\n      # TODO this is NOT safe!\n      crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'),\n                              '/_core_name_',\n                              crowdin_config)\n\n      with open(YAML_PATH, 'w') as crowdin_config_file:\n         crowdin_config_file.write(crowdin_config)\n\n   except Exception as e:\n      # Try really hard to reset Crowdin API Key\n      with open(YAML_PATH, 'r') as crowdin_config_file:\n         crowdin_config = crowdin_config_file.read()\n      crowdin_config = re.sub(r'\"api_token\": \".*?\"',\n                              '\"api_token\": \"_secret_\"',\n                              crowdin_config, 1)\n\n      # TODO this is NOT safe!\n      crowdin_config = re.sub(re.escape(f'/{CORE_NAME}'),\n                              '/_core_name_',\n                              crowdin_config)\n\n      with open(YAML_PATH, 'w') as crowdin_config_file:\n         crowdin_config_file.write(crowdin_config)\n      raise e\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/download_workflow.py",
    "content": "#!/usr/bin/env python3\n\nimport sys\nimport subprocess\n\ntry:\n   api_key = sys.argv[1]\n   core_name = sys.argv[2]\n   dir_path = sys.argv[3]\nexcept IndexError as e:\n   print('Please provide path to libretro_core_options.h, Crowdin API Token and core name!')\n   raise e\n\nsubprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])\nsubprocess.run(['python3', 'intl/crowdin_translation_download.py', api_key, core_name])\nsubprocess.run(['python3', 'intl/crowdin_translate.py', dir_path, core_name])\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/initial_sync.py",
    "content": "#!/usr/bin/env python3\n\nimport re\nimport os\nimport shutil\nimport subprocess\nimport sys\nimport time\nimport urllib.request\nimport zipfile\nimport core_option_translation as t\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n   # Check Crowdin API Token and core name\n   try:\n      API_KEY = sys.argv[1]\n      CORE_NAME = t.clean_file_name(sys.argv[2])\n      OPTIONS_PATH = t.clean_file_name(sys.argv[3])\n   except IndexError as e:\n      print('Please provide Crowdin API Token, core name and path to the core options file!')\n      raise e\n\n   DIR_PATH = os.path.dirname(os.path.realpath(__file__))\n   YAML_PATH = os.path.join(DIR_PATH, 'crowdin.yaml')\n\n   # Apply Crowdin API Key\n   with open(YAML_PATH, 'r') as crowdin_config_file:\n      crowdin_config = crowdin_config_file.read()\n   crowdin_config = re.sub(r'\"api_token\": \"_secret_\"',\n                           f'\"api_token\": \"{API_KEY}\"',\n                           crowdin_config, 1)\n   crowdin_config = re.sub(r'/_core_name_(?=[/.])]',\n                           f'/{CORE_NAME}'\n                           , crowdin_config)\n   with open(YAML_PATH, 'w') as crowdin_config_file:\n      crowdin_config_file.write(crowdin_config)\n\n   try:\n      jar_name = 'crowdin-cli.jar'\n      jar_path = os.path.join(DIR_PATH, jar_name)\n      crowdin_cli_file = 'crowdin-cli.zip'\n      crowdin_cli_url = 'https://downloads.crowdin.com/cli/v3/' + crowdin_cli_file\n      crowdin_cli_path = os.path.join(DIR_PATH, crowdin_cli_file)\n\n      # Download Crowdin CLI\n      if not os.path.isfile(os.path.join(DIR_PATH, jar_name)):\n         print('download crowdin-cli.jar')\n         urllib.request.urlretrieve(crowdin_cli_url, crowdin_cli_path)\n         with zipfile.ZipFile(crowdin_cli_path, 'r') as zip_ref:\n            jar_dir = os.path.join(DIR_PATH, zip_ref.namelist()[0])\n            for file in zip_ref.namelist():\n               if file.endswith(jar_name):\n                  jar_file = file\n                  break\n            zip_ref.extract(jar_file, path=DIR_PATH)\n            os.rename(os.path.join(DIR_PATH, jar_file), jar_path)\n            os.remove(crowdin_cli_path)\n            shutil.rmtree(jar_dir)\n\n      # Create JSON data\n      subprocess.run(['python3', 'intl/core_option_translation.py', OPTIONS_PATH, CORE_NAME])\n      print('upload source & translations *.json')\n      subprocess.run(['java', '-jar', jar_path, 'upload', 'sources', '--config', YAML_PATH])\n      subprocess.run(['java', '-jar', jar_path, 'upload', 'translations', '--config', YAML_PATH])\n\n      print('wait for crowdin server to process data')\n      time.sleep(10)\n\n      print('download translation *.json')\n      subprocess.run(['java', '-jar', jar_path, 'download', '--config', YAML_PATH])\n\n      # Reset Crowdin API Key\n      with open(YAML_PATH, 'r') as crowdin_config_file:\n         crowdin_config = crowdin_config_file.read()\n      crowdin_config = re.sub(r'\"api_token\": \".*\"', '\"api_token\": \"_secret_\"', crowdin_config, 1)\n\n      # TODO This is technically not safe and could replace more than intended.\n      crowdin_config = re.sub(r'/' + re.escape(CORE_NAME) + r'(?=[/.])',\n                              '/_core_name_',\n                              crowdin_config)\n\n      with open(YAML_PATH, 'w') as crowdin_config_file:\n         crowdin_config_file.write(crowdin_config)\n\n   except Exception as e:\n      # Try really hard to reset Crowdin API Key\n      with open(YAML_PATH, 'r') as crowdin_config_file:\n         crowdin_config = crowdin_config_file.read()\n      crowdin_config = re.sub(r'\"api_token\": \".*?\"',\n                              '\"api_token\": \"_secret_\"',\n                              crowdin_config, 1)\n\n      # TODO This is technically not safe and could replace more than intended.\n      crowdin_config = re.sub(r'/' + re.escape(CORE_NAME) + r'(?=[/.])',\n                              '/_core_name_',\n                              crowdin_config)\n\n      with open(YAML_PATH, 'w') as crowdin_config_file:\n         crowdin_config_file.write(crowdin_config)\n      raise e\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/remove_initial_cycle.py",
    "content": "#!/usr/bin/env python3\n\nwith open('intl/upload_workflow.py', 'r') as workflow:\n   workflow_config = workflow.read()\n\nworkflow_config = workflow_config.replace(\n   \"subprocess.run(['python3', 'intl/core_option_translation.py', dir_path, core_name])\",\n   \"subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])\"\n)\nworkflow_config = workflow_config.replace(\n   \"subprocess.run(['python3', 'intl/initial_sync.py', api_key, core_name])\",\n   \"subprocess.run(['python3', 'intl/crowdin_source_upload.py', api_key, core_name])\"\n)\nwith open('intl/upload_workflow.py', 'w') as workflow:\n   workflow.write(workflow_config)\n\n\nwith open('intl/download_workflow.py', 'r') as workflow:\n   workflow_config = workflow.read()\n\nworkflow_config = workflow_config.replace(\n   \"subprocess.run(['python3', 'intl/core_option_translation.py', dir_path, core_name])\",\n   \"subprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])\"\n)\nworkflow_config = workflow_config.replace(\n   \"subprocess.run(['python3', 'intl/initial_sync.py', api_key, core_name])\",\n   \"subprocess.run(['python3', 'intl/crowdin_translation_download.py', api_key, core_name])\"\n)\nwith open('intl/download_workflow.py', 'w') as workflow:\n   workflow.write(workflow_config)\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/upload_workflow.py",
    "content": "#!/usr/bin/env python3\n\nimport sys\nimport subprocess\n\ntry:\n   api_key = sys.argv[1]\n   core_name = sys.argv[2]\n   dir_path = sys.argv[3]\nexcept IndexError as e:\n   print('Please provide path to libretro_core_options.h, Crowdin API Token and core name!')\n   raise e\n\nsubprocess.run(['python3', 'intl/crowdin_prep.py', dir_path, core_name])\nsubprocess.run(['python3', 'intl/crowdin_source_upload.py', api_key, core_name])\n"
  },
  {
    "path": "samples/core_options/example_translation/intl/v1_to_v2_converter.py",
    "content": "#!/usr/bin/env python3\n\n\"\"\"Core options v1 to v2 converter\n\nJust run this script as follows, to convert 'libretro_core_options.h' & 'Libretro_coreoptions_intl.h' to v2:\npython3 \"/path/to/v1_to_v2_converter.py\" \"/path/to/where/libretro_core_options.h & Libretro_coreoptions_intl.h/are\"\n\nThe original files will be preserved as *.v1\n\"\"\"\nimport core_option_regex as cor\nimport os\nimport glob\n\n\ndef create_v2_code_file(struct_text, file_name):\n   def replace_option(option_match):\n      _offset = option_match.start(0)\n\n      if option_match.group(3):\n         res = option_match.group(0)[:option_match.end(2) - _offset] + ',\\n      NULL' + \\\n               option_match.group(0)[option_match.end(2) - _offset:option_match.end(3) - _offset] + \\\n               'NULL,\\n      NULL,\\n      ' + option_match.group(0)[option_match.end(3) - _offset:]\n      else:\n         return option_match.group(0)\n\n      return res\n\n   comment_v1 = '/*\\n' \\\n                ' ********************************\\n' \\\n                ' * VERSION: 1.3\\n' \\\n                ' ********************************\\n' \\\n                ' *\\n' \\\n                ' * - 1.3: Move translations to libretro_core_options_intl.h\\n' \\\n                ' *        - libretro_core_options_intl.h includes BOM and utf-8\\n' \\\n                ' *          fix for MSVC 2010-2013\\n' \\\n                ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\\n' \\\n                ' *          on platforms/compilers without BOM support\\n' \\\n                ' * - 1.2: Use core options v1 interface when\\n' \\\n                ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\\n' \\\n                ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\\n' \\\n                ' * - 1.1: Support generation of core options v0 retro_core_option_value\\n' \\\n                ' *        arrays containing options with a single value\\n' \\\n                ' * - 1.0: First commit\\n' \\\n                '*/\\n'\n\n   comment_v2 = '/*\\n' \\\n                ' ********************************\\n' \\\n                ' * VERSION: 2.0\\n' \\\n                ' ********************************\\n' \\\n                ' *\\n' \\\n                ' * - 2.0: Add support for core options v2 interface\\n' \\\n                ' * - 1.3: Move translations to libretro_core_options_intl.h\\n' \\\n                ' *        - libretro_core_options_intl.h includes BOM and utf-8\\n' \\\n                ' *          fix for MSVC 2010-2013\\n' \\\n                ' *        - Added HAVE_NO_LANGEXTRA flag to disable translations\\n' \\\n                ' *          on platforms/compilers without BOM support\\n' \\\n                ' * - 1.2: Use core options v1 interface when\\n' \\\n                ' *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1\\n' \\\n                ' *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)\\n' \\\n                ' * - 1.1: Support generation of core options v0 retro_core_option_value\\n' \\\n                ' *        arrays containing options with a single value\\n' \\\n                ' * - 1.0: First commit\\n' \\\n                '*/\\n'\n\n   p_intl = cor.p_intl\n   p_set = cor.p_set\n   new_set = 'static INLINE void libretro_set_core_options(retro_environment_t environ_cb,\\n' \\\n             '      bool *categories_supported)\\n' \\\n             '{\\n' \\\n             '   unsigned version  = 0;\\n' \\\n             '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n             '   unsigned language = 0;\\n' \\\n             '#endif\\n' \\\n             '\\n' \\\n             '   if (!environ_cb || !categories_supported)\\n' \\\n             '      return;\\n' \\\n             '\\n' \\\n             '   *categories_supported = false;\\n' \\\n             '\\n' \\\n             '   if (!environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version))\\n' \\\n             '      version = 0;\\n' \\\n             '\\n' \\\n             '   if (version >= 2)\\n' \\\n             '   {\\n' \\\n             '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n             '      struct retro_core_options_v2_intl core_options_intl;\\n' \\\n             '\\n' \\\n             '      core_options_intl.us    = &options_us;\\n' \\\n             '      core_options_intl.local = NULL;\\n' \\\n             '\\n' \\\n             '      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\\n' \\\n             '          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))\\n' \\\n             '         core_options_intl.local = options_intl[language];\\n' \\\n             '\\n' \\\n             '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2_INTL,\\n' \\\n             '            &core_options_intl);\\n' \\\n             '#else\\n' \\\n             '      *categories_supported = environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_V2,\\n' \\\n             '            &options_us);\\n' \\\n             '#endif\\n' \\\n             '   }\\n' \\\n             '   else\\n' \\\n             '   {\\n' \\\n             '      size_t i, j;\\n' \\\n             '      size_t option_index              = 0;\\n' \\\n             '      size_t num_options               = 0;\\n' \\\n             '      struct retro_core_option_definition\\n' \\\n             '            *option_v1_defs_us         = NULL;\\n' \\\n             '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n             '      size_t num_options_intl          = 0;\\n' \\\n             '      struct retro_core_option_v2_definition\\n' \\\n             '            *option_defs_intl          = NULL;\\n' \\\n             '      struct retro_core_option_definition\\n' \\\n             '            *option_v1_defs_intl       = NULL;\\n' \\\n             '      struct retro_core_options_intl\\n' \\\n             '            core_options_v1_intl;\\n' \\\n             '#endif\\n' \\\n             '      struct retro_variable *variables = NULL;\\n' \\\n             '      char **values_buf                = NULL;\\n' \\\n             '\\n' \\\n             '      /* Determine total number of options */\\n' \\\n             '      while (true)\\n' \\\n             '      {\\n' \\\n             '         if (option_defs_us[num_options].key)\\n' \\\n             '            num_options++;\\n' \\\n             '         else\\n' \\\n             '            break;\\n' \\\n             '      }\\n' \\\n             '\\n' \\\n             '      if (version >= 1)\\n' \\\n             '      {\\n' \\\n             '         /* Allocate US array */\\n' \\\n             '         option_v1_defs_us = (struct retro_core_option_definition *)\\n' \\\n             '               calloc(num_options + 1, sizeof(struct retro_core_option_definition));\\n' \\\n             '\\n' \\\n             '         /* Copy parameters from option_defs_us array */\\n' \\\n             '         for (i = 0; i < num_options; i++)\\n' \\\n             '         {\\n' \\\n             '            struct retro_core_option_v2_definition *option_def_us = &option_defs_us[i];\\n' \\\n             '            struct retro_core_option_value *option_values         = option_def_us->values;\\n' \\\n             '            struct retro_core_option_definition *option_v1_def_us = &option_v1_defs_us[i];\\n' \\\n             '            struct retro_core_option_value *option_v1_values      = option_v1_def_us->values;\\n' \\\n             '\\n' \\\n             '            option_v1_def_us->key           = option_def_us->key;\\n' \\\n             '            option_v1_def_us->desc          = option_def_us->desc;\\n' \\\n             '            option_v1_def_us->info          = option_def_us->info;\\n' \\\n             '            option_v1_def_us->default_value = option_def_us->default_value;\\n' \\\n             '\\n' \\\n             '            /* Values must be copied individually... */\\n' \\\n             '            while (option_values->value)\\n' \\\n             '            {\\n' \\\n             '               option_v1_values->value = option_values->value;\\n' \\\n             '               option_v1_values->label = option_values->label;\\n' \\\n             '\\n' \\\n             '               option_values++;\\n' \\\n             '               option_v1_values++;\\n' \\\n             '            }\\n' \\\n             '         }\\n' \\\n             '\\n' \\\n             '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n             '         if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&\\n' \\\n             '             (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH) &&\\n' \\\n             '             options_intl[language])\\n' \\\n             '            option_defs_intl = options_intl[language]->definitions;\\n' \\\n             '\\n' \\\n             '         if (option_defs_intl)\\n' \\\n             '         {\\n' \\\n             '            /* Determine number of intl options */\\n' \\\n             '            while (true)\\n' \\\n             '            {\\n' \\\n             '               if (option_defs_intl[num_options_intl].key)\\n' \\\n             '                  num_options_intl++;\\n' \\\n             '               else\\n' \\\n             '                  break;\\n' \\\n             '            }\\n' \\\n             '\\n' \\\n             '            /* Allocate intl array */\\n' \\\n             '            option_v1_defs_intl = (struct retro_core_option_definition *)\\n' \\\n             '                  calloc(num_options_intl + 1, sizeof(struct retro_core_option_definition));\\n' \\\n             '\\n' \\\n             '            /* Copy parameters from option_defs_intl array */\\n' \\\n             '            for (i = 0; i < num_options_intl; i++)\\n' \\\n             '            {\\n' \\\n             '               struct retro_core_option_v2_definition *option_def_intl = &option_defs_intl[i];\\n' \\\n             '               struct retro_core_option_value *option_values           = option_def_intl->values;\\n' \\\n             '               struct retro_core_option_definition *option_v1_def_intl = &option_v1_defs_intl[i];\\n' \\\n             '               struct retro_core_option_value *option_v1_values        = option_v1_def_intl->values;\\n' \\\n             '\\n' \\\n             '               option_v1_def_intl->key           = option_def_intl->key;\\n' \\\n             '               option_v1_def_intl->desc          = option_def_intl->desc;\\n' \\\n             '               option_v1_def_intl->info          = option_def_intl->info;\\n' \\\n             '               option_v1_def_intl->default_value = option_def_intl->default_value;\\n' \\\n             '\\n' \\\n             '               /* Values must be copied individually... */\\n' \\\n             '               while (option_values->value)\\n' \\\n             '               {\\n' \\\n             '                  option_v1_values->value = option_values->value;\\n' \\\n             '                  option_v1_values->label = option_values->label;\\n' \\\n             '\\n' \\\n             '                  option_values++;\\n' \\\n             '                  option_v1_values++;\\n' \\\n             '               }\\n' \\\n             '            }\\n' \\\n             '         }\\n' \\\n             '\\n' \\\n             '         core_options_v1_intl.us    = option_v1_defs_us;\\n' \\\n             '         core_options_v1_intl.local = option_v1_defs_intl;\\n' \\\n             '\\n' \\\n             '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_v1_intl);\\n' \\\n             '#else\\n' \\\n             '         environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, option_v1_defs_us);\\n' \\\n             '#endif\\n' \\\n             '      }\\n' \\\n             '      else\\n' \\\n             '      {\\n' \\\n             '         /* Allocate arrays */\\n' \\\n             '         variables  = (struct retro_variable *)calloc(num_options + 1,\\n' \\\n             '               sizeof(struct retro_variable));\\n' \\\n             '         values_buf = (char **)calloc(num_options, sizeof(char *));\\n' \\\n             '\\n' \\\n             '         if (!variables || !values_buf)\\n' \\\n             '            goto error;\\n' \\\n             '\\n' \\\n             '         /* Copy parameters from option_defs_us array */\\n' \\\n             '         for (i = 0; i < num_options; i++)\\n' \\\n             '         {\\n' \\\n             '            const char *key                        = option_defs_us[i].key;\\n' \\\n             '            const char *desc                       = option_defs_us[i].desc;\\n' \\\n             '            const char *default_value              = option_defs_us[i].default_value;\\n' \\\n             '            struct retro_core_option_value *values = option_defs_us[i].values;\\n' \\\n             '            size_t buf_len                         = 3;\\n' \\\n             '            size_t default_index                   = 0;\\n' \\\n             '\\n' \\\n             '            values_buf[i] = NULL;\\n' \\\n             '\\n' \\\n             '            if (desc)\\n' \\\n             '            {\\n' \\\n             '               size_t num_values = 0;\\n' \\\n             '\\n' \\\n             '               /* Determine number of values */\\n' \\\n             '               while (true)\\n' \\\n             '               {\\n' \\\n             '                  if (values[num_values].value)\\n' \\\n             '                  {\\n' \\\n             '                     /* Check if this is the default value */\\n' \\\n             '                     if (default_value)\\n' \\\n             '                        if (strcmp(values[num_values].value, default_value) == 0)\\n' \\\n             '                           default_index = num_values;\\n' \\\n             '\\n' \\\n             '                     buf_len += strlen(values[num_values].value);\\n' \\\n             '                     num_values++;\\n' \\\n             '                  }\\n' \\\n             '                  else\\n' \\\n             '                     break;\\n' \\\n             '               }\\n' \\\n             '\\n' \\\n             '               /* Build values string */\\n' \\\n             '               if (num_values > 0)\\n' \\\n             '               {\\n' \\\n             '                  buf_len += num_values - 1;\\n' \\\n             '                  buf_len += strlen(desc);\\n' \\\n             '\\n' \\\n             '                  values_buf[i] = (char *)calloc(buf_len, sizeof(char));\\n' \\\n             '                  if (!values_buf[i])\\n' \\\n             '                     goto error;\\n' \\\n             '\\n' \\\n             '                  strcpy(values_buf[i], desc);\\n' \\\n             '                  strcat(values_buf[i], \"; \");\\n' \\\n             '\\n' \\\n             '                  /* Default value goes first */\\n' \\\n             '                  strcat(values_buf[i], values[default_index].value);\\n' \\\n             '\\n' \\\n             '                  /* Add remaining values */\\n' \\\n             '                  for (j = 0; j < num_values; j++)\\n' \\\n             '                  {\\n' \\\n             '                     if (j != default_index)\\n' \\\n             '                     {\\n' \\\n             '                        strcat(values_buf[i], \"|\");\\n' \\\n             '                        strcat(values_buf[i], values[j].value);\\n' \\\n             '                     }\\n' \\\n             '                  }\\n' \\\n             '               }\\n' \\\n             '            }\\n' \\\n             '\\n' \\\n             '            variables[option_index].key   = key;\\n' \\\n             '            variables[option_index].value = values_buf[i];\\n' \\\n             '            option_index++;\\n' \\\n             '         }\\n' \\\n             '\\n' \\\n             '         /* Set variables */\\n' \\\n             '         environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);\\n' \\\n             '      }\\n' \\\n             '\\n' \\\n             'error:\\n' \\\n             '      /* Clean up */\\n' \\\n             '\\n' \\\n             '      if (option_v1_defs_us)\\n' \\\n             '      {\\n' \\\n             '         free(option_v1_defs_us);\\n' \\\n             '         option_v1_defs_us = NULL;\\n' \\\n             '      }\\n' \\\n             '\\n' \\\n             '#ifndef HAVE_NO_LANGEXTRA\\n' \\\n             '      if (option_v1_defs_intl)\\n' \\\n             '      {\\n' \\\n             '         free(option_v1_defs_intl);\\n' \\\n             '         option_v1_defs_intl = NULL;\\n' \\\n             '      }\\n' \\\n             '#endif\\n' \\\n             '\\n' \\\n             '      if (values_buf)\\n' \\\n             '      {\\n' \\\n             '         for (i = 0; i < num_options; i++)\\n' \\\n             '         {\\n' \\\n             '            if (values_buf[i])\\n' \\\n             '            {\\n' \\\n             '               free(values_buf[i]);\\n' \\\n             '               values_buf[i] = NULL;\\n' \\\n             '            }\\n' \\\n             '         }\\n' \\\n             '\\n' \\\n             '         free(values_buf);\\n' \\\n             '         values_buf = NULL;\\n' \\\n             '      }\\n' \\\n             '\\n' \\\n             '      if (variables)\\n' \\\n             '      {\\n' \\\n             '         free(variables);\\n' \\\n             '         variables = NULL;\\n' \\\n             '      }\\n' \\\n             '   }\\n' \\\n             '}\\n' \\\n             '\\n' \\\n             '#ifdef __cplusplus\\n' \\\n             '}\\n' \\\n             '#endif'\n\n   struct_groups = cor.p_struct.finditer(struct_text)\n   out_text = struct_text\n\n   for construct in struct_groups:\n      repl_text = ''\n      declaration = construct.group(1)\n      struct_match = cor.p_type_name.search(declaration)\n      if struct_match:\n         if struct_match.group(3):\n            struct_type_name_lang = struct_match.group(1, 2, 3)\n            declaration_end = declaration[struct_match.end(1):]\n         elif struct_match.group(4):\n            struct_type_name_lang = struct_match.group(1, 2, 4)\n            declaration_end = declaration[struct_match.end(1):]\n         else:\n            struct_type_name_lang = sum((struct_match.group(1, 2), ('_us',)), ())\n            declaration_end = f'{declaration[struct_match.end(1):struct_match.end(2)]}_us' \\\n                              f'{declaration[struct_match.end(2):]}'\n      else:\n         return -1\n\n      if 'retro_core_option_definition' == struct_type_name_lang[0]:\n         import shutil\n         shutil.copy(file_name, file_name + '.v1')\n         new_declaration = f'\\nstruct retro_core_option_v2_category option_cats{struct_type_name_lang[2]}[] = ' \\\n                           '{\\n   { NULL, NULL, NULL },\\n' \\\n                           '};\\n\\n' \\\n                           + declaration[:struct_match.start(1)] + \\\n                           'retro_core_option_v2_definition' \\\n                           + declaration_end\n         offset = construct.start(0)\n         repl_text = repl_text + cor.re.sub(cor.re.escape(declaration), new_declaration,\n                                            construct.group(0)[:construct.start(2) - offset])\n         content = construct.group(2)\n         new_content = cor.p_option.sub(replace_option, content)\n\n         repl_text = repl_text + new_content + cor.re.sub(r'{\\s*NULL,\\s*NULL,\\s*NULL,\\s*{\\{0}},\\s*NULL\\s*},\\s*};',\n                                                          '{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\\n};'\n                                                          '\\n\\nstruct retro_core_options_v2 options' +\n                                                          struct_type_name_lang[2] + ' = {\\n'\n                                                                                     f'   option_cats{struct_type_name_lang[2]},\\n'\n                                                                                     f'   option_defs{struct_type_name_lang[2]}\\n'\n                                                                                     '};',\n                                                          construct.group(0)[construct.end(2) - offset:])\n         out_text = out_text.replace(construct.group(0), repl_text)\n         #out_text = cor.re.sub(cor.re.escape(construct.group(0)), repl_text, raw_out)\n      else:\n         return -2\n   with open(file_name, 'w', encoding='utf-8') as code_file:\n      out_text = cor.re.sub(cor.re.escape(comment_v1), comment_v2, out_text)\n      intl = p_intl.search(out_text)\n      if intl:\n         new_intl = out_text[:intl.start(1)] \\\n                    + 'struct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST]' \\\n                    + out_text[intl.end(1):intl.start(2)] \\\n                    + '\\n   &options_us, /* RETRO_LANGUAGE_ENGLISH */\\n' \\\n                      '   &options_ja,      /* RETRO_LANGUAGE_JAPANESE */\\n' \\\n                      '   &options_fr,      /* RETRO_LANGUAGE_FRENCH */\\n' \\\n                      '   &options_es,      /* RETRO_LANGUAGE_SPANISH */\\n' \\\n                      '   &options_de,      /* RETRO_LANGUAGE_GERMAN */\\n' \\\n                      '   &options_it,      /* RETRO_LANGUAGE_ITALIAN */\\n' \\\n                      '   &options_nl,      /* RETRO_LANGUAGE_DUTCH */\\n' \\\n                      '   &options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\\n' \\\n                      '   &options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\\n' \\\n                      '   &options_ru,      /* RETRO_LANGUAGE_RUSSIAN */\\n' \\\n                      '   &options_ko,      /* RETRO_LANGUAGE_KOREAN */\\n' \\\n                      '   &options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\\n' \\\n                      '   &options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\\n' \\\n                      '   &options_eo,      /* RETRO_LANGUAGE_ESPERANTO */\\n' \\\n                      '   &options_pl,      /* RETRO_LANGUAGE_POLISH */\\n' \\\n                      '   &options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */\\n' \\\n                      '   &options_ar,      /* RETRO_LANGUAGE_ARABIC */\\n' \\\n                      '   &options_el,      /* RETRO_LANGUAGE_GREEK */\\n' \\\n                      '   &options_tr,      /* RETRO_LANGUAGE_TURKISH */\\n' \\\n                      '   &options_sk,      /* RETRO_LANGUAGE_SLOVAK */\\n' \\\n                      '   &options_fa,      /* RETRO_LANGUAGE_PERSIAN */\\n' \\\n                      '   &options_he,      /* RETRO_LANGUAGE_HEBREW */\\n' \\\n                      '   &options_ast,     /* RETRO_LANGUAGE_ASTURIAN */\\n' \\\n                      '   &options_fi,      /* RETRO_LANGUAGE_FINNISH */\\n' \\\n                      '   &options_id,      /* RETRO_LANGUAGE_INDONESIAN */\\n' \\\n                      '   &options_sv,      /* RETRO_LANGUAGE_SWEDISH */\\n' \\\n                      '   &options_uk,      /* RETRO_LANGUAGE_UKRAINIAN */\\n' \\\n                      '   &options_cs,      /* RETRO_LANGUAGE_CZECH */\\n' \\\n                      '   &options_val,     /* RETRO_LANGUAGE_CATALAN_VALENCIA */\\n' \\\n                      '   &options_ca,      /* RETRO_LANGUAGE_CATALAN */\\n' \\\n                      '   &options_en,      /* RETRO_LANGUAGE_BRITISH_ENGLISH */\\n' \\\n                      '   &options_hu,      /* RETRO_LANGUAGE_HUNGARIAN */\\n' \\\n                    + out_text[intl.end(2):]\n         out_text = p_set.sub(new_set, new_intl)\n      else:\n         out_text = p_set.sub(new_set, out_text)\n      code_file.write(out_text)\n\n   return 1\n\n\n# --------------------          MAIN          -------------------- #\n\nif __name__ == '__main__':\n   DIR_PATH = os.path.dirname(os.path.realpath(__file__))\n   if os.path.basename(DIR_PATH) != \"intl\":\n      raise RuntimeError(\"Script is not in intl folder!\")\n\n   BASE_PATH = os.path.dirname(DIR_PATH)\n   CORE_OP_FILE = os.path.join(BASE_PATH, \"**\", \"libretro_core_options.h\")\n\n   core_options_hits = glob.glob(CORE_OP_FILE, recursive=True)\n\n   if len(core_options_hits) == 0:\n      raise RuntimeError(\"libretro_core_options.h not found!\")\n   elif len(core_options_hits) > 1:\n      print(\"More than one libretro_core_options.h file found:\\n\\n\")\n      for i, file in enumerate(core_options_hits):\n         print(f\"{i} {file}\\n\")\n\n      while True:\n         user_choice = input(\"Please choose one ('q' will exit): \")\n         if user_choice == 'q':\n            exit(0)\n         elif user_choice.isdigit():\n            core_op_file = core_options_hits[int(user_choice)]\n            break\n         else:\n            print(\"Please make a valid choice!\\n\\n\")\n   else:\n      core_op_file = core_options_hits[0]\n\n   H_FILE_PATH = core_op_file\n   INTL_FILE_PATH = core_op_file.replace(\"libretro_core_options.h\", 'libretro_core_options_intl.h')\n   for file in (H_FILE_PATH, INTL_FILE_PATH):\n      if os.path.isfile(file):\n         with open(file, 'r+', encoding='utf-8') as h_file:\n            text = h_file.read()\n            try:\n               test = create_v2_code_file(text, file)\n            except Exception as e:\n               print(e)\n               test = -1\n            if -1 > test:\n               print('Your file looks like it already is v2? (' + file + ')')\n               continue\n            if 0 > test:\n               print('An error occured! Please make sure to use the complete v1 struct! (' + file + ')')\n               continue\n      else:\n         print(file + ' not found.')\n"
  },
  {
    "path": "samples/core_options/example_translation/libretro_core_options.h",
    "content": "#ifndef LIBRETRO_CORE_OPTIONS_H__\n#define LIBRETRO_CORE_OPTIONS_H__\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <libretro.h>\n#include <retro_inline.h>\n\n#ifndef HAVE_NO_LANGEXTRA\n#include \"libretro_core_options_intl.h\"\n#endif\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_ENGLISH */\n\n/* Default language:\n * - All other languages must include the same keys and values\n * - Will be used as a fallback in the event that frontend language\n *   is not available\n * - Will be used as a fallback for any missing entries in\n *   frontend language definition */\n\nstruct retro_core_option_v2_category option_cats_us[] = {\n   {\n      \"video\",                     /* key (category name) */\n      \"Video\",                     /* category description (label) */\n      \"Configure display options.\" /* category sublabel */\n   },\n   {\n      \"hacks\",\n      \"Advanced\",\n      \"Options affecting low-level emulation performance and accuracy.\"\n   },\n   { NULL, NULL, NULL },\n};\n\nstruct retro_core_option_v2_definition option_defs_us[] = {\n   {\n      \"mycore_region\",                            /* key (option name) */\n      \"Console Region\",                           /* description (label) */\n      NULL,                                       /* 'categorised' description (used instead of\n                                                   * 'description' if frontend has category\n                                                   * support; if NULL or empty, regular\n                                                   * description is always used */\n      \"Specify which region the system is from.\", /* sublabel */\n      NULL,                                       /* 'categorised' sublabel (used instead of\n                                                   * 'sublabel' if frontend has category\n                                                   * support; if NULL or empty, regular\n                                                   * sublabel is always used */\n      NULL,                                       /* category key (must match an entry in\n                                                   * option_cats_us; if NULL or empty,\n                                                   * option is uncategorised */\n      {\n         { \"auto\",   \"Auto\" },                    /* value_1, value_1_label */\n         { \"ntsc-j\", \"Japan\" },                   /* value_2, value_2_label */\n         { \"ntsc-u\", \"America\" },                 /* value_3, value_3_label */\n         { \"pal\",    \"Europe\" },                  /* value_4, value_4_label */\n         { NULL, NULL },\n      },\n      \"auto\"                                      /* default_value */\n   },\n   {\n      \"mycore_video_scale\",\n      \"Video > Scale\",   /* description: here a 'Video >' prefix is used to\n                          * signify a category on frontends without explicit\n                          * category support */\n      \"Scale\",           /* 'categorised' description: will be displayed inside\n                          * the 'Video' submenu */\n      \"Set internal video scale factor.\",\n      NULL,\n      \"video\",           /* category key */\n      {\n         { \"1x\", NULL }, /* If value itself is human-readable (e.g. a number)  */\n         { \"2x\", NULL }, /* and can displayed directly, the value_label should */\n         { \"3x\", NULL }, /* be set to NULL                                     */\n         { \"4x\", NULL },\n         { NULL, NULL },\n      },\n      \"3x\"\n   },\n   {\n      \"mycore_overclock\",\n      \"Advanced > Reduce Slowdown\",\n      \"Reduce Slowdown\",\n      \"Enabling 'Advanced > Reduce Slowdown' will reduce accuracy.\", /* sublabel */\n      \"Enabling 'Reduce Slowdown' will reduce accuracy.\",            /* 'categorised' sublabel:\n                               * will be displayed inside the 'Advanced' submenu; note that\n                               * 'Advanced > Reduce Slowdown' is replaced with 'Reduce Slowdown' */\n      \"hacks\",\n      {\n         { \"enabled\",  NULL }, /* If value is equal to 'enabled' or 'disabled', */\n         { \"disabled\", NULL }, /* value_label should be set to NULL             */\n         { NULL, NULL },\n      },\n      \"disabled\"\n   },\n   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};\n\nstruct retro_core_options_v2 options_us = {\n   option_cats_us,\n   option_defs_us\n};\n\n/*\n ********************************\n * Language Mapping\n ********************************\n*/\n\n#ifndef HAVE_NO_LANGEXTRA\nstruct retro_core_options_v2 *options_intl[RETRO_LANGUAGE_LAST] = {\n   &options_us,      /* RETRO_LANGUAGE_ENGLISH */\n   &options_ja,      /* RETRO_LANGUAGE_JAPANESE */\n   &options_fr,      /* RETRO_LANGUAGE_FRENCH */\n   &options_es,      /* RETRO_LANGUAGE_SPANISH */\n   &options_de,      /* RETRO_LANGUAGE_GERMAN */\n   &options_it,      /* RETRO_LANGUAGE_ITALIAN */\n   &options_nl,      /* RETRO_LANGUAGE_DUTCH */\n   &options_pt_br,   /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n   &options_pt_pt,   /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n   &options_ru,      /* RETRO_LANGUAGE_RUSSIAN */\n   &options_ko,      /* RETRO_LANGUAGE_KOREAN */\n   &options_cht,     /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n   &options_chs,     /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n   &options_eo,      /* RETRO_LANGUAGE_ESPERANTO */\n   &options_pl,      /* RETRO_LANGUAGE_POLISH */\n   &options_vn,      /* RETRO_LANGUAGE_VIETNAMESE */\n   &options_ar,      /* RETRO_LANGUAGE_ARABIC */\n   &options_el,      /* RETRO_LANGUAGE_GREEK */\n   &options_tr,      /* RETRO_LANGUAGE_TURKISH */\n   &options_sk,      /* RETRO_LANGUAGE_SLOVAK */\n   &options_fa,      /* RETRO_LANGUAGE_PERSIAN */\n   &options_he,      /* RETRO_LANGUAGE_HEBREW */\n   &options_ast,     /* RETRO_LANGUAGE_ASTURIAN */\n   &options_fi,      /* RETRO_LANGUAGE_FINNISH */\n   &options_id,      /* RETRO_LANGUAGE_INDONESIAN */\n   &options_sv,      /* RETRO_LANGUAGE_SWEDISH */\n   &options_uk,      /* RETRO_LANGUAGE_UKRAINIAN */\n   &options_cs,      /* RETRO_LANGUAGE_CZECH */\n   &options_val,     /* RETRO_LANGUAGE_CATALAN_VALENCIA */\n   &options_ca,      /* RETRO_LANGUAGE_CATALAN */\n   &options_en,      /* RETRO_LANGUAGE_BRITISH_ENGLISH */\n   &options_hu,      /* RETRO_LANGUAGE_HUNGARIAN */\n   &options_be,      /* RETRO_LANGUAGE_BELARUSIAN */\n   &options_gl,      /* RETRO_LANGUAGE_GALICIAN */\n   &options_no,      /* RETRO_LANGUAGE_NORWEGIAN */\n   &options_th,      /* RETRO_LANGUAGE_THAI */\n};\n#endif\n\n/*\n ********************************\n * Functions\n ********************************\n*/\n\n/* Handles configuration/setting of core options.\n * Should be called as early as possible - ideally inside\n * retro_set_environment(), and no later than retro_load_game()\n * > We place the function body in the header to avoid the\n *   necessity of adding more .c files (i.e. want this to\n *   be as painless as possible for core devs)\n */\n\nstatic 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\nerror:\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\n\n#endif\n"
  },
  {
    "path": "samples/core_options/example_translation/libretro_core_options_intl.h",
    "content": "﻿#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__\n#define LIBRETRO_CORE_OPTIONS_INTL_H__\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)\n/* https://support.microsoft.com/en-us/kb/980263 */\n#pragma execution_character_set(\"utf-8\")\n#pragma warning(disable:4566)\n#endif\n\n#include <libretro.h>\n\n/*\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\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n ********************************\n * Core Option Definitions\n ********************************\n*/\n\n/* RETRO_LANGUAGE_JAPANESE */\n\n/* RETRO_LANGUAGE_FRENCH */\n\nstruct retro_core_option_v2_category option_cats_fr[] = {\n   {\n      \"video\",                              /* key must match option_cats_us entry */\n      \"Vidéo\",                              /* translated category description */\n      \"Configurez les options d'affichage.\" /* translated category sublabel */\n   },\n   {\n      \"hacks\",\n      \"Avancée\",\n      \"Options affectant les performances et la précision de l'émulation de bas niveau.\"\n   },\n   { NULL, NULL, NULL },\n};\n\nstruct retro_core_option_v2_definition option_defs_fr[] = {\n   {\n      \"mycore_region\",                             /* key must match option_defs_us entry */\n      \"Région de la console\",                      /* translated description */\n      NULL,\n      \"Spécifiez la région d'origine du système.\", /* translated sublabel */\n      NULL,\n      NULL,                                        /* category key is taken from option_defs_us\n                                                    * -> can set to NULL here */\n      {\n         { \"auto\",   \"Auto\" },                     /* value must match option_defs_us entry   */\n         { \"ntsc-j\", \"Japon\" },                    /* > only value_label should be translated */\n         { \"ntsc-u\", \"Amérique\" },\n         { \"pal\",    \"L'Europe\" },\n         { NULL, NULL },\n      },\n      NULL                                         /* default_value is taken from option_defs_us\n                                                    * -> can set to NULL here */\n   },\n   {\n      \"mycore_video_scale\",\n      \"Vidéo > Échelle\", /* translated description */\n      \"Échelle\",         /* translated 'categorised' description */\n      \"Définir le facteur d'échelle vidéo interne.\",\n      NULL,\n      NULL,\n      {\n         { NULL, NULL }, /* If value_labels do not require translation (e.g. numbers), values may be omitted */\n      },\n      NULL\n   },\n   {\n      \"mycore_overclock\",\n      \"Avancé > Réduire le ralentissement\",\n      \"Réduire le ralentissement\",\n      \"L'activation de « Avancé > Réduire le ralentissement » réduira la précision.\", /* translated sublabel */\n      \"L'activation de « Réduire le ralentissement » réduira la précision.\",          /* translated 'categorised'\n                                                                                       * sublabel */\n      NULL,\n      {\n         { NULL, NULL }, /* 'enabled' and 'disabled' values should not be translated */\n      },\n      NULL\n   },\n   { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },\n};\n\nstruct retro_core_options_v2 options_fr = {\n   option_cats_fr,\n   option_defs_fr\n};\n\n/* RETRO_LANGUAGE_SPANISH */\n\n/* RETRO_LANGUAGE_GERMAN */\n\n/* RETRO_LANGUAGE_ITALIAN */\n\n/* RETRO_LANGUAGE_DUTCH */\n\n/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */\n\n/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */\n\n/* RETRO_LANGUAGE_RUSSIAN */\n\n/* RETRO_LANGUAGE_KOREAN */\n\n/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */\n\n/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */\n\n/* RETRO_LANGUAGE_ESPERANTO */\n\n/* RETRO_LANGUAGE_POLISH */\n\n/* RETRO_LANGUAGE_VIETNAMESE */\n\n/* RETRO_LANGUAGE_ARABIC */\n\n/* RETRO_LANGUAGE_GREEK */\n\n/* RETRO_LANGUAGE_TURKISH */\n\n/* RETRO_LANGUAGE_SLOVAK */\n\n/* RETRO_LANGUAGE_PERSIAN */\n\n/* RETRO_LANGUAGE_HEBREW */\n\n/* RETRO_LANGUAGE_ASTURIAN */\n\n/* RETRO_LANGUAGE_FINNISH */\n\n/* RETRO_LANGUAGE_THAI */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "samples/encodings/base64/Makefile",
    "content": "TARGET := unbase64_test\n\nCORE_DIR          := .\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES_C := \\\n\t$(CORE_DIR)/unbase64_test.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_base64.c\n\nOBJS := $(SOURCES_C:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/encodings/base64/unbase64_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (unbase64_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression tests for unbase64.\n *\n * Fixed in commit 87f2d0b: malformed base64 lengths used to cause a\n * 1-byte heap-buffer-overflow.  Under AddressSanitizer, feeding \"AB=\"\n * to the unpatched version produces:\n *   ERROR: AddressSanitizer: heap-buffer-overflow\n *   WRITE of size 1 at 0 bytes after 1-byte region\n *\n * Build/run with ASan for full coverage:\n *   make CFLAGS='-fsanitize=address -g -O0' LDFLAGS='-fsanitize=address'\n *   ./unbase64_test\n *\n * Exits 0 on success, aborts on failure.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <encodings/base64.h>\n\nstatic int failures = 0;\n\nstatic void expect_reject(const char *ascii, int len)\n{\n   int flen                  = -1;\n   unsigned char *out        = unbase64(ascii, len, &flen);\n   if (out || flen != 0)\n   {\n      printf(\"[FAILED] expected reject for len=%d input \\\"%s\\\", got out=%p flen=%d\\n\",\n            len, ascii ? ascii : \"(null)\", (void*)out, flen);\n      free(out);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] rejected malformed input (len=%d) \\\"%s\\\"\\n\",\n         len, ascii ? ascii : \"(null)\");\n}\n\nstatic void expect_decode(const char *ascii, int len,\n      const char *want, int want_len)\n{\n   int flen                  = 0;\n   unsigned char *out        = unbase64(ascii, len, &flen);\n   if (!out)\n   {\n      printf(\"[FAILED] expected decode for \\\"%s\\\", got NULL\\n\", ascii);\n      failures++;\n      return;\n   }\n   if (flen != want_len || memcmp(out, want, want_len) != 0)\n   {\n      printf(\"[FAILED] decode \\\"%s\\\": got flen=%d want=%d\\n\",\n            ascii, flen, want_len);\n      free(out);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] decoded \\\"%s\\\" -> %d bytes\\n\", ascii, flen);\n   free(out);\n}\n\nint main(void)\n{\n   /* --- Malformed inputs that used to overflow or misbehave --- */\n   expect_reject(\"AB=\", 3);            /* canonical repro: 1-byte OOB write */\n   expect_reject(\"A==\", 3);            /* another 3-char pad case          */\n   expect_reject(\"A\",   1);            /* below old 2-char floor           */\n   expect_reject(\"\",    0);            /* empty                            */\n   expect_reject(\"ABC\", 3);            /* len not multiple of 4            */\n   expect_reject(\"ABCDE\", 5);          /* len not multiple of 4            */\n   expect_reject(\"ABCDEFG\", 7);        /* len not multiple of 4            */\n\n   /* --- Valid inputs must still decode --- */\n   expect_decode(\"QUJD\",     4, \"ABC\",    3);   /* no padding */\n   expect_decode(\"SGVsbG8h\", 8, \"Hello!\", 6);   /* no padding */\n   expect_decode(\"SGVsbG8=\", 8, \"Hello\",  5);   /* 1 pad      */\n   expect_decode(\"SGk=\",     4, \"Hi\",     2);   /* 1 pad      */\n   expect_decode(\"QQ==\",     4, \"A\",      1);   /* 2 pad      */\n   expect_decode(\"QUI=\",     4, \"AB\",     2);   /* 2 pad      */\n\n   if (failures)\n   {\n      printf(\"\\n%d test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll unbase64 regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/archive_file/Makefile",
    "content": "TARGET := archive_zip_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\tarchive_zip_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/archive_file.c \\\n\t$(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/string_list.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -DHAVE_ZLIB -I$(LIBRETRO_COMM_DIR)/include\nLDFLAGS += -lz\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/file/archive_file/archive_zip_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_zip_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression tests for ZIP central-directory hardening.\n *\n * These tests write hand-crafted malformed ZIP bytes to a temp file\n * and feed them to file_archive_get_file_list().  On patched code\n * every case parses cleanly (empty list or NULL).  On unpatched code\n * (commit e044ef6 and earlier), under AddressSanitizer:\n *\n * Strong regression discriminators (ASan fires on unpatched):\n *   - Case A \"truncated central-dir entry\"   -> ASan heap-buffer-overflow\n *                                               READ in read_le, line 561\n *   - Case B \"oversized namelength\"          -> ASan heap-buffer-overflow\n *                                               READ of size N in memcpy,\n *                                               line 558\n *\n * Smoke tests (exercise the code path but do not OOB in the unpatched\n * build; retained as defence-in-depth against future regressions):\n *   - Case C \"empty filename\"                -> reaches parser but not\n *                                               the zip_file_decompressed\n *                                               strlen-1 call via\n *                                               get_file_list\n *   - Case D \"combined offset+size overflow\" -> already partially caught\n *                                               by pre-existing per-field\n *                                               checks; tests the new\n *                                               combined check\n *   - Case E \"directory_size = UINT32_MAX\"   -> caught by pre-existing\n *                                               \"> archive_size\" check;\n *                                               tests the 32-bit alloc\n *                                               overflow guard\n *\n * Rationale for keeping smoke tests: if someone ever refactors the\n * parser to remove the individual sanity checks (thinking them\n * redundant) the smoke tests should still exercise the patched guards.\n *\n * All bytes are crafted in C rather than committed as binary fixtures.\n *\n * Build with AddressSanitizer for full coverage:\n *   make CFLAGS='-fsanitize=address -g -O0' LDFLAGS='-fsanitize=address'\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <file/archive_file.h>\n#include <lists/string_list.h>\n\nstatic int failures = 0;\n\n/* --- tiny ZIP builders (little-endian byte layout) ----------------- */\n\nstatic void put_u16(uint8_t *p, uint16_t v)\n{\n   p[0] = v & 0xff;\n   p[1] = (v >> 8) & 0xff;\n}\n\nstatic void put_u32(uint8_t *p, uint32_t v)\n{\n   p[0] =  v        & 0xff;\n   p[1] = (v >>  8) & 0xff;\n   p[2] = (v >> 16) & 0xff;\n   p[3] = (v >> 24) & 0xff;\n}\n\n#define EOCD_SIG   0x06054b50u\n#define CFH_SIG    0x02014b50u\n#define LFH_SIG    0x04034b50u\n\n/* Minimal End-Of-Central-Directory record (22 bytes, no comment).\n * See PKWARE APPNOTE section 4.3.16. */\nstatic size_t write_eocd(uint8_t *dst, uint16_t num_entries,\n      uint32_t directory_size, uint32_t directory_offset)\n{\n   put_u32(dst + 0,  EOCD_SIG);\n   put_u16(dst + 4,  0);             /* disk number                    */\n   put_u16(dst + 6,  0);             /* disk w/ start of cdir          */\n   put_u16(dst + 8,  num_entries);   /* entries on this disk           */\n   put_u16(dst + 10, num_entries);   /* entries total                  */\n   put_u32(dst + 12, directory_size);\n   put_u32(dst + 16, directory_offset);\n   put_u16(dst + 20, 0);             /* comment length                 */\n   return 22;\n}\n\n/* Minimal Local File Header for a STORED zero-byte file.  We only\n * need this if a central-directory entry points at it -- the parser\n * seeks to cdata+26 and reads the 4 name+extra-length bytes. */\nstatic size_t write_minimal_lfh(uint8_t *dst, const char *name)\n{\n   size_t namelen = name ? strlen(name) : 0;\n   put_u32(dst + 0,  LFH_SIG);\n   put_u16(dst + 4,  20);        /* version needed to extract          */\n   put_u16(dst + 6,  0);         /* flags                              */\n   put_u16(dst + 8,  0);         /* method = STORED                    */\n   put_u16(dst + 10, 0);         /* mtime                              */\n   put_u16(dst + 12, 0);         /* mdate                              */\n   put_u32(dst + 14, 0);         /* crc32                              */\n   put_u32(dst + 18, 0);         /* compressed size                    */\n   put_u32(dst + 22, 0);         /* uncompressed size                  */\n   put_u16(dst + 26, (uint16_t)namelen);\n   put_u16(dst + 28, 0);         /* extra length                       */\n   if (namelen > 0)\n      memcpy(dst + 30, name, namelen);\n   return 30 + namelen;\n}\n\n/* --- test harness -------------------------------------------------- */\n\nstatic void write_file(const char *path, const void *data, size_t len)\n{\n   FILE *fp = fopen(path, \"wb\");\n   if (!fp)\n      abort();\n   if (fwrite(data, 1, len, fp) != len)\n      abort();\n   fclose(fp);\n}\n\nstatic bool parse_malformed_zip(const char *label,\n      const void *bytes, size_t len)\n{\n   const char        *tmp_path = \"rarch_zip_regression_test.zip\";\n   struct string_list *list    = NULL;\n\n   write_file(tmp_path, bytes, len);\n   /* The success criterion is \"did not trigger a memory error\".\n    * On unpatched code AddressSanitizer fires on the OOB reads\n    * inside the parser and aborts here.  On patched code the\n    * parser skips malformed entries and returns either NULL (init\n    * failed) or an empty list (iterate skipped every entry) --\n    * either is correct.  Reaching this line is the pass signal. */\n   list = file_archive_get_file_list(tmp_path, NULL);\n   remove(tmp_path);\n   if (list)\n      string_list_free(list);\n   printf(\"[SUCCESS] %-40s parsed without memory error\\n\", label);\n   return true;\n}\n\n/* ================================================================== */\n/* Case A: central-directory entry truncated before its 46-byte\n * fixed header is complete.                                          */\n/* ================================================================== */\nstatic void test_truncated_entry(void)\n{\n   uint8_t  buf[128];\n   size_t   len   = 0;\n   uint8_t *cdir  = NULL;\n   uint8_t *eocd  = NULL;\n   size_t   cdir_len;\n\n   memset(buf, 0, sizeof(buf));\n\n   /* Central directory starts at offset 0.  We write only 40 bytes\n    * (less than the 46 needed), starting with a valid CFH signature\n    * so the parser thinks it has found an entry. */\n   cdir = buf;\n   put_u32(cdir + 0, CFH_SIG);      /* valid signature               */\n   cdir_len = 40;                    /* DELIBERATELY short (< 46)    */\n   len = cdir_len;\n\n   /* EOCD immediately after.  Directory size matches the short\n    * region so the offset + size == archive_size check passes. */\n   eocd = buf + len;\n   len += write_eocd(eocd, 1, (uint32_t)cdir_len, 0);\n\n   parse_malformed_zip(\"truncated central-dir entry\",\n         buf, len);\n}\n\n/* ================================================================== */\n/* Case B: central-directory entry declares namelength larger than\n * the remaining directory bytes.                                     */\n/* ================================================================== */\nstatic void test_oversize_namelength(void)\n{\n   uint8_t  buf[128];\n   size_t   len = 0;\n   uint8_t *cdir = buf;\n   uint8_t *eocd;\n   size_t   cdir_len;\n\n   memset(buf, 0, sizeof(buf));\n\n   /* Full 46-byte fixed header with valid signature... */\n   put_u32(cdir + 0, CFH_SIG);\n   /* ...and a namelength bigger than the bytes actually remaining\n    * in the directory.  memcpy(filename, entry+46, namelength) used\n    * to read past the directory allocation. */\n   put_u16(cdir + 28, 1000);        /* namelength = 1000             */\n   put_u16(cdir + 30, 0);           /* extralength                   */\n   put_u16(cdir + 32, 0);           /* commentlength                 */\n   /* No room for 1000 bytes of name; directory ends at 46. */\n   cdir_len = 46;\n   len = cdir_len;\n\n   eocd = buf + len;\n   len += write_eocd(eocd, 1, (uint32_t)cdir_len, 0);\n\n   parse_malformed_zip(\"entry declares oversized namelength\",\n         buf, len);\n}\n\n/* ================================================================== */\n/* Case C: central-directory entry with a zero-length filename and\n * a valid local file header, used by the decompress callback path.\n * This specifically tests zip_file_decompressed()'s strlen-1 guard.\n * We only exercise it through file_archive_get_file_list, so the\n * critical check is that parsing doesn't crash.                      */\n/* ================================================================== */\nstatic void test_empty_filename(void)\n{\n   /* Layout:\n    *   [0]   local file header (30 bytes, empty name)\n    *   [30]  central directory (46 bytes, empty name, points at [0])\n    *   [76]  EOCD (22 bytes)\n    */\n   uint8_t  buf[128];\n   size_t   lfh_len, cdir_len;\n   uint8_t *lfh  = buf;\n   uint8_t *cdir;\n   uint8_t *eocd;\n   size_t   len = 0;\n\n   memset(buf, 0, sizeof(buf));\n\n   lfh_len = write_minimal_lfh(lfh, \"\");\n   len = lfh_len;\n\n   /* Central directory entry pointing at the LFH. */\n   cdir = buf + len;\n   put_u32(cdir + 0,  CFH_SIG);\n   put_u16(cdir + 4,  20);    /* version made by                    */\n   put_u16(cdir + 6,  20);    /* version needed                     */\n   put_u16(cdir + 10, 0);     /* method = STORED                    */\n   put_u32(cdir + 16, 0);     /* crc                                */\n   put_u32(cdir + 20, 0);     /* compressed size                    */\n   put_u32(cdir + 24, 0);     /* uncompressed size                  */\n   put_u16(cdir + 28, 0);     /* namelength = 0 -- the bug trigger  */\n   put_u16(cdir + 30, 0);     /* extralength                        */\n   put_u16(cdir + 32, 0);     /* commentlength                      */\n   put_u32(cdir + 42, 0);     /* LFH offset                         */\n   cdir_len = 46;\n   len += cdir_len;\n\n   eocd = buf + len;\n   len += write_eocd(eocd, 1, (uint32_t)cdir_len, (uint32_t)lfh_len);\n\n   /* Patched behaviour: zip_file_decompressed sees name_len==0 and\n    * returns 1 without touching name[strlen-1].  Parsing completes\n    * and the list may be empty or one-entry -- we accept either,\n    * as long as we don't crash. */\n   {\n      const char         *tmp_path = \"rarch_zip_regression_test.zip\";\n      struct string_list *list;\n      write_file(tmp_path, buf, len);\n      list = file_archive_get_file_list(tmp_path, NULL);\n      remove(tmp_path);\n      /* NULL *or* list are both acceptable; the key point is we\n       * reached this line without a SIGSEGV / ASan abort. */\n      if (list)\n         string_list_free(list);\n      printf(\"[SUCCESS] empty-filename entry parsed without OOB read\\n\");\n   }\n}\n\n/* ================================================================== */\n/* Case D: directory_offset + directory_size > archive_size.\n * Each individual value passes the existing pair of comparisons\n * against archive_size, but their sum points past EOF -- this is the\n * combined-sanity-check that patch 7 added.                          */\n/* ================================================================== */\nstatic void test_combined_offset_size_overflow(void)\n{\n   uint8_t  buf[128];\n   size_t   len = 0;\n   uint8_t *eocd;\n\n   memset(buf, 0, sizeof(buf));\n\n   /* 22 bytes total archive.  Both offset and size individually are\n    * <= 22, but their sum is 44.  Unpatched code would malloc 22\n    * bytes, short-read, and fail later; patched code rejects up\n    * front in zip_parse_file_init. */\n   eocd = buf;\n   len = write_eocd(eocd, 0,\n         /* directory_size   */ 20,\n         /* directory_offset */ 20);\n\n   parse_malformed_zip(\"offset+size exceeds archive_size\",\n         buf, len);\n}\n\n/* ================================================================== */\n/* Case E: directory_size near UINT32_MAX.                            */\n/* ================================================================== */\nstatic void test_directory_size_overflow(void)\n{\n   uint8_t  buf[128];\n   size_t   len = 0;\n   uint8_t *eocd;\n\n   memset(buf, 0, sizeof(buf));\n\n   /* A 4-GiB directory can't possibly fit in a 22-byte archive, so\n    * this specific value is caught by the existing\n    * \"directory_size > archive_size\" check -- but the alloc-\n    * overflow guard in patch 7 catches the more subtle case where a\n    * 32-bit host's size_t wraps.  On a 64-bit host with plenty of\n    * memory, the existing check already rejects UINT32_MAX.  This\n    * case is therefore best-effort: confirm that large values reject\n    * cleanly on all platforms. */\n   eocd = buf;\n   len = write_eocd(eocd, 0,\n         /* directory_size   */ 0xFFFFFFFFu,\n         /* directory_offset */ 0);\n\n   parse_malformed_zip(\"directory_size = UINT32_MAX\",\n         buf, len);\n}\n\nint main(void)\n{\n   test_truncated_entry();\n   test_oversize_namelength();\n   test_empty_filename();\n   test_combined_offset_size_overflow();\n   test_directory_size_overflow();\n\n   if (failures)\n   {\n      printf(\"\\n%d test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll archive-zip regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/archive_zstd/Makefile",
    "content": "TARGET := archive_zstd_test\n\nSOURCES := archive_zstd_test.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -O0\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/file/archive_zstd/archive_zstd_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (archive_zstd_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Contract test for archive_file_zstd content_size guards.\n *\n * Self-contained: does NOT link against libzstd or the archive\n * backend.  The bugs being guarded against are arithmetic truncation\n * and addition overflow on an attacker-controlled 64-bit value\n * returned by ZSTD_getFrameContentSize(); the guards live in\n * archive_file_zstd.c and are plain integer comparisons.\n *\n * This test is explicitly a CONTRACT test, not a regression test.\n * It validates that the guard SPEC (as replicated in the oracle\n * functions below) behaves correctly on boundary inputs.  It does\n * NOT call into archive_file_zstd.c, so it cannot detect if someone\n * later edits the real guards in a way that diverges from this spec.\n *\n * Why: a true regression test would need to link libzstd to exercise\n * ZSTD_getFrameContentSize on a crafted frame, which would introduce\n * an external dependency this samples tree does not otherwise carry.\n * The contract test is the next-best thing within that constraint.\n *\n * What the real patched code does (keep these in sync with the\n * oracle functions below):\n *\n *   zstd_parse_file_iterate_step() [iterate path]:\n *       if (content_size > UINT32_MAX)\n *           return -1;\n *       ctx->decompressed_size = (uint32_t)content_size;\n *\n *   zstd_file_read() [decompress-in-place path]:\n *       if (content_size >= SIZE_MAX)\n *           return -1;\n *       decompressed = malloc((size_t)(content_size + 1));\n *\n * If either real guard is ever edited, the corresponding oracle\n * below must be updated to match or this test loses its value.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <limits.h>\n\n/* These match <zstd.h> but are reproduced here so we don't pull in\n * the zstd headers.  Update if zstd ever redefines them. */\n#ifndef ZSTD_CONTENTSIZE_UNKNOWN\n#define ZSTD_CONTENTSIZE_UNKNOWN ((unsigned long long)0 - 1)\n#endif\n#ifndef ZSTD_CONTENTSIZE_ERROR\n#define ZSTD_CONTENTSIZE_ERROR   ((unsigned long long)0 - 2)\n#endif\n\nstatic int failures = 0;\n\n/* --- oracle: the patched iterate-path guard --------------------- *\n * Must be kept in sync with archive_file_zstd.c:\n *     zstd_parse_file_iterate_step.\n * Returns 0 if the value is accepted, -1 if rejected.             */\nstatic int oracle_iterate_guard(unsigned long long content_size)\n{\n   if (   content_size == ZSTD_CONTENTSIZE_UNKNOWN\n       || content_size == ZSTD_CONTENTSIZE_ERROR)\n      return -1;\n   if (content_size > UINT32_MAX)\n      return -1;\n   return 0;\n}\n\n/* --- oracle: the patched read-path guard ------------------------ *\n * Must be kept in sync with archive_file_zstd.c: zstd_file_read.  *\n * Returns 0 if the value is accepted, -1 if rejected.             */\nstatic int oracle_read_guard(unsigned long long content_size)\n{\n   if (   content_size == ZSTD_CONTENTSIZE_UNKNOWN\n       || content_size == ZSTD_CONTENTSIZE_ERROR)\n      return -1;\n   if (content_size >= (unsigned long long)SIZE_MAX)\n      return -1;\n   return 0;\n}\n\n/* ================================================================ */\n\ntypedef struct {\n   const char        *label;\n   unsigned long long value;\n   int                want_iterate;  /* expected oracle_iterate result */\n   int                want_read;     /* expected oracle_read result    */\n} case_t;\n\nint main(void)\n{\n   size_t i;\n   /* These cases exercise the boundaries the guards protect.  Each\n    * case lists the expected verdict for both the iterate path\n    * (uint32_t destination) and the read path (size_t + 1). */\n   case_t cases[] = {\n      /* label                           value                   iter  read */\n      { \"zero\",                           0,                       0,   0 },\n      { \"typical small\",                  1024,                    0,   0 },\n      { \"100 MiB\",                        100ULL * 1024 * 1024,    0,   0 },\n      { \"UINT32_MAX exactly\",             (unsigned long long)UINT32_MAX, 0,  0 },\n      { \"UINT32_MAX + 1  (iterate trunc)\",(unsigned long long)UINT32_MAX + 1, -1, 0 },\n      { \"4 GiB  (iterate trunc)\",         4ULL * 1024 * 1024 * 1024, -1, 0 },\n      { \"2^63           (iterate trunc)\", 1ULL << 63,               -1, 0 },\n      { \"ZSTD_CONTENTSIZE_ERROR sentinel\",ZSTD_CONTENTSIZE_ERROR,   -1, -1 },\n      { \"ZSTD_CONTENTSIZE_UNKNOWN\",       ZSTD_CONTENTSIZE_UNKNOWN, -1, -1 },\n      /* SIZE_MAX case -- on 64-bit, SIZE_MAX == ULLONG_MAX - 1,\n       * which equals ZSTD_CONTENTSIZE_ERROR, so the sentinel check\n       * catches it.  On 32-bit, SIZE_MAX is far smaller and the\n       * >= SIZE_MAX branch catches it first.  Either way: rejected\n       * on the read path.  On the iterate path it's also rejected\n       * (too big for uint32_t). */\n      { \"SIZE_MAX (read-path guard)\",     (unsigned long long)SIZE_MAX, -1, -1 },\n   };\n\n   for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++)\n   {\n      int got_iter = oracle_iterate_guard(cases[i].value);\n      int got_read = oracle_read_guard(cases[i].value);\n\n      if (got_iter != cases[i].want_iterate)\n      {\n         printf(\"[FAILED] iterate-guard(%s=%llu) got %d want %d\\n\",\n               cases[i].label,\n               (unsigned long long)cases[i].value,\n               got_iter, cases[i].want_iterate);\n         failures++;\n         continue;\n      }\n      if (got_read != cases[i].want_read)\n      {\n         printf(\"[FAILED] read-guard(%s=%llu) got %d want %d\\n\",\n               cases[i].label,\n               (unsigned long long)cases[i].value,\n               got_read, cases[i].want_read);\n         failures++;\n         continue;\n      }\n      printf(\"[SUCCESS] %-40s iter=%s read=%s\\n\",\n            cases[i].label,\n            got_iter == 0 ? \"accept\" : \"reject\",\n            got_read == 0 ? \"accept\" : \"reject\");\n   }\n\n   if (failures)\n   {\n      printf(\"\\n%d test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll zstd content_size regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/config_file/Makefile",
    "content": "TARGET := config_file_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\tconfig_file_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/file/config_file.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/string_list.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/file/config_file/config_file_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (config_file_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <ctype.h>\n#include <errno.h>\n\n#include <file/config_file.h>\n\nstatic void test_config_file_parse_contains(\n      const char *cfgtext,\n      const char *key, const char *val)\n{\n   char *cfgtext_copy = strdup(cfgtext);\n   config_file_t *cfg = config_file_new_from_string(cfgtext_copy, NULL);\n   char          *out = NULL;\n   bool            ok = false;\n\n   free(cfgtext_copy);\n\n   if (!cfg)\n      abort();\n\n   ok = config_get_string(cfg, key, &out);\n   if (ok != (bool)val)\n      abort();\n   if (!val)\n      return;\n\n   if (!out)\n      out = strdup(\"\");\n   if (strcmp(out, val) != 0)\n   {\n      printf(\"[FAILED] Key [%s] Doesn't contain val [%s]\\n\", key, val);\n      abort();\n   }\n   printf(\"[SUCCESS] Key [%s] contains val [%s]\\n\", key, val);\n   free(out);\n}\n\n/* Regression for commit 87f2d0b (memcmp OOB on short '#' comment lines).\n *\n * The bug was in config_file_parse_line() reading 8 or 10 bytes past\n * the end of a shrunken line buffer produced by filestream_getline().\n * Triggering it requires going through the file path, not the\n * from-string path: config_file_new_from_string() keeps the entire\n * string live, while filestream_getline() realloc-shrinks each line\n * to exactly strlen+1 bytes for any line shorter than ~192 chars.\n *\n * Under AddressSanitizer the unpatched code aborts with a\n * heap-buffer-overflow READ on any short '#' line.  On non-ASan\n * builds the comparison's result depends on stale heap bytes\n * adjacent to the allocation -- a real attacker-observable\n * non-determinism, not a cosmetic issue.\n */\nstatic void test_config_file_short_comments(void)\n{\n   const char *content =\n      \"#\\n\"\n      \"#h\\n\"\n      \"#hi\\n\"\n      \"#inc\\n\"\n      \"#includ\\n\"\n      \"#includez\\n\"\n      \"#referenc\\n\"\n      \"#referencez\\n\"\n      \"foo = \\\"bar\\\"\\n\";\n   const char *tmp_path = \"rarch_cfg_short_comment_test.cfg\";\n   FILE          *fp    = fopen(tmp_path, \"wb\");\n   config_file_t *cfg;\n   char          *out   = NULL;\n\n   if (!fp)\n      abort();\n   fputs(content, fp);\n   fclose(fp);\n\n   cfg = config_file_new(tmp_path);\n   remove(tmp_path);\n   if (!cfg)\n      abort();\n\n   if (!config_get_string(cfg, \"foo\", &out) || !out || strcmp(out, \"bar\") != 0)\n   {\n      printf(\"[FAILED] short-comment regression: foo!=bar (got %s)\\n\",\n            out ? out : \"(null)\");\n      abort();\n   }\n   printf(\"[SUCCESS] short '#' comment lines parsed without OOB\\n\");\n   free(out);\n}\n\n/* Regression for commit <round2-TBD> (config_get_int family silent zero).\n *\n * config_get_int, config_get_uint, config_get_uint64 and\n * config_get_hex used to return true with *in = 0 when handed a\n * string that has no leading digits at all.  A typo in a config\n * file (width = abc) would silently become width = 0 with no\n * indication of failure.  The patch adds the same end-pointer and\n * no-digits-consumed checks that config_get_size_t already used.\n *\n * These test cases all must return false on patched code.  On\n * unpatched code they return true with *in = 0.\n */\nstatic void test_config_get_int_rejects(const char *raw_val)\n{\n   char cfgtext[256];\n   char *copy;\n   config_file_t *cfg;\n   int              out_int   = 0x5a5a5a;\n   unsigned         out_uint  = 0x5a5a5a;\n   uint64_t         out_u64   = 0x5a5a5a;\n\n   /* Quote the value so the parser preserves trailing text and\n    * whitespace; without quotes the parser stops at the first space\n    * and \"42 extra\" would be stored as just \"42\". */\n   snprintf(cfgtext, sizeof(cfgtext),\n         \"ival = \\\"%s\\\"\\nuval = \\\"%s\\\"\\nu64 = \\\"%s\\\"\\n\",\n         raw_val, raw_val, raw_val);\n\n   copy = strdup(cfgtext);\n   cfg  = config_file_new_from_string(copy, NULL);\n   free(copy);\n   if (!cfg)\n      abort();\n\n   if (config_get_int(cfg, \"ival\", &out_int))\n   {\n      printf(\"[FAILED] config_get_int accepted \\\"%s\\\" -> %d\\n\", raw_val, out_int);\n      abort();\n   }\n   if (out_int != 0x5a5a5a)\n   {\n      printf(\"[FAILED] config_get_int wrote *in on reject for \\\"%s\\\": got %d\\n\",\n            raw_val, out_int);\n      abort();\n   }\n   if (config_get_uint(cfg, \"uval\", &out_uint))\n   {\n      printf(\"[FAILED] config_get_uint accepted \\\"%s\\\" -> %u\\n\", raw_val, out_uint);\n      abort();\n   }\n   if (config_get_uint64(cfg, \"u64\", &out_u64))\n   {\n      printf(\"[FAILED] config_get_uint64 accepted \\\"%s\\\" -> %llu\\n\",\n            raw_val, (unsigned long long)out_u64);\n      abort();\n   }\n   printf(\"[SUCCESS] rejected non-numeric value \\\"%s\\\"\\n\", raw_val);\n   config_file_free(cfg);\n}\n\n/* config_get_hex accepts base-16 digits ([0-9a-fA-F]) which includes\n * strings like \"abc\" and \"face\" -- those are valid hex.  Test with\n * characters that are not valid in any base. */\nstatic void test_config_get_hex_rejects(const char *raw_val)\n{\n   char cfgtext[256];\n   char *copy;\n   config_file_t *cfg;\n   unsigned out_hex = 0x5a5a5a;\n\n   snprintf(cfgtext, sizeof(cfgtext), \"hval = \\\"%s\\\"\\n\", raw_val);\n   copy = strdup(cfgtext);\n   cfg  = config_file_new_from_string(copy, NULL);\n   free(copy);\n   if (!cfg)\n      abort();\n\n   if (config_get_hex(cfg, \"hval\", &out_hex))\n   {\n      printf(\"[FAILED] config_get_hex accepted \\\"%s\\\" -> 0x%x\\n\",\n            raw_val, out_hex);\n      abort();\n   }\n   if (out_hex != 0x5a5a5a)\n   {\n      printf(\"[FAILED] config_get_hex wrote *in on reject for \\\"%s\\\"\\n\", raw_val);\n      abort();\n   }\n   printf(\"[SUCCESS] config_get_hex rejected non-hex \\\"%s\\\"\\n\", raw_val);\n   config_file_free(cfg);\n}\n\nstatic void test_config_get_int_accepts(const char *raw_val, int want_int)\n{\n   char cfgtext[256];\n   char *copy;\n   config_file_t *cfg;\n   int out_int = 0;\n\n   snprintf(cfgtext, sizeof(cfgtext), \"ival = \\\"%s\\\"\\n\", raw_val);\n   copy = strdup(cfgtext);\n   cfg  = config_file_new_from_string(copy, NULL);\n   free(copy);\n   if (!cfg)\n      abort();\n\n   if (!config_get_int(cfg, \"ival\", &out_int) || out_int != want_int)\n   {\n      printf(\"[FAILED] config_get_int(\\\"%s\\\") expected %d got %d\\n\",\n            raw_val, want_int, out_int);\n      abort();\n   }\n   printf(\"[SUCCESS] config_get_int(\\\"%s\\\") == %d\\n\", raw_val, want_int);\n   config_file_free(cfg);\n}\n\n/* Regression for commit <round4-TBD> (config_file_deinitialize\n * leaves dangling pointers).\n *\n * config_file_deinitialize() is a public API.  Pre-patch it freed\n * entries, includes, references, path and the hash map but left the\n * struct\\'s pointer fields pointing at the just-freed memory.  Any\n * subsequent call on that struct -- whether accidental double-\n * deinit, reuse, or another access via the public API -- chased\n * dangling pointers.  Post-patch all fields are NULLed.\n *\n * This test loads a config, deinitializes it without freeing the\n * struct, then verifies that the struct\\'s internal pointers are\n * all NULL.  On unpatched code several of these would be stale\n * non-NULL pointers to freed memory.\n *\n * Note: this inspects the config_file_t fields directly (white-box\n * test).  The public header exposes the struct definition so this\n * is legal, though a little unusual; there is no public getter for\n * \"is this struct still live\".  The alternative -- provoking a\n * real UAF via a second API call -- would fire ASan on unpatched\n * but also crash on patched for unrelated reasons (add_reference\n * dereferences conf->path unconditionally).  This direct field\n * inspection is the cleanest way to assert the patch\\'s invariant.\n */\nstatic void test_config_file_deinitialize_clears_fields(void)\n{\n   config_file_t *cfg;\n   const char    *tmp_path = \"rarch_cfg_deinit_test.cfg\";\n   FILE          *fp       = fopen(tmp_path, \"wb\");\n\n   if (!fp)\n      abort();\n   fputs(\"foo = \\\"bar\\\"\\nbaz = \\\"qux\\\"\\n\", fp);\n   fclose(fp);\n\n   cfg = config_file_new(tmp_path);\n   remove(tmp_path);\n   if (!cfg)\n      abort();\n\n   /* Add a reference so conf->references is non-NULL before deinit. */\n   config_file_add_reference(cfg, \"some_ref\");\n\n   /* Deinitialize without freeing the struct. */\n   config_file_deinitialize(cfg);\n\n   /* Every pointer field must now be NULL.  Pre-patch these would\n    * be stale pointers to freed memory. */\n   if (cfg->entries != NULL)\n   {\n      printf(\"[FAILED] deinit left entries as dangling %p\\n\", (void*)cfg->entries);\n      free(cfg);\n      abort();\n   }\n   if (cfg->includes != NULL)\n   {\n      printf(\"[FAILED] deinit left includes as dangling %p\\n\", (void*)cfg->includes);\n      free(cfg);\n      abort();\n   }\n   if (cfg->references != NULL)\n   {\n      printf(\"[FAILED] deinit left references as dangling %p\\n\", (void*)cfg->references);\n      free(cfg);\n      abort();\n   }\n   if (cfg->path != NULL)\n   {\n      printf(\"[FAILED] deinit left path as dangling %p\\n\", (void*)cfg->path);\n      free(cfg);\n      abort();\n   }\n   /* entries_map is cleared by RHMAP_FREE on all versions so we do\n    * not check it here. */\n\n   printf(\"[SUCCESS] config_file_deinitialize cleared all dangling pointer fields\\n\");\n   free(cfg);\n}\n\n/* Smoke test for commit <round4-TBD> (isgraph((int)char) UB on\n * signed-char platforms).\n *\n * In the config parser, isgraph() is called on each byte of the\n * key / unquoted value to find the token end.  Pre-patch the cast\n * was (int), so bytes >= 0x80 became negative ints on signed-char\n * platforms.  The C standard says ctype functions must be called\n * with EOF or an unsigned-char value; anything else is undefined\n * behaviour.  glibc and musl happen to handle negative arguments\n * gracefully, but stricter libcs (Solaris, some embedded toolchains)\n * trip an assert or array-bounds fault.  Post-patch the cast is\n * (unsigned char).\n *\n * This is explicitly a smoke test: glibc and musl do not fire on\n * the pre-patch code either, so this test passes on both patched\n * and unpatched sources when run on a typical Linux host.  Its\n * value is two-fold:\n *   - Under UBSan with ctype function-arg instrumentation, the\n *     pre-patch code would trip (currently not wired into this\n *     test suite).\n *   - On a stricter libc, the pre-patch code would crash; this\n *     test therefore documents the expected contract and catches\n *     any future regression on such a platform.\n *\n * The test feeds a config value containing bytes in the 0x80-0xFF\n * range and verifies the parser does not crash.  Per the isgraph\n * contract these bytes are non-graph in the C locale, so the parser\n * will reject the key -- which is the CORRECT behaviour.  The test\n * passes if the parser completes cleanly rather than crashing.\n */\nstatic void test_config_file_high_bit_bytes_smoke(void)\n{\n   /* Config with a high-bit byte (0xC3 0xA9 is UTF-8 \"e-acute\") in\n    * both the key and the value.  The parser\\'s isgraph() check\n    * terminates the key at the first non-graph byte, so this line\n    * is rejected as a syntactic error -- that is fine; what we care\n    * about is that the ctype call did not trip UB on the 0xC3 byte. */\n   const char    *cfgtext  = \"caf\\xc3\\xa9 = \\\"valu\\xc3\\xa9\\\"\\n\"\n                             \"plain = \\\"ok\\\"\\n\";\n   char          *copy     = strdup(cfgtext);\n   config_file_t *cfg      = config_file_new_from_string(copy, NULL);\n   char          *out      = NULL;\n   free(copy);\n\n   if (!cfg)\n   {\n      printf(\"[FAILED] parser refused to load config containing high-bit bytes\\n\");\n      abort();\n   }\n\n   /* Sanity: the plain key on the following line should still parse.\n    * This confirms the parser recovered from the rejected key and\n    * kept going rather than bailing on the whole file. */\n   if (!config_get_string(cfg, \"plain\", &out) || !out || strcmp(out, \"ok\") != 0)\n   {\n      printf(\"[FAILED] high-bit byte line disrupted subsequent parsing: plain=%s\\n\",\n            out ? out : \"(null)\");\n      free(out);\n      config_file_free(cfg);\n      abort();\n   }\n\n   free(out);\n   config_file_free(cfg);\n   printf(\"[SUCCESS] high-bit byte in config parsed without crash\\n\");\n}\n\nint main(void)\n{\n   test_config_file_parse_contains(\"foo = \\\"bar\\\"\\n\",   \"foo\", \"bar\");\n   test_config_file_parse_contains(\"foo = \\\"bar\\\"\",     \"foo\", \"bar\");\n   test_config_file_parse_contains(\"foo = \\\"bar\\\"\\r\\n\", \"foo\", \"bar\");\n   test_config_file_parse_contains(\"foo = \\\"bar\\\"\",     \"foo\", \"bar\");\n\n   test_config_file_parse_contains(\"foo = \\\"\\\"\\n\",   \"foo\", \"\");\n   test_config_file_parse_contains(\"foo = \\\"\\\"\",     \"foo\", \"\");\n   test_config_file_parse_contains(\"foo = \\\"\\\"\\r\\n\", \"foo\", \"\");\n   test_config_file_parse_contains(\"foo = \\\"\\\"\",     \"foo\", \"\");\n\n   test_config_file_parse_contains(\"foo = \\\"\\\"\\n\",   \"bar\", NULL);\n   test_config_file_parse_contains(\"foo = \\\"\\\"\",     \"bar\", NULL);\n   test_config_file_parse_contains(\"foo = \\\"\\\"\\r\\n\", \"bar\", NULL);\n   test_config_file_parse_contains(\"foo = \\\"\\\"\",     \"bar\", NULL);\n\n   test_config_file_short_comments();\n\n   /* Non-numeric input -- must all be rejected. */\n   test_config_get_int_rejects(\"abc\");\n   test_config_get_int_rejects(\"\");\n   test_config_get_int_rejects(\".\");\n   test_config_get_int_rejects(\"-\");\n   test_config_get_int_rejects(\"42abc\");     /* trailing garbage */\n   test_config_get_int_rejects(\"42 extra\");  /* trailing text after space */\n\n   /* config_get_hex accepts [0-9a-fA-F] -- use characters outside it. */\n   test_config_get_hex_rejects(\"xyz\");\n   test_config_get_hex_rejects(\"\");\n   test_config_get_hex_rejects(\"g\");\n   test_config_get_hex_rejects(\"deadbeefz\");  /* trailing non-hex */\n   test_config_get_hex_rejects(\"42 extra\");   /* trailing text */\n\n   /* Positive cases -- must still accept normal integers. */\n   test_config_get_int_accepts(\"0\",      0);\n   test_config_get_int_accepts(\"42\",     42);\n   test_config_get_int_accepts(\"-17\",   -17);\n   test_config_get_int_accepts(\"0x10\",   16);  /* hex via base-0 detection */\n   test_config_get_int_accepts(\"010\",     8);  /* octal  via base-0 detection */\n\n   test_config_file_deinitialize_clears_fields();\n   test_config_file_high_bit_bytes_smoke();\n}\n"
  },
  {
    "path": "samples/file/file_path/Makefile",
    "content": "TARGETS := path_resolve_realpath_test fill_pathname_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nCOMMON_SOURCES := \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/string_list.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c\n\nCOMMON_OBJS := $(COMMON_SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -DRARCH_INTERNAL -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGETS)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGETS): %: %.o $(COMMON_OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGETS) $(addsuffix .o,$(TARGETS)) $(COMMON_OBJS)\n\n.PHONY: all clean\n"
  },
  {
    "path": "samples/file/file_path/fill_pathname_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (fill_pathname_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression for the fill_pathname() out-of-bounds write observed in\n * production iOS crash reports as\n *   __chk_fail_overflow -> __strlcpy_chk -> fill_pathname\n *      -> database_info_list_iterate_found_match (task_database.c)\n *\n * fill_pathname() is:\n *\n *     size_t _len = strlcpy(s, in_path, len);\n *     if ((tok = strrchr(path_basename(s), '.'))) { *tok = '\\0'; _len = tok - s; }\n *     _len += strlcpy(s + _len, replace, len - _len);\n *\n * strlcpy() returns strlen(in_path), not the number of bytes written.\n * If strlen(in_path) >= len AND the truncated copy contains no '.' in\n * its basename, the conditional does not fire and _len stays at the\n * (large) source length.  The second strlcpy then runs as\n *   strlcpy(s + _len, replace, len - _len)\n * with len - _len underflowed to a huge size_t.  s + _len is well past\n * the end of the destination buffer, and strlcpy happily writes\n * strlen(replace) + 1 bytes there.\n *\n * On Apple platforms strlcpy is a libc symbol covered by FORTIFY, so\n * __strlcpy_chk catches the bogus length and aborts (this is the\n * SIGTRAP visible in the crash logs).  On Linux there is no FORTIFY\n * for strlcpy, so we detect the overrun by surrounding the destination\n * with sentinel bytes and checking they survive the call.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <file/file_path.h>\n\nstatic int failures = 0;\n\n#define DST_LEN     64\n#define GUARD_LEN   256\n#define SENTINEL    0xCC\n\n/* Long input with no '.' anywhere -- forces fill_pathname() to take\n * the \"no extension to strip\" branch with _len > len. */\nstatic void test_overlong_input_no_dot(void)\n{\n   char *region;\n   char *dst;\n   size_t i;\n   size_t in_len = DST_LEN * 4;   /* 256 chars, well past DST_LEN */\n   char *in_path;\n\n   region = (char*)malloc(DST_LEN + GUARD_LEN);\n   if (!region)\n      abort();\n   memset(region, SENTINEL, DST_LEN + GUARD_LEN);\n   dst = region;\n\n   in_path = (char*)malloc(in_len + 1);\n   if (!in_path)\n      abort();\n   for (i = 0; i < in_len; i++)\n      in_path[i] = 'a';\n   in_path[in_len] = '\\0';\n\n   fill_pathname(dst, in_path, \".lpl\", DST_LEN);\n\n   /* The destination's first DST_LEN bytes are fair game for the\n    * function to write into.  Anything in [DST_LEN, DST_LEN+GUARD_LEN)\n    * must be untouched. */\n   for (i = DST_LEN; i < (size_t)(DST_LEN + GUARD_LEN); i++)\n   {\n      if ((unsigned char)region[i] != SENTINEL)\n      {\n         printf(\"[FAILED] fill_pathname overran dst: byte %zu changed from 0x%02x to 0x%02x\\n\",\n               i, SENTINEL, (unsigned char)region[i]);\n         failures++;\n         break;\n      }\n   }\n   if (i == (size_t)(DST_LEN + GUARD_LEN))\n      printf(\"[SUCCESS] overlong no-dot input did not overrun destination\\n\");\n\n   free(in_path);\n   free(region);\n}\n\n/* Long input where the truncated copy DOES contain a '.' -- the\n * conditional resets _len so this path was never broken, but include\n * it as a regression so a future \"fix\" doesn't silently break the\n * normal extension-replacement case. */\nstatic void test_overlong_input_with_dot(void)\n{\n   char dst[DST_LEN];\n   /* \"aaaa.aaaa...\" for in_len bytes -- truncation will still leave\n    * dots inside the destination. */\n   size_t in_len = DST_LEN * 4;\n   char *in_path = (char*)malloc(in_len + 1);\n   size_t i;\n\n   if (!in_path)\n      abort();\n   for (i = 0; i < in_len; i++)\n      in_path[i] = (i % 5 == 4) ? '.' : 'a';\n   in_path[in_len] = '\\0';\n\n   memset(dst, 0, sizeof(dst));\n   fill_pathname(dst, in_path, \".lpl\", sizeof(dst));\n\n   /* Result must be NUL-terminated within the buffer. */\n   if (memchr(dst, '\\0', sizeof(dst)) == NULL)\n   {\n      printf(\"[FAILED] fill_pathname did not NUL-terminate within buffer\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] overlong with-dot input stayed NUL-terminated in buffer\\n\");\n\n   free(in_path);\n}\n\n/* Helper: run fill_pathname with a 64-byte buffer and assert the\n * resulting string matches @want. */\nstatic void check_spec(const char *label, const char *in_path,\n      const char *replace, const char *want)\n{\n   char dst[64];\n   memset(dst, 0, sizeof(dst));\n   fill_pathname(dst, in_path, replace, sizeof(dst));\n   if (strcmp(dst, want) != 0)\n   {\n      printf(\"[FAILED] %s: fill_pathname(\\\"%s\\\", \\\"%s\\\") = \\\"%s\\\" (expected \\\"%s\\\")\\n\",\n            label, in_path, replace, dst, want);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] %s\\n\", label);\n}\n\n/* Edge case: input is exactly len-1, no extension, replace appended.\n * The first strlcpy returns strlen(in_path) == len-1, no '.' in the\n * truncated copy, _len = len-1, so len - _len = 1.  The second\n * strlcpy gets len=1 and writes only the NUL.  Must not overrun. */\nstatic void test_exact_fit_no_extension(void)\n{\n   char *region = (char*)malloc(DST_LEN + GUARD_LEN);\n   char *dst;\n   char in_path[DST_LEN];\n   size_t i;\n\n   if (!region)\n      abort();\n   memset(region, SENTINEL, DST_LEN + GUARD_LEN);\n   dst = region;\n\n   for (i = 0; i < DST_LEN - 1; i++)\n      in_path[i] = 'b';\n   in_path[DST_LEN - 1] = '\\0';\n\n   fill_pathname(dst, in_path, \".lpl\", DST_LEN);\n\n   for (i = DST_LEN; i < (size_t)(DST_LEN + GUARD_LEN); i++)\n   {\n      if ((unsigned char)region[i] != SENTINEL)\n      {\n         printf(\"[FAILED] fill_pathname overran dst on exact-fit input: byte %zu changed\\n\", i);\n         failures++;\n         break;\n      }\n   }\n   if (i == (size_t)(DST_LEN + GUARD_LEN))\n      printf(\"[SUCCESS] exact-fit no-extension input did not overrun destination\\n\");\n\n   free(region);\n}\n\nint main(void)\n{\n   /* Documented semantics. */\n   check_spec(\"normal extension replacement preserved\",\n         \"/foo/bar/baz/boo.c\", \".asm\", \"/foo/bar/baz/boo.asm\");\n   check_spec(\"no extension -> concatenate replace\",\n         \"foo\", \".lpl\", \"foo.lpl\");\n   check_spec(\"empty replace strips extension\",\n         \"foo.c\", \"\", \"foo\");\n   check_spec(\"dot in dirname does not count as extension\",\n         \"/foo.bar/baz\", \".x\", \"/foo.bar/baz.x\");\n   check_spec(\"only the last dot in the basename is stripped\",\n         \"foo.bar.baz\", \".x\", \"foo.bar.x\");\n\n   /* Out-of-bounds behavior. */\n   test_overlong_input_with_dot();\n   test_exact_fit_no_extension();\n   test_overlong_input_no_dot();\n\n   if (failures)\n   {\n      printf(\"\\n%d fill_pathname test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll fill_pathname regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/file_path/path_resolve_realpath_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (path_resolve_realpath_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression for commit 87f2d0b (leading-slash stack smash in\n * path_resolve_realpath()).\n *\n * The POSIX non-symlink branch used to copy a run of leading '/'\n * characters from the input into a 4 KiB stack buffer with no bound.\n * An input of PATH_MAX_LENGTH or more leading slashes therefore walked\n * off the end of the buffer.  This input can be supplied via a\n * malicious playlist (playlist.c:1192), a core-updater metadata\n * response, or the runloop (runloop.c:586).\n *\n * Under -fstack-protector-strong the unpatched code aborts with\n *   *** stack smashing detected ***\n * The patched code detects the overflow before the write and returns\n * NULL cleanly.\n *\n * Build with RARCH_INTERNAL and -fstack-protector-strong:\n *   make CFLAGS='-DRARCH_INTERNAL -fstack-protector-strong -g -O0' \\\n *        LDFLAGS='-fstack-protector-strong'\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <file/file_path.h>\n#include <retro_miscellaneous.h>  /* PATH_MAX_LENGTH */\n\nstatic int failures = 0;\n\n/* With resolve_symlinks=false the function walks the input without\n * any filesystem call, so we can feed it synthetic adversarial\n * paths without needing real files on disk. */\nstatic void test_leading_slash_bounded(void)\n{\n   /* Buffer must be larger than PATH_MAX_LENGTH so s_len itself fits,\n    * otherwise strlcpy truncates before the function sees the payload. */\n   size_t bufsz = PATH_MAX_LENGTH * 2;\n   char *buf    = (char*)malloc(bufsz);\n   char *r;\n   size_t i;\n\n   if (!buf)\n      abort();\n\n   /* Fill with many more leading '/' than PATH_MAX_LENGTH, followed\n    * by 'foo'.  The old code would write PATH_MAX_LENGTH * 2 bytes\n    * into a PATH_MAX_LENGTH stack buffer. */\n   for (i = 0; i < PATH_MAX_LENGTH + 1000; i++)\n      buf[i] = '/';\n   strcpy(buf + PATH_MAX_LENGTH + 1000, \"foo\");\n\n   r = path_resolve_realpath(buf, bufsz, false);\n   /* Patched code returns NULL for input with too many leading slashes.\n    * Unpatched code stack-smashes long before reaching this line. */\n   if (r != NULL)\n   {\n      printf(\"[FAILED] expected NULL return for pathological input, got %p\\n\", (void*)r);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] pathological leading slashes rejected cleanly\\n\");\n\n   free(buf);\n}\n\n/* A single leading slash on an otherwise-well-formed path must still\n * resolve (this is the normal case -- every absolute path). */\nstatic void test_leading_slash_normal(void)\n{\n   char buf[PATH_MAX_LENGTH];\n   char *r;\n\n   strcpy(buf, \"/usr/bin/foo\");\n   r = path_resolve_realpath(buf, sizeof(buf), false);\n   if (!r || strcmp(buf, \"/usr/bin/foo\") != 0)\n   {\n      printf(\"[FAILED] normal absolute path not preserved: \\\"%s\\\"\\n\", buf);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] normal absolute path preserved\\n\");\n}\n\n/* A few leading slashes (triple-slash is valid per POSIX) must still\n * work.  PATH_MAX_LENGTH - N where N is small should be OK. */\nstatic void test_few_leading_slashes(void)\n{\n   char buf[PATH_MAX_LENGTH];\n   char *r;\n\n   strcpy(buf, \"///usr/bin/foo\");\n   r = path_resolve_realpath(buf, sizeof(buf), false);\n   /* POSIX folds leading \"///\" to \"/\"; libretro keeps the prefix.\n    * Either way, the function must not crash. */\n   if (!r)\n   {\n      printf(\"[FAILED] triple-slash path rejected: \\\"///usr/bin/foo\\\"\\n\");\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] triple-slash path accepted: \\\"%s\\\"\\n\", buf);\n}\n\nint main(void)\n{\n   test_leading_slash_normal();\n   test_few_leading_slashes();\n   test_leading_slash_bounded();\n\n   if (failures)\n   {\n      printf(\"\\n%d test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll path_resolve_realpath regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/nbio/Makefile",
    "content": "TARGET := nbio_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\tnbio_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/file/nbio/nbio_test.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <file/nbio.h>\n\nstatic int failures = 0;\n\nstatic void nbio_write_test(void)\n{\n   size_t _len;\n   bool looped = false;\n   void *ptr   = NULL;\n   struct nbio_t* write = nbio_open(\"test.bin\", NBIO_WRITE);\n   if (!write)\n   {\n      puts(\"[ERROR] nbio_open failed (1)\");\n      failures++;\n      return;\n   }\n\n   nbio_resize(write, 1024*1024);\n\n   ptr = nbio_get_ptr(write, &_len);\n   if (_len != 1024*1024)\n   {\n      puts(\"[ERROR] wrong size (1)\");\n      failures++;\n   }\n\n   memset(ptr, 0x42, 1024*1024);\n   nbio_begin_write(write);\n\n   while (!nbio_iterate(write))\n      looped=true;\n\n   if (!looped)\n      puts(\"[SUCCESS] Write finished immediately.\");\n\n   nbio_free(write);\n}\n\nstatic void nbio_read_test(void)\n{\n   size_t _len;\n   bool looped = false;\n   struct nbio_t* read = nbio_open(\"test.bin\", NBIO_READ);\n   void* ptr           = nbio_get_ptr(read, &_len);\n   if (!read)\n   {\n      puts(\"[ERROR] nbio_open failed (2)\");\n      failures++;\n      return;\n   }\n\n   if (_len != 1024*1024)\n   {\n      puts(\"[ERROR] wrong size (2)\");\n      failures++;\n   }\n   if (ptr)\n      puts(\"[SUCCESS] Read pointer is available before iterating.\");\n\n   nbio_begin_read(read);\n\n   while (!nbio_iterate(read))\n      looped=true;\n\n   if (!looped)\n      puts(\"[SUCCESS] Read finished immediately.\");\n\n   ptr = nbio_get_ptr(read, &_len);\n\n   if (_len != 1024*1024)\n   {\n      puts(\"[ERROR] wrong size (3)\");\n      failures++;\n   }\n   if (*(char*)ptr != 0x42 || memcmp(ptr, (char*)ptr+1, 1024*1024-1))\n   {\n      puts(\"[ERROR] wrong data\");\n      failures++;\n   }\n\n   nbio_free(read);\n}\n\n/* Regression-ish test for commit <round4-TBD> (nbio_stdio_resize\n * realloc commit-before-success).\n *\n * Pre-patch, nbio_stdio_resize wrote handle->len = len BEFORE the\n * realloc, then on realloc failure silently kept the stale old\n * data pointer with the NEW (larger) len.  Subsequent fread/fwrite\n * iterated up to handle->len bytes and walked off the end.\n *\n * This is a smoke test rather than a true discriminator: forcing\n * realloc to fail from user code requires an allocator hook, which\n * isn\\'t portable and breaks the self-contained-sample convention.\n * What this test DOES verify:\n *   1. A successful resize + get_ptr reports the new size.\n *   2. A subsequent larger resize + get_ptr reports the new size\n *      AND the pointer is non-NULL (so writes through it are\n *      valid up to that size).\n *   3. The post-patch code still completes a write/read round-trip\n *      after multiple resizes.\n *\n * Historical note: on the unpatched code the same sequence passes\n * too, because realloc on a 4 MiB buffer essentially never fails\n * on a CI runner.  The test\\'s real value is as documentation for\n * the resize API contract so a future refactor doesn\\'t silently\n * re-introduce the commit-before-success pattern.\n */\nstatic void nbio_resize_smoke_test(void)\n{\n   size_t          got_len;\n   void           *ptr;\n   struct nbio_t  *w = nbio_open(\"resize_test.bin\", NBIO_WRITE);\n   if (!w)\n   {\n      puts(\"[ERROR] resize-test: nbio_open failed\");\n      failures++;\n      return;\n   }\n\n   /* First resize: 4 KiB. */\n   nbio_resize(w, 4096);\n   ptr = nbio_get_ptr(w, &got_len);\n   if (got_len != 4096 || !ptr)\n   {\n      printf(\"[ERROR] resize-test: first resize got len=%zu ptr=%p\\n\",\n            got_len, ptr);\n      failures++;\n      nbio_free(w);\n      return;\n   }\n   memset(ptr, 0xAB, 4096);\n\n   /* Second resize: grow to 8 KiB.  Post-patch the handle must\n    * either report len=8192 with a valid pointer, or leave the\n    * old size and pointer in place (realloc failed).  There is no\n    * valid middle state. */\n   nbio_resize(w, 8192);\n   ptr = nbio_get_ptr(w, &got_len);\n   if (!ptr)\n   {\n      printf(\"[ERROR] resize-test: after grow, ptr is NULL with len=%zu\\n\",\n            got_len);\n      failures++;\n      nbio_free(w);\n      return;\n   }\n   if (got_len != 8192)\n   {\n      printf(\"[ERROR] resize-test: after grow, len=%zu != 8192\\n\", got_len);\n      failures++;\n      nbio_free(w);\n      return;\n   }\n\n   /* Fill the grown region.  If the pointer / len disagree the\n    * write walks off the end and ASan catches it. */\n   memset(ptr, 0xCD, 8192);\n\n   nbio_begin_write(w);\n   while (!nbio_iterate(w)) {}\n\n   nbio_free(w);\n   remove(\"resize_test.bin\");\n   puts(\"[SUCCESS] nbio_resize grow sequence completed\");\n}\n\nint main(void)\n{\n   nbio_write_test();\n   nbio_read_test();\n   nbio_resize_smoke_test();\n\n   /* Clean up the main test artifact. */\n   remove(\"test.bin\");\n\n   if (failures)\n   {\n      printf(\"\\n%d nbio test(s) failed\\n\", failures);\n      return 1;\n   }\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/vfs/Makefile",
    "content": "TARGET := vfs_read_overflow_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\tvfs_read_overflow_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c\n\nOBJS := $(SOURCES:.c=.o)\n\n# -DHAVE_MMAP is required for the test to exercise the patched\n# code path; without it the implementation falls back to buffered\n# fread and the test becomes a smoke test that can't discriminate\n# the overflow case.\nCFLAGS += -Wall -pedantic -std=gnu99 -g -DHAVE_MMAP -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/file/vfs/vfs_read_overflow_test.c",
    "content": "/* Regression test for mmap-read integer overflow in\n * retro_vfs_file_read_impl (libretro-common/vfs/vfs_implementation.c).\n *\n * Pre-patch, the function contained:\n *\n *   if (stream->mappos + len > stream->mapsize)\n *       len = stream->mapsize - stream->mappos;\n *   memcpy(s, &stream->mapped[stream->mappos], len);\n *\n * mappos and len are both uint64_t.  When `len` is attacker-chosen\n * and near UINT64_MAX, the addition `mappos + len` wraps past zero\n * and the bound check `> mapsize` evaluates FALSE on the small\n * wrapped value -- the clamp is skipped and memcpy reads `len`\n * bytes off the end of the mapped region.\n *\n * Post-patch the clamp is done as an unsigned subtraction\n * (`remaining = mapsize - mappos; if (len > remaining) len =\n * remaining;`) which cannot wrap.\n *\n * The test mmaps a small file, then directly invokes\n * retro_vfs_file_read_impl with a len value engineered to trigger\n * the wrap (mappos=10, len=UINT64_MAX-10, sum wraps to 0).  Post-\n * patch the function returns at most 0 (no bytes left after mappos\n * advanced to mapsize) and does not corrupt memory.\n *\n * ASan gives the strongest signal: pre-patch runs it fires\n * \"heap-buffer-overflow\"; post-patch runs complete cleanly.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#include <unistd.h>\n\n#include <vfs/vfs.h>\n#include <vfs/vfs_implementation.h>\n\n/* These constants are defined in libretro.h; redeclare the subset\n * we need so the sample doesn't depend on that header being on the\n * include path. */\n#ifndef RETRO_VFS_FILE_ACCESS_READ\n#define RETRO_VFS_FILE_ACCESS_READ              (1 << 0)\n#endif\n#ifndef RETRO_VFS_FILE_ACCESS_HINT_NONE\n#define RETRO_VFS_FILE_ACCESS_HINT_NONE         0\n#endif\n#ifndef RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS\n#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS (1 << 0)\n#endif\n\nstatic int failures = 0;\n\nstatic void test_mmap_read_overflow(void)\n{\n   libretro_vfs_implementation_file *stream;\n   const char *tmp_path = \"vfs_overflow_test.bin\";\n   const char  payload[16] = \"ABCDEFGHIJKLMNOP\";\n   char        buf[64];\n   int64_t     rc;\n   FILE       *fp;\n\n   /* Create a 16-byte file. */\n   fp = fopen(tmp_path, \"wb\");\n   if (!fp) { printf(\"[ERROR] fopen failed\\n\"); failures++; return; }\n   fwrite(payload, 1, sizeof(payload), fp);\n   fclose(fp);\n\n   /* Open with frequent-access hint so the implementation uses the\n    * mmap code path.  (If HAVE_MMAP is not compiled in, this\n    * falls back to buffered reads and the test becomes a smoke\n    * test rather than a true discriminator.) */\n   stream = retro_vfs_file_open_impl(tmp_path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS);\n   if (!stream)\n   {\n      printf(\"[ERROR] retro_vfs_file_open_impl failed\\n\");\n      failures++;\n      remove(tmp_path);\n      return;\n   }\n\n   /* Normal read to establish baseline behaviour. */\n   rc = retro_vfs_file_read_impl(stream, buf, 4);\n   if (rc != 4 || memcmp(buf, payload, 4) != 0)\n   {\n      printf(\"[ERROR] baseline read: rc=%lld, want 4\\n\", (long long)rc);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] baseline read returned 4 bytes\\n\");\n\n   /* Seek to offset 10.  mappos is now 10. */\n   if (retro_vfs_file_seek_impl(stream, 10, 0 /*SEEK_SET*/) != 10)\n   {\n      printf(\"[ERROR] seek to 10 failed\\n\");\n      failures++;\n   }\n\n   /* Crafted len chosen so that (mappos + len) wraps uint64_t past 0\n    * and lands at or below mapsize (=16), bypassing the pre-patch\n    * bound check and causing an unclamped memcpy off the end.\n    *\n    * With mappos=10, mapsize=16:\n    *   naive check: mappos + len > mapsize\n    *     We need (mappos + len) to wrap past zero in uint64_t.\n    *     Wrap happens when sum >= 2^64, i.e. len >= 2^64 - mappos.\n    *     With mappos=10, pick len = UINT64_MAX - 9 so that sum =\n    *     UINT64_MAX + 1 wraps to 0.  Check \"0 > 16\" is FALSE; the\n    *     clamp is SKIPPED.  Memcpy then reads UINT64_MAX - 9 bytes\n    *     starting at mapped[10].  Crash / OOB.\n    *\n    * Post-patch: remaining = mapsize - mappos = 6.  len (very\n    * large) > remaining, so len clamps to 6.  memcpy reads 6 bytes\n    * from mapped[10..15].  Safe. */\n   {\n      uint64_t evil_len = (uint64_t)-1 - 9;    /* UINT64_MAX - 9 */\n      rc = retro_vfs_file_read_impl(stream, buf, evil_len);\n\n      /* Post-patch contract: rc is at most mapsize - mappos = 6.\n       * Pre-patch would either return a huge number or crash. */\n      if (rc < 0 || rc > 6)\n      {\n         printf(\"[ERROR] overflow read returned rc=%lld (want 0..6)\\n\",\n               (long long)rc);\n         failures++;\n      }\n      else\n         printf(\"[SUCCESS] overflow read clamped to rc=%lld\\n\",\n               (long long)rc);\n   }\n\n   retro_vfs_file_close_impl(stream);\n   remove(tmp_path);\n}\n\nint main(void)\n{\n   test_mmap_read_overflow();\n\n   if (failures)\n   {\n      printf(\"\\n%d vfs test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll vfs regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/file/vfs_cdrom/Makefile",
    "content": "TARGET := cdrom_cuesheet_overflow_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# vfs_implementation_cdrom.c pulls in cdrom.c transitively for its\n# helper functions (cdrom_read, cdrom_write_cue, etc.).  We only\n# exercise the cuesheet read path, but the source file must link\n# against the full cdrom helper library plus file_path for\n# path_get_extension.\nSOURCES := \\\n\tcdrom_cuesheet_overflow_test.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t$(LIBRETRO_COMM_DIR)/cdrom/cdrom.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/string_list.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/dir_list.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/memmap/memalign.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_fnmatch.c \\\n\t$(LIBRETRO_COMM_DIR)/file/retro_dirent.c \\\n\t$(LIBRETRO_COMM_DIR)/string/stdstring.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_cdrom.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -DHAVE_CDROM -I$(LIBRETRO_COMM_DIR)/include\n\nLDLIBS += -lm\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/file/vfs_cdrom/cdrom_cuesheet_overflow_test.c",
    "content": "/* Regression test for retro_vfs_file_read_cdrom cuesheet byte_pos\n * wrap (libretro-common/vfs/vfs_implementation_cdrom.c).\n *\n * Pre-patch, the cuesheet read path contained:\n *\n *   if ((int64_t)len >= (int64_t)stream->cdrom.cue_len\n *         - stream->cdrom.byte_pos)\n *       len = stream->cdrom.cue_len - stream->cdrom.byte_pos - 1;\n *   memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, len);\n *\n * cue_len is size_t, byte_pos is int64_t.  The subtraction\n * \"cue_len - byte_pos - 1\" is performed as unsigned (size_t).  If\n * byte_pos >= cue_len, the subtraction wraps to a huge size_t and\n * memcpy reads off the end of cue_buf.  byte_pos can be set to any\n * value by seek, which does not clamp.\n *\n * Post-patch, the read clamps against the remaining bytes with\n * unsigned subtraction *after* checking that byte_pos is in range,\n * and returns 0 (EOF) if byte_pos is out of range.\n *\n * Post-patch also returns 0 when the computed clamp would be\n * negative, rather than wrapping to SIZE_MAX.\n *\n * The test directly constructs a libretro_vfs_implementation_file\n * with a small cue_buf, sets byte_pos to a value >= cue_len, and\n * calls the read function.  Under ASan the pre-patch behaviour\n * fires heap-buffer-overflow; post-patch returns 0 cleanly.\n *\n * Note: this is a Linux-only test because HAVE_CDROM is the only\n * configuration that compiles the cuesheet code path.  The same\n * bug exists in the Windows branch of the same file but would\n * require Win32 headers to exercise directly.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <vfs/vfs.h>\n\n/* Forward-declare the function we're testing.  The real declaration\n * lives in vfs_implementation_cdrom.h which requires various\n * platform headers we don't want to drag in for a unit test. */\nint64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,\n      void *s, uint64_t len);\n\nstatic int failures = 0;\n\nstatic void test_cuesheet_byte_pos_wrap(void)\n{\n   libretro_vfs_implementation_file stream;\n   char out[64];\n   int64_t rc;\n   const char *fake_cue = \"FILE \\\"track01.bin\\\" BINARY\\nTRACK 01 MODE1/2048\\n\";\n   size_t cue_size      = strlen(fake_cue) + 1;  /* incl NUL */\n\n   memset(&stream, 0, sizeof(stream));\n\n   stream.cdrom.cue_buf = strdup(fake_cue);\n   if (!stream.cdrom.cue_buf)\n   {\n      printf(\"[ERROR] strdup failed\\n\");\n      failures++;\n      return;\n   }\n   stream.cdrom.cue_len = cue_size;\n\n   /* orig_path must end in \".cue\" for the read function to dispatch\n    * into the cuesheet path.  The function calls path_get_extension\n    * on it. */\n   stream.orig_path = strdup(\"test.cue\");\n   if (!stream.orig_path)\n   {\n      free(stream.cdrom.cue_buf);\n      printf(\"[ERROR] strdup failed (orig_path)\\n\");\n      failures++;\n      return;\n   }\n\n   /* Baseline: read at byte_pos=0 with small len should succeed. */\n   stream.cdrom.byte_pos = 0;\n   rc = retro_vfs_file_read_cdrom(&stream, out, 10);\n   if (rc < 0 || rc > 10)\n   {\n      printf(\"[ERROR] baseline read: rc=%lld, want 0..10\\n\",\n            (long long)rc);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] baseline cuesheet read rc=%lld\\n\", (long long)rc);\n\n   /* Attack 1: byte_pos at cue_len.  Pre-patch:\n    *   cue_len - byte_pos - 1 = 0 - 1 = SIZE_MAX (size_t wrap)\n    *   len = SIZE_MAX, memcpy reads gigabytes -> OOB.\n    * Post-patch: byte_pos >= cue_len, return 0. */\n   stream.cdrom.byte_pos = (int64_t)cue_size;\n   rc = retro_vfs_file_read_cdrom(&stream, out, 10);\n   if (rc != 0)\n   {\n      printf(\"[ERROR] byte_pos==cue_len: rc=%lld, want 0\\n\",\n            (long long)rc);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] byte_pos==cue_len returned 0\\n\");\n\n   /* Attack 2: byte_pos past cue_len.  Pre-patch: same size_t wrap. */\n   stream.cdrom.byte_pos = (int64_t)cue_size + 100;\n   rc = retro_vfs_file_read_cdrom(&stream, out, 10);\n   if (rc != 0)\n   {\n      printf(\"[ERROR] byte_pos > cue_len: rc=%lld, want 0\\n\",\n            (long long)rc);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] byte_pos > cue_len returned 0\\n\");\n\n   /* Attack 3: negative byte_pos.  Pre-patch: cast to size_t gives\n    * SIZE_MAX-ish, then cue_len - huge wraps around into a small\n    * positive value, then memcpy reads gigabytes off cue_buf.\n    * Post-patch: byte_pos < 0, return 0. */\n   stream.cdrom.byte_pos = -1;\n   rc = retro_vfs_file_read_cdrom(&stream, out, 10);\n   if (rc != 0)\n   {\n      printf(\"[ERROR] byte_pos < 0: rc=%lld, want 0\\n\", (long long)rc);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] byte_pos < 0 returned 0\\n\");\n\n   /* Attack 4: huge len at legitimate byte_pos.  Pre-patch: the\n    * (int64_t)len cast makes large len negative and the bound\n    * check behaves unpredictably.  With len = UINT64_MAX the cast\n    * is -1, and the check is \"-1 >= cue_len - byte_pos\" which for\n    * small cue_len-byte_pos is false -- so the clamp is SKIPPED\n    * and the full UINT64_MAX reaches memcpy.  OOB.\n    * Post-patch: clamp is unsigned, len is compared to unsigned\n    * remaining, clamp always fires correctly. */\n   stream.cdrom.byte_pos = 5;\n   rc = retro_vfs_file_read_cdrom(&stream, out, (uint64_t)-1);\n   {\n      int64_t max_expected = (int64_t)cue_size - 5 - 1;\n      if (rc < 0 || rc > max_expected)\n      {\n         printf(\"[ERROR] huge len: rc=%lld, want 0..%lld\\n\",\n               (long long)rc, (long long)max_expected);\n         failures++;\n      }\n      else\n         printf(\"[SUCCESS] huge len clamped to rc=%lld\\n\", (long long)rc);\n   }\n\n   free(stream.cdrom.cue_buf);\n   free(stream.orig_path);\n}\n\nint main(void)\n{\n   test_cuesheet_byte_pos_wrap();\n\n   if (failures)\n   {\n      printf(\"\\n%d cdrom test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll cdrom regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/bmp/Makefile",
    "content": "TARGET := rbmp_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\trbmp_test.c \\\n\t$(LIBRETRO_COMM_DIR)/formats/bmp/rbmp.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/formats/bmp/rbmp_test.c",
    "content": "/* Regression tests for libretro-common/formats/bmp/rbmp.c\n *\n * Targets (a mix of testable discriminators + honest smokes):\n *\n *  1. img_y = 0x80000000 rejection.  Pre-patch the code did\n *       flip_vertically = ((int) s->img_y) > 0;\n *       s->img_y        = abs((int) s->img_y);\n *     When img_y == 0x80000000u, the cast to int is INT_MIN and\n *     abs(INT_MIN) is undefined behaviour.  On 2's-complement\n *     systems abs(INT_MIN) returns INT_MIN, then the uint32_t\n *     assignment leaves img_y == 0x80000000 -- a huge dimension\n *     that then drives the buffer allocation in a bad direction.\n *     Post-patch this is rejected at the header step and\n *     rbmp_process_image returns IMAGE_PROCESS_ERROR cleanly.\n *\n *  2. img_x * img_y overflow rejection.  A crafted BMP with\n *     width = 0x10001 (65537) and height = 0x10000 (65536)\n *     would pre-patch have wrapped the uint32_t multiplication\n *     to 0x10000 on 32-bit builds, producing a 256 KiB malloc\n *     for 16 GiB of claimed image data -- heap overflow at the\n *     first pixel write.  On 64-bit size_t doesn't wrap, so\n *     we can only directly verify the rejection path on 32-bit,\n *     but the size_t arithmetic IS exercised here and the\n *     17 GiB allocation reliably fails on any realistic test\n *     machine -- the test asserts the decoder returns\n *     IMAGE_PROCESS_ERROR rather than corrupting memory.\n *\n *  3. Happy path: a tiny 1x1 24bpp BMP decodes without error.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <formats/rbmp.h>\n#include <formats/image.h>\n\nstatic int failures = 0;\n\nstatic void put16le(uint8_t *p, uint16_t v)\n{\n   p[0] = (uint8_t)(v & 0xFF);\n   p[1] = (uint8_t)(v >> 8);\n}\n\nstatic void put32le(uint8_t *p, uint32_t v)\n{\n   p[0] = (uint8_t)(v & 0xFF);\n   p[1] = (uint8_t)((v >> 8) & 0xFF);\n   p[2] = (uint8_t)((v >> 16) & 0xFF);\n   p[3] = (uint8_t)((v >> 24) & 0xFF);\n}\n\n/* Build a BITMAPFILEHEADER + BITMAPINFOHEADER (hsz=40, 24bpp, BI_RGB)\n * into out.  Returns 14 + 40 = 54. */\nstatic int make_bmp_header(uint8_t *out,\n      uint32_t width, uint32_t height, uint16_t bpp,\n      uint32_t compression)\n{\n   memset(out, 0, 54);\n   /* BITMAPFILEHEADER */\n   out[0] = 'B';\n   out[1] = 'M';\n   put32le(out + 2, 0);     /* file size, ignored */\n   put32le(out + 6, 0);     /* reserved */\n   put32le(out + 10, 54);   /* offset to pixel data */\n   /* BITMAPINFOHEADER */\n   put32le(out + 14, 40);   /* hsz */\n   put32le(out + 18, width);\n   put32le(out + 22, height);\n   put16le(out + 26, 1);    /* planes */\n   put16le(out + 28, bpp);\n   put32le(out + 30, compression);\n   /* remaining 40-byte header fields = 0 from memset */\n   return 54;\n}\n\nstatic void test_img_y_int_min(void)\n{\n   /* img_y = 0x80000000 -- pre-patch abs((int)0x80000000) is UB.\n    * Post-patch header check bails cleanly. */\n   uint8_t file[128];\n   rbmp_t *rbmp;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   int hdr_len = make_bmp_header(file, 1u, 0x80000000u, 24, 0);\n   /* a few bytes of pseudo pixel data */\n   memset(file + hdr_len, 0, 16);\n\n   rbmp = rbmp_alloc();\n   rbmp_set_buf_ptr(rbmp, file);\n   rc = rbmp_process_image(rbmp, &out, (size_t)hdr_len + 16, &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_ERROR)\n   {\n      printf(\"[ERROR] img_y=0x80000000 not rejected (rc=%d w=%u h=%u)\\n\",\n            rc, w, h);\n      failures++;\n      free(out);\n   }\n   else\n      printf(\"[SUCCESS] BMP img_y=0x80000000 (abs(INT_MIN) UB) rejected\\n\");\n   rbmp_free(rbmp);\n}\n\nstatic void test_dimension_overflow(void)\n{\n   /* width * height would overflow uint32_t on 32-bit and also\n    * requests an unrealistic allocation on 64-bit.  Post-patch\n    * this is rejected via the SIZE_MAX overflow guard OR via\n    * malloc failure, either way the decoder returns\n    * IMAGE_PROCESS_ERROR rather than corrupting memory. */\n   uint8_t file[128];\n   rbmp_t *rbmp;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   int hdr_len = make_bmp_header(file, 0x10001u, 0x10000u, 24, 0);\n   memset(file + hdr_len, 0, 16);\n\n   rbmp = rbmp_alloc();\n   rbmp_set_buf_ptr(rbmp, file);\n   rc = rbmp_process_image(rbmp, &out, (size_t)hdr_len + 16, &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_ERROR)\n   {\n      printf(\"[ERROR] oversized dimensions not rejected \"\n            \"(rc=%d w=%u h=%u out=%p)\\n\", rc, w, h, out);\n      failures++;\n      free(out);\n   }\n   else\n      printf(\"[SUCCESS] BMP 0x10001 x 0x10000 rejected (no heap overflow)\\n\");\n   rbmp_free(rbmp);\n}\n\nstatic void test_happy_1x1_24bpp(void)\n{\n   /* Tiny valid 1x1 24bpp BGR. */\n   uint8_t file[64];\n   rbmp_t *rbmp;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   int hdr_len = make_bmp_header(file, 1, 1, 24, 0);\n   /* One pixel: B=0x12 G=0x34 R=0x56.  BMPs are padded to 4-byte\n    * row alignment, so one 24bpp row = 3 bytes pixel + 1 byte pad. */\n   file[hdr_len + 0] = 0x12;\n   file[hdr_len + 1] = 0x34;\n   file[hdr_len + 2] = 0x56;\n   file[hdr_len + 3] = 0x00;\n\n   rbmp = rbmp_alloc();\n   rbmp_set_buf_ptr(rbmp, file);\n   rc = rbmp_process_image(rbmp, &out, (size_t)hdr_len + 4, &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_END || w != 1 || h != 1 || !out)\n   {\n      printf(\"[ERROR] happy-path 1x1 BMP: rc=%d w=%u h=%u out=%p\\n\",\n            rc, w, h, out);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] BMP 1x1 24bpp happy path\\n\");\n   free(out);\n   rbmp_free(rbmp);\n}\n\nint main(void)\n{\n   test_img_y_int_min();\n   test_dimension_overflow();\n   test_happy_1x1_24bpp();\n\n   if (failures)\n   {\n      printf(\"\\n%d rbmp test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll rbmp regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/cdfs/Makefile",
    "content": "TARGET := cdfs_dir_record_test\n\nSOURCES := cdfs_dir_record_test.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -O0\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/formats/cdfs/cdfs_dir_record_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (cdfs_dir_record_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression test for the directory-record iterator bounds in\n * libretro-common/formats/cdfs/cdfs.c::cdfs_find_file.\n *\n * The function reads a 2048-byte ECMA-119 directory sector\n * from the disc image into a stack buffer and walks the\n * variable-length records:\n *\n *   while (tmp < buffer + sizeof(buffer))\n *   {\n *      if (!*tmp) break;\n *      if (tmp[33 + path_length] == ';' || tmp[33 + path_length] == '\\0')\n *         ...\n *      tmp += tmp[0];\n *   }\n *\n * Pre-this-patch the loop had three composable issues:\n *\n *  1. The guard tmp < buffer + sizeof(buffer) only confirmed\n *     the record header byte was in bounds.  tmp[33 +\n *     path_length] could read past the buffer end, leaking\n *     up to ~32 bytes of adjacent stack into the comparison.\n *\n *  2. tmp[2..4] and tmp[10..13] were read after a successful\n *     filename comparison, with the same shape problem -- a\n *     record positioned near the buffer end produced\n *     attacker-influenced stack bytes flowing into `sector`\n *     (which redirects the next intfstream_read) and\n *     `file->size`.\n *\n *  3. The advance \"tmp += tmp[0]\" with tmp[0] attacker-\n *     controlled could land tmp anywhere up to 255 bytes\n *     past the safe range.  A record that claimed length\n *     less than 33 + filename_length + 1 (the minimum legal\n *     ECMA-119 record size) was a primitive for jumping the\n *     iterator to an unsafe offset.\n *\n * Reachability: user loads a malicious .iso/.bin/.cue.  Same\n * threat class as other disc-image bugs (CHD, BSV).\n *\n * Fix: tighten the loop guard to require the entire record\n * (header through tmp[33 + path_length]) to fit, and require\n * the record's claimed length to be >= 33 + path_length + 1\n * before doing the filename comparison.\n *\n * IMPORTANT: this test keeps a verbatim copy of the post-fix\n * loop predicate.  If cdfs.c's loop amends, the copy below\n * must follow.  Convention used by the other regression\n * tests under libretro-common/samples/.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>   /* strncasecmp */\n\n#define SECTOR_SIZE 2048\n\nstatic int failures = 0;\n\n/* === verbatim copy of the post-fix iterator from\n *     libretro-common/formats/cdfs/cdfs.c::cdfs_find_file.\n *     If cdfs.c amends, this copy must follow. ===\n *\n * Returns the matched record's \"sector\" value (tmp[2..4])\n * on success, -1 if no record matches, -2 if the loop\n * would have run off the buffer. */\nstatic int find_dir_record(const uint8_t *buffer,\n      size_t buffer_size, const char *path)\n{\n   const uint8_t *tmp = buffer;\n   size_t path_length = strlen(path);\n\n   while (   tmp < buffer + buffer_size\n          && (size_t)(tmp - buffer) + 33 + path_length < buffer_size)\n   {\n      if (!*tmp)\n         break;\n\n      if (tmp[0] < 33 + path_length + 1)\n         break;\n\n      if (        (tmp[33 + path_length] == ';'\n               || (tmp[33 + path_length] == '\\0'))\n               &&  strncasecmp((const char*)(tmp + 33), path, path_length) == 0)\n      {\n         return tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);\n      }\n\n      tmp += tmp[0];\n   }\n\n   return -1;\n}\n/* === end verbatim copy === */\n\n/* Build a single legitimate directory record into `out`.\n * Returns the record's length. */\nstatic size_t build_record(uint8_t *out, const char *filename,\n      uint32_t sector, uint32_t size)\n{\n   size_t fn_len    = strlen(filename);\n   size_t total     = 33 + fn_len + 1;  /* +1 for ';' */\n   memset(out, 0, total);\n   out[0]           = (uint8_t)total;\n   /* sector at bytes 2..4 (little-endian 24-bit) */\n   out[2]           = (uint8_t)(sector & 0xff);\n   out[3]           = (uint8_t)((sector >> 8) & 0xff);\n   out[4]           = (uint8_t)((sector >> 16) & 0xff);\n   /* size at bytes 10..13 */\n   out[10]          = (uint8_t)(size & 0xff);\n   out[11]          = (uint8_t)((size >> 8) & 0xff);\n   out[12]          = (uint8_t)((size >> 16) & 0xff);\n   out[13]          = (uint8_t)((size >> 24) & 0xff);\n   memcpy(out + 33, filename, fn_len);\n   out[33 + fn_len] = ';';\n   return total;\n}\n\n/* ---- tests ---- */\n\nstatic void test_finds_legitimate_record(void)\n{\n   uint8_t buffer[SECTOR_SIZE];\n   size_t  off;\n   int     rv;\n   memset(buffer, 0, sizeof(buffer));\n   off = build_record(buffer, \"FOO\", 0x123456, 1024);\n   /* terminator: a 0-length record marks end-of-records */\n   buffer[off] = 0;\n\n   rv = find_dir_record(buffer, sizeof(buffer), \"FOO\");\n   if (rv != 0x123456)\n   {\n      printf(\"[ERROR] legitimate record: rv=0x%x, want 0x123456\\n\", rv);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] legitimate record found and decoded correctly\\n\");\n}\n\nstatic void test_record_at_buffer_end_does_not_oob(void)\n{\n   /* Fill the buffer with single-byte-length records so the\n    * iterator walks 1 byte at a time, then place a non-zero\n    * byte close to the end so the guard would have allowed\n    * the body to run pre-fix.  Allocate the buffer as exactly\n    * SECTOR_SIZE bytes on the heap with no slack so ASan\n    * flags any read past the end. */\n   uint8_t *buffer = (uint8_t*)malloc(SECTOR_SIZE);\n   int rv;\n   if (!buffer) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n\n   /* Records of length 1 from offset 0 to SECTOR_SIZE - 5. */\n   memset(buffer, 1, SECTOR_SIZE - 4);\n   /* The last 4 bytes are zero, terminating the chain. */\n   memset(buffer + SECTOR_SIZE - 4, 0, 4);\n\n   /* Search for a 0-length filename: path_length = 0, so the\n    * pre-fix bug fires when tmp + 33 > buffer + 2048, i.e.\n    * tmp > buffer + 2015.  The iterator walks single-byte\n    * records right up to the boundary; pre-fix it would have\n    * read tmp[33] for tmp >= buffer + 2016. */\n   rv = find_dir_record(buffer, SECTOR_SIZE, \"\");\n   /* Behavioural check: no match should be found, and (under\n    * ASan) no OOB read should have occurred. */\n   if (rv >= 0)\n   {\n      /* \"\" matches if tmp[33] == ';' or '\\0'.  Some matches are\n       * possible from random buffer content -- accept any rv,\n       * the point of the test is that ASan didn't fire. */\n   }\n   printf(\"[SUCCESS] record-near-buffer-end iteration stayed in bounds\\n\");\n\n   free(buffer);\n}\n\nstatic void test_short_record_length_rejected(void)\n{\n   /* A record claiming length 5 (less than the 33-byte\n    * minimum) used to advance the iterator only 5 bytes,\n    * letting subsequent reads of tmp[33+plen] reach into\n    * undefined territory.  The post-fix guard\n    *    if (tmp[0] < 33 + path_length + 1) break;\n    * stops the iterator. */\n   uint8_t *buffer = (uint8_t*)malloc(SECTOR_SIZE);\n   int rv;\n   if (!buffer) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n\n   memset(buffer, 0, SECTOR_SIZE);\n   buffer[0] = 5;  /* claimed length way below 33 */\n   /* Subsequent bytes are zero so even if the iterator\n    * advances we hit the !*tmp break. */\n\n   rv = find_dir_record(buffer, SECTOR_SIZE, \"FOO\");\n   if (rv != -1)\n   {\n      printf(\"[ERROR] short-length record produced rv=%d\\n\", rv);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] short-length record rejected without iteration\\n\");\n\n   free(buffer);\n}\n\nstatic void test_pathological_record_at_2046(void)\n{\n   /* Place a record claiming length 1 at buffer[2046].  Pre-fix\n    * the loop guard tmp < buffer + 2048 admitted this iteration\n    * but tmp[33 + path_length] = buffer[2079 + plen] read way\n    * off the end.  Heap-alloc with exact SECTOR_SIZE so ASan\n    * catches the read.\n    *\n    * To get there the iterator needs to walk to offset 2046.\n    * Single-byte records all the way is the simplest path. */\n   uint8_t *buffer = (uint8_t*)malloc(SECTOR_SIZE);\n   int rv;\n   if (!buffer) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n\n   memset(buffer, 1, SECTOR_SIZE);\n   /* Make sure the byte at 2046 is non-zero (it already is from\n    * the memset). */\n   buffer[2046] = 1;\n   buffer[2047] = 0;  /* any value */\n\n   rv = find_dir_record(buffer, SECTOR_SIZE, \"BAR\");\n   /* Behaviour: no match.  Under ASan: no OOB. */\n   (void)rv;\n   printf(\"[SUCCESS] iterator at offset 2046 stayed in bounds\\n\");\n\n   free(buffer);\n}\n\nint main(void)\n{\n   test_finds_legitimate_record();\n   test_record_at_buffer_end_does_not_oob();\n   test_short_record_length_rejected();\n   test_pathological_record_at_2046();\n\n   if (failures)\n   {\n      printf(\"\\n%d cdfs_dir_record test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll cdfs_dir_record regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/json/Makefile",
    "content": "TARGET := rjson_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\trjson_test.c \\\n\t$(LIBRETRO_COMM_DIR)/formats/json/rjson.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS  += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\nLDLIBS  += -lz\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS) $(LDLIBS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/formats/json/rjson_test.c",
    "content": "/* Regression tests for libretro-common/formats/json/rjson.c\n *\n * Exercises the parser and writer on inputs that previously\n * triggered the following bugs (all fixed in the adjoining\n * patch):\n *\n *  1. _rjson_grow_string: size_t doubling overflow on ~2 GiB\n *     inputs on 32-bit.  Not reproducible in a CI sample, so\n *     the cap is validated indirectly via a happy-path parse\n *     that repeatedly grows string_cap and verifies the output\n *     is intact.\n *\n *  2. _rjsonwriter_memory_io: int overflow on buf_num + len + 512\n *     when the writer's in-memory buffer approaches 2 GiB.  Also\n *     not reproducible in CI; the rewritten arithmetic is\n *     exercised by a happy-path write/read-back.\n *\n *  3. rjsonwriter_raw: did not guard a negative len parameter.\n *     A caller passing a negative len could pre-patch advance\n *     buf_num past buf_cap through the signed-overflow path.\n *     This is directly testable and IS a true discriminator.\n *\n *  4. rjson_open_user: no lower bound on io_block_size.  A very\n *     small (or negative) block size underallocated input_buf\n *     and the first read overran it.  Directly testable.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <formats/rjson.h>\n#include <formats/rjson_helpers.h>\n\nstatic int failures = 0;\n\n/* ------------------------------------------------------------------ */\n/* Parser smoke tests                                                 */\n/* ------------------------------------------------------------------ */\n\nstruct count_ctx { int strings; int numbers; int objects; int arrays; };\n\nstatic bool cb_string(void *ctx, const char *s, size_t n)\n{ (void)s; (void)n; ((struct count_ctx*)ctx)->strings++; return true; }\nstatic bool cb_number(void *ctx, const char *s, size_t n)\n{ (void)s; (void)n; ((struct count_ctx*)ctx)->numbers++; return true; }\nstatic bool cb_start_obj(void *ctx)\n{ ((struct count_ctx*)ctx)->objects++; return true; }\nstatic bool cb_start_arr(void *ctx)\n{ ((struct count_ctx*)ctx)->arrays++; return true; }\nstatic bool cb_ignore_default(void *ctx) { (void)ctx; return true; }\nstatic bool cb_ignore_bool(void *ctx, bool v) { (void)ctx; (void)v; return true; }\n\nstatic void test_parser_happy_path(void)\n{\n   const char *json = \"{\\\"name\\\":\\\"libretro\\\",\\\"version\\\":42,\\\"tags\\\":[\\\"a\\\",\\\"b\\\",\\\"c\\\"],\\\"nested\\\":{\\\"x\\\":1}}\";\n   struct count_ctx ctx;\n   bool rc;\n\n   memset(&ctx, 0, sizeof(ctx));\n   rc = rjson_parse_quick(json, strlen(json), &ctx, 0,\n         cb_string, cb_string, cb_number,\n         cb_start_obj, cb_ignore_default,\n         cb_start_arr, cb_ignore_default,\n         cb_ignore_bool, cb_ignore_default, NULL);\n\n   if (!rc)\n   {\n      printf(\"[ERROR] happy path: parse failed\\n\");\n      failures++;\n      return;\n   }\n   /* \"name\", \"libretro\", \"version\", \"tags\", \"a\", \"b\", \"c\", \"nested\", \"x\"\n    * => member-or-value strings = 9 */\n   if (ctx.strings != 9)\n   {\n      printf(\"[ERROR] happy path: strings=%d, want 9\\n\", ctx.strings);\n      failures++;\n      return;\n   }\n   if (ctx.numbers != 2)\n   {\n      printf(\"[ERROR] happy path: numbers=%d, want 2\\n\", ctx.numbers);\n      failures++;\n      return;\n   }\n   if (ctx.objects != 2 || ctx.arrays != 1)\n   {\n      printf(\"[ERROR] happy path: objects=%d arrays=%d\\n\",\n             ctx.objects, ctx.arrays);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] parser happy path\\n\");\n}\n\nstatic void test_parser_long_string(void)\n{\n   /* Forces multiple _rjson_grow_string growths: start from the\n    * inline 512-byte string and grow to > 8 KiB.  Post-patch the\n    * cap logic must not interfere with legitimate growth. */\n   size_t N = 9000;\n   size_t i;\n   char *input;\n   struct count_ctx ctx;\n   bool rc;\n\n   input = (char*)malloc(N + 16);\n   if (!input) { printf(\"[ERROR] long string: OOM\\n\"); failures++; return; }\n\n   input[0] = '\"';\n   for (i = 1; i <= N; ++i)\n      input[i] = 'x';\n   input[N + 1] = '\"';\n   input[N + 2] = '\\0';\n\n   memset(&ctx, 0, sizeof(ctx));\n   rc = rjson_parse_quick(input, N + 2, &ctx, 0,\n         cb_string, cb_string, cb_number,\n         cb_start_obj, cb_ignore_default,\n         cb_start_arr, cb_ignore_default,\n         cb_ignore_bool, cb_ignore_default, NULL);\n   free(input);\n\n   if (!rc || ctx.strings != 1)\n   {\n      printf(\"[ERROR] long string: rc=%d strings=%d\\n\",\n            (int)rc, ctx.strings);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] long-string parse (grew past inline buffer)\\n\");\n}\n\nstatic void test_parser_malformed(void)\n{\n   /* A handful of malformed inputs that must NOT crash. */\n   static const char *bad[] = {\n      \"\",\n      \"{\",\n      \"[\",\n      \"[,\",\n      \"{\\\"x\\\":\",\n      \"[1,2,\",\n      \"\\\"unterminated\",\n      \"\\\\u\",\n      \"{\\\"\\\\uD800\\\":1}\",  /* dangling high surrogate */\n      \"1e\",\n      \"0.\",\n      \"-\",\n      NULL\n   };\n   int i;\n   for (i = 0; bad[i]; ++i)\n   {\n      struct count_ctx ctx;\n      memset(&ctx, 0, sizeof(ctx));\n      /* We don't care about rc; we care that this returns rather\n       * than crashing.  Post-patch all error paths are clean. */\n      (void)rjson_parse_quick(bad[i], strlen(bad[i]), &ctx, 0,\n            cb_string, cb_string, cb_number,\n            cb_start_obj, cb_ignore_default,\n            cb_start_arr, cb_ignore_default,\n            cb_ignore_bool, cb_ignore_default, NULL);\n   }\n   printf(\"[SUCCESS] malformed inputs did not crash (%d variants)\\n\", i);\n}\n\n/* ------------------------------------------------------------------ */\n/* Writer tests                                                       */\n/* ------------------------------------------------------------------ */\n\nstatic void test_writer_happy_path(void)\n{\n   rjsonwriter_t *w = rjsonwriter_open_memory();\n   const char *out;\n   int outlen = 0;\n\n   if (!w) { printf(\"[ERROR] writer open failed\\n\"); failures++; return; }\n\n   rjsonwriter_add_start_object(w);\n   rjsonwriter_add_string(w, \"key\");\n   rjsonwriter_raw(w, \":\", 1);\n   rjsonwriter_add_string(w, \"value\");\n   rjsonwriter_add_end_object(w);\n\n   out = rjsonwriter_get_memory_buffer(w, &outlen);\n   if (!out || outlen <= 0 || strcmp(out, \"{\\\"key\\\":\\\"value\\\"}\") != 0)\n   {\n      printf(\"[ERROR] writer happy path: out='%s' len=%d\\n\",\n            out ? out : \"(null)\", outlen);\n      failures++;\n      rjsonwriter_free(w);\n      return;\n   }\n   printf(\"[SUCCESS] writer happy path: '%s'\\n\", out);\n   rjsonwriter_free(w);\n}\n\nstatic void test_writer_negative_len(void)\n{\n   /* Pre-patch: rjsonwriter_raw with a negative len performed\n    *    (buf_num + NEG > buf_cap)\n    * in signed int, which may be FALSE for large negative NEG\n    * (skipping the flush), then memcpy(buf+buf_num, buf_src, NEG)\n    * was called with a huge size_t.\n    * Post-patch: negative len is rejected at the top of the\n    * function and the call is a no-op.\n    *\n    * We validate by writing a bunch of sane bytes around a\n    * negative-len call and confirming the output is exactly the\n    * sane bytes. */\n   rjsonwriter_t *w = rjsonwriter_open_memory();\n   const char *out;\n   int outlen = 0;\n\n   if (!w) { printf(\"[ERROR] open memory writer failed\\n\"); failures++; return; }\n\n   rjsonwriter_raw(w, \"AAA\", 3);\n   rjsonwriter_raw(w, \"SHOULDBEIGNORED\", -99);\n   rjsonwriter_raw(w, \"BBB\", 3);\n\n   out = rjsonwriter_get_memory_buffer(w, &outlen);\n   if (!out || outlen != 6 || memcmp(out, \"AAABBB\", 6) != 0)\n   {\n      printf(\"[ERROR] negative len: out='%.*s' len=%d\\n\",\n            outlen, out ? out : \"\", outlen);\n      failures++;\n      rjsonwriter_free(w);\n      return;\n   }\n   printf(\"[SUCCESS] negative-len raw() ignored (out='%.*s')\\n\",\n         outlen, out);\n   rjsonwriter_free(w);\n}\n\n/* ------------------------------------------------------------------ */\n/* open_user floor                                                    */\n/* ------------------------------------------------------------------ */\n\nstatic int dummy_io(void *buf, int len, void *user)\n{\n   /* Pretend EOF immediately.  Just needs to not crash. */\n   (void)buf; (void)len; (void)user;\n   return 0;\n}\n\nstatic void test_open_user_tiny_block(void)\n{\n   /* Pre-patch: io_block_size = 0 allocated only the fixed part\n    * of rjson_t, zero bytes for input_buf.  The first read into\n    * input_buf was OOB.\n    * Post-patch: io_block_size is floored at 16.  This opens\n    * and frees without crashing. */\n   rjson_t *json;\n   int i;\n   for (i = -10; i <= 8; ++i)\n   {\n      json = rjson_open_user(dummy_io, NULL, i);\n      if (!json)\n      {\n         printf(\"[ERROR] open_user(%d) returned NULL\\n\", i);\n         failures++;\n         continue;\n      }\n      (void)rjson_next(json);  /* triggers a read into input_buf */\n      rjson_free(json);\n   }\n   printf(\"[SUCCESS] open_user with tiny io_block_size floors cleanly\\n\");\n}\n\nint main(void)\n{\n   test_parser_happy_path();\n   test_parser_long_string();\n   test_parser_malformed();\n   test_writer_happy_path();\n   test_writer_negative_len();\n   test_open_user_tiny_block();\n\n   if (failures)\n   {\n      printf(\"\\n%d rjson test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll rjson regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/png/Makefile",
    "content": "TARGET := rpng\nTARGET_TEST := rpng_chunk_overflow_test\nTARGET_TEST2 := rpng_roundtrip_test\n\nCORE_DIR          := .\nLIBRETRO_PNG_DIR  := ../../../formats/png\nLIBRETRO_COMM_DIR := ../../..\n\nHAVE_IMLIB2=0\n\nLDFLAGS +=  -lz\n\nifeq ($(HAVE_IMLIB2),1)\nCFLAGS += -DHAVE_IMLIB2\nLDFLAGS += -lImlib2\nendif\n\nSOURCES_C := \t\\\n\t$(CORE_DIR)/rpng_test.c \\\n\t$(LIBRETRO_PNG_DIR)/rpng.c \\\n\t$(LIBRETRO_PNG_DIR)/rpng_encode.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \\\n\t$(LIBRETRO_COMM_DIR)/file/archive_file.c \\\n\t$(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/rzip_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/string_list.c\n\n# The chunk-overflow regression test exercises only\n# rpng_iterate_image, which doesn't invoke the inflate stream,\n# but rpng.c itself pulls in trans_stream.h so the\n# trans_stream/zlib objects must still be linked in.\nTEST_SOURCES_C := \\\n\t$(CORE_DIR)/rpng_chunk_overflow_test.c \\\n\t$(LIBRETRO_PNG_DIR)/rpng.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c\n\n# The round-trip regression test writes with rpng_encode and reads\n# back with rpng, so it needs the full file/nbio/stream stack.\n# Sources intentionally mirror $(SOURCES_C) minus the demo's\n# rpng_test.c entry point, plus the new test entry point.\nTEST2_SOURCES_C := \\\n\t$(CORE_DIR)/rpng_roundtrip_test.c \\\n\t$(LIBRETRO_PNG_DIR)/rpng.c \\\n\t$(LIBRETRO_PNG_DIR)/rpng_encode.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_intf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_stdio.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_linux.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_unixmmap.c \\\n\t$(LIBRETRO_COMM_DIR)/file/nbio/nbio_windowsmmap.c \\\n\t$(LIBRETRO_COMM_DIR)/file/archive_file.c \\\n\t$(LIBRETRO_COMM_DIR)/file/archive_file_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/rzip_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t$(LIBRETRO_COMM_DIR)/lists/string_list.c\n\nOBJS := $(SOURCES_C:.c=.o)\nTEST_OBJS := $(TEST_SOURCES_C:.c=.o)\nTEST2_OBJS := $(TEST2_SOURCES_C:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -O0 -g -DHAVE_ZLIB -DRPNG_TEST -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET) $(TARGET_TEST) $(TARGET_TEST2)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\n$(TARGET_TEST): $(TEST_OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\n$(TARGET_TEST2): $(TEST2_OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(TARGET_TEST) $(TARGET_TEST2) $(OBJS) $(TEST_OBJS) $(TEST2_OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/formats/png/rpng_chunk_overflow_test.c",
    "content": "/* Regression tests for libretro-common/formats/png/rpng.c\n *\n * Exercises the chunk-header phase of rpng_iterate_image after\n * the integer-overflow hardening in the accompanying patch.\n *\n * Honest note on discriminator status: the headline bug fixed\n * here is a pointer-arithmetic overflow in\n *      if (buf + 8 + chunk_size > rpng->buff_end) return false;\n * that is only genuinely reachable on 32-bit builds -- on a\n * 64-bit host the pointer has enough headroom that the compare\n * still returns the right answer (the arithmetic itself is UB\n * per C99, but no sanitizer flags it in practice on 64-bit).\n * These tests therefore exercise the NEW size_t-based guard and\n * serve as regression protection against anyone reintroducing\n * unguarded pointer arithmetic; they are not pre/post\n * discriminators on a 64-bit CI host.\n *\n * Subtests:\n *   1. chunk_size near UINT32_MAX is rejected.\n *   2. chunk_size larger than remaining input is rejected.\n *   3. Valid minimal PNG with just IHDR iterates cleanly.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <formats/rpng.h>\n#include <formats/image.h>\n\nstatic int failures = 0;\n\nstatic void put32be(uint8_t *p, uint32_t v)\n{\n   p[0] = (uint8_t)(v >> 24);\n   p[1] = (uint8_t)(v >> 16);\n   p[2] = (uint8_t)(v >> 8);\n   p[3] = (uint8_t)(v & 0xFF);\n}\n\n/* Minimal PNG magic. */\nstatic const uint8_t png_magic[8] = {\n   0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A\n};\n\nstatic void test_chunk_size_uint32_max(void)\n{\n   /* PNG with a single chunk declaring chunk_size = 0xFFFFFFF8.\n    * On 32-bit pre-patch this defeated the pointer compare and\n    * the IDAT handler's memcpy could read up to ~4 GiB past\n    * the end of the input.  Post-patch the size compare rejects\n    * on any word size. */\n   uint8_t file[64];\n   rpng_t *rpng;\n   bool iter;\n   size_t off = 0;\n\n   memcpy(file + off, png_magic, 8); off += 8;\n   put32be(file + off, 0xFFFFFFF8u); off += 4;      /* size */\n   memcpy(file + off, \"IHDR\", 4);    off += 4;      /* type */\n   memset(file + off, 0xAA, sizeof(file) - off);\n\n   rpng = rpng_alloc();\n   if (!rpng) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   rpng_set_buf_ptr(rpng, file, sizeof(file));\n   rpng_start(rpng);\n   iter = rpng_iterate_image(rpng);\n   if (iter)\n   {\n      printf(\"[ERROR] chunk_size=0xFFFFFFF8 was accepted\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] chunk_size=0xFFFFFFF8 rejected\\n\");\n   rpng_free(rpng);\n}\n\nstatic void test_chunk_size_larger_than_input(void)\n{\n   /* chunk_size = 1000 with only 40 bytes of input.  Must\n    * reject -- the size compare catches this on all hosts. */\n   uint8_t file[40];\n   rpng_t *rpng;\n   bool iter;\n   size_t off = 0;\n\n   memcpy(file + off, png_magic, 8); off += 8;\n   put32be(file + off, 1000);        off += 4;\n   memcpy(file + off, \"zzzz\", 4);    off += 4;\n   memset(file + off, 0, sizeof(file) - off);\n\n   rpng = rpng_alloc();\n   rpng_set_buf_ptr(rpng, file, sizeof(file));\n   rpng_start(rpng);\n   iter = rpng_iterate_image(rpng);\n   if (iter)\n   {\n      printf(\"[ERROR] chunk_size=1000 in 40-byte file accepted\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] oversized chunk_size rejected\\n\");\n   rpng_free(rpng);\n}\n\nstatic void test_happy_ihdr(void)\n{\n   /* Minimal valid framing: magic + IHDR (13 bytes) + space for\n    * CRC.  iterate_image should return true for IHDR. */\n   uint8_t file[64];\n   uint8_t ihdr[13];\n   rpng_t *rpng;\n   size_t off = 0;\n   bool iter;\n\n   memset(file, 0, sizeof(file));\n   memcpy(file + off, png_magic, 8); off += 8;\n\n   /* IHDR body: 8x8 RGBA-8. */\n   put32be(ihdr + 0, 8);          /* width  */\n   put32be(ihdr + 4, 8);          /* height */\n   ihdr[8]  = 8;                  /* depth = 8 */\n   ihdr[9]  = 6;                  /* color_type = RGBA */\n   ihdr[10] = 0;                  /* compression */\n   ihdr[11] = 0;                  /* filter */\n   ihdr[12] = 0;                  /* interlace */\n\n   put32be(file + off, 13);             off += 4;   /* chunk size */\n   memcpy(file + off, \"IHDR\", 4);       off += 4;   /* type */\n   memcpy(file + off, ihdr, 13);        off += 13;  /* data */\n   /* 4-byte CRC space (value doesn't matter, not verified here) */\n   memset(file + off, 0, 4);            off += 4;\n\n   rpng = rpng_alloc();\n   rpng_set_buf_ptr(rpng, file, sizeof(file));\n   rpng_start(rpng);\n   iter = rpng_iterate_image(rpng);\n   if (!iter)\n   {\n      printf(\"[ERROR] IHDR iteration failed unexpectedly\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] IHDR chunk iterated successfully\\n\");\n   rpng_free(rpng);\n}\n\nint main(void)\n{\n   test_chunk_size_uint32_max();\n   test_chunk_size_larger_than_input();\n   test_happy_ihdr();\n\n   if (failures)\n   {\n      printf(\"\\n%d rpng chunk-overflow test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll rpng chunk-overflow regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/png/rpng_roundtrip_test.c",
    "content": "/* Regression tests for libretro-common/formats/png/rpng_encode.c\n *\n * Round-trip tests the PNG encoder by writing a known pixel pattern\n * to disk, reading it back with the PNG decoder, and comparing pixel\n * for pixel. Any byte-level change to the encoder's deflate output\n * is allowed (different chunking of the same input data can legitimately\n * produce different deflate streams), but the decoded pixels must\n * always round-trip unchanged. This is the right invariant for any\n * encoder refactor -- including a future streaming-deflate rewrite.\n *\n * Exercised entry points:\n *   - rpng_save_image_argb      (uint32 ARGB source, RGBA PNG output)\n *   - rpng_save_image_bgr24     (BGR24 source, RGB PNG output, positive pitch)\n *   - rpng_save_image_bgr24     (BGR24 source, bottom-up, negative pitch\n *                                via the (unsigned)(-pitch) convention used\n *                                by task_screenshot's viewport fast path)\n *\n * Exercised sizes: tiny (4x4), moderate non-power-of-two (37x29),\n * and screenshot-shaped (320x240). The last is big enough that a\n * streaming encoder would span multiple deflate output chunks.\n *\n * Exercised pixel patterns: solid colour, horizontal gradient\n * (stresses the 'sub' filter), vertical gradient ('up' filter),\n * diagonal ('paeth'), and a pseudo-random pattern ('none' filter\n * typically wins). Catches filter-selection regressions as well as\n * byte-level round-trip failures.\n *\n * Usage:\n *   rpng_roundtrip_test            (uses ./rpng_roundtrip_tmp.png)\n *   rpng_roundtrip_test <tmp.png>  (caller-chosen path, useful on\n *                                   systems without /tmp semantics)\n *\n * Returns 0 on success, nonzero on any round-trip mismatch.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#include <file/nbio.h>\n#include <formats/rpng.h>\n#include <formats/image.h>\n#include <encodings/crc32.h>\n\nstatic int failures = 0;\n\n/* ---- Structural validation of encoded PNGs ----\n *\n * Two layers, tried in order:\n *\n *   1. External pngcheck(1) if installed -- the gold-standard\n *      third-party PNG validator. Used when available.\n *   2. Built-in fallback otherwise -- walks chunk headers, verifies\n *      CRCs, checks required chunk ordering (IHDR first, IEND last,\n *      exactly one of each). Covers the main class of bug a\n *      streaming-encoder rewrite could introduce: rpng's own encoder\n *      producing output rpng's own decoder will happily read but\n *      other PNG decoders reject.\n *\n * Neither pngcheck nor any additional libraries are a hard\n * dependency. The built-in fallback has no external deps at all\n * (uses encoding_crc32 which is already linked for the encoder).\n *\n * The test banner reports which layer is active so reviewers can\n * tell at a glance whether the stronger third-party check ran. */\n\nstatic const uint8_t png_magic_bytes[8] = {\n   0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A\n};\n\nstatic uint32_t read_be32(const uint8_t *p)\n{\n   return ((uint32_t)p[0] << 24)\n        | ((uint32_t)p[1] << 16)\n        | ((uint32_t)p[2] <<  8)\n        | ((uint32_t)p[3] <<  0);\n}\n\n/* Built-in fallback. Returns true if the file at `path` looks like\n * a well-formed PNG: valid magic, chunks with correct CRCs, IHDR\n * first and present exactly once, IEND last and present exactly\n * once, at least one IDAT. Does not decompress the IDAT stream\n * (the round-trip check that follows does that). Reads whole file\n * into memory -- fine for test image sizes, not a strategy for\n * production code. */\nstatic bool rpng_structural_check(const char *path)\n{\n   FILE *f;\n   long  file_len_l;\n   size_t file_len;\n   uint8_t *buf = NULL;\n   size_t off;\n   bool ret       = false;\n   bool seen_ihdr = false;\n   bool seen_iend = false;\n   unsigned idat_count = 0;\n\n   f = fopen(path, \"rb\");\n   if (!f)\n      return false;\n\n   if (fseek(f, 0, SEEK_END) != 0) goto done;\n   file_len_l = ftell(f);\n   if (file_len_l < 0) goto done;\n   file_len = (size_t)file_len_l;\n   if (fseek(f, 0, SEEK_SET) != 0) goto done;\n\n   if (file_len < sizeof(png_magic_bytes) + 12) /* magic + one chunk min */\n      goto done;\n\n   buf = (uint8_t*)malloc(file_len);\n   if (!buf) goto done;\n   if (fread(buf, 1, file_len, f) != file_len) goto done;\n\n   if (memcmp(buf, png_magic_bytes, sizeof(png_magic_bytes)) != 0)\n      goto done;\n\n   off = sizeof(png_magic_bytes);\n   while (off + 12 <= file_len) /* length(4) + type(4) + CRC(4) */\n   {\n      uint32_t chunk_len = read_be32(buf + off);\n      const uint8_t *type;\n      uint32_t declared_crc;\n      uint32_t computed_crc;\n\n      /* Guard chunk_len before it's used in pointer arithmetic:\n       * attacker-controlled value, must not overflow off. */\n      if (chunk_len > file_len - off - 12)\n         goto done;\n\n      type         = buf + off + 4;\n      declared_crc = read_be32(buf + off + 8 + chunk_len);\n      /* CRC is computed over type(4) + data(chunk_len). */\n      computed_crc = encoding_crc32(0, buf + off + 4, 4 + chunk_len);\n\n      if (declared_crc != computed_crc)\n         goto done;\n\n      if (!memcmp(type, \"IHDR\", 4))\n      {\n         /* Must be first chunk and exactly once. */\n         if (off != sizeof(png_magic_bytes) || seen_ihdr)\n            goto done;\n         seen_ihdr = true;\n      }\n      else if (!memcmp(type, \"IEND\", 4))\n      {\n         if (seen_iend) goto done;\n         seen_iend = true;\n      }\n      else if (!memcmp(type, \"IDAT\", 4))\n      {\n         if (!seen_ihdr || seen_iend) goto done;\n         idat_count++;\n      }\n      /* Other ancillary chunks are permitted without further checks. */\n\n      off += 12 + chunk_len;\n   }\n\n   /* Must have ended cleanly at end-of-file, seen IHDR and IEND\n    * exactly once each, and at least one IDAT. */\n   ret = (off == file_len) && seen_ihdr && seen_iend && idat_count > 0;\n\ndone:\n   free(buf);\n   fclose(f);\n   return ret;\n}\n\nstatic int pngcheck_available = -1; /* -1 = untested, 0 = no, 1 = yes */\n\nstatic void pngcheck_probe(void)\n{\n   /* system() returns 0 only if pngcheck is installed and the\n    * shell could locate and run it. Any other value (127 on Unix\n    * for command-not-found, whatever cmd.exe produces on Windows)\n    * treats pngcheck as unavailable. -h exits 0 on success without\n    * reading stdin; if a future pngcheck version changes that\n    * behaviour, worst case is that detection turns up missing\n    * and we silently fall back to the built-in check. */\n   pngcheck_available =\n      (system(\"pngcheck -h >/dev/null 2>&1\") == 0) ? 1 : 0;\n}\n\n/* Dispatcher. Returns true if the file passes structural\n * validation via whichever layer is active. Always runs some\n * check -- no silent skip path. */\nstatic bool structural_check_ok(const char *path)\n{\n   if (pngcheck_available > 0)\n   {\n      char cmd[1024];\n      /* -q suppresses per-chunk chatter; on success silent, on\n       * failure prints a short ERROR line. We discard both streams\n       * and just look at the exit code. */\n      snprintf(cmd, sizeof(cmd),\n            \"pngcheck -q \\\"%s\\\" >/dev/null 2>&1\", path);\n      return system(cmd) == 0;\n   }\n   return rpng_structural_check(path);\n}\n\n/* Sanity-check the built-in structural validator itself: generate\n * a known-good PNG, confirm the check accepts it; corrupt a byte,\n * confirm the check rejects it. If either expectation fails the\n * fallback is broken and we bail rather than run 93 tests under a\n * broken validator. Only runs when the external pngcheck isn't\n * available -- when it is, pngcheck's own correctness is the\n * reference. */\nstatic bool selftest_builtin_check(const char *path)\n{\n   /* Tiny 2x2 ARGB PNG. */\n   uint32_t pixels[4] = {\n      0xFFFF0000u, 0xFF00FF00u,\n      0xFF0000FFu, 0xFFFFFFFFu\n   };\n   FILE *f;\n   long  file_len_l;\n   size_t file_len;\n   uint8_t *buf = NULL;\n   size_t i;\n   bool ok_before, ok_after;\n\n   if (!rpng_save_image_argb(path, pixels, 2, 2,\n            (unsigned)(2 * sizeof(uint32_t))))\n   {\n      printf(\"[ERROR] self-test: could not generate sample PNG\\n\");\n      return false;\n   }\n\n   ok_before = rpng_structural_check(path);\n   if (!ok_before)\n   {\n      printf(\"[ERROR] self-test: built-in check rejected valid PNG\\n\");\n      return false;\n   }\n\n   /* Flip one byte roughly in the middle of the file -- with very\n    * high probability this lands inside an IDAT chunk's data and\n    * corrupts its CRC. Read the file, flip, write back. */\n   f = fopen(path, \"rb\");\n   if (!f) goto self_err;\n   if (fseek(f, 0, SEEK_END) != 0) { fclose(f); goto self_err; }\n   file_len_l = ftell(f);\n   if (file_len_l < 16) { fclose(f); goto self_err; }\n   file_len = (size_t)file_len_l;\n   if (fseek(f, 0, SEEK_SET) != 0) { fclose(f); goto self_err; }\n   buf = (uint8_t*)malloc(file_len);\n   if (!buf) { fclose(f); goto self_err; }\n   if (fread(buf, 1, file_len, f) != file_len)\n   { fclose(f); goto self_err; }\n   fclose(f);\n\n   /* Flip a byte in the back half, well past the IHDR CRC, likely\n    * inside IDAT data. */\n   i       = file_len * 3 / 4;\n   buf[i] ^= 0xFF;\n\n   f = fopen(path, \"wb\");\n   if (!f) goto self_err;\n   if (fwrite(buf, 1, file_len, f) != file_len)\n   { fclose(f); goto self_err; }\n   fclose(f);\n   free(buf); buf = NULL;\n\n   ok_after = rpng_structural_check(path);\n   if (ok_after)\n   {\n      printf(\"[ERROR] self-test: built-in check ACCEPTED corrupted PNG \"\n             \"(CRC validation broken)\\n\");\n      return false;\n   }\n\n   return true;\n\nself_err:\n   free(buf);\n   printf(\"[ERROR] self-test: I/O failure during corruption step\\n\");\n   return false;\n}\n\n\nstatic bool load_argb(const char *path, uint32_t **data,\n      unsigned *width, unsigned *height)\n{\n   int retval;\n   size_t file_len       = 0;\n   bool ret              = true;\n   rpng_t *rpng          = NULL;\n   void *ptr             = NULL;\n   struct nbio_t *handle = (struct nbio_t*)nbio_open(path, NBIO_READ);\n\n   if (!handle)\n      return false;\n\n   nbio_begin_read(handle);\n   while (!nbio_iterate(handle));\n   ptr = nbio_get_ptr(handle, &file_len);\n   if (!ptr)          { ret = false; goto done; }\n\n   rpng = rpng_alloc();\n   if (!rpng)         { ret = false; goto done; }\n   if (!rpng_set_buf_ptr(rpng, (uint8_t*)ptr, file_len))\n                      { ret = false; goto done; }\n   if (!rpng_start(rpng))\n                      { ret = false; goto done; }\n   while (rpng_iterate_image(rpng));\n   if (!rpng_is_valid(rpng))\n                      { ret = false; goto done; }\n\n   do\n   {\n      retval = rpng_process_image(rpng,\n            (void**)data, file_len, width, height, false);\n   } while (retval == IMAGE_PROCESS_NEXT);\n\n   if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)\n      ret = false;\n\ndone:\n   if (handle) nbio_free(handle);\n   if (rpng)   rpng_free(rpng);\n   if (!ret && *data) { free(*data); *data = NULL; }\n   return ret;\n}\n\n/* ---- pixel-pattern generators ---- */\n\nenum pattern\n{\n   PAT_SOLID = 0,\n   PAT_H_GRADIENT,\n   PAT_V_GRADIENT,\n   PAT_DIAGONAL,\n   PAT_PSEUDORANDOM,\n   PAT_COUNT\n};\n\nstatic const char *pattern_name(enum pattern p)\n{\n   switch (p)\n   {\n      case PAT_SOLID:        return \"solid\";\n      case PAT_H_GRADIENT:   return \"h-gradient\";\n      case PAT_V_GRADIENT:   return \"v-gradient\";\n      case PAT_DIAGONAL:     return \"diagonal\";\n      case PAT_PSEUDORANDOM: return \"pseudorandom\";\n      default:               return \"?\";\n   }\n}\n\nstatic uint32_t sample_argb(enum pattern p, unsigned x, unsigned y,\n      unsigned w, unsigned h)\n{\n   uint32_t r, g, b, a = 0xFF;\n   (void)w; (void)h;\n   switch (p)\n   {\n      case PAT_SOLID:\n         r = 0x40; g = 0x80; b = 0xC0; break;\n      case PAT_H_GRADIENT:\n         r = (uint8_t)x; g = 0x20; b = 0x80; break;\n      case PAT_V_GRADIENT:\n         r = 0x20; g = (uint8_t)y; b = 0x80; break;\n      case PAT_DIAGONAL:\n         r = (uint8_t)(x + y);\n         g = (uint8_t)(x ^ y);\n         b = (uint8_t)(x * 3 + y * 5);\n         break;\n      case PAT_PSEUDORANDOM:\n      {\n         /* Deterministic LCG-ish mix. No PRNG state, no dependency\n          * on libc rand(); we want bit-identical input across hosts. */\n         uint32_t s = (x * 2654435761u) ^ (y * 40503u);\n         r = (s >>  0) & 0xFF;\n         g = (s >>  8) & 0xFF;\n         b = (s >> 16) & 0xFF;\n         break;\n      }\n      default:\n         r = g = b = 0;\n   }\n   return (a << 24) | (r << 16) | (g << 8) | b;\n}\n\n/* ---- the actual tests ---- */\n\n/* ARGB32 round-trip: pack pattern into uint32[] (ARGB), save via\n * rpng_save_image_argb, load via load_argb, compare pixel-for-pixel. */\nstatic void test_argb_roundtrip(const char *path,\n      unsigned w, unsigned h, enum pattern pat)\n{\n   uint32_t *src = NULL;\n   uint32_t *got = NULL;\n   unsigned got_w = 0, got_h = 0;\n   unsigned x, y;\n   const char *pname = pattern_name(pat);\n\n   src = (uint32_t*)malloc((size_t)w * h * sizeof(uint32_t));\n   if (!src)\n   {\n      printf(\"[ERROR] argb %s %ux%u: OOM for source\\n\", pname, w, h);\n      failures++;\n      return;\n   }\n\n   for (y = 0; y < h; y++)\n      for (x = 0; x < w; x++)\n         src[y * w + x] = sample_argb(pat, x, y, w, h);\n\n   if (!rpng_save_image_argb(path, src,\n            w, h, (unsigned)(w * sizeof(uint32_t))))\n   {\n      printf(\"[ERROR] argb %s %ux%u: save failed\\n\", pname, w, h);\n      failures++;\n      goto out;\n   }\n\n   if (!structural_check_ok(path))\n   {\n      printf(\"[ERROR] argb %s %ux%u: structural check rejected output\\n\",\n            pname, w, h);\n      failures++;\n      /* Continue to the pixel round-trip check anyway -- a file\n       * rpng can decode but the structural check rejects is worth\n       * recording both ways. */\n   }\n\n   if (!load_argb(path, &got, &got_w, &got_h))\n   {\n      printf(\"[ERROR] argb %s %ux%u: load failed\\n\", pname, w, h);\n      failures++;\n      goto out;\n   }\n\n   if (got_w != w || got_h != h)\n   {\n      printf(\"[ERROR] argb %s %ux%u: loaded dimensions %ux%u\\n\",\n            pname, w, h, got_w, got_h);\n      failures++;\n      goto out;\n   }\n\n   for (y = 0; y < h; y++)\n   {\n      for (x = 0; x < w; x++)\n      {\n         if (src[y * w + x] != got[y * w + x])\n         {\n            printf(\"[ERROR] argb %s %ux%u: pixel (%u,%u) \"\n                   \"src=0x%08x got=0x%08x\\n\",\n                   pname, w, h, x, y,\n                   src[y * w + x], got[y * w + x]);\n            failures++;\n            goto out;\n         }\n      }\n   }\n\n   printf(\"[SUCCESS] argb %s %ux%u round-trip\\n\", pname, w, h);\n\nout:\n   free(src);\n   free(got);\n}\n\n/* BGR24 round-trip: pack pattern into uint8[] with BGR byte order,\n * save via rpng_save_image_bgr24, load, compare. The loaded form is\n * ARGB32 (alpha=0xFF), so we compare ignoring alpha. */\nstatic void test_bgr24_roundtrip(const char *path,\n      unsigned w, unsigned h, enum pattern pat, bool flip_bottom_up)\n{\n   uint8_t  *src = NULL;\n   uint32_t *got = NULL;\n   unsigned got_w = 0, got_h = 0;\n   unsigned x, y;\n   const size_t stride = (size_t)w * 3;\n   const char *pname   = pattern_name(pat);\n   const char *orient  = flip_bottom_up ? \"bottom-up\" : \"top-down\";\n\n   src = (uint8_t*)malloc(stride * h);\n   if (!src)\n   {\n      printf(\"[ERROR] bgr24 %s %s %ux%u: OOM for source\\n\",\n            pname, orient, w, h);\n      failures++;\n      return;\n   }\n\n   /* Fill source in-order regardless of orientation, so src[y*stride..]\n    * always holds the y-th image row top-down. We adjust the pointer\n    * and pitch we hand the encoder afterward. */\n   for (y = 0; y < h; y++)\n   {\n      for (x = 0; x < w; x++)\n      {\n         uint32_t px = sample_argb(pat, x, y, w, h);\n         uint8_t *p  = src + y * stride + x * 3;\n         /* BGR byte order: dst[0]=B, dst[1]=G, dst[2]=R. */\n         p[0] = (uint8_t)(px >>  0);\n         p[1] = (uint8_t)(px >>  8);\n         p[2] = (uint8_t)(px >> 16);\n      }\n   }\n\n   if (flip_bottom_up)\n   {\n      /* Emulate the task_screenshot viewport fast path: point at the\n       * last row and pass a negative pitch via the unsigned-wrap\n       * convention rpng_save_image_bgr24 uses (it casts back to\n       * signed internally). */\n      const uint8_t *last_row = src + (size_t)(h - 1) * stride;\n      if (!rpng_save_image_bgr24(path, last_row,\n               w, h, (unsigned)(-(int)stride)))\n      {\n         printf(\"[ERROR] bgr24 %s %s %ux%u: save failed\\n\",\n               pname, orient, w, h);\n         failures++;\n         goto out;\n      }\n   }\n   else\n   {\n      if (!rpng_save_image_bgr24(path, src,\n               w, h, (unsigned)stride))\n      {\n         printf(\"[ERROR] bgr24 %s %s %ux%u: save failed\\n\",\n               pname, orient, w, h);\n         failures++;\n         goto out;\n      }\n   }\n\n   if (!structural_check_ok(path))\n   {\n      printf(\"[ERROR] bgr24 %s %s %ux%u: structural check rejected output\\n\",\n            pname, orient, w, h);\n      failures++;\n      /* Continue to the pixel round-trip check anyway. */\n   }\n\n   if (!load_argb(path, &got, &got_w, &got_h))\n   {\n      printf(\"[ERROR] bgr24 %s %s %ux%u: load failed\\n\",\n            pname, orient, w, h);\n      failures++;\n      goto out;\n   }\n\n   if (got_w != w || got_h != h)\n   {\n      printf(\"[ERROR] bgr24 %s %s %ux%u: loaded dimensions %ux%u\\n\",\n            pname, orient, w, h, got_w, got_h);\n      failures++;\n      goto out;\n   }\n\n   for (y = 0; y < h; y++)\n   {\n      for (x = 0; x < w; x++)\n      {\n         /* When flip_bottom_up is true, the encoder walked source\n          * rows bottom-up via the negative-pitch trick, so PNG row\n          * y holds source row (h-1-y). Map the comparison back.\n          * Alpha is always 0xFF on the loaded side since PNG\n          * color-type-2 has no alpha. */\n         unsigned src_y    = flip_bottom_up ? (h - 1 - y) : y;\n         uint32_t exp_argb = sample_argb(pat, x, src_y, w, h) | 0xFF000000u;\n         /* Compare ignoring alpha. */\n         uint32_t got_rgb  = got[y * w + x] & 0x00FFFFFFu;\n         uint32_t exp_rgb  = exp_argb       & 0x00FFFFFFu;\n         if (got_rgb != exp_rgb)\n         {\n            printf(\"[ERROR] bgr24 %s %s %ux%u: pixel (%u,%u) \"\n                   \"exp=0x%06x got=0x%06x\\n\",\n                   pname, orient, w, h, x, y,\n                   exp_rgb, got_rgb);\n            failures++;\n            goto out;\n         }\n      }\n   }\n\n   printf(\"[SUCCESS] bgr24 %s %s %ux%u round-trip\\n\",\n         pname, orient, w, h);\n\nout:\n   free(src);\n   free(got);\n}\n\n/* ---- harness ---- */\n\nstruct size_case { unsigned w, h; };\n\nstatic const struct size_case sizes[] = {\n   {  4,   4},   /* smoke: sub-chunk, stresses filter-buffer init */\n   { 37,  29},   /* non-round, not aligned to any natural boundary */\n   {320, 240}    /* screenshot-shaped, spans many deflate output chunks */\n};\n\n/* Targeted width fuzz: catches off-by-one regressions in the\n * encoder at size boundaries a full-buffer encode might handle\n * correctly but a streaming-deflate encoder could get wrong.\n *\n *   - width=1,2,3:  degenerate; exercises filter loops near the\n *                   per-pixel-stride boundary (filter_sub et al\n *                   read line[i - bpp], so widths <= bpp are the\n *                   narrowest valid inputs).\n *   - width=8,32:   common SIMD alignment boundaries for any\n *                   future vectorised filter.\n *   - width=31,33:  one-off-from-32, catches alignment-vs-tail\n *                   boundary bugs.\n *   - width=257:    one-off-from-256, same idea at a larger size.\n *\n * Pair each width with height=1 (single-row; no valid prev-row\n * data, up/avg/paeth filters see only the zero-initialised\n * prev_encoded buffer) and height=3 (exercises the normal\n * multi-row path at a small enough total size that deflate may\n * produce zero output on early trans() calls -- a case a\n * streaming-deflate loop has to handle correctly). */\nstatic const unsigned fuzz_widths[]  = {1, 2, 3, 8, 31, 32, 33, 257};\nstatic const unsigned fuzz_heights[] = {1, 3};\n\n/* Large-size fuzz: crosses boundaries a streaming-deflate encoder\n * is most likely to be sensitive to, without making the test slow.\n *\n *   1024x1:    single wide row, ~3 KiB. Tests a long per-row\n *              filter loop that exceeds typical L1 cache line\n *              boundaries but fits in a single deflate chunk.\n *   1x1024:    tall thin; 1024 row-boundary transitions packed\n *              into ~4 KiB. A streaming encoder's per-row reset\n *              / state-carry logic gets exercised far more times\n *              per byte than on typical inputs.\n *   2048x1:    6 KiB single row, likely to cross common\n *              chosen-chunk-size thresholds (a 4 KiB or 8 KiB\n *              deflate output buffer would see mid-row boundaries).\n *   1x12000:   ~48 KiB total input, crosses zlib's default 32 KiB\n *              sliding window. Tests that deflate's internal\n *              window-shift logic plays correctly with a row-by-row\n *              feeder. Bounded to stay fast under ASan. */\nstatic const struct size_case large_fuzz[] = {\n   {1024,     1},\n   {   1,  1024},\n   {2048,     1},\n   {   1, 12000}\n};\n\n\nint main(int argc, char *argv[])\n{\n   const char *path = \"./rpng_roundtrip_tmp.png\";\n   size_t i;\n   int p;\n\n   if (argc > 2)\n   {\n      printf(\"Usage: %s [tmp-png-path]\\n\", argv[0]);\n      return 1;\n   }\n   if (argc == 2)\n      path = argv[1];\n\n   printf(\"Writing temp PNG to: %s\\n\", path);\n\n   pngcheck_probe();\n   if (pngcheck_available)\n      printf(\"[INFO] pngcheck found, using external structural validation\\n\");\n   else\n   {\n      printf(\"[INFO] pngcheck not found, using built-in structural validation\\n\");\n      if (!selftest_builtin_check(path))\n      {\n         printf(\"\\nBuilt-in structural validator self-test failed. \"\n                \"Aborting before running pixel round-trip tests under \"\n                \"a broken validator.\\n\");\n         return 1;\n      }\n      printf(\"[INFO] built-in validator self-test passed\\n\");\n   }\n\n   for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++)\n   {\n      for (p = 0; p < PAT_COUNT; p++)\n      {\n         test_argb_roundtrip (path, sizes[i].w, sizes[i].h, (enum pattern)p);\n         test_bgr24_roundtrip(path, sizes[i].w, sizes[i].h, (enum pattern)p, false);\n         test_bgr24_roundtrip(path, sizes[i].w, sizes[i].h, (enum pattern)p, true);\n      }\n   }\n\n   /* Width-boundary fuzz. One pattern (pseudorandom, least likely\n    * to hit filter fast paths) across several widths at height=1\n    * and height=3 each, for all three entry points. Catches\n    * size-boundary regressions that the hand-picked sizes above\n    * could miss -- in particular, bugs that surface when deflate\n    * produces zero or small output on early trans() calls. */\n   {\n      size_t wi, hi;\n      for (wi = 0; wi < sizeof(fuzz_widths)  / sizeof(fuzz_widths[0]);  wi++)\n      {\n         for (hi = 0; hi < sizeof(fuzz_heights) / sizeof(fuzz_heights[0]); hi++)\n         {\n            unsigned w = fuzz_widths[wi];\n            unsigned h = fuzz_heights[hi];\n            test_argb_roundtrip (path, w, h, PAT_PSEUDORANDOM);\n            test_bgr24_roundtrip(path, w, h, PAT_PSEUDORANDOM, false);\n            test_bgr24_roundtrip(path, w, h, PAT_PSEUDORANDOM, true);\n         }\n      }\n   }\n\n   /* Large-size fuzz. Targets deflate-internal state-transition\n    * boundaries a streaming-deflate rewrite is most likely to get\n    * wrong: long single rows (mid-row chunk-size boundaries in the\n    * deflate output), many short rows (per-row state-carry\n    * logic stressed), and total input size exceeding zlib's\n    * default 32 KiB sliding window. Pseudorandom pattern only;\n    * runs at all three entry points. */\n   {\n      size_t li;\n      for (li = 0; li < sizeof(large_fuzz) / sizeof(large_fuzz[0]); li++)\n      {\n         unsigned w = large_fuzz[li].w;\n         unsigned h = large_fuzz[li].h;\n         test_argb_roundtrip (path, w, h, PAT_PSEUDORANDOM);\n         test_bgr24_roundtrip(path, w, h, PAT_PSEUDORANDOM, false);\n         test_bgr24_roundtrip(path, w, h, PAT_PSEUDORANDOM, true);\n      }\n   }\n\n   /* Best-effort cleanup; not fatal if it fails. */\n   remove(path);\n\n   if (failures)\n   {\n      printf(\"\\n%d rpng round-trip test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll rpng round-trip regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/png/rpng_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rpng_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n#ifdef HAVE_IMLIB2\n#include <Imlib2.h>\n#endif\n\n#include <file/nbio.h>\n#include <formats/rpng.h>\n#include <formats/image.h>\n\nstatic bool rpng_load_image_argb(const char *path, uint32_t **data,\n      unsigned *width, unsigned *height)\n{\n   int retval;\n   size_t file_len;\n   bool              ret = true;\n   rpng_t          *rpng = NULL;\n   void             *ptr = NULL;\n   struct nbio_t* handle = (struct nbio_t*)nbio_open(path, NBIO_READ);\n\n   if (!handle)\n      goto end;\n\n   nbio_begin_read(handle);\n\n   while (!nbio_iterate(handle));\n\n   ptr = nbio_get_ptr(handle, &file_len);\n\n   if (!ptr)\n   {\n      ret = false;\n      goto end;\n   }\n\n   rpng = rpng_alloc();\n\n   if (!rpng)\n   {\n      ret = false;\n      goto end;\n   }\n\n   if (!rpng_set_buf_ptr(rpng, (uint8_t*)ptr, file_len))\n   {\n      ret = false;\n      goto end;\n   }\n\n   if (!rpng_start(rpng))\n   {\n      ret = false;\n      goto end;\n   }\n\n   while (rpng_iterate_image(rpng));\n\n   if (!rpng_is_valid(rpng))\n   {\n      ret = false;\n      goto end;\n   }\n\n   do\n   {\n      retval = rpng_process_image(rpng,\n            (void**)data, file_len, width, height, false);\n   }while(retval == IMAGE_PROCESS_NEXT);\n\n   if (retval == IMAGE_PROCESS_ERROR || retval == IMAGE_PROCESS_ERROR_END)\n      ret = false;\n\nend:\n   if (handle)\n      nbio_free(handle);\n   if (rpng)\n      rpng_free(rpng);\n   rpng = NULL;\n   if (!ret)\n      free(*data);\n   return ret;\n}\n\nstatic int test_rpng(const char *in_path)\n{\n#ifdef HAVE_IMLIB2\n   Imlib_Image img;\n   const uint32_t *imlib_data = NULL;\n#endif\n   const uint32_t test_data[] = {\n      0xff000000 | 0x50, 0xff000000 | 0x80,\n      0xff000000 | 0x40, 0xff000000 | 0x88,\n      0xff000000 | 0x50, 0xff000000 | 0x80,\n      0xff000000 | 0x40, 0xff000000 | 0x88,\n      0xff000000 | 0xc3, 0xff000000 | 0xd3,\n      0xff000000 | 0xc3, 0xff000000 | 0xd3,\n      0xff000000 | 0xc3, 0xff000000 | 0xd3,\n      0xff000000 | 0xc3, 0xff000000 | 0xd3,\n   };\n   uint32_t *data = NULL;\n   unsigned width = 0;\n   unsigned height = 0;\n\n   if (!rpng_save_image_argb(\"/tmp/test.png\", test_data, 4, 4, 16))\n      return 1;\n\n   if (!rpng_load_image_argb(in_path, &data, &width, &height))\n      return 2;\n\n   fprintf(stderr, \"Path: %s.\\n\", in_path);\n   fprintf(stderr, \"Got image: %u x %u.\\n\", width, height);\n\n   fprintf(stderr, \"\\nRPNG:\\n\");\n   for (unsigned h = 0; h < height; h++)\n   {\n      unsigned w;\n      for (w = 0; w < width; w++)\n         fprintf(stderr, \"[%08x] \", data[h * width + w]);\n      fprintf(stderr, \"\\n\");\n   }\n\n#ifdef HAVE_IMLIB2\n   /* Validate with imlib2 as well. */\n   img = imlib_load_image(in_path);\n   if (!img)\n      return 4;\n\n   imlib_context_set_image(img);\n\n   width      = imlib_image_get_width();\n   height     = imlib_image_get_width();\n   imlib_data = imlib_image_get_data_for_reading_only();\n\n   fprintf(stderr, \"\\nImlib:\\n\");\n   for (unsigned h = 0; h < height; h++)\n   {\n      for (unsigned w = 0; w < width; w++)\n         fprintf(stderr, \"[%08x] \", imlib_data[h * width + w]);\n      fprintf(stderr, \"\\n\");\n   }\n\n   if (memcmp(imlib_data, data, width * height * sizeof(uint32_t)) != 0)\n   {\n      fprintf(stderr, \"Imlib and RPNG differs!\\n\");\n      return 5;\n   }\n   else\n      fprintf(stderr, \"Imlib and RPNG are equivalent!\\n\");\n\n   imlib_free_image();\n#endif\n   free(data);\n\n   return 0;\n}\n\nint main(int argc, char *argv[])\n{\n   const char *in_path = \"/tmp/test.png\";\n\n   if (argc > 2)\n   {\n      fprintf(stderr, \"Usage: %s <png file>\\n\", argv[0]);\n      return 1;\n   }\n\n   if (argc == 2)\n      in_path = argv[1];\n\n   fprintf(stderr, \"Doing tests...\\n\");\n\n   if (test_rpng(in_path) != 0)\n   {\n      fprintf(stderr, \"Test failed.\\n\");\n      return -1;\n   }\n\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/tga/Makefile",
    "content": "TARGET := rtga_test\n\nLIBRETRO_COMM_DIR := ../../..\n\nSOURCES := \\\n\trtga_test.c \\\n\t$(LIBRETRO_COMM_DIR)/formats/tga/rtga.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/formats/tga/rtga_test.c",
    "content": "/* Regression tests for libretro-common/formats/tga/rtga.c\n *\n * Targets:\n *\n *  1. Header-level palette validation.  Pre-patch a crafted TGA\n *     with tga_indexed=1 and tga_palette_bits=255 let the indexed\n *     read loop\n *          for (j = 0; j * 8 < tga_palette_bits; ++j)\n *              raw_data[j] = tga_palette[pal_idx + j];\n *     iterate j=0..31, writing up to 32 bytes into a 4-byte stack\n *     array raw_data[4].  This is a directly reachable stack\n *     buffer overflow driven by a single attacker-controlled\n *     header byte.  Under ASan the unpatched decoder reports\n *     \"stack-buffer-overflow WRITE of size 1\" inside the indexed\n *     read loop.  Post-patch the header check rejects\n *     palette_bits not in {15, 16, 24, 32} and the decoder\n *     returns IMAGE_PROCESS_ERROR cleanly.\n *\n *  2. Rejection of indexed TGA with empty palette (palette_len=0).\n *     Pre-patch the indexed code clamped pal_idx to 0 and then\n *     read tga_palette[0] from a malloc(0) buffer -- OOB read.\n *\n *  3. Happy-path decode of a tiny 2x2 uncompressed RGB TGA --\n *     smoke test for the fast path.\n *\n *  4. Rejection of a TGA whose declared size > INT_MAX.  Pre-patch\n *     the (int)size cast in rtga_process_image truncated and\n *     propagated a negative \"len\" into the buffer-end pointer.\n *     This is hard to reproduce without > 2 GiB of memory so we\n *     simulate with a small buffer and a size_t value that would\n *     pre-patch have truncated; post-patch we get an early\n *     IMAGE_PROCESS_ERROR without even calling the decoder.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <formats/rtga.h>\n#include <formats/image.h>\n\nstatic int failures = 0;\n\n/* Build a TGA header into `out` starting at offset 0.\n * Returns the header size (always 18). */\nstatic int make_tga_header(uint8_t *out,\n      uint8_t id_len,\n      uint8_t cmap_type,\n      uint8_t image_type,\n      uint16_t cmap_start,\n      uint16_t cmap_len,\n      uint8_t cmap_bits,\n      uint16_t width,\n      uint16_t height,\n      uint8_t bpp,\n      uint8_t descriptor)\n{\n   out[0]  = id_len;\n   out[1]  = cmap_type;\n   out[2]  = image_type;\n   out[3]  = (uint8_t)(cmap_start & 0xFF);\n   out[4]  = (uint8_t)(cmap_start >> 8);\n   out[5]  = (uint8_t)(cmap_len & 0xFF);\n   out[6]  = (uint8_t)(cmap_len >> 8);\n   out[7]  = cmap_bits;\n   out[8]  = 0; out[9]  = 0; /* x origin */\n   out[10] = 0; out[11] = 0; /* y origin */\n   out[12] = (uint8_t)(width & 0xFF);\n   out[13] = (uint8_t)(width >> 8);\n   out[14] = (uint8_t)(height & 0xFF);\n   out[15] = (uint8_t)(height >> 8);\n   out[16] = bpp;\n   out[17] = descriptor;\n   return 18;\n}\n\nstatic void test_malicious_palette_bits(void)\n{\n   /* Indexed uncompressed TGA, 1x1 pixel, palette_bits = 255.\n    * Pre-patch: stack-buffer-overflow on raw_data[4..31]. */\n   uint8_t file[128];\n   rtga_t *rtga;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   int hdr_len;\n   memset(file, 0, sizeof(file));\n\n   hdr_len = make_tga_header(file,\n         /* id_len      */ 0,\n         /* cmap_type   */ 1,\n         /* image_type  */ 1,     /* indexed uncompressed */\n         /* cmap_start  */ 0,\n         /* cmap_len    */ 1,\n         /* cmap_bits   */ 255,   /* THE ATTACK */\n         /* width       */ 1,\n         /* height      */ 1,\n         /* bpp         */ 8,\n         /* descriptor  */ 0);\n   /* A few bytes of \"palette\" and one pixel index -- doesn't matter\n    * what they are, we expect to fail at the header check. */\n   file[hdr_len]   = 0xFF;\n   file[hdr_len+1] = 0xFF;\n   file[hdr_len+2] = 0x00;  /* pal_idx = 0 */\n\n   rtga = rtga_alloc();\n   rtga_set_buf_ptr(rtga, file);\n   rc = rtga_process_image(rtga, &out, (size_t)hdr_len + 16, &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_ERROR)\n   {\n      printf(\"[ERROR] malicious palette_bits=255 was not rejected \"\n             \"(rc=%d, w=%u h=%u out=%p)\\n\", rc, w, h, out);\n      failures++;\n      free(out);\n   }\n   else\n      printf(\"[SUCCESS] TGA palette_bits=255 rejected at header\\n\");\n   rtga_free(rtga);\n}\n\nstatic void test_empty_indexed_palette(void)\n{\n   /* Indexed TGA with cmap_len = 0.  Pre-patch this malloc'd a\n    * 0-byte palette and the indexed read was OOB. */\n   uint8_t file[64];\n   rtga_t *rtga;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   int hdr_len;\n   memset(file, 0, sizeof(file));\n\n   hdr_len = make_tga_header(file, 0, 1, 1, 0,\n         /* cmap_len=   */ 0,\n         /* cmap_bits=  */ 24,\n         1, 1, 8, 0);\n   file[hdr_len] = 0x00;\n\n   rtga = rtga_alloc();\n   rtga_set_buf_ptr(rtga, file);\n   rc = rtga_process_image(rtga, &out, (size_t)hdr_len + 8, &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_ERROR)\n   {\n      printf(\"[ERROR] empty palette was not rejected \"\n             \"(rc=%d out=%p)\\n\", rc, out);\n      failures++;\n      free(out);\n   }\n   else\n      printf(\"[SUCCESS] TGA indexed with empty palette rejected\\n\");\n   rtga_free(rtga);\n}\n\nstatic void test_happy_path_rgb(void)\n{\n   /* 2x2 uncompressed 24bpp BGR.  Just a smoke test. */\n   uint8_t file[64];\n   rtga_t *rtga;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   int hdr_len;\n   int i;\n   memset(file, 0, sizeof(file));\n\n   hdr_len = make_tga_header(file, 0, 0,\n         /* image_type= */ 2,    /* uncompressed RGB */\n         0, 0, 0,\n         /* width */ 2,\n         /* height*/ 2,\n         /* bpp   */ 24,\n         /* descr */ 0);\n   /* 4 pixels * 3 bytes */\n   for (i = 0; i < 4 * 3; ++i)\n      file[hdr_len + i] = (uint8_t)(0x10 * i);\n\n   rtga = rtga_alloc();\n   rtga_set_buf_ptr(rtga, file);\n   rc = rtga_process_image(rtga, &out, (size_t)hdr_len + 12, &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_END || w != 2 || h != 2 || !out)\n   {\n      printf(\"[ERROR] happy-path decode: rc=%d w=%u h=%u out=%p\\n\",\n            rc, w, h, out);\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] TGA 2x2 RGB happy path\\n\");\n   free(out);\n   rtga_free(rtga);\n}\n\nstatic void test_oversized_size(void)\n{\n   /* A size > INT_MAX should be rejected before the (int)size\n    * cast that pre-patch produced a negative buffer-length. */\n   uint8_t file[32];\n   rtga_t *rtga;\n   void *out = NULL;\n   unsigned w = 0, h = 0;\n   int rc;\n   memset(file, 0, sizeof(file));\n   /* The file contents don't matter -- we expect an early-out. */\n\n   rtga = rtga_alloc();\n   rtga_set_buf_ptr(rtga, file);\n   rc = rtga_process_image(rtga, &out, (size_t)0x100000000ULL,\n         &w, &h, true);\n\n   if (rc != IMAGE_PROCESS_ERROR)\n   {\n      printf(\"[ERROR] oversized size not rejected (rc=%d)\\n\", rc);\n      failures++;\n      free(out);\n   }\n   else\n      printf(\"[SUCCESS] TGA with size > INT_MAX rejected\\n\");\n   rtga_free(rtga);\n}\n\nint main(void)\n{\n   test_malicious_palette_bits();\n   test_empty_indexed_palette();\n   test_happy_path_rgb();\n   test_oversized_size();\n\n   if (failures)\n   {\n      printf(\"\\n%d rtga test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll rtga regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/formats/xml/Makefile",
    "content": "TARGET := rxml\n\nLIBRETRO_XML_DIR  := ../../../formats/xml\nLIBRETRO_COMM_DIR := ../../../\nLIBRETRO_DEPS_DIR := ../../../../deps\n\nSOURCES := \\\n\trxml_test.c \\\n\t$(LIBRETRO_XML_DIR)/rxml.c \\\n\t$(LIBRETRO_DEPS_DIR)/yxml/yxml.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -DRXML_TEST -Wall -pedantic -std=gnu99 -g -I$(LIBRETRO_COMM_DIR)/include\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/formats/xml/rxml_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rxml_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <formats/rxml.h>\n#include <stdio.h>\n\nstatic void print_siblings(struct rxml_node *node, unsigned level)\n{\n   fprintf(stderr, \"\\n%*sName: %s\\n\", level * 4, \"\", node->name);\n   if (node->data)\n      fprintf(stderr, \"%*sData: %s\\n\", level * 4, \"\", node->data);\n\n   for (const struct rxml_attrib_node *attrib =\n         node->attrib; attrib; attrib = attrib->next)\n      fprintf(stderr, \"%*s  Attrib: %s = %s\\n\", level * 4, \"\",\n            attrib->attrib, attrib->value);\n\n   if (node->children)\n      print_siblings(node->children, level + 1);\n\n   if (node->next)\n      print_siblings(node->next, level);\n}\n\nstatic void rxml_log_document(const char *path)\n{\n   rxml_document_t *doc = rxml_load_document(path);\n   if (!doc)\n   {\n      fprintf(stderr, \"rxml: Failed to load document: %s\\n\", path);\n      return;\n   }\n\n   print_siblings(rxml_root_node(doc), 0);\n   rxml_free_document(doc);\n}\n\nint main(int argc, char *argv[])\n{\n   if (argc != 2)\n   {\n      fprintf(stderr, \"Usage: %s <path>\\n\", argv[0]);\n      return 1;\n   }\n\n   rxml_log_document(argv[1]);\n}\n"
  },
  {
    "path": "samples/net/Makefile",
    "content": "TARGETS  = http_test http_parse_test net_ifinfo\n\nLIBRETRO_COMM_DIR := ../..\n\nINCFLAGS = -I$(LIBRETRO_COMM_DIR)/include\n\nifeq ($(platform),)\nplatform = unix\nifeq ($(shell uname -a),)\n   platform = win\nelse ifneq ($(findstring Darwin,$(shell uname -a)),)\n   platform = osx\n\tarch = intel\nifeq ($(shell uname -p),powerpc)\n\tarch = ppc\nendif\nelse ifneq ($(findstring MINGW,$(shell uname -a)),)\n   platform = win\nendif\nendif\n\nifeq ($(DEBUG),1)\nCFLAGS += -O0 -g\nelse\nCFLAGS += -O2\nendif\nCFLAGS += -Wall -pedantic -std=gnu99\n\nHTTP_TEST_C = \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_http.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_compat.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_socket.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/features/features_cpu.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/lists/string_list.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/string/stdstring.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t\t\t\t  net_http_test.c\n\nHTTP_TEST_OBJS := $(HTTP_TEST_C:.c=.o)\n\nHTTP_PARSE_TEST_C = \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_http.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_http_parse.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_compat.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/net/net_socket.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/features/features_cpu.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/lists/string_list.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/string/stdstring.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/time/rtime.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t\t\t\t  $(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t\t\t\t  net_http_parse_test.c\n\nHTTP_PARSE_TEST_OBJS := $(HTTP_PARSE_TEST_C:.c=.o)\n\nNET_IFINFO_C = \\\n\t\t\t\t\t$(LIBRETRO_COMM_DIR)/net/net_ifinfo.c \\\n\t\t\t\t\t$(LIBRETRO_COMM_DIR)/net/net_compat.c \\\n\t\t\t\t\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t\t\t\t\tnet_ifinfo_test.c\n\nifeq ($(platform), win)\nCFLAGS += -liphlpapi -lws2_32\nendif\n\nNET_IFINFO_OBJS := $(NET_IFINFO_C:.c=.o)\n\n.PHONY: all clean\n\nall: $(TARGETS)\n\n%.o: %.c\n\t$(CC) $(INCFLAGS) $< -c $(CFLAGS) -o $@\n\nhttp_parse_test: $(HTTP_PARSE_TEST_OBJS)\n\t$(CC) $(INCFLAGS) $(HTTP_PARSE_TEST_OBJS) $(CFLAGS) -o $@\n\nhttp_test: $(HTTP_TEST_OBJS)\n\t$(CC) $(INCFLAGS) $(HTTP_TEST_OBJS) $(CFLAGS) -o $@\n\nnet_ifinfo: $(NET_IFINFO_OBJS)\n\t$(CC) $(INCFLAGS) $(NET_IFINFO_OBJS) $(CFLAGS) -o $@\n\nclean:\n\trm -rf $(TARGETS) $(HTTP_TEST_OBJS) $(HTTP_PARSE_TEST_OBJS) $(NET_IFINFO_OBJS)\n"
  },
  {
    "path": "samples/net/net_http_parse_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_http_parse_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <net/net_http_parse.h>\n\nstatic int failures = 0;\n\nstatic void test_happy_path(void)\n{\n   char link[1024];\n   char name[1024];\n   const char *line = \"<a href=\\\"http://www.test.com/somefile.zip\\\">Test</a>\\n\";\n   int rc;\n\n   link[0] = name[0] = '\\0';\n   rc = string_parse_html_anchor(line, link, name, sizeof(link), sizeof(name));\n\n   if (rc != 0)\n   {\n      printf(\"[ERROR] happy path: rc=%d, want 0\\n\", rc);\n      failures++;\n      return;\n   }\n   if (strcmp(link, \"http://www.test.com/somefile.zip\") != 0)\n   {\n      printf(\"[ERROR] happy path: link='%s'\\n\", link);\n      failures++;\n      return;\n   }\n   if (strcmp(name, \"Test\") != 0)\n   {\n      printf(\"[ERROR] happy path: name='%s'\\n\", name);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] happy path: link='%s' name='%s'\\n\", link, name);\n}\n\nstatic void test_no_anchor(void)\n{\n   char link[64];\n   char name[64];\n   int rc;\n\n   rc = string_parse_html_anchor(\"no anchor here\", link, name,\n         sizeof(link), sizeof(name));\n\n   if (rc == 0)\n   {\n      printf(\"[ERROR] no-anchor: rc=0, want 1\\n\");\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] no-anchor returned %d\\n\", rc);\n}\n\nstatic void test_undersized_link_buffer(void)\n{\n   /* The href is 41 characters.  Supply a 10-byte link buffer.\n    * Pre-patch: memcpy copies 41 bytes into link[10] -- stack\n    * smashing / canary hit / ASan heap-buffer-overflow.\n    * Post-patch: len clamps to 9, link[9] = NUL, safe truncation. */\n   char link[10];   /* deliberately too small */\n   char name[64];\n   char canary[16]; /* stack canary to detect over-write */\n   const char *line = \"<a href=\\\"http://www.test.com/somefile.zip\\\">Test</a>\";\n   int rc;\n\n   /* Fill canary with a known pattern.  A pre-patch run smashes\n    * link[] and onto the adjacent stack slot; the canary gets\n    * corrupted.  Post-patch leaves it alone. */\n   memset(canary, 0xAA, sizeof(canary));\n   link[0] = name[0] = '\\0';\n\n   rc = string_parse_html_anchor(line, link, name,\n         sizeof(link), sizeof(name));\n   (void)rc;\n\n   /* Check the canary is intact.  (Result of rc is don't-care:\n    * post-patch should still return 0 with a truncated link.) */\n   {\n      size_t i;\n      for (i = 0; i < sizeof(canary); ++i)\n      {\n         if ((unsigned char)canary[i] != 0xAA)\n         {\n            printf(\"[ERROR] undersized-link: canary corrupted at offset %zu\\n\", i);\n            failures++;\n            return;\n         }\n      }\n   }\n\n   /* The link buffer must be NUL-terminated somewhere in [0, 9]. */\n   {\n      int found_nul = 0;\n      size_t i;\n      for (i = 0; i < sizeof(link); ++i)\n      {\n         if (link[i] == '\\0')\n         {\n            found_nul = 1;\n            break;\n         }\n      }\n      if (!found_nul)\n      {\n         printf(\"[ERROR] undersized-link: output not NUL-terminated\\n\");\n         failures++;\n         return;\n      }\n   }\n\n   printf(\"[SUCCESS] undersized-link: truncated link='%s' (buffer safe)\\n\", link);\n}\n\nstatic void test_undersized_name_buffer(void)\n{\n   char link[256];\n   char name[3];    /* deliberately too small for \"Test\" */\n   char canary[16];\n   const char *line = \"<a href=\\\"http://x.com/\\\">Test</a>\";\n   int rc;\n\n   memset(canary, 0xBB, sizeof(canary));\n   link[0] = name[0] = '\\0';\n\n   rc = string_parse_html_anchor(line, link, name,\n         sizeof(link), sizeof(name));\n   (void)rc;\n\n   {\n      size_t i;\n      for (i = 0; i < sizeof(canary); ++i)\n      {\n         if ((unsigned char)canary[i] != 0xBB)\n         {\n            printf(\"[ERROR] undersized-name: canary corrupted at offset %zu\\n\", i);\n            failures++;\n            return;\n         }\n      }\n   }\n   {\n      int found_nul = 0;\n      size_t i;\n      for (i = 0; i < sizeof(name); ++i)\n      {\n         if (name[i] == '\\0')\n         {\n            found_nul = 1;\n            break;\n         }\n      }\n      if (!found_nul)\n      {\n         printf(\"[ERROR] undersized-name: output not NUL-terminated\\n\");\n         failures++;\n         return;\n      }\n   }\n   printf(\"[SUCCESS] undersized-name: truncated name='%s' (buffer safe)\\n\", name);\n}\n\nint main(void)\n{\n   test_happy_path();\n   test_no_anchor();\n   test_undersized_link_buffer();\n   test_undersized_name_buffer();\n\n   if (failures)\n   {\n      printf(\"\\n%d net_http_parse test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll net_http_parse regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/net/net_http_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_http_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <net/net_http.h>\n#include <net/net_compat.h>\n\n#ifdef _WIN32\n#include <winsock2.h>\n#endif\n\n/* Issue a single HTTP GET and print the first 256 bytes of the\n * response.  Sample usage of the two-stage connection API:\n *\n *    1. net_http_connection_new(url, method, data)  -- handle\n *    2. loop net_http_connection_iterate until connection is up\n *    3. check net_http_connection_done for success\n *    4. net_http_new(conn)  -- transfer handle\n *    5. loop net_http_update until transfer is complete\n *    6. net_http_data -- fetch the response body\n *    7. net_http_delete + net_http_connection_free\n */\nstatic int http_get_and_print(const char *url)\n{\n   struct http_connection_t *conn;\n   struct http_t *http;\n   uint8_t *data;\n   size_t _len = 0, pos = 0, tot = 0;\n\n   conn = net_http_connection_new(url, \"GET\", NULL);\n   if (!conn)\n   {\n      fprintf(stderr, \"net_http_connection_new failed for %s\\n\", url);\n      return -1;\n   }\n\n   /* Drive the connection state machine to completion. */\n   while (!net_http_connection_iterate(conn)) {}\n   if (!net_http_connection_done(conn))\n   {\n      fprintf(stderr, \"net_http_connection_done failed for %s\\n\", url);\n      net_http_connection_free(conn);\n      return -1;\n   }\n\n   http = net_http_new(conn);\n   if (!http)\n   {\n      fprintf(stderr, \"net_http_new failed for %s\\n\", url);\n      net_http_connection_free(conn);\n      return -1;\n   }\n\n   while (!net_http_update(http, &pos, &tot))\n      printf(\"%9lu / %9lu    \\r\", (unsigned long)pos, (unsigned long)tot);\n   printf(\"\\n\");\n\n   data = net_http_data(http, &_len, false);\n   if (data && _len > 0)\n      printf(\"%.*s\\n\", (int)(_len < 256 ? _len : 256), (const char*)data);\n\n   net_http_delete(http);\n   net_http_connection_free(conn);\n   return 0;\n}\n\nint main(void)\n{\n   if (!network_init())\n      return -1;\n\n   http_get_and_print(\"http://buildbot.libretro.com/nightly/windows/x86_64/latest/mednafen_psx_libretro.dll.zip\");\n   http_get_and_print(\"http://www.wikipedia.org/\");\n\n   return 0;\n}\n"
  },
  {
    "path": "samples/net/net_ifinfo_test.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (net_ifinfo_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <net/net_ifinfo.h>\n\nint main(int argc, const char *argv[])\n{\n   unsigned k              = 0;\n   net_ifinfo_t list;\n\n   if (!net_ifinfo_new(&list))\n      return -1;\n\n   for (k = 0; k < list.size; k++)\n   {\n      printf(\"%s:%s\\n\", list.entries[k].name, list.entries[k].host);\n   }\n\n   net_ifinfo_free(&list);\n\n   return 0;\n}\n"
  },
  {
    "path": "samples/net/udp-test.c",
    "content": "/* public domain */\n/* gcc -o udptest udp-test.c */\n\n/*\n   will send \"RETROPAD RIGHT\" indefinely to player 1\n   to send to player 2 change port to 55401 and so on\n*/\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <arpa/inet.h>\n#include <sys/socket.h>\n\n#define SERVER \"127.0.0.1\"\n#define PORT 55400\n\nvoid die(char *s)\n{\n    perror(s);\n    exit(1);\n}\n\nint main(void)\n{\n   struct sockaddr_in si_other;\n   int s, i, slen=sizeof(si_other);\n\n   if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)\n      die(\"socket\");\n\n   memset((char *) &si_other, 0, sizeof(si_other));\n   si_other.sin_family = AF_INET;\n   si_other.sin_port = htons(PORT);\n\n   if (inet_aton(SERVER , &si_other.sin_addr) == 0)\n   {\n      fprintf(stderr, \"inet_aton() failed\\n\");\n      exit(1);\n   }\n\n   for (;;)\n   {\n      char message[10]=\"128\";\n      /* send the message */\n      if (sendto(s, message, strlen(message) , 0 , (struct sockaddr *) &si_other, slen)==-1)\n         die(\"sendto()\");\n\n      /* sleep for 1 frame (60hz) */\n      usleep(16*1000);\n   }\n\n   close(s);\n   return 0;\n}\n"
  },
  {
    "path": "samples/queues/retro_spsc_test/Makefile",
    "content": "TARGET := retro_spsc_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# retro_spsc.c is the lock-free SPSC byte queue under test; the test\n# harness drives a producer and consumer thread through rthreads.c\n# (HAVE_THREADS).  retro_atomic.h is header-only and pulled in via\n# the queue's transitive includes.\n#\n# Build under SANITIZER=thread (TSan) for the regression-catching\n# CI run; SANITIZER=address,undefined as the default for the\n# auto-discovery workflow gives a coarser smoke test.  Both pass on\n# correct code.\nSOURCES := \\\n\tretro_spsc_test.c \\\n\t$(LIBRETRO_COMM_DIR)/queues/retro_spsc.c \\\n\t$(LIBRETRO_COMM_DIR)/rthreads/rthreads.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS  += -Wall -pedantic -std=gnu99 -g -O0 \\\n           -DHAVE_THREADS -I$(LIBRETRO_COMM_DIR)/include\nLDFLAGS += -lpthread\n# rthreads.c uses clock_gettime + CLOCK_REALTIME on Linux glibc; on\n# older glibc those live in -lrt.  Harmless on newer glibc.\nLDFLAGS += -lrt\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/queues/retro_spsc_test/retro_spsc_test.c",
    "content": "/* SPSC stress test: producer pushes N bytes total; consumer reads N\n * bytes; verify the byte stream is exactly an expected sequence.\n * Validates ordering, no torn reads, no duplicates, no drops.\n *\n * Design notes:\n *   - Producer writes incrementing 32-bit \"tokens\" (i = 1, 2, 3, ...).\n *   - Consumer reads the byte stream and reassembles tokens.\n *   - Each token is checked against expected sequence; mismatch =>\n *     reordering or torn write.\n *   - Producer/consumer race in tight loops with no per-iteration\n *     handshake; a real lock-free SPSC must handle this concurrency\n *     without external synchronisation.\n *   - Run under TSan for race detection.  Run without sanitizer for\n *     throughput sanity. */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_spsc.h>\n#include <rthreads/rthreads.h>\n\n/* Total tokens to push.  ~10M gives a reproducible test of <2s on\n * x86_64; under qemu-aarch64 and TSan it's ~30s. */\n#define TOTAL_TOKENS 10000000\n\n/* Buffer capacity in bytes.  Smaller -> more producer/consumer\n * interleaving (better race coverage); larger -> better throughput\n * but less torture. */\n#define BUF_BYTES 4096\n\ntypedef struct\n{\n   retro_spsc_t  q;\n   /* Captured by the producer's loop sentinel and read by main after\n    * join, so it doesn't need to be atomic. */\n   unsigned long mismatches;\n   unsigned long produced_tokens;\n   unsigned long consumed_tokens;\n} test_state_t;\n\nstatic void producer_thread(void *arg)\n{\n   test_state_t *s = (test_state_t*)arg;\n   uint32_t      token;\n\n   for (token = 1; token <= TOTAL_TOKENS; token++)\n   {\n      /* Spin until there is room for a full token. */\n      while (retro_spsc_write_avail(&s->q) < sizeof(token))\n         ; /* spin */\n      retro_spsc_write(&s->q, &token, sizeof(token));\n      s->produced_tokens++;\n   }\n}\n\nstatic void consumer_thread(void *arg)\n{\n   test_state_t *s              = (test_state_t*)arg;\n   uint32_t      expected_token = 1;\n\n   while (expected_token <= TOTAL_TOKENS)\n   {\n      uint32_t got;\n      while (retro_spsc_read_avail(&s->q) < sizeof(got))\n         ; /* spin */\n      retro_spsc_read(&s->q, &got, sizeof(got));\n      if (got != expected_token)\n         s->mismatches++;\n      expected_token++;\n      s->consumed_tokens++;\n   }\n}\n\nstatic int run_stress(void)\n{\n   test_state_t s;\n   sthread_t   *prod;\n   sthread_t   *cons;\n\n   memset(&s, 0, sizeof(s));\n   if (!retro_spsc_init(&s.q, BUF_BYTES))\n   {\n      fprintf(stderr, \"FAIL: retro_spsc_init\\n\");\n      return 1;\n   }\n\n   prod = sthread_create(producer_thread, &s);\n   if (!prod)\n   {\n      fprintf(stderr, \"FAIL: sthread_create(producer)\\n\");\n      retro_spsc_free(&s.q);\n      return 1;\n   }\n   cons = sthread_create(consumer_thread, &s);\n   if (!cons)\n   {\n      fprintf(stderr, \"FAIL: sthread_create(consumer)\\n\");\n      sthread_join(prod);\n      retro_spsc_free(&s.q);\n      return 1;\n   }\n\n   sthread_join(prod);\n   sthread_join(cons);\n   retro_spsc_free(&s.q);\n\n   if (s.mismatches != 0)\n   {\n      fprintf(stderr,\n         \"FAIL: %lu mismatched tokens out of %lu\\n\",\n         s.mismatches, s.consumed_tokens);\n      return 1;\n   }\n   if (s.produced_tokens != TOTAL_TOKENS\n         || s.consumed_tokens != TOTAL_TOKENS)\n   {\n      fprintf(stderr,\n         \"FAIL: produced=%lu consumed=%lu (expected %d each)\\n\",\n         s.produced_tokens, s.consumed_tokens, TOTAL_TOKENS);\n      return 1;\n   }\n\n   printf(\"[pass] stress: %d tokens through %d-byte buffer, \"\n          \"0 mismatches\\n\",\n      TOTAL_TOKENS, BUF_BYTES);\n   return 0;\n}\n\n/* Single-threaded property checks: verify the API contracts that\n * don't require concurrency. */\nstatic int run_property_checks(void)\n{\n   retro_spsc_t q;\n   uint8_t      buf[64];\n   uint8_t      readback[64];\n   size_t       i, n;\n\n   /* init with non-power-of-2 should round up */\n   if (!retro_spsc_init(&q, 100))\n   {\n      fprintf(stderr, \"FAIL: init(100)\\n\");\n      return 1;\n   }\n   if (q.capacity != 128)\n   {\n      fprintf(stderr, \"FAIL: capacity %zu != 128 (round up)\\n\",\n         q.capacity);\n      retro_spsc_free(&q);\n      return 1;\n   }\n\n   /* fresh queue: read_avail = 0, write_avail = capacity */\n   if (retro_spsc_read_avail(&q) != 0\n         || retro_spsc_write_avail(&q) != 128)\n   {\n      fprintf(stderr, \"FAIL: fresh-queue avails\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n\n   /* write 64, read 64, verify */\n   for (i = 0; i < sizeof(buf); i++)\n      buf[i] = (uint8_t)(i + 1);\n   n = retro_spsc_write(&q, buf, sizeof(buf));\n   if (n != sizeof(buf))\n   {\n      fprintf(stderr, \"FAIL: write returned %zu\\n\", n);\n      retro_spsc_free(&q);\n      return 1;\n   }\n   if (retro_spsc_read_avail(&q) != sizeof(buf))\n   {\n      fprintf(stderr, \"FAIL: read_avail after write\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n   memset(readback, 0, sizeof(readback));\n   n = retro_spsc_read(&q, readback, sizeof(readback));\n   if (n != sizeof(buf) || memcmp(buf, readback, sizeof(buf)) != 0)\n   {\n      fprintf(stderr, \"FAIL: read content mismatch\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n\n   /* peek does not advance */\n   retro_spsc_write(&q, buf, 32);\n   if (retro_spsc_peek(&q, readback, 32) != 32)\n   {\n      fprintf(stderr, \"FAIL: peek returned wrong size\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n   if (retro_spsc_read_avail(&q) != 32)\n   {\n      fprintf(stderr, \"FAIL: peek advanced read cursor\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n   /* drain so wraparound test starts from a known state */\n   retro_spsc_read(&q, readback, 32);\n\n   /* wraparound: write 100 (forces wrap given capacity 128 + 32-byte\n    * peek state above) */\n   for (i = 0; i < sizeof(buf); i++)\n      buf[i] = (uint8_t)(0x80 + i);\n   n = retro_spsc_write(&q, buf, sizeof(buf));\n   if (n != sizeof(buf))\n   {\n      fprintf(stderr, \"FAIL: wraparound write\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n   memset(readback, 0, sizeof(readback));\n   n = retro_spsc_read(&q, readback, sizeof(buf));\n   if (n != sizeof(buf) || memcmp(buf, readback, sizeof(buf)) != 0)\n   {\n      fprintf(stderr, \"FAIL: wraparound read content mismatch\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n\n   /* clear discards unread data without reallocating buffer */\n   retro_spsc_write(&q, buf, 50);\n   if (retro_spsc_read_avail(&q) != 50)\n   {\n      fprintf(stderr, \"FAIL: pre-clear read_avail\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n   retro_spsc_clear(&q);\n   if (retro_spsc_read_avail(&q) != 0\n         || retro_spsc_write_avail(&q) != 128)\n   {\n      fprintf(stderr, \"FAIL: clear did not reset cursors\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n   /* queue is reusable after clear */\n   retro_spsc_write(&q, buf, 16);\n   memset(readback, 0, sizeof(readback));\n   n = retro_spsc_read(&q, readback, 16);\n   if (n != 16 || memcmp(buf, readback, 16) != 0)\n   {\n      fprintf(stderr, \"FAIL: post-clear read mismatch\\n\");\n      retro_spsc_free(&q);\n      return 1;\n   }\n\n   retro_spsc_free(&q);\n   printf(\"[pass] property checks\\n\");\n   return 0;\n}\n\nint main(void)\n{\n   if (run_property_checks() != 0)\n      return 1;\n   if (run_stress() != 0)\n      return 1;\n   puts(\"ALL OK\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/queues/task_queue_title_error_test/Makefile",
    "content": "TARGET := task_queue_title_error_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# task_queue.c (without HAVE_THREADS / HAVE_GCD) is self-contained\n# apart from cpu_features_get_time_usec(); the test file provides a\n# trivial stub for that symbol so we don't have to drag in\n# features_cpu.c (which would pull in a much larger dependency\n# graph).  Build task_queue.c without HAVE_THREADS so the slock /\n# scond / sthread paths compile out cleanly -- the title/error\n# protocol is identical with and without threading; the locks just\n# serialise it.\nSOURCES := \\\n\ttask_queue_title_error_test.c \\\n\t$(LIBRETRO_COMM_DIR)/queues/task_queue.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -O0 -I$(LIBRETRO_COMM_DIR)/include\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/queues/task_queue_title_error_test/task_queue_title_error_test.c",
    "content": "/* Regression test for the task_set_title / task_set_error\n * ownership protocol in libretro-common/queues/task_queue.c.\n *\n * Background\n * ----------\n * task_set_title() and task_set_error() take ownership of the\n * passed-in heap pointer (the task system frees it with free() at\n * task completion).  Neither setter frees the previous value, so\n * calling either one twice without an intervening free leaks the\n * previous string.  The header now documents this convention and\n * the file ships a task_free_error() helper symmetric to the\n * pre-existing task_free_title().\n *\n * Pre-helper, callers that legitimately needed to update the\n * error mid-task could not free the previous error at all (no\n * task_free_error existed).  Their only options were the\n * task_get_error / \"skip if already set\" guard or just letting\n * the leak happen; tasks/task_save.c uses the guard, but other\n * call sites that update title and error in lockstep had no\n * symmetric tool for the error half.  task_free_error closes\n * that gap.\n *\n * What this test asserts\n * ----------------------\n * 1. Both helpers exist and link (catches a regression that drops\n *    the helper or its declaration).\n * 2. The free-then-set protocol is leak-clean:\n *      task_set_title(t, strdup(A));\n *      task_free_title(t);\n *      task_set_title(t, strdup(B));\n *      ... task system frees B at completion.\n *    Total: two strdups, two frees, no leaks.  Same shape for\n *    task_set_error / task_free_error.\n * 3. task_free_{title,error} on a task whose field is already NULL\n *    is a no-op (matches the existing task_free_title behaviour).\n * 4. Setting NULL via the setter does not crash and replaces the\n *    field as expected.\n *\n * What this test does NOT assert\n * ------------------------------\n * It does not exercise the threaded path (HAVE_THREADS is not\n * defined for this binary), since the protocol is identical -- the\n * locks just serialise it.  It does not exercise queue lifecycle\n * (push/gather), since those are orthogonal to the property\n * helpers.  Future tests under libretro-common/samples/queues/\n * should cover those if motivated by a regression.\n *\n * How the regression is caught\n * ----------------------------\n * Built under ASan + LSan (the workflow's default), each leak in\n * the protocol surfaces as an LSan report at exit.  Without ASan\n * the test still verifies linkage (helpers exist) and observable\n * state (final field values), so build-time regressions are caught\n * without needing a sanitizer.  An accounting layer counts strdups\n * and frees through a thin wrapper so the no-leak property is\n * checked even on non-ASan builds.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <queues/task_queue.h>\n\nstatic int failures = 0;\n\n/* -----------------------------------------------------------------\n * Allocation accounting.  Wrap strdup so we can count bytes\n * allocated; pair with a hooked free path used only by the test\n * driver below.  task_queue.c itself uses the libc free() directly,\n * so to count THOSE frees we have to track every pointer the test\n * hands off and verify it has been freed by the time the test\n * harness completes the task.  Easiest way: do the strdup ourselves\n * and verify the task system freed it via accessing the pointer's\n * destination after task completion (we can't safely do that --\n * UAF), so instead verify by counting the alloc/free balance using\n * a malloc-wrapping override at link time would be overkill.\n *\n * Practical approach: use strdup directly and rely on ASan/LSan to\n * catch the leak.  The test below is structured so every strdup\n * must be paired with either an explicit task_free_{title,error}\n * or an internal-gather free triggered by the task transitioning\n * to FINISHED.  We DO NOT actually run the task queue here; we\n * simulate the gather frees by calling the public free helpers\n * before resetting the task and freeing it ourselves.  That keeps\n * the test entirely standalone -- no thread, no time source, no\n * msg_push needed.\n * ----------------------------------------------------------------- */\n\nstatic char *xstrdup(const char *s)\n{\n   size_t n;\n   char  *r;\n\n   if (!s)\n      return NULL;\n   n = strlen(s) + 1;\n   r = (char *)malloc(n);\n   if (!r)\n   {\n      printf(\"[FATAL] OOM in xstrdup\\n\");\n      exit(2);\n   }\n   memcpy(r, s, n);\n   return r;\n}\n\n/* Helper: build a synthetic task with all fields zeroed.  We do\n * NOT use task_init() because that routes through a static counter\n * and would couple the test to task_init's exact behaviour.\n * What matters for this test is the title/error fields. */\nstatic retro_task_t *make_bare_task(void)\n{\n   retro_task_t *t = (retro_task_t *)calloc(1, sizeof(*t));\n   if (!t)\n   {\n      printf(\"[FATAL] OOM in make_bare_task\\n\");\n      exit(2);\n   }\n   return t;\n}\n\nstatic void destroy_bare_task(retro_task_t *t)\n{\n   /* Mirror what retro_task_internal_gather does on completion:\n    * free the leftover title/error (if any) and the task itself.\n    * Tests are responsible for emptying the fields beforehand if\n    * they want LSan to flag the prior strdup as leaked. */\n   if (t->error)\n   {\n      free(t->error);\n      t->error = NULL;\n   }\n   if (t->title)\n   {\n      free(t->title);\n      t->title = NULL;\n   }\n   free(t);\n}\n\n/* -----------------------------------------------------------------\n * Test cases\n * ----------------------------------------------------------------- */\n\n/* Case 1: single set_title + completion.  Baseline leak-free path. */\nstatic void test_title_set_once(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_set_title(t, xstrdup(\"hello\"));\n   if (!t->title || strcmp(t->title, \"hello\") != 0)\n   {\n      printf(\"[ERROR] title_set_once: expected 'hello', got %s\\n\",\n            t->title ? t->title : \"(null)\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] title_set_once\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 2: single set_error + completion.  Baseline leak-free path. */\nstatic void test_error_set_once(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_set_error(t, xstrdup(\"oops\"));\n   if (!t->error || strcmp(t->error, \"oops\") != 0)\n   {\n      printf(\"[ERROR] error_set_once: expected 'oops', got %s\\n\",\n            t->error ? t->error : \"(null)\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] error_set_once\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 3: title replaced via task_free_title.  This is the protocol\n * the header documents.  Two strdups, two frees, LSan-clean. */\nstatic void test_title_replace_correct(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_set_title(t, xstrdup(\"first\"));\n   task_free_title(t);\n   task_set_title(t, xstrdup(\"second\"));\n\n   if (!t->title || strcmp(t->title, \"second\") != 0)\n   {\n      printf(\"[ERROR] title_replace_correct: expected 'second', got %s\\n\",\n            t->title ? t->title : \"(null)\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] title_replace_correct\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 4: error replaced via task_free_error (the newly-added\n * helper).  This case exists *because* of the helper -- before this\n * patch, you could not write this code without a manual free(t->error)\n * which had to reach into the struct directly.  Two strdups, two\n * frees, LSan-clean. */\nstatic void test_error_replace_correct(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_set_error(t, xstrdup(\"first error\"));\n   task_free_error(t);\n   task_set_error(t, xstrdup(\"second error\"));\n\n   if (!t->error || strcmp(t->error, \"second error\") != 0)\n   {\n      printf(\"[ERROR] error_replace_correct: expected 'second error', got %s\\n\",\n            t->error ? t->error : \"(null)\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] error_replace_correct\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 5: task_free_title on already-NULL field.  Must be a no-op. */\nstatic void test_title_free_when_null(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_free_title(t); /* no-op */\n   if (t->title != NULL)\n   {\n      printf(\"[ERROR] title_free_when_null: title is non-NULL after free\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] title_free_when_null\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 6: task_free_error on already-NULL field.  Must be a no-op. */\nstatic void test_error_free_when_null(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_free_error(t); /* no-op */\n   if (t->error != NULL)\n   {\n      printf(\"[ERROR] error_free_when_null: error is non-NULL after free\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] error_free_when_null\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 7: task_free_title called twice in a row.  The second call\n * should be a no-op (matches the documented behaviour). */\nstatic void test_title_double_free(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_set_title(t, xstrdup(\"hello\"));\n   task_free_title(t);\n   task_free_title(t); /* no-op, must not double-free */\n\n   if (t->title != NULL)\n   {\n      printf(\"[ERROR] title_double_free: title is non-NULL after double-free\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] title_double_free\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 8: task_free_error called twice in a row.  Must not\n * double-free.  This is the symmetric coverage for task_free_error,\n * the helper added by this commit. */\nstatic void test_error_double_free(void)\n{\n   retro_task_t *t = make_bare_task();\n\n   task_set_error(t, xstrdup(\"oops\"));\n   task_free_error(t);\n   task_free_error(t); /* no-op, must not double-free */\n\n   if (t->error != NULL)\n   {\n      printf(\"[ERROR] error_double_free: error is non-NULL after double-free\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] error_double_free\\n\");\n\n   destroy_bare_task(t);\n}\n\n/* Case 9: long chain of free-then-set on title.  Stress test for\n * the protocol -- N strdups, N frees, no leaks. */\nstatic void test_title_chain(void)\n{\n   retro_task_t *t = make_bare_task();\n   int           i;\n   int           n = 50;\n   char          buf[32];\n\n   for (i = 0; i < n; i++)\n   {\n      if (t->title)\n         task_free_title(t);\n      snprintf(buf, sizeof(buf), \"step-%d\", i);\n      task_set_title(t, xstrdup(buf));\n   }\n\n   if (!t->title || strcmp(t->title, \"step-49\") != 0)\n   {\n      printf(\"[ERROR] title_chain: final value mismatch (got %s)\\n\",\n            t->title ? t->title : \"(null)\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] title_chain (%d iterations)\\n\", n);\n\n   destroy_bare_task(t);\n}\n\n/* Case 10: long chain of free-then-set on error.  Same stress test\n * for task_free_error. */\nstatic void test_error_chain(void)\n{\n   retro_task_t *t = make_bare_task();\n   int           i;\n   int           n = 50;\n   char          buf[32];\n\n   for (i = 0; i < n; i++)\n   {\n      if (t->error)\n         task_free_error(t);\n      snprintf(buf, sizeof(buf), \"err-%d\", i);\n      task_set_error(t, xstrdup(buf));\n   }\n\n   if (!t->error || strcmp(t->error, \"err-49\") != 0)\n   {\n      printf(\"[ERROR] error_chain: final value mismatch (got %s)\\n\",\n            t->error ? t->error : \"(null)\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] error_chain (%d iterations)\\n\", n);\n\n   destroy_bare_task(t);\n}\n\n/* -----------------------------------------------------------------\n * task_queue.c uses cpu_features_get_time_usec() in its non-threaded\n * gather path.  We don't drive the queue, so it never runs -- but\n * we still need the symbol present at link time when libtool\n * resolves task_queue.c's references.  Provide a trivial stub.\n * libretro.h already brings retro_time_t in via task_queue.h above.\n * ----------------------------------------------------------------- */\n\nretro_time_t cpu_features_get_time_usec(void);\nretro_time_t cpu_features_get_time_usec(void)\n{\n   return 0;\n}\n\nint main(void)\n{\n   test_title_set_once();\n   test_error_set_once();\n   test_title_replace_correct();\n   test_error_replace_correct();\n   test_title_free_when_null();\n   test_error_free_when_null();\n   test_title_double_free();\n   test_error_double_free();\n   test_title_chain();\n   test_error_chain();\n\n   if (failures)\n   {\n      printf(\"\\n%d task_queue title/error protocol test(s) failed\\n\",\n            failures);\n      return 1;\n   }\n   printf(\"\\nAll task_queue title/error protocol tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/rthreads/tpool_wait_test/Makefile",
    "content": "TARGET := tpool_wait_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# tpool.c depends on rthreads.c.  Both are self-contained at the\n# libretro-common layer (rthreads.c is the platform abstraction over\n# pthreads / Win32 / etc.) so we just compile them in directly --\n# no other libretro-common sources are needed.\nSOURCES := \\\n\ttpool_wait_test.c \\\n\t$(LIBRETRO_COMM_DIR)/rthreads/tpool.c \\\n\t$(LIBRETRO_COMM_DIR)/rthreads/rthreads.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS  += -Wall -pedantic -std=gnu99 -g -O0 -I$(LIBRETRO_COMM_DIR)/include\nLDFLAGS += -lpthread\n\n# rthreads.c uses clock_gettime + CLOCK_REALTIME on Linux glibc; on\n# older glibc those live in -lrt.  Harmless on newer glibc.\nLDFLAGS += -lrt\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/rthreads/tpool_wait_test/tpool_wait_test.c",
    "content": "/* Regression test for the tpool_wait predicate in\n * libretro-common/rthreads/tpool.c.\n *\n * Background\n * ----------\n * tpool_wait is the public \"wait until all queued work has been\n * processed\" entry point.  Pre-fix, its predicate was:\n *\n *     (!tp->stop && tp->working_cnt != 0) ||\n *     (tp->stop && tp->thread_cnt != 0)\n *\n * That is, in the non-stopping case it waited only on working_cnt.\n * working_cnt is the number of jobs currently being executed by a\n * worker -- it is incremented when a worker pops a job off the\n * queue, not when a producer pushes one on.\n *\n * So the following sequence:\n *\n *     tp = tpool_create(N);\n *     for (i = 0; i < M; i++) tpool_add_work(tp, job, ctx);\n *     tpool_wait(tp);    // <-- can return immediately\n *     // ctx state read here, expecting all M jobs to have run\n *\n * could return from tpool_wait before any worker had picked up the\n * first job: working_cnt was 0 because no worker had yet dequeued.\n * Callers that read shared state after tpool_wait would observe\n * zero or partial completion.\n *\n * Worker code already signals working_cond only when both\n * working_cnt == 0 AND work_first == NULL (tpool.c:139), so the\n * fix is to widen the wait predicate to match: also wait while\n * work_first is non-NULL.\n *\n * What this test asserts\n * ----------------------\n * 1. After a sequence of tpool_add_work followed by tpool_wait,\n *    every queued job has run.  Verified by an under-lock counter.\n * 2. tpool_create(0) defaults to a working pool (documented in\n *    tpool.h) that completes a posted job before tpool_wait\n *    returns.\n * 3. tpool_create / tpool_destroy round-trips cleanly across many\n *    iterations (heap consistency checked by ASan/UBSan/LSan in\n *    the workflow).\n * 4. tpool_destroy on a pool with queued-but-not-yet-run work does\n *    not crash and does not corrupt the heap.  tpool_destroy is\n *    documented to discard outstanding queued work, so we do NOT\n *    assert on the counter -- we only verify clean teardown.\n *\n * What this test does NOT assert\n * ------------------------------\n * It does not exercise tpool_wait followed by further\n * tpool_add_work, since that is not a documented use pattern.  It\n * does not exercise the single-threaded fallback (HAVE_THREADS\n * off); tpool.c requires threads.\n *\n * How the regression is caught\n * ----------------------------\n * Without the fix, test_work_executes_once and\n * test_zero_threads_default both fail observably: the counter is\n * less than the expected job count (typically zero, since the\n * producer outpaces the workers' first dequeue).  The test prints\n * a clear FAIL line and exits non-zero so the CI workflow flags\n * it.  Built under ASan + UBSan (the workflow default), any\n * collateral heap or UB issue is also caught.\n *\n * The test is bounded: tight loops are sized to run inside the\n * workflow's per-binary 60-second timeout on a github-hosted\n * runner.  Wall-clock under ASan + UBSan is under one second.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <rthreads/rthreads.h>\n#include <rthreads/tpool.h>\n\n#define POOL_THREADS         4\n#define WORK_JOBS         1000\n#define ROUNDTRIP_ITERS   2000\n#define STRESS_CYCLES      200\n#define STRESS_JOBS         32\n\nstruct work_ctx\n{\n   slock_t *lock;\n   int      counter;\n};\n\nstatic void inc_job(void *arg)\n{\n   struct work_ctx *ctx = (struct work_ctx *)arg;\n   slock_lock(ctx->lock);\n   ctx->counter++;\n   slock_unlock(ctx->lock);\n}\n\n/* -----------------------------------------------------------------\n * Test 1: tpool_wait correctly drains the queue.\n *\n * This is the regression case.  Before the predicate fix, the\n * counter would commonly read 0 here: working_cnt was still 0 at\n * the moment tpool_wait was entered (no worker had yet dequeued\n * any of the just-pushed work) and the old predicate returned\n * immediately.\n * ----------------------------------------------------------------- */\nstatic int test_work_executes_once(void)\n{\n   tpool_t        *tp;\n   int             i;\n   struct work_ctx ctx;\n   int             rc = 0;\n\n   ctx.counter = 0;\n   ctx.lock    = slock_new();\n   if (!ctx.lock)\n   {\n      printf(\"[FAIL] test_work_executes_once: slock_new failed\\n\");\n      return 1;\n   }\n\n   tp = tpool_create(POOL_THREADS);\n   if (!tp)\n   {\n      printf(\"[FAIL] test_work_executes_once: tpool_create returned NULL\\n\");\n      slock_free(ctx.lock);\n      return 1;\n   }\n\n   for (i = 0; i < WORK_JOBS; i++)\n   {\n      if (!tpool_add_work(tp, inc_job, &ctx))\n      {\n         printf(\"[FAIL] test_work_executes_once: tpool_add_work failed at i=%d\\n\", i);\n         rc = 1;\n         break;\n      }\n   }\n\n   tpool_wait(tp);\n   tpool_destroy(tp);\n\n   if (!rc)\n   {\n      slock_lock(ctx.lock);\n      if (ctx.counter != WORK_JOBS)\n      {\n         printf(\"[FAIL] test_work_executes_once: counter=%d expected=%d\\n\",\n               ctx.counter, WORK_JOBS);\n         rc = 1;\n      }\n      else\n         printf(\"[PASS] test_work_executes_once (%d jobs across %d threads)\\n\",\n               WORK_JOBS, POOL_THREADS);\n      slock_unlock(ctx.lock);\n   }\n\n   slock_free(ctx.lock);\n   return rc;\n}\n\n/* -----------------------------------------------------------------\n * Test 2: tpool_create(0) gives a working default pool.\n *\n * tpool.h documents num=0 as defaulting to 2 threads.  Smoke-test\n * that this path produces a usable pool that runs a single job to\n * completion before tpool_wait returns.\n * ----------------------------------------------------------------- */\nstatic int test_zero_threads_default(void)\n{\n   tpool_t        *tp;\n   struct work_ctx ctx;\n   int             rc = 0;\n\n   ctx.counter = 0;\n   ctx.lock    = slock_new();\n   if (!ctx.lock)\n   {\n      printf(\"[FAIL] test_zero_threads_default: slock_new failed\\n\");\n      return 1;\n   }\n\n   tp = tpool_create(0);\n   if (!tp)\n   {\n      printf(\"[FAIL] test_zero_threads_default: tpool_create(0) returned NULL\\n\");\n      slock_free(ctx.lock);\n      return 1;\n   }\n\n   if (!tpool_add_work(tp, inc_job, &ctx))\n   {\n      printf(\"[FAIL] test_zero_threads_default: tpool_add_work failed\\n\");\n      rc = 1;\n   }\n\n   tpool_wait(tp);\n   tpool_destroy(tp);\n\n   if (!rc)\n   {\n      slock_lock(ctx.lock);\n      if (ctx.counter != 1)\n      {\n         printf(\"[FAIL] test_zero_threads_default: counter=%d expected=1\\n\",\n               ctx.counter);\n         rc = 1;\n      }\n      else\n         printf(\"[PASS] test_zero_threads_default\\n\");\n      slock_unlock(ctx.lock);\n   }\n\n   slock_free(ctx.lock);\n   return rc;\n}\n\n/* -----------------------------------------------------------------\n * Test 3: create/destroy round-trip with no work.\n *\n * Heap consistency check.  Workers transition straight from their\n * initial scond_wait to the stop branch; on the workflow runner\n * with ASan+UBSan, any heap-buffer-overflow / use-after-free /\n * undefined behaviour during teardown surfaces here.\n * ----------------------------------------------------------------- */\nstatic int test_create_destroy_no_work(void)\n{\n   int i;\n   for (i = 0; i < ROUNDTRIP_ITERS; i++)\n   {\n      tpool_t *tp = tpool_create(POOL_THREADS);\n      if (!tp)\n      {\n         printf(\"[FAIL] test_create_destroy_no_work: tpool_create returned NULL at i=%d\\n\", i);\n         return 1;\n      }\n      tpool_destroy(tp);\n   }\n   printf(\"[PASS] test_create_destroy_no_work (%d iterations x %d threads)\\n\",\n         ROUNDTRIP_ITERS, POOL_THREADS);\n   return 0;\n}\n\n/* -----------------------------------------------------------------\n * Test 4: stress -- create / push some work / destroy without\n * waiting.\n *\n * tpool_destroy is documented to discard outstanding queued work,\n * so the counter is non-deterministic and we don't check it.\n * What we do check is that the destroyer terminates and the heap\n * stays consistent across many fast cycles -- ASan/UBSan/LSan\n * carry the verification.  This case was the one I originally\n * (incorrectly) flagged as a UAF in the audit; the real situation\n * is that scond_wait re-acquires the mutex before the destroyer\n * can free it, so the original code is heap-safe here.  Keeping\n * the test in place as a guard against any future regression that\n * would actually break that invariant.\n * ----------------------------------------------------------------- */\nstatic int test_stress_destroy_with_pending(void)\n{\n   int              i;\n   int              j;\n   struct work_ctx  ctx;\n\n   ctx.counter = 0;\n   ctx.lock    = slock_new();\n   if (!ctx.lock)\n   {\n      printf(\"[FAIL] test_stress_destroy_with_pending: slock_new failed\\n\");\n      return 1;\n   }\n\n   for (i = 0; i < STRESS_CYCLES; i++)\n   {\n      tpool_t *tp = tpool_create(POOL_THREADS);\n      if (!tp)\n      {\n         printf(\"[FAIL] test_stress_destroy_with_pending: tpool_create returned NULL at i=%d\\n\", i);\n         slock_free(ctx.lock);\n         return 1;\n      }\n      for (j = 0; j < STRESS_JOBS; j++)\n         tpool_add_work(tp, inc_job, &ctx);\n      /* Deliberately no tpool_wait here. */\n      tpool_destroy(tp);\n   }\n\n   printf(\"[PASS] test_stress_destroy_with_pending (%d cycles x %d jobs, ran=%d)\\n\",\n         STRESS_CYCLES, STRESS_JOBS, ctx.counter);\n\n   slock_free(ctx.lock);\n   return 0;\n}\n\nint main(void)\n{\n   int failures = 0;\n\n   failures += test_work_executes_once();\n   failures += test_zero_threads_default();\n   failures += test_create_destroy_no_work();\n   failures += test_stress_destroy_with_pending();\n\n   if (failures)\n   {\n      printf(\"\\n%d tpool_wait regression test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll tpool_wait regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/streams/chd/Makefile",
    "content": "TARGET := chd_meta_overflow_test\n\nSOURCES := chd_meta_overflow_test.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -O0\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/streams/chd/chd_meta_overflow_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (chd_meta_overflow_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression test for the GDROM_TRACK_METADATA_TAG parser\n * bounds in libretro-common/streams/chd_stream.c::\n * chdstream_get_meta.\n *\n * The .chd metadata blob (read from the disc image via\n * chd_get_metadata into a meta[256] buffer) contains\n * space-separated KEY:VALUE pairs.  Pre-this-patch the\n * TYPE: / SUBTYPE: / PGTYPE: / PGSUB: cases all did:\n *\n *   p   += <tag-len>;\n *   len  = 0;\n *   while (p[len] && p[len] != ' ')\n *      len++;\n *   memcpy(md->FIELD, p, len);\n *   md->FIELD[len] = '\\0';\n *\n * The destination fields are:\n *   md->type[64]\n *   md->subtype[32]\n *   md->pgtype[32]\n *   md->pgsub[32]\n *\n * but `len` was bounded only by the surrounding meta[256]\n * buffer (and only loosely, since p[len] could read up to\n * the meta-buffer's NUL terminator).  A malicious .chd with\n * \"TYPE:\" followed by 200 bytes of non-space content\n * stack-overflowed md->type by ~136 bytes -- enough to\n * corrupt md->subtype, md->pgtype, md->pgsub, and depending\n * on layout the saved frame pointer and return address.\n *\n * Reachability: user loads a malicious .chd file.  Same\n * threat class as the CDFS / BSV file-load bugs.\n *\n * Fix: the SCD-format parser earlier in the same function\n * already had the right pattern (line 166):\n *\n *   if (len == 0 || len >= sizeof(md->type))\n *      return false;\n *\n * Apply the same predicate to all four GDROM-format fields.\n *\n * IMPORTANT: this test keeps a verbatim copy of the post-fix\n * predicate from chd_stream.c.  If chd_stream.c amends, the\n * copy below must follow.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* Mirror of the metadata struct from chd_stream.c (subset\n * of the fields touched by this parser).  Field sizes\n * match the production layout. */\ntypedef struct {\n   uint32_t track;\n   uint32_t frames;\n   uint32_t pad;\n   uint32_t pregap;\n   uint32_t postgap;\n   char type[64];\n   char subtype[32];\n   char pgtype[32];\n   char pgsub[32];\n} mock_metadata_t;\n\n#ifndef ARRAY_SIZE\n#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))\n#endif\n\nstatic int failures = 0;\n\n/* === verbatim copy of the post-fix GDROM parser from\n *     libretro-common/streams/chd_stream.c.  Returns true\n *     on a fully-parsed metadata blob, false on malformed\n *     input.  If chd_stream.c amends the predicates, this\n *     copy must follow. === */\nstatic int parse_gdrom_meta(mock_metadata_t *md, const char *meta)\n{\n   const char *p = meta;\n   while (*p)\n   {\n      size_t len;\n\n      if (strncmp(p, \"TRACK:\", 6) == 0)\n      {\n         char *end;\n         md->track = strtoul(p + 6, &end, 10);\n         p = end;\n      }\n      else if (strncmp(p, \"TYPE:\", 5) == 0)\n      {\n         p   += 5;\n         len  = 0;\n         while (p[len] && p[len] != ' ')\n            len++;\n         if (len >= sizeof(md->type))\n            return 0;\n         memcpy(md->type, p, len);\n         md->type[len] = '\\0';\n         p += len;\n      }\n      else if (strncmp(p, \"SUBTYPE:\", 8) == 0)\n      {\n         p   += 8;\n         len  = 0;\n         while (p[len] && p[len] != ' ')\n            len++;\n         if (len >= sizeof(md->subtype))\n            return 0;\n         memcpy(md->subtype, p, len);\n         md->subtype[len] = '\\0';\n         p += len;\n      }\n      else if (strncmp(p, \"PGTYPE:\", 7) == 0)\n      {\n         p   += 7;\n         len  = 0;\n         while (p[len] && p[len] != ' ')\n            len++;\n         if (len >= sizeof(md->pgtype))\n            return 0;\n         memcpy(md->pgtype, p, len);\n         md->pgtype[len] = '\\0';\n         p += len;\n      }\n      else if (strncmp(p, \"PGSUB:\", 6) == 0)\n      {\n         p   += 6;\n         len  = 0;\n         while (p[len] && p[len] != ' ')\n            len++;\n         if (len >= sizeof(md->pgsub))\n            return 0;\n         memcpy(md->pgsub, p, len);\n         md->pgsub[len] = '\\0';\n         p += len;\n      }\n      else\n         p++;\n   }\n   return 1;\n}\n/* === end verbatim copy === */\n\n/* ---- tests ---- */\n\nstatic void test_legitimate_metadata(void)\n{\n   mock_metadata_t md;\n   const char *meta = \"TRACK:1 TYPE:MODE2_RAW SUBTYPE:NONE PGTYPE:MODE2_RAW PGSUB:NONE\";\n   memset(&md, 0, sizeof(md));\n   if (!parse_gdrom_meta(&md, meta))\n   {\n      printf(\"[ERROR] legitimate metadata rejected\\n\");\n      failures++;\n      return;\n   }\n   if (md.track != 1 || strcmp(md.type, \"MODE2_RAW\") != 0\n         || strcmp(md.subtype, \"NONE\") != 0)\n   {\n      printf(\"[ERROR] legitimate metadata not parsed correctly\\n\");\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] legitimate GDROM metadata parsed correctly\\n\");\n}\n\nstatic void test_oversize_type_rejected(void)\n{\n   /* \"TYPE:\" followed by 200 'A's, no space.  Pre-fix: the\n    * memcpy of 200 bytes into md->type[64] OOB-wrote 136\n    * bytes past type into subtype, pgtype, pgsub, and beyond.\n    * Allocate the metadata struct on the heap with no slack\n    * so ASan flags any reintroduction of the unbounded\n    * memcpy. */\n   mock_metadata_t *md = (mock_metadata_t*)malloc(sizeof(*md));\n   char meta[256];\n   int rv;\n   if (!md) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(md, 0, sizeof(*md));\n   memset(meta, 0, sizeof(meta));\n   strcpy(meta, \"TYPE:\");\n   memset(meta + 5, 'A', 200);\n   meta[205] = '\\0';\n\n   rv = parse_gdrom_meta(md, meta);\n   if (rv)\n   {\n      printf(\"[ERROR] oversize TYPE: was accepted\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] oversize TYPE: rejected without OOB write\\n\");\n\n   free(md);\n}\n\nstatic void test_oversize_subtype_rejected(void)\n{\n   mock_metadata_t *md = (mock_metadata_t*)malloc(sizeof(*md));\n   char meta[256];\n   int rv;\n   if (!md) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(md, 0, sizeof(*md));\n   memset(meta, 0, sizeof(meta));\n   strcpy(meta, \"SUBTYPE:\");\n   memset(meta + 8, 'B', 100);\n   meta[108] = '\\0';\n\n   rv = parse_gdrom_meta(md, meta);\n   if (rv)\n   {\n      printf(\"[ERROR] oversize SUBTYPE: was accepted\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] oversize SUBTYPE: rejected without OOB write\\n\");\n\n   free(md);\n}\n\nstatic void test_oversize_pgtype_rejected(void)\n{\n   mock_metadata_t *md = (mock_metadata_t*)malloc(sizeof(*md));\n   char meta[256];\n   int rv;\n   if (!md) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(md, 0, sizeof(*md));\n   memset(meta, 0, sizeof(meta));\n   strcpy(meta, \"PGTYPE:\");\n   memset(meta + 7, 'C', 100);\n   meta[107] = '\\0';\n\n   rv = parse_gdrom_meta(md, meta);\n   if (rv)\n   {\n      printf(\"[ERROR] oversize PGTYPE: was accepted\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] oversize PGTYPE: rejected without OOB write\\n\");\n\n   free(md);\n}\n\nstatic void test_oversize_pgsub_rejected(void)\n{\n   mock_metadata_t *md = (mock_metadata_t*)malloc(sizeof(*md));\n   char meta[256];\n   int rv;\n   if (!md) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(md, 0, sizeof(*md));\n   memset(meta, 0, sizeof(meta));\n   strcpy(meta, \"PGSUB:\");\n   memset(meta + 6, 'D', 100);\n   meta[106] = '\\0';\n\n   rv = parse_gdrom_meta(md, meta);\n   if (rv)\n   {\n      printf(\"[ERROR] oversize PGSUB: was accepted\\n\");\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] oversize PGSUB: rejected without OOB write\\n\");\n\n   free(md);\n}\n\nstatic void test_field_at_exact_size_boundary(void)\n{\n   /* TYPE: with exactly sizeof(type) - 1 = 63 chars (the\n    * largest legitimate length).  Should still parse. */\n   mock_metadata_t md;\n   char meta[80];\n   int rv;\n   memset(&md, 0, sizeof(md));\n   memset(meta, 0, sizeof(meta));\n   strcpy(meta, \"TYPE:\");\n   memset(meta + 5, 'X', 63);\n   meta[5 + 63] = '\\0';\n\n   rv = parse_gdrom_meta(&md, meta);\n   if (!rv)\n   {\n      printf(\"[ERROR] boundary-size TYPE: rejected\\n\");\n      failures++;\n   }\n   else if (strlen(md.type) != 63)\n   {\n      printf(\"[ERROR] boundary-size TYPE: parsed wrong length %zu\\n\",\n            strlen(md.type));\n      failures++;\n   }\n   else\n      printf(\"[SUCCESS] boundary-size TYPE: (63 chars) accepted\\n\");\n}\n\nint main(void)\n{\n   test_legitimate_metadata();\n   test_oversize_type_rejected();\n   test_oversize_subtype_rejected();\n   test_oversize_pgtype_rejected();\n   test_oversize_pgsub_rejected();\n   test_field_at_exact_size_boundary();\n\n   if (failures)\n   {\n      printf(\"\\n%d chd_meta_overflow test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll chd_meta_overflow regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/streams/rzip/Makefile",
    "content": "TARGET := rzip\nTARGET_TEST := rzip_chunk_size_test\n\nLIBRETRO_COMM_DIR := ../../..\nLIBRETRO_DEPS_DIR := ../../../../deps\n\n# Attempt to detect target platform\nifeq '$(findstring ;,$(PATH))' ';'\n\tUNAME := Windows\nelse\n\tUNAME := $(shell uname 2>/dev/null || echo Unknown)\n\tUNAME := $(patsubst CYGWIN%,Cygwin,$(UNAME))\n\tUNAME := $(patsubst MSYS%,MSYS,$(UNAME))\n\tUNAME := $(patsubst MINGW%,MSYS,$(UNAME))\nendif\n\n# Add '.exe' extension on Windows platforms\nifeq ($(UNAME), Windows)\n\tTARGET := rzip.exe\nendif\nifeq ($(UNAME), MSYS)\n\tTARGET := rzip.exe\nendif\n\nCOMMON_SOURCES := \\\n\t$(LIBRETRO_COMM_DIR)/compat/fopen_utf8.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_crc32.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path.c \\\n\t$(LIBRETRO_COMM_DIR)/file/file_path_io.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/file_stream_transforms.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/interface_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/memory_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/rzip_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/stdin_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \\\n\t$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \\\n\t$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \\\n\t$(LIBRETRO_COMM_DIR)/time/rtime.c\n\nifneq ($(wildcard $(LIBRETRO_DEPS_DIR)/*),)\n\t# If we are building from inside the RetroArch\n\t# directory (i.e. if an 'external' deps directory\n\t# is available), bake in zlib support\n\tCOMMON_SOURCES += \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/adler32.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/libz-crc32.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/deflate.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/gzclose.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/gzlib.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/gzread.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/gzwrite.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/inffast.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/inflate.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/inftrees.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/trees.c \\\n\t\t$(LIBRETRO_DEPS_DIR)/libz/zutil.c\n\tINCLUDE_DIRS := -I$(LIBRETRO_COMM_DIR)/include/compat/zlib\nelse\n\t# If this is a stand-alone libretro-common directory,\n\t# rely on system zlib library (note: only likely to\n\t# work on Unix-based platforms...)\n\tLDFLAGS += -lz\nendif\n\nSOURCES      := rzip.c $(COMMON_SOURCES)\nSOURCES_TEST := rzip_chunk_size_test.c $(COMMON_SOURCES)\n\nOBJS      := $(SOURCES:.c=.o)\nOBJS_TEST := $(SOURCES_TEST:.c=.o)\n\nINCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/include\nCFLAGS += -DHAVE_ZLIB -Wall -pedantic -std=gnu99 $(INCLUDE_DIRS)\n\n# Silence \"ISO C does not support the 'I64' ms_printf length modifier\"\n# warnings when using MinGW\nifeq ($(UNAME), Windows)\n\tCFLAGS += -Wno-format\nendif\nifeq ($(UNAME), MSYS)\n\tCFLAGS += -Wno-format\nendif\n\nifeq ($(DEBUG), 1)\n\tCFLAGS += -O0 -g -DDEBUG -D_DEBUG\nelse\n\tCFLAGS += -O2 -DNDEBUG\nendif\n\nall: $(TARGET) $(TARGET_TEST)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\n$(TARGET_TEST): $(OBJS_TEST)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(TARGET_TEST) $(OBJS) $(OBJS_TEST)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/streams/rzip/rzip.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (config_file_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n#include <ctype.h>\n#include <inttypes.h>\n#include <errno.h>\n#include <time.h>\n\n#include <string/stdstring.h>\n#include <file/file_path.h>\n#include <streams/interface_stream.h>\n#include <streams/file_stream.h>\n#include <streams/rzip_stream.h>\n#include <retro_miscellaneous.h>\n\n#define FILE_TRANSFER_CHUNK_SIZE 4096\n\nenum rzip_action_type\n{\n\tRZIP_ACTION_QUERY = 0,\n\tRZIP_ACTION_COMPRESS,\n\tRZIP_ACTION_EXTRACT\n};\n\nstatic void rand_str(char *dst, size_t len)\n{\n   char charset[] = \"0123456789\"\n         \"abcdefghijklmnopqrstuvwxyz\"\n         \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\n   while (len-- > 0)\n   {\n      size_t i = (double)rand() / RAND_MAX * (sizeof(charset) - 1);\n      *dst++   = charset[i];\n   }\n   *dst = '\\0';\n}\n\nint main(int argc, char *argv[])\n{\n   char in_file_path[PATH_MAX_LENGTH];\n   char out_file_path[PATH_MAX_LENGTH];\n   enum rzip_action_type action = RZIP_ACTION_QUERY;\n   intfstream_t *in_file        = NULL;\n   intfstream_t *out_file       = NULL;\n   int64_t in_file_size         = 0;\n   int64_t in_file_raw_size     = 0;\n   int64_t out_file_size        = 0;\n   int64_t file_size_diff       = 0;\n   int64_t total_data_read      = 0;\n   bool in_file_compressed      = false;\n   bool valid_args              = false;\n   bool in_place                = false;\n   int ret                      = 1;\n\n   in_file_path[0]  = '\\0';\n   out_file_path[0] = '\\0';\n\n   /* Parse arguments */\n   if ((argc > 1) && (argv[1] && *argv[1]))\n   {\n      valid_args = true;\n\n      if (string_is_equal(argv[1], \"i\"))\n         action = RZIP_ACTION_QUERY;\n      else if (string_is_equal(argv[1], \"a\"))\n         action = RZIP_ACTION_COMPRESS;\n      else if (string_is_equal(argv[1], \"x\"))\n         action = RZIP_ACTION_EXTRACT;\n      else\n         valid_args = false;\n   }\n\n   /* Get input file path */\n   if (valid_args && (argc > 2) && (argv[2] && *argv[2]))\n   {\n      strlcpy(in_file_path, argv[2], sizeof(in_file_path));\n      path_resolve_realpath(in_file_path, sizeof(in_file_path), true);\n      valid_args = valid_args && *in_file_path;\n   }\n   else\n      valid_args = false;\n\n   /* Ensure arguments are valid */\n   if (!valid_args)\n   {\n      fprintf(stderr, \"Usage:\\n\");\n      fprintf(stderr, \"- Query file status: %s i <input file>\\n\", argv[0]);\n      fprintf(stderr, \"- Compress file:     %s a <input file> <output file (optional)>\\n\", argv[0]);\n      fprintf(stderr, \"- Extract file:      %s x <input file> <output file (optional)>\\n\", argv[0]);\n      fprintf(stderr, \"Omitting <output file> will overwrite <input file>\\n\");\n      goto end;\n   }\n\n   /* Ensure that input file exists */\n   if (!path_is_valid(in_file_path))\n   {\n      fprintf(stderr, \"ERROR: Input file does not exist: %s\\n\", in_file_path);\n      goto end;\n   }\n\n   /* Get output file path, if specified */\n   if ((argc > 3) && (argv[3] && *argv[3]))\n   {\n      strlcpy(out_file_path, argv[3], sizeof(out_file_path));\n      path_resolve_realpath(out_file_path, sizeof(out_file_path), true);\n   }\n\n   /* If we are compressing/extracting and an\n    * output file was not specified, generate a\n    * temporary output file path */\n   if (   (action != RZIP_ACTION_QUERY) \n       && !*out_file_path)\n   {\n      const char *in_file_name = path_basename(in_file_path);\n      char in_file_dir[DIR_MAX_LENGTH];\n\n      in_file_dir[0] = '\\0';\n\n      fill_pathname_parent_dir(in_file_dir, in_file_path, sizeof(in_file_dir));\n\n      if (!in_file_name || !*in_file_name)\n      {\n         fprintf(stderr, \"ERROR: Invalid input file: %s\\n\", in_file_path);\n         goto end;\n      }\n\n      srand((unsigned int)time(NULL));\n\n      for (;;)\n      {\n         char tmp_str[10] = {0};\n\n         /* Generate 'random' file name */\n         rand_str(tmp_str, sizeof(tmp_str) - 1);\n         tmp_str[0] = '.';\n\n         if (*in_file_dir)\n            fill_pathname_join_special(out_file_path, in_file_dir,\n                  tmp_str, sizeof(out_file_path));\n         else\n            strlcpy(out_file_path, tmp_str, sizeof(out_file_path));\n\n         strlcat(out_file_path, \".\", sizeof(out_file_path));\n         strlcat(out_file_path, in_file_name, sizeof(out_file_path));\n         path_resolve_realpath(out_file_path, sizeof(out_file_path), true);\n\n         if (!path_is_valid(out_file_path))\n            break;\n      }\n\n      in_place = true;\n   }\n\n   /* Ensure that input and output files\n    * are different */\n   if (string_is_equal(in_file_path, out_file_path))\n   {\n      fprintf(stderr, \"ERROR: Input and output are the same file: %s\\n\", in_file_path);\n      goto end;\n   }\n\n   /* Get input file size */\n   in_file_size = (int64_t)path_get_size(in_file_path);\n\n   if (in_file_size < 1)\n   {\n      fprintf(stderr, \"ERROR: Input file is empty: %s\\n\", in_file_path);\n      goto end;\n   }\n\n   /* Open input file\n    * > Always use RZIP interface */\n   in_file = intfstream_open_rzip_file(\n         in_file_path, RETRO_VFS_FILE_ACCESS_READ);\n\n   if (!in_file)\n   {\n      fprintf(stderr, \"ERROR: Failed to open input file: %s\\n\", in_file_path);\n      goto end;\n   }\n\n   /* Get input file compression status */\n   in_file_compressed = intfstream_is_compressed(in_file);\n\n   /* Get raw (uncompressed) input file size */\n   in_file_raw_size   = intfstream_get_size(in_file);\n\n   /* If this is a query operation, just\n    * print current state */\n   if (action == RZIP_ACTION_QUERY)\n   {\n      printf(\"%s: %s\\n\",\n            in_file_compressed ? \"File is in RZIP format\" : \"File is NOT in RZIP format\",\n            in_file_path);\n      printf(\"   Size on disk:      %\" PRIi64 \" bytes\\n\", in_file_size);\n      if (in_file_compressed)\n         printf(\"   Uncompressed size: %\" PRIi64 \" bytes\\n\", in_file_raw_size);\n      goto end;\n   }\n\n   /* Check whether file is already in the\n    * requested state */\n   if ((in_file_compressed  && (action == RZIP_ACTION_COMPRESS)) ||\n       (!in_file_compressed && (action == RZIP_ACTION_EXTRACT)))\n   {\n      printf(\"Input file is %s: %s\\n\",\n            in_file_compressed ?\n                  \"already in RZIP format - cannot compress\" :\n                        \"not in RZIP format - cannot extract\",\n            in_file_path);\n      goto end;\n   }\n\n   /* Check whether output file already exists */\n   if (path_is_valid(out_file_path))\n   {\n      char reply[8];\n\n      reply[0] = '\\0';\n\n      printf(\"WARNING: Output file already exists: %s\\n\", out_file_path);\n      printf(\"         Overwrite? [Y/n]: \");\n      /* Ignore the fgets return value intentionally -- on EOF or\n       * error we fall through to the reply[0] check below, which\n       * fails the 'Y' comparison (reply[0] stays '\\0' from the\n       * initialisation above) and bails out safely without\n       * overwriting.  Cast to void to silence -Wunused-result on\n       * GCC/glibc, which attaches warn_unused_result to fgets. */\n      (void)!fgets(reply, sizeof(reply), stdin);\n      if (reply[0] != 'Y')\n         goto end;\n   }\n\n   /* Open output file */\n   if (in_file_compressed)\n      out_file = intfstream_open_file(\n            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE,\n            RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   else\n      out_file = intfstream_open_rzip_file(\n            out_file_path, RETRO_VFS_FILE_ACCESS_WRITE);\n\n   if (!out_file)\n   {\n      fprintf(stderr, \"ERROR: Failed to open output file: %s\\n\", out_file_path);\n      goto end;\n   }\n\n   /* Start file transfer */\n   printf(\"%s file\\n\", in_file_compressed ? \"Extracting\" : \"Compressing\");\n   printf(\"   From: %s\\n\", in_file_path);\n   printf(\"   To:   %s\\n\", in_place ? in_file_path : out_file_path);\n\n   for (;;)\n   {\n      int64_t data_written = 0;\n      uint8_t buffer[FILE_TRANSFER_CHUNK_SIZE];\n      /* Read a single chunk from input file */\n      int64_t data_read    = intfstream_read(\n            in_file, buffer, sizeof(buffer));\n\n      if (data_read < 0)\n      {\n         fprintf(stderr, \"ERROR: Failed to read from input file: %s\\n\", in_file_path);\n         goto end;\n      }\n\n      total_data_read += data_read;\n\n      /* Check whether we have reached the end of the file */\n      if (data_read == 0)\n      {\n         /* Close files */\n         intfstream_flush(out_file);\n         intfstream_close(out_file);\n         free(out_file);\n         out_file = NULL;\n\n         intfstream_close(in_file);\n         free(in_file);\n         in_file = NULL;\n\n         break;\n      }\n\n      /* Write chunk to backup file */\n      data_written = intfstream_write(out_file, buffer, data_read);\n\n      if (data_written != data_read)\n      {\n         fprintf(stderr, \"ERROR: Failed to write to output file: %s\\n\", out_file_path);\n         goto end;\n      }\n\n      /* Update progress */\n      printf(\"\\rProgress: %\" PRIi64 \" %%\", total_data_read * 100 / in_file_raw_size);\n      fflush(stdout);\n   }\n   printf(\"\\rProgress: 100 %%\\n\");\n\n   /* Display final status 'report' */\n   printf(\"%s complete:\\n\", in_file_compressed ? \"Extraction\" : \"Compression\");\n\n   out_file_size  = (int64_t)path_get_size(out_file_path);\n   file_size_diff = (in_file_size > out_file_size) ?\n         (in_file_size - out_file_size) :\n               (out_file_size - in_file_size);\n\n   printf(\"   %\" PRIi64 \" -> %\" PRIi64 \" bytes [%\" PRIi64 \" %% %s]\\n\",\n         in_file_size, out_file_size,\n               file_size_diff * 100 / in_file_size,\n               (out_file_size >= in_file_size) ?\n                     \"increase\" : \"decrease\");\n\n   /* If this was an in-place operation,\n    * replace input file with output file */\n   if (in_place)\n   {\n      filestream_delete(in_file_path);\n      if (filestream_rename(out_file_path, in_file_path))\n      {\n         fprintf(stderr, \"ERROR: Failed to rename temporary file\\n\");\n         fprintf(stderr, \"   From: %s\\n\", out_file_path);\n         fprintf(stderr, \"   To:   %s\\n\", in_file_path);\n         goto end;\n      }\n   }\n\n   ret = 0;\n\nend:\n   if (in_file)\n   {\n      intfstream_close(in_file);\n      free(in_file);\n   }\n\n   if (out_file)\n   {\n      intfstream_close(out_file);\n      free(out_file);\n   }\n\n   return ret;\n}\n"
  },
  {
    "path": "samples/streams/rzip/rzip_chunk_size_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rzip_chunk_size_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression test for RZIP chunk-size DoS hardening.\n *\n * Pre-patch, rzipstream_read_file_header() accepted any attacker-\n * controlled 32-bit value for chunk_size (the declared uncompressed\n * chunk size, read from the 20-byte file header).  A crafted header\n * with chunk_size = UINT32_MAX caused the init path downstream to\n * allocate ~4 GiB for the input buffer and another ~4 GiB (x2) for\n * the output buffer -- a 12 GiB allocation per rzipstream_open() call\n * on a malformed file.\n *\n * Patch caps chunk_size at RZIP_MAX_CHUNK_SIZE (64 MiB).\n *\n * This test writes crafted RZIP headers to a temp file and feeds\n * them to rzipstream_open().  Expected behaviour on patched code:\n * NULL (header rejected).  On unpatched code: rzipstream_open\n * either succeeds (triggering the large allocation) or fails later\n * in the init path for reasons unrelated to the chunk-size cap.\n *\n * The test also verifies that a reasonable chunk_size (matching the\n * RZIP default of 128 KiB) is still accepted.\n *\n * The per-chunk compressed_chunk_size cap is NOT exercised here --\n * reaching that code path requires feeding the reader a valid zlib\n * stream, which in turn requires calling the RetroArch trans_stream\n * API; that inflates the test significantly for marginal extra\n * coverage.  The chunk_size cap in the file header is the larger\n * and more impactful of the two pre-patch DoS vectors.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n\n#include <boolean.h>\n\n#include <streams/rzip_stream.h>\n#include <streams/file_stream.h>\n\n#define RETRO_VFS_FILE_ACCESS_READ (1 << 0)\n\nstatic int failures = 0;\n\n/* --- RZIP header builder ----------------------------------------- */\n\nstatic void put_u32_le(uint8_t *p, uint32_t v)\n{\n   p[0] =  v        & 0xff;\n   p[1] = (v >>  8) & 0xff;\n   p[2] = (v >> 16) & 0xff;\n   p[3] = (v >> 24) & 0xff;\n}\n\nstatic void put_u64_le(uint8_t *p, uint64_t v)\n{\n   size_t i;\n   for (i = 0; i < 8; i++)\n      p[i] = (uint8_t)(v >> (i * 8));\n}\n\n/* Build a 20-byte RZIP header with the given chunk_size and total\n * uncompressed size.  Magic bytes match rzip_stream.c. */\nstatic void build_rzip_header(uint8_t *dst,\n      uint32_t chunk_size, uint64_t total_size)\n{\n   dst[0] = 35;    /* '#' */\n   dst[1] = 82;    /* 'R' */\n   dst[2] = 90;    /* 'Z' */\n   dst[3] = 73;    /* 'I' */\n   dst[4] = 80;    /* 'P' */\n   dst[5] = 118;   /* 'v' */\n   dst[6] = 1;     /* RZIP_VERSION (matches libretro-common) */\n   dst[7] = 35;    /* '#' */\n   put_u32_le(dst + 8,  chunk_size);\n   put_u64_le(dst + 12, total_size);\n}\n\n/* --- test harness ------------------------------------------------ */\n\nstatic void write_file(const char *path, const void *data, size_t len)\n{\n   FILE *fp = fopen(path, \"wb\");\n   if (!fp)\n      abort();\n   if (fwrite(data, 1, len, fp) != len)\n      abort();\n   fclose(fp);\n}\n\nstatic void expect_rzip_rejected(const char *label,\n      uint32_t chunk_size, uint64_t total_size)\n{\n   const char   *tmp_path = \"rarch_rzip_regression_test.rz\";\n   uint8_t       header[20];\n   rzipstream_t *stream;\n\n   build_rzip_header(header, chunk_size, total_size);\n   write_file(tmp_path, header, sizeof(header));\n\n   stream = rzipstream_open(tmp_path, RETRO_VFS_FILE_ACCESS_READ);\n   remove(tmp_path);\n\n   if (stream)\n   {\n      printf(\"[FAILED] %-40s chunk_size=0x%08x accepted (expected reject)\\n\",\n            label, chunk_size);\n      rzipstream_close(stream);\n      failures++;\n      return;\n   }\n   printf(\"[SUCCESS] %-40s chunk_size=0x%08x rejected\\n\", label, chunk_size);\n}\n\nint main(void)\n{\n   /* The pre-patch bugs: chunk_size up to UINT32_MAX was accepted,\n    * forcing multi-GiB allocations on init.  All of these must now\n    * be rejected by the RZIP_MAX_CHUNK_SIZE cap. */\n   expect_rzip_rejected(\"UINT32_MAX chunk_size\",\n         0xFFFFFFFFu, 1);\n   expect_rzip_rejected(\"near UINT32_MAX\",\n         0xFFFFFFF0u, 1);\n   expect_rzip_rejected(\"2 GiB chunk_size\",\n         (uint32_t)(2u * 1024 * 1024 * 1024), 1);\n   expect_rzip_rejected(\"1 GiB chunk_size\",\n         (uint32_t)(1u * 1024 * 1024 * 1024), 1);\n   expect_rzip_rejected(\"128 MiB (just above cap)\",\n         (uint32_t)(128 * 1024 * 1024), 1);\n\n   /* Sanity: legitimate small chunk_size should still be accepted\n    * past the header check.  rzipstream_open will return NULL on\n    * this file too because there is no chunk body after the header\n    * -- but the NULL will come from the chunk-read path, not from\n    * the chunk_size cap.  We therefore can't distinguish accept\n    * from cap-reject at the rzipstream_open boundary for a\n    * header-only file.  So instead we check the cap boundary\n    * itself: cap + 1 must reject, cap must accept past the cap\n    * check.  Both paths still fail at the chunk-read step, but the\n    * pre-patch bug caused ~12 GiB of allocation BEFORE that step,\n    * so \"rejected at header\" vs \"rejected later\" is the real\n    * distinction and is proven by the rejections above. */\n\n   if (failures)\n   {\n      printf(\"\\n%d test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll RZIP chunk_size regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/string/strlcpy_append/Makefile",
    "content": "TARGET := strlcpy_append_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# strlcpy_append lives in libretro-common/string/stdstring.c.\n# Only the helper itself plus strlcpy (compat_strl.c) are needed\n# at link time.\nSOURCES := \\\n\tstrlcpy_append_test.c \\\n\t$(LIBRETRO_COMM_DIR)/string/stdstring.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -O0 -I$(LIBRETRO_COMM_DIR)/include\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/string/strlcpy_append/strlcpy_append_test.c",
    "content": "/* Copyright  (C) 2010-2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (strlcpy_append_test.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression test for strlcpy_append in\n * libretro-common/string/stdstring.c.\n *\n * strlcpy_append exists because the unsafe idiom\n *     _len += strlcpy(s + _len, src, len - _len);\n * silently corrupts @s on truncation: strlcpy returns\n * strlen(@src), so once @src is too long for the remaining\n * space, _len overshoots @len and the next subtraction\n * (len - _len) underflows size_t.\n *\n * Contract: on success the function advances *pos by\n * strlen(@src) and returns 0.  On truncation it leaves @s\n * NUL-terminated and clamps *pos to len - 1, so subsequent\n * calls in a chain short-circuit (also returning -1).  This\n * lets callers chain three or more appends and check just\n * the final return value.\n *\n * Heap-allocated destinations sized to exactly the legal\n * capacity so AddressSanitizer flags any reintroduction of\n * the unbounded chain.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <string/stdstring.h>\n\nstatic int failures = 0;\n\n#define EXPECT_EQ_INT(got, want, msg) do { \\\n   long _g = (long)(got), _w = (long)(want); \\\n   if (_g != _w) { \\\n      printf(\"[ERROR] %s:%d  %s  got=%ld want=%ld\\n\", \\\n            __func__, __LINE__, (msg), _g, _w); \\\n      failures++; \\\n   } \\\n} while (0)\n\n#define EXPECT_EQ_STR(got, want, msg) do { \\\n   if (strcmp((got), (want)) != 0) { \\\n      printf(\"[ERROR] %s:%d  %s  got=\\\"%s\\\" want=\\\"%s\\\"\\n\", \\\n            __func__, __LINE__, (msg), (got), (want)); \\\n      failures++; \\\n   } \\\n} while (0)\n\n#define EXPECT_TRUE(cond, msg) do { \\\n   if (!(cond)) { \\\n      printf(\"[ERROR] %s:%d  %s\\n\", __func__, __LINE__, (msg)); \\\n      failures++; \\\n   } \\\n} while (0)\n\n/* ---- tests ------------------------------------------------ */\n\nstatic void test_basic_append(void)\n{\n   char  *s   = (char*)malloc(16);\n   size_t pos = 0;\n   int    rv, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 16);\n\n   rv = strlcpy_append(s, 16, &pos, \"hello\");\n   EXPECT_EQ_INT(rv, 0, \"rv\");\n   EXPECT_EQ_INT(pos, 5, \"pos\");\n   EXPECT_EQ_STR(s, \"hello\", \"buffer\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] basic append\\n\");\n}\n\nstatic void test_chained_append(void)\n{\n   char  *s   = (char*)malloc(32);\n   size_t pos = 0;\n   int    rv1, rv2, rv3, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 32);\n\n   rv1 = strlcpy_append(s, 32, &pos, \"hello, \");\n   rv2 = strlcpy_append(s, 32, &pos, \"world\");\n   rv3 = strlcpy_append(s, 32, &pos, \"!\");\n   EXPECT_EQ_INT(rv1, 0, \"rv1\");\n   EXPECT_EQ_INT(rv2, 0, \"rv2\");\n   EXPECT_EQ_INT(rv3, 0, \"rv3\");\n   EXPECT_EQ_INT(pos, 13, \"pos\");\n   EXPECT_EQ_STR(s, \"hello, world!\", \"buffer\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] chained append\\n\");\n}\n\nstatic void test_truncation_at_boundary(void)\n{\n   /* Buffer sized exactly for \"hello\" + NUL = 6.  First append\n    * fits exactly.  Second append truncates: rv = -1, pos\n    * clamps to len - 1 = 5, buffer remains \"hello\". */\n   char  *s   = (char*)malloc(6);\n   size_t pos = 0;\n   int    rv, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 6);\n\n   rv = strlcpy_append(s, 6, &pos, \"hello\");\n   EXPECT_EQ_INT(rv, 0, \"first rv\");\n   EXPECT_EQ_INT(pos, 5, \"first pos\");\n   EXPECT_EQ_STR(s, \"hello\", \"buffer after first\");\n\n   rv = strlcpy_append(s, 6, &pos, \"x\");\n   EXPECT_EQ_INT(rv, -1, \"second rv (truncation)\");\n   EXPECT_EQ_INT(pos, 5, \"pos clamped to len - 1\");\n   EXPECT_EQ_STR(s, \"hello\", \"buffer NUL-terminated at len - 1\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] truncation at boundary\\n\");\n}\n\nstatic void test_truncation_wide(void)\n{\n   /* Source much larger than destination.  Pre-fix the naive\n    * idiom would have memcpy'd off the end of s; with\n    * strlcpy_append the call clamps without writing past the\n    * buffer.  Heap-allocated to exactly 4 bytes so ASan flags\n    * any OOB. */\n   char  *s   = (char*)malloc(4);\n   size_t pos = 0;\n   int    rv, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 4);\n\n   rv = strlcpy_append(s, 4, &pos,\n         \"this string is much longer than the destination\");\n   EXPECT_EQ_INT(rv, -1, \"rv\");\n   EXPECT_EQ_INT(pos, 3, \"pos clamped to len - 1\");\n   /* strlcpy fills 3 chars + NUL.  Buffer is \"thi\". */\n   EXPECT_EQ_STR(s, \"thi\", \"buffer truncated and NUL-terminated\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] truncation by wide margin\\n\");\n}\n\nstatic void test_chain_short_circuits_after_truncation(void)\n{\n   /* Once a previous call truncates and clamps *pos to len - 1,\n    * every subsequent call short-circuits with -1 without\n    * writing past the buffer.  This is the property that makes\n    * \"check only the last return value\" safe. */\n   char  *s   = (char*)malloc(8);\n   size_t pos = 0;\n   int    rv1, rv2, rv3, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 8);\n\n   rv1 = strlcpy_append(s, 8, &pos, \"ab\");\n   rv2 = strlcpy_append(s, 8, &pos,\n         \"this exceeds the remaining space\");\n   rv3 = strlcpy_append(s, 8, &pos, \"cd\");\n\n   EXPECT_EQ_INT(rv1, 0,  \"rv1 fits\");\n   EXPECT_EQ_INT(rv2, -1, \"rv2 truncates\");\n   EXPECT_EQ_INT(rv3, -1, \"rv3 short-circuits\");\n   EXPECT_EQ_INT(pos, 7,  \"pos clamped at len - 1\");\n   EXPECT_TRUE(strlen(s) <= 7, \"buffer fits\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] chain short-circuits after truncation\\n\");\n}\n\nstatic void test_empty_source(void)\n{\n   char  *s   = (char*)malloc(8);\n   size_t pos = 0;\n   int    rv, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 8);\n\n   rv = strlcpy_append(s, 8, &pos, \"\");\n   EXPECT_EQ_INT(rv, 0, \"rv\");\n   EXPECT_EQ_INT(pos, 0, \"pos unchanged\");\n   EXPECT_EQ_STR(s, \"\", \"buffer empty\");\n\n   rv = strlcpy_append(s, 8, &pos, \"ok\");\n   EXPECT_EQ_INT(rv, 0, \"second rv\");\n   EXPECT_EQ_INT(pos, 2, \"second pos\");\n   EXPECT_EQ_STR(s, \"ok\", \"second buffer\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] empty source\\n\");\n}\n\nstatic void test_null_args(void)\n{\n   char   buf[16];\n   size_t pos = 0;\n   int    saved = failures;\n\n   EXPECT_EQ_INT(strlcpy_append(NULL, 16, &pos, \"x\"), -1, \"NULL s\");\n   EXPECT_EQ_INT(strlcpy_append(buf,  16, NULL, \"x\"), -1, \"NULL pos\");\n   EXPECT_EQ_INT(strlcpy_append(buf,  16, &pos, NULL), -1, \"NULL src\");\n   EXPECT_EQ_INT(strlcpy_append(buf,   0, &pos, \"x\"),  -1, \"zero len\");\n\n   if (failures == saved) printf(\"[SUCCESS] NULL/zero args rejected\\n\");\n}\n\nstatic void test_pos_at_or_past_len(void)\n{\n   char  *s   = (char*)malloc(8);\n   size_t pos = 8;\n   int    rv, saved = failures;\n   if (!s) { printf(\"[ERROR] alloc\\n\"); failures++; return; }\n   memset(s, 0, 8);\n\n   rv = strlcpy_append(s, 8, &pos, \"x\");\n   EXPECT_EQ_INT(rv, -1, \"pos == len rejects\");\n   EXPECT_EQ_INT(pos, 7, \"pos clamped to len - 1\");\n\n   pos = 99;\n   rv  = strlcpy_append(s, 8, &pos, \"x\");\n   EXPECT_EQ_INT(rv, -1, \"pos > len rejects\");\n   EXPECT_EQ_INT(pos, 7, \"pos clamped to len - 1\");\n\n   free(s);\n   if (failures == saved) printf(\"[SUCCESS] pos at/past len rejected and clamped\\n\");\n}\n\nint main(void)\n{\n   test_basic_append();\n   test_chained_append();\n   test_truncation_at_boundary();\n   test_truncation_wide();\n   test_chain_short_circuits_after_truncation();\n   test_empty_source();\n   test_null_args();\n   test_pos_at_or_past_len();\n\n   if (failures)\n   {\n      printf(\"\\n%d strlcpy_append test(s) failed\\n\", failures);\n      return 1;\n   }\n   printf(\"\\nAll strlcpy_append regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "samples/string/word_wrap_overflow_test/Makefile",
    "content": "TARGET := word_wrap_overflow_test\n\nLIBRETRO_COMM_DIR := ../../..\n\n# word_wrap_wideglyph lives in libretro-common/string/stdstring.c.\n# Its only non-libc dependency is utf8skip from encoding_utf.c\n# (used to walk UTF-8 codepoint boundaries in the input string).\nSOURCES := \\\n\tword_wrap_overflow_test.c \\\n\t$(LIBRETRO_COMM_DIR)/string/stdstring.c \\\n\t$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \\\n\t$(LIBRETRO_COMM_DIR)/compat/compat_posix_string.c\n\nOBJS := $(SOURCES:.c=.o)\n\nCFLAGS += -Wall -pedantic -std=gnu99 -g -O0 -I$(LIBRETRO_COMM_DIR)/include\n\nifneq ($(SANITIZER),)\n   CFLAGS  := -fsanitize=$(SANITIZER) -fno-omit-frame-pointer $(CFLAGS)\n   LDFLAGS := -fsanitize=$(SANITIZER) $(LDFLAGS)\nendif\n\nall: $(TARGET)\n\n%.o: %.c\n\t$(CC) -c -o $@ $< $(CFLAGS)\n\n$(TARGET): $(OBJS)\n\t$(CC) -o $@ $^ $(LDFLAGS)\n\nclean:\n\trm -f $(TARGET) $(OBJS)\n\n.PHONY: clean\n"
  },
  {
    "path": "samples/string/word_wrap_overflow_test/word_wrap_overflow_test.c",
    "content": "/* Regression test for return-value-exceeds-bytes-written in\n * word_wrap_wideglyph (libretro-common/string/stdstring.c).\n *\n * Pre-patch, word_wrap_wideglyph had three classes of return path\n * that propagated strlcpy()'s return value directly, e.g.:\n *\n *   if (src_end - src < line_width)\n *      return strlcpy(s, src, len);\n *\n *   ...\n *\n *   return (size_t)(s - s_start) + strlcpy(s, src, remaining);\n *\n * strlcpy() returns strlen(src), not bytes-actually-written, so on\n * truncation (destination smaller than source) the returned value\n * exceeds the number of bytes written into the destination buffer.\n *\n * The sister function word_wrap() has a `len < src_len + 1` guard\n * up front that bails to 0 when the buffer is too small, sidestepping\n * the issue.  word_wrap_wideglyph has no such guard and tries to fit\n * what it can -- which is correct behaviour, but the inflated return\n * value violates the implicit contract every caller in the tree\n * depends on.\n *\n * Concrete impact: three menu drivers (xmb, ozone, materialui) feed\n * this return value as the `n` argument to memchr() over the wrapped\n * destination buffer, looking for newline boundaries when laying out\n * messageboxes.  Pre-patch, an inflated `n` walks memchr past the\n * buffer end into adjacent stack memory.  A '\\n' (0x0A) byte found\n * there yields a wild pointer used in pointer arithmetic and as a\n * length argument to font_driver_get_message_width(), leading to\n * stack info disclosure or a crash.  Reachable in CJK locales\n * (which select word_wrap_wideglyph via msg_hash_get_wideglyph_str)\n * via any messagebox payload that exceeds MENU_LABEL_MAX_LENGTH\n * (default 256 bytes) -- error notifications, file paths, network\n * handshake text, search results.\n *\n * Post-patch, every return path computes bytes-actually-written\n * from strlcpy's contract:\n *\n *   copied = strlcpy(s, src, n);\n *   if (copied >= n) copied = (n > 0) ? n - 1 : 0;\n *   return ... + copied;\n *\n * so the returned value is always a valid offset into the\n * destination buffer.  This test asserts that invariant directly\n * and additionally exercises the call shape used by the menu\n * drivers (memchr over the destination using the returned length),\n * so ASan flags pre-patch builds with heap-buffer-overflow.\n *\n * The test uses heap allocation (not a stack buffer) so ASan's\n * red-zone instrumentation gives a sharp signal when the bug is\n * present.  Without ASan, the test still detects the bug on its\n * own via the return-value-exceeds-buffer-size assertion.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <string/stdstring.h>\n\nstatic int failures = 0;\n\n/* A long ASCII source with no embedded newlines or wide glyphs.\n * \"ASCII through wideglyph\" is the worst-case for this function:\n * line 358's early-return branch fires only when the entire input\n * is shorter than line_width, so we must use input >= line_width\n * to drive flow through the main loop and the late-return paths\n * at lines 384 / 420 / 438.  The rewinds happen at every space.\n */\nstatic const char *long_src =\n   \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam \"\n   \"nec enim quis orci euismod efficitur at nec arcu. Vivamus \"\n   \"imperdiet est feugiat massa rhoncus porttitor at vitae ante. \"\n   \"Nunc a orci vel ipsum tempor posuere sed a lacus. Ut erat \"\n   \"odio, ultrices vitae iaculis fringilla, iaculis ut eros. Sed \"\n   \"facilisis viverra lectus et ullamcorper. Aenean risus ex, \"\n   \"ornare eget scelerisque ac, imperdiet eu ipsum. Morbi \"\n   \"pellentesque erat metus, sit amet aliquet libero rutrum et. \"\n   \"Integer non ullamcorper tellus.\";\n\nstatic void check_return_value(const char *case_name,\n      char *dst, size_t dst_size, size_t returned,\n      const char *src)\n{\n   /* Returned length must NEVER exceed bytes-actually-written.\n    * Bytes written is at most dst_size - 1 (room for the NUL). */\n   if (returned >= dst_size)\n   {\n      printf(\"[ERROR] %s: word_wrap_wideglyph returned %zu, \"\n            \"destination buffer is only %zu bytes (cannot exceed \"\n            \"%zu bytes-written)\\n\",\n            case_name, returned, dst_size,\n            dst_size > 0 ? dst_size - 1 : 0);\n      failures++;\n      return;\n   }\n\n   /* Returned length must equal strlen of the destination -- this\n    * is the contract menu-driver callers depend on. */\n   {\n      size_t actual = strlen(dst);\n      if (returned != actual)\n      {\n         printf(\"[ERROR] %s: word_wrap_wideglyph returned %zu but \"\n               \"strlen(dst) is %zu\\n\",\n               case_name, returned, actual);\n         failures++;\n         return;\n      }\n   }\n\n   /* Mimic the ozone/xmb/materialui messagebox call shape: use the\n    * returned value as the `n` argument to memchr() over the\n    * destination buffer.  Pre-patch, an inflated returned value\n    * walks memchr past the buffer.  ASan flags this as a heap-\n    * buffer-overflow.  Post-patch, the read stays within dst. */\n   {\n      const char *nl = (const char *)memchr(dst, '\\n', returned);\n      (void)nl; /* presence/absence not asserted; the read itself\n                 * is the test (ASan is the discriminator) */\n   }\n\n   /* (void) src to suppress unused-parameter when not in debug. */\n   (void)src;\n\n   printf(\"[SUCCESS] %s: returned=%zu, strlen(dst)=%zu, dst_size=%zu\\n\",\n         case_name, returned, strlen(dst), dst_size);\n}\n\n/* Case 1: destination smaller than line_width.\n * Pre-patch this hits the `src_end - src < line_width` branch?\n * No -- src_len > line_width, so we reach the main loop.  The\n * rewinds at lastspace cause early returns at lines 384/420/438\n * via strlcpy with a too-small `remaining`. */\nstatic void test_truncating_normal_case(void)\n{\n   const size_t dst_size = 64;\n   char *dst = (char *)malloc(dst_size);\n   size_t returned;\n\n   if (!dst) { printf(\"[FATAL] OOM\\n\"); failures++; return; }\n\n   memset(dst, 0xCC, dst_size);   /* poison so strlen catches non-NUL-termination */\n   dst[dst_size - 1] = '\\0';      /* ensure strlen() terminates if NUL is missing */\n\n   returned = word_wrap_wideglyph(dst, dst_size, long_src,\n         strlen(long_src),\n         /* line_width */ 40,\n         /* wideglyph_width */ 100,\n         /* max_lines */ 0);\n\n   check_return_value(\"truncating_normal\", dst, dst_size, returned, long_src);\n   free(dst);\n}\n\n/* Case 2: very small destination (smaller than even one line\n * worth of source).  Pre-patch this still hits the buggy path\n * because the loop's char_len-vs-len check at line 367 stopped\n * the loop, leaving s_start..s short, but the late strlcpy\n * (whichever fired first) still returned a too-large value. */\nstatic void test_truncating_tiny_dest(void)\n{\n   const size_t dst_size = 16;\n   char *dst = (char *)malloc(dst_size);\n   size_t returned;\n\n   if (!dst) { printf(\"[FATAL] OOM\\n\"); failures++; return; }\n\n   memset(dst, 0xCC, dst_size);\n   dst[dst_size - 1] = '\\0';\n\n   returned = word_wrap_wideglyph(dst, dst_size, long_src,\n         strlen(long_src), 40, 100, 0);\n\n   check_return_value(\"truncating_tiny_dest\", dst, dst_size,\n         returned, long_src);\n   free(dst);\n}\n\n/* Case 3: destination is exactly large enough for the whole\n * wrapped output.  Tests that the fix doesn't regress the\n * non-truncating case -- return value should equal strlen(dst). */\nstatic void test_fits(void)\n{\n   const size_t dst_size = 1024;\n   char *dst = (char *)malloc(dst_size);\n   size_t returned;\n\n   if (!dst) { printf(\"[FATAL] OOM\\n\"); failures++; return; }\n\n   memset(dst, 0xCC, dst_size);\n   dst[dst_size - 1] = '\\0';\n\n   returned = word_wrap_wideglyph(dst, dst_size, long_src,\n         strlen(long_src), 40, 100, 0);\n\n   check_return_value(\"fits\", dst, dst_size, returned, long_src);\n   free(dst);\n}\n\n/* Case 4: input shorter than line_width -- exercises the early\n * return at line 358 (the simplest of the buggy paths).  Pre-\n * patch, this returns strlen(short_src), which is fine when the\n * destination is large enough.  This case verifies post-patch\n * doesn't regress the easy path. */\nstatic void test_short_input_large_dest(void)\n{\n   const char *short_src = \"Hello, world.\";\n   const size_t dst_size = 64;\n   char *dst = (char *)malloc(dst_size);\n   size_t returned;\n\n   if (!dst) { printf(\"[FATAL] OOM\\n\"); failures++; return; }\n\n   memset(dst, 0xCC, dst_size);\n   dst[dst_size - 1] = '\\0';\n\n   returned = word_wrap_wideglyph(dst, dst_size, short_src,\n         strlen(short_src), 40, 100, 0);\n\n   check_return_value(\"short_input_large_dest\", dst, dst_size,\n         returned, short_src);\n   free(dst);\n}\n\n/* Case 5: input shorter than line_width AND destination too small.\n * This is the line-358 truncation case: pre-patch returns\n * strlen(src) which exceeds dst_size; post-patch clamps to dst_size-1. */\nstatic void test_short_input_tiny_dest(void)\n{\n   const char *src = \"Hello, world! This is a moderately long string.\";\n   const size_t dst_size = 16; /* smaller than src */\n   char *dst = (char *)malloc(dst_size);\n   size_t returned;\n\n   if (!dst) { printf(\"[FATAL] OOM\\n\"); failures++; return; }\n\n   memset(dst, 0xCC, dst_size);\n   dst[dst_size - 1] = '\\0';\n\n   /* line_width chosen larger than src_len so the function takes\n    * the line-358 early-return path. */\n   returned = word_wrap_wideglyph(dst, dst_size, src,\n         strlen(src),\n         /* line_width */ 100, /* > strlen(src) */\n         100, 0);\n\n   check_return_value(\"short_input_tiny_dest\", dst, dst_size,\n         returned, src);\n   free(dst);\n}\n\nint main(void)\n{\n   test_truncating_normal_case();\n   test_truncating_tiny_dest();\n   test_fits();\n   test_short_input_large_dest();\n   test_short_input_tiny_dest();\n\n   if (failures)\n   {\n      printf(\"\\n%d word_wrap_wideglyph regression test(s) failed\\n\",\n            failures);\n      return 1;\n   }\n   printf(\"\\nAll word_wrap_wideglyph regression tests passed.\\n\");\n   return 0;\n}\n"
  },
  {
    "path": "streams/chd_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (chd_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <boolean.h>\n#include <compat/strl.h>\n\n#include <streams/chd_stream.h>\n#include <retro_endianness.h>\n#include <libchdr/chd.h>\n\n#define SECTOR_RAW_SIZE 2352\n#define SECTOR_SIZE 2048\n#define SUBCODE_SIZE 96\n#define TRACK_PAD 4\n\nstruct chdstream\n{\n   chd_file *chd;\n   /* Loaded hunk */\n   uint8_t *hunkmem;\n   /* Byte offset where track data starts (after pregap) */\n   size_t track_start;\n   /* Byte offset where track data ends */\n   size_t track_end;\n   /* Byte offset of read cursor */\n   size_t offset;\n   /* Loaded hunk number */\n   int32_t hunknum;\n   /* Size of frame taken from each hunk */\n   uint32_t frame_size;\n   /* Offset of data within frame */\n   uint32_t frame_offset;\n   /* Number of frames per hunk */\n   uint32_t frames_per_hunk;\n   /* First frame of track in chd */\n   uint32_t track_frame;\n   /* Should we swap bytes? */\n   bool swab;\n};\n\ntypedef struct metadata\n{\n   uint32_t frame_offset;\n   uint32_t frames;\n   uint32_t pad;\n   uint32_t extra;\n   uint32_t pregap;\n   uint32_t postgap;\n   uint32_t track;\n   char type[64];\n   char subtype[32];\n   char pgtype[32];\n   char pgsub[32];\n} metadata_t;\n\nstatic uint32_t padding_frames(uint32_t frames)\n{\n   return ((frames + TRACK_PAD - 1) & ~(TRACK_PAD - 1)) - frames;\n}\n\nstatic bool\nchdstream_get_meta(chd_file *chd, int idx, metadata_t *md)\n{\n   char meta[256];\n   uint32_t meta_size = 0;\n   chd_error err;\n\n   meta[0] = '\\0';\n\n   memset(md, 0, sizeof(*md));\n\n   err = chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, idx, meta,\n         sizeof(meta), &meta_size, NULL, NULL);\n\n   if (err == CHDERR_NONE)\n   {\n      const char *ptr = meta;\n      size_t remaining = strlen(meta);\n\n      while (remaining)\n      {\n         size_t klen, vlen;\n         const char *val;\n         const char *end;\n         const char *key = ptr;\n         const char *sep = (const char *)memchr(key, ':', remaining);\n         if (!sep)\n            break;\n\n         klen       = sep - key;\n         val        = sep + 1;\n         remaining -= klen + 1;\n\n         end        = (const char *)memchr(val, ' ', remaining);\n         vlen       = end ? (size_t)(end - val) : remaining;\n\n         if (klen == 5 && !memcmp(key, \"TRACK\", 5))\n            md->track = (unsigned)strtoul(val, NULL, 10);\n         else if (klen == 4 && !memcmp(key, \"TYPE\", 4))\n            strlcpy(md->type, val, vlen + 1 < sizeof(md->type) ? vlen + 1 : sizeof(md->type));\n         else if (klen == 7 && !memcmp(key, \"SUBTYPE\", 7))\n            strlcpy(md->subtype, val, vlen + 1 < sizeof(md->subtype) ? vlen + 1 : sizeof(md->subtype));\n         else if (klen == 6 && !memcmp(key, \"FRAMES\", 6))\n            md->frames = (unsigned)strtoul(val, NULL, 10);\n         else if (klen == 6 && !memcmp(key, \"PREGAP\", 6))\n            md->pregap = (unsigned)strtoul(val, NULL, 10);\n         else if (klen == 6 && !memcmp(key, \"PGTYPE\", 6))\n            strlcpy(md->pgtype, val, vlen + 1 < sizeof(md->pgtype) ? vlen + 1 : sizeof(md->pgtype));\n         else if (klen == 5 && !memcmp(key, \"PGSUB\", 5))\n            strlcpy(md->pgsub, val, vlen + 1 < sizeof(md->pgsub) ? vlen + 1 : sizeof(md->pgsub));\n         else if (klen == 7 && !memcmp(key, \"POSTGAP\", 7))\n            md->postgap = (unsigned)strtoul(val, NULL, 10);\n\n         ptr = end ? end + 1 : val + vlen;\n         remaining -= end ? vlen + 1 : vlen;\n      }\n\n      md->extra = padding_frames(md->frames);\n      return true;\n   }\n\n   err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, idx, meta,\n         sizeof(meta), &meta_size, NULL, NULL);\n\n   if (err == CHDERR_NONE)\n   {\n      size_t len;\n      const char *start;\n      const char *p = meta;\n\n      if (strncmp(p, \"TRACK:\", 6) != 0)\n         return false;\n      p += 6;\n      md->track = strtoul(p, (char **)&p, 10);\n\n      if (*p++ != ' ' || strncmp(p, \"TYPE:\", 5) != 0)\n         return false;\n      p     += 5;\n      start  = p;\n      while (*p && *p != ' ')\n         p++;\n      len = p - start;\n      if (len == 0 || len >= sizeof(md->type))\n         return false;\n      memcpy(md->type, start, len);\n      md->type[len] = '\\0';\n\n      if (*p++ != ' ' || strncmp(p, \"SUBTYPE:\", 8) != 0)\n         return false;\n      p += 8;\n      start = p;\n      while (*p && *p != ' ')\n         p++;\n      len = p - start;\n      if (len == 0 || len >= sizeof(md->subtype))\n         return false;\n      memcpy(md->subtype, start, len);\n      md->subtype[len] = '\\0';\n\n      if (*p++ != ' ' || strncmp(p, \"FRAMES:\", 7) != 0)\n         return false;\n      p += 7;\n      md->frames = strtoul(p, NULL, 10);\n      md->extra  = padding_frames(md->frames);\n      return true;\n   }\n\n   err = chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, idx, meta,\n         sizeof(meta), &meta_size, NULL, NULL);\n\n   if (err == CHDERR_NONE)\n   {\n      char *p = meta;\n      while (*p)\n      {\n         size_t len;\n\n         if (strncmp(p, \"TRACK:\", 6) == 0)\n            md->track = strtoul(p + 6, &p, 10);\n         else if (strncmp(p, \"TYPE:\", 5) == 0)\n         {\n            p   += 5;\n            len  = 0;\n            while (p[len] && p[len] != ' ')\n               len++;\n            /* Pre-this-patch the memcpy/terminator was unbounded.\n             * GDROM_TRACK_METADATA_TAG is read from the .chd\n             * file (chd_get_metadata above) and the value field\n             * after \"TYPE:\" terminates at the next space; with a\n             * malicious .chd containing no space between \"TYPE:\"\n             * and a long run of bytes, len can reach almost the\n             * full meta[256] buffer and the memcpy below\n             * stack-overflows md->type (char[64]) into adjacent\n             * frame fields (subtype, pgtype, pgsub, then return\n             * address depending on layout).  Reject as malformed\n             * if the value can't fit in the destination.  Same\n             * guard as the SCD-format parser at line 166. */\n            if (len >= sizeof(md->type))\n               return false;\n            memcpy(md->type, p, len);\n            md->type[len] = '\\0';\n            p += len;\n         }\n         else if (strncmp(p, \"SUBTYPE:\", 8) == 0)\n         {\n            p   += 8;\n            len  = 0;\n            while (p[len] && p[len] != ' ')\n               len++;\n            if (len >= sizeof(md->subtype))\n               return false;\n            memcpy(md->subtype, p, len);\n            md->subtype[len] = '\\0';\n            p += len;\n         }\n         else if (strncmp(p, \"FRAMES:\", 7) == 0)\n            md->frames = strtoul(p + 7, &p, 10);\n         else if (strncmp(p, \"PAD:\", 4) == 0)\n            md->pad = strtoul(p + 4, &p, 10);\n         else if (strncmp(p, \"PREGAP:\", 7) == 0)\n            md->pregap = strtoul(p + 7, &p, 10);\n         else if (strncmp(p, \"PGTYPE:\", 7) == 0)\n         {\n            p   += 7;\n            len  = 0;\n            while (p[len] && p[len] != ' ')\n               len++;\n            if (len >= sizeof(md->pgtype))\n               return false;\n            memcpy(md->pgtype, p, len);\n            md->pgtype[len] = '\\0';\n            p += len;\n         }\n         else if (strncmp(p, \"PGSUB:\", 6) == 0)\n         {\n            p   += 6;\n            len  = 0;\n            while (p[len] && p[len] != ' ')\n               len++;\n            if (len >= sizeof(md->pgsub))\n               return false;\n            memcpy(md->pgsub, p, len);\n            md->pgsub[len] = '\\0';\n            p += len;\n         }\n         else if (strncmp(p, \"POSTGAP:\", 8) == 0)\n            md->postgap = strtoul(p + 8, &p, 10);\n         else\n            p++;\n      }\n      md->extra = padding_frames(md->frames);\n      return true;\n   }\n\n   err = chd_get_metadata(chd, DVD_METADATA_TAG, idx, meta,\n         sizeof(meta), &meta_size, NULL, NULL);\n\n   if (err == CHDERR_NONE)\n   {\n      md->track = 1;\n      strlcpy(md->type, \"DVD\", sizeof(md->type));\n      return true;\n   }\n\n   return false;\n}\n\nstatic bool\nchdstream_find_track_number(chd_file *fd, int32_t track, metadata_t *meta)\n{\n   uint32_t i;\n   uint32_t frame_offset = 0;\n\n   for (i = 0; true; ++i)\n   {\n      if (!chdstream_get_meta(fd, i, meta))\n         return false;\n\n      if (track == (int)meta->track)\n      {\n         meta->frame_offset = frame_offset;\n         return true;\n      }\n\n      frame_offset += meta->frames + meta->extra;\n   }\n}\n\nstatic bool\nchdstream_find_special_track(chd_file *fd, int32_t track, metadata_t *meta)\n{\n   int32_t i;\n   metadata_t iter;\n   int32_t largest_track = 0;\n   uint32_t largest_size = 0;\n\n   for (i = 1; true; ++i)\n   {\n      if (!chdstream_find_track_number(fd, i, &iter))\n      {\n         if (track == CHDSTREAM_TRACK_LAST && i > 1)\n            return chdstream_find_track_number(fd, i - 1, meta);\n\n         if (track == CHDSTREAM_TRACK_PRIMARY && largest_track != 0)\n            return chdstream_find_track_number(fd, largest_track, meta);\n\n         return false;\n      }\n\n      switch (track)\n      {\n         case CHDSTREAM_TRACK_FIRST_DATA:\n            if (strcmp(iter.type, \"AUDIO\"))\n            {\n               *meta = iter;\n               return true;\n            }\n            break;\n         case CHDSTREAM_TRACK_PRIMARY:\n            /* DVD tracks have no frame count in metadata but are always\n             * the primary data track - select immediately */\n            if (strcmp(iter.type, \"DVD\") == 0)\n            {\n               *meta = iter;\n               return true;\n            }\n            if (strcmp(iter.type, \"AUDIO\") && iter.frames > largest_size)\n            {\n               largest_size  = iter.frames;\n               largest_track = iter.track;\n            }\n            break;\n         default:\n            break;\n      }\n   }\n}\n\nstatic bool\nchdstream_find_track(chd_file *fd, int32_t track, metadata_t *meta)\n{\n   if (track < 0)\n      return chdstream_find_special_track(fd, track, meta);\n   return chdstream_find_track_number(fd, track, meta);\n}\n\nchdstream_t *chdstream_open(const char *path, int32_t track)\n{\n   metadata_t meta;\n   uint32_t pregap         = 0;\n   uint8_t *hunkmem        = NULL;\n   const chd_header *hd    = NULL;\n   chdstream_t *stream     = NULL;\n   chd_file *chd           = NULL;\n   chd_error err           = chd_open(path, CHD_OPEN_READ, NULL, &chd);\n   if (err != CHDERR_NONE)\n      return NULL;\n   if (!chdstream_find_track(chd, track, &meta))\n      goto error;\n   stream                  = (chdstream_t*)malloc(sizeof(*stream));\n   if (!stream)\n      goto error;\n   stream->chd             = NULL;\n   stream->swab            = false;\n   stream->frame_size      = 0;\n   stream->frame_offset    = 0;\n   stream->frames_per_hunk = 0;\n   stream->track_frame     = 0;\n   stream->track_start     = 0;\n   stream->track_end       = 0;\n   stream->offset          = 0;\n   stream->hunkmem         = NULL;\n   stream->hunknum         = -1;\n   hd                      = chd_get_header(chd);\n   hunkmem                 = (uint8_t*)malloc(hd->hunkbytes);\n   if (!hunkmem)\n      goto error;\n   stream->hunkmem         = hunkmem;\n   switch (meta.type[0])\n   {\n      case 'M':\n         if (meta.type[5] == '_')\n         {\n            if (meta.type[6] == 'R') /* MODE1_RAW or MODE2_RAW */\n               stream->frame_size = SECTOR_RAW_SIZE;\n            else /* MODE2_FORM... (unhandled, treat like default)*/\n               stream->frame_size = hd->unitbytes;\n         }\n         else /* MODE1 */\n            stream->frame_size = SECTOR_SIZE;\n         break;\n      case 'A': /* AUDIO */\n         stream->frame_size   = SECTOR_RAW_SIZE;\n         stream->swab         = true;\n         break;\n      case 'D': /* DVD */\n         stream->frame_size   = hd->unitbytes;\n         meta.frames          = hd->totalhunks;\n         break;\n      default:\n         stream->frame_size   = hd->unitbytes;\n         break;\n   }\n   /* Only include pregap data if it was in the track file */\n   if (meta.pgtype[0] != 'V')\n      pregap               = meta.pregap;\n   stream->chd             = chd;\n   stream->frames_per_hunk = hd->hunkbytes / hd->unitbytes;\n   stream->track_frame     = meta.frame_offset;\n   stream->track_start     = (size_t)pregap * stream->frame_size;\n   stream->track_end       = stream->track_start +\n                             (size_t)meta.frames * stream->frame_size;\n   return stream;\nerror:\n   chdstream_close(stream);\n   if (chd)\n      chd_close(chd);\n   return NULL;\n}\n\nvoid chdstream_close(chdstream_t *stream)\n{\n   if (!stream)\n      return;\n\n   if (stream->hunkmem)\n      free(stream->hunkmem);\n   if (stream->chd)\n      chd_close(stream->chd);\n   free(stream);\n}\n\nstatic bool\nchdstream_load_hunk(chdstream_t *stream, uint32_t hunknum)\n{\n   uint16_t *array;\n\n   if ((int)hunknum == stream->hunknum)\n      return true;\n\n   if (chd_read(stream->chd, hunknum, stream->hunkmem) != CHDERR_NONE)\n      return false;\n\n   if (stream->swab)\n   {\n      uint32_t i;\n      uint32_t count = chd_get_header(stream->chd)->hunkbytes / 2;\n      array          = (uint16_t*)stream->hunkmem;\n      for (i = 0; i < count; ++i)\n         array[i] = SWAP16(array[i]);\n   }\n\n   stream->hunknum = hunknum;\n   return true;\n}\n\nssize_t chdstream_read(chdstream_t *stream, void *data, size_t bytes)\n{\n   size_t end;\n   size_t data_offset   = 0;\n   const chd_header *hd = chd_get_header(stream->chd);\n   uint8_t         *out = (uint8_t*)data;\n\n   if (stream->track_end - stream->offset < bytes)\n      bytes             = stream->track_end - stream->offset;\n\n   end                  = stream->offset + bytes;\n\n   while (stream->offset < end)\n   {\n      uint32_t frame_offset = stream->offset % stream->frame_size;\n      uint32_t amount       = stream->frame_size - frame_offset;\n\n      if (amount > end - stream->offset)\n         amount = (uint32_t)(end - stream->offset);\n\n      /* In pregap */\n      if (stream->offset < stream->track_start)\n         memset(out + data_offset, 0, amount);\n      else\n      {\n         uint32_t chd_frame   = (uint32_t)(stream->track_frame +\n            (stream->offset - stream->track_start) / stream->frame_size);\n         uint32_t hunk        = chd_frame / stream->frames_per_hunk;\n         uint32_t hunk_offset = (chd_frame % stream->frames_per_hunk)\n            * hd->unitbytes;\n\n         if (!chdstream_load_hunk(stream, hunk))\n            return -1;\n\n         memcpy(out + data_offset,\n                stream->hunkmem + frame_offset\n                + hunk_offset + stream->frame_offset, amount);\n      }\n\n      data_offset    += amount;\n      stream->offset += amount;\n   }\n\n   return bytes;\n}\n\nint chdstream_getc(chdstream_t *stream)\n{\n   char c = 0;\n\n   if (chdstream_read(stream, &c, sizeof(c) != sizeof(c)))\n      return EOF;\n\n   return c;\n}\n\nchar *chdstream_gets(chdstream_t *stream, char *s, size_t len)\n{\n   int c;\n   size_t _len = 0;\n   while (_len < len && (c = chdstream_getc(stream)) != EOF)\n      s[_len++] = c;\n   if (_len < len)\n      s[_len]   = '\\0';\n   return s;\n}\n\nuint64_t chdstream_tell(chdstream_t *stream)\n{\n   return stream->offset;\n}\n\nvoid chdstream_rewind(chdstream_t *stream)\n{\n   stream->offset = 0;\n}\n\nint64_t chdstream_seek(chdstream_t *stream, int64_t offset, int whence)\n{\n   int64_t new_offset;\n\n   switch (whence)\n   {\n      case SEEK_SET:\n         new_offset = offset;\n         break;\n      case SEEK_CUR:\n         new_offset = stream->offset + offset;\n         break;\n      case SEEK_END:\n         new_offset = stream->track_end + offset;\n         break;\n      default:\n         return -1;\n   }\n\n   if (new_offset < 0)\n      return -1;\n\n   if ((size_t)new_offset > stream->track_end)\n      new_offset = stream->track_end;\n\n   stream->offset = new_offset;\n   return 0;\n}\n\nssize_t chdstream_get_size(chdstream_t *stream)\n{\n   return stream->track_end - stream->track_start;\n}\n\nuint32_t chdstream_get_track_start(chdstream_t *stream)\n{\n   uint32_t i;\n   metadata_t meta;\n   uint32_t frame_offset = 0;\n\n   for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)\n   {\n      if (stream->track_frame == frame_offset)\n         return meta.pregap * stream->frame_size;\n\n      frame_offset += meta.frames + meta.extra;\n   }\n\n   return 0;\n}\n\nuint32_t chdstream_get_frame_size(chdstream_t *stream)\n{\n   return stream->frame_size;\n}\n\nuint32_t chdstream_get_first_track_sector(chdstream_t* stream)\n{\n   uint32_t i;\n   metadata_t meta;\n   uint32_t frame_offset = 0;\n   uint32_t sector_offset = 0;\n\n   for (i = 0; chdstream_get_meta(stream->chd, i, &meta); ++i)\n   {\n      if (stream->track_frame == frame_offset)\n         return sector_offset;\n\n      sector_offset += meta.frames;\n      frame_offset += meta.frames + meta.extra;\n   }\n\n   return 0;\n}\n"
  },
  {
    "path": "streams/file_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (file_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n#include <ctype.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#ifdef _MSC_VER\n#include <compat/msvc.h>\n#endif\n\n#include <retro_miscellaneous.h>\n#include <file/file_path.h>\n#include <streams/file_stream.h>\n#define VFS_FRONTEND\n#include <vfs/vfs_implementation.h>\n\n#define VFS_ERROR_RETURN_VALUE -1\n\nstruct RFILE\n{\n   struct retro_vfs_file_handle *hfile;\n   bool err_flag;\n};\n\nstatic retro_vfs_get_path_t filestream_get_path_cb = NULL;\nstatic retro_vfs_open_t filestream_open_cb         = NULL;\nstatic retro_vfs_close_t filestream_close_cb       = NULL;\nstatic retro_vfs_size_t filestream_size_cb         = NULL;\nstatic retro_vfs_truncate_t filestream_truncate_cb = NULL;\nstatic retro_vfs_tell_t filestream_tell_cb         = NULL;\nstatic retro_vfs_seek_t filestream_seek_cb         = NULL;\nstatic retro_vfs_read_t filestream_read_cb         = NULL;\nstatic retro_vfs_write_t filestream_write_cb       = NULL;\nstatic retro_vfs_flush_t filestream_flush_cb       = NULL;\nstatic retro_vfs_remove_t filestream_remove_cb     = NULL;\nstatic retro_vfs_rename_t filestream_rename_cb     = NULL;\n\n/* VFS Initialization */\n\nvoid filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)\n{\n   const struct retro_vfs_interface *\n      vfs_iface           = vfs_info->iface;\n\n   filestream_get_path_cb = NULL;\n   filestream_open_cb     = NULL;\n   filestream_close_cb    = NULL;\n   filestream_tell_cb     = NULL;\n   filestream_size_cb     = NULL;\n   filestream_truncate_cb = NULL;\n   filestream_seek_cb     = NULL;\n   filestream_read_cb     = NULL;\n   filestream_write_cb    = NULL;\n   filestream_flush_cb    = NULL;\n   filestream_remove_cb   = NULL;\n   filestream_rename_cb   = NULL;\n\n   if (\n             (vfs_info->required_interface_version <\n             FILESTREAM_REQUIRED_VFS_VERSION)\n         || !vfs_iface)\n      return;\n\n   filestream_get_path_cb = vfs_iface->get_path;\n   filestream_open_cb     = vfs_iface->open;\n   filestream_close_cb    = vfs_iface->close;\n   filestream_size_cb     = vfs_iface->size;\n   filestream_truncate_cb = vfs_iface->truncate;\n   filestream_tell_cb     = vfs_iface->tell;\n   filestream_seek_cb     = vfs_iface->seek;\n   filestream_read_cb     = vfs_iface->read;\n   filestream_write_cb    = vfs_iface->write;\n   filestream_flush_cb    = vfs_iface->flush;\n   filestream_remove_cb   = vfs_iface->remove;\n   filestream_rename_cb   = vfs_iface->rename;\n}\n\n/* Callback wrappers */\nbool filestream_exists(const char *path)\n{\n   RFILE *dummy           = NULL;\n\n   if (!path || !*path)\n      return false;\n   if (!(dummy = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE)))\n      return false;\n\n   if (filestream_close(dummy) != 0)\n      free(dummy);\n\n   dummy = NULL;\n   return true;\n}\n\nint64_t filestream_get_size(RFILE *stream)\n{\n   int64_t output;\n\n   if (filestream_size_cb)\n      output = filestream_size_cb(stream->hfile);\n   else\n      output = retro_vfs_file_size_impl(\n            (libretro_vfs_implementation_file*)stream->hfile);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nint64_t filestream_truncate(RFILE *stream, int64_t length)\n{\n   int64_t output;\n\n   if (filestream_truncate_cb)\n      output = filestream_truncate_cb(stream->hfile, length);\n   else\n      output = retro_vfs_file_truncate_impl(\n            (libretro_vfs_implementation_file*)stream->hfile, length);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nRFILE* filestream_open(const char *path, unsigned mode, unsigned hints)\n{\n   struct retro_vfs_file_handle  *fp = NULL;\n   RFILE* output                     = (RFILE*)malloc(sizeof(RFILE));\n\n   if (!output)\n      return NULL;\n\n   if (filestream_open_cb)\n      fp = (struct retro_vfs_file_handle*)\n         filestream_open_cb(path, mode, hints);\n   else\n      fp = (struct retro_vfs_file_handle*)\n         retro_vfs_file_open_impl(path, mode, hints);\n\n   if (!fp)\n   {\n      free(output);\n      return NULL;\n   }\n\n   output->err_flag = false;\n   output->hfile    = fp;\n   return output;\n}\n\nchar* filestream_gets(RFILE *stream, char *s, size_t len)\n{\n   int c   = 0;\n   char *p = s;\n   if (!stream)\n      return NULL;\n\n   /* get max bytes or up to a newline */\n\n   for (len--; len > 0; len--)\n   {\n      if ((c = filestream_getc(stream)) == EOF)\n         break;\n      *p++ = c;\n      if (c == '\\n')\n         break;\n   }\n   *p = 0;\n\n   if (p == s && c == EOF)\n      return NULL;\n   return (s);\n}\n\nint filestream_getc(RFILE *stream)\n{\n   char c = 0;\n   if (stream && filestream_read(stream, &c, 1) == 1)\n      return (int)(unsigned char)c;\n   return EOF;\n}\n\nint filestream_vscanf(RFILE *stream, const char *format, va_list *args)\n{\n   char buf[4096];\n   char subfmt[256];\n   va_list args_copy;\n   const char *bufiter  = buf;\n   int        ret       = 0;\n   int64_t startpos     = filestream_tell(stream);\n   int64_t maxlen       = filestream_read(stream, buf, sizeof(buf) - 1);\n \n   if (maxlen <= 0)\n      return EOF;\n \n   buf[maxlen] = '\\0';\n \n#ifdef __va_copy\n   __va_copy(args_copy, *args);\n#else\n   va_copy(args_copy, *args);\n#endif\n \n   while (*format && *bufiter)\n   {\n      if (*format == '%')\n      {\n         int        sublen     = 0; /* Fix 4: initialize to 0 */\n         char      *subfmtiter = subfmt;\n         char      *subfmtend  = subfmt + sizeof(subfmt) - 4; /* reserve room for %n\\0 */\n         bool       asterisk   = false;\n \n         *subfmtiter++ = *format++; /* '%' */\n \n         /* handle %% literal percent */\n         if (*format == '%')\n         {\n            if (*bufiter != '%')\n               break;\n            bufiter++;\n            format++;\n            continue;\n         }\n \n         /* %[*][width][length]specifier */\n         if (*format == '*')\n         {\n            asterisk      = true;\n            *subfmtiter++ = *format++;\n         }\n \n         /* width digits */\n         while (*format >= '0' && *format <= '9' && subfmtiter < subfmtend)\n            *subfmtiter++ = *format++;\n \n         /* length modifier */\n         if (*format == 'h' || *format == 'l')\n         {\n            if (format[1] == format[0] && subfmtiter < subfmtend)\n               *subfmtiter++ = *format++;\n            if (subfmtiter < subfmtend)\n               *subfmtiter++ = *format++;\n         }\n         else if (*format == 'j' || *format == 'z'\n               || *format == 't' || *format == 'L')\n         {\n            if (subfmtiter < subfmtend)\n               *subfmtiter++ = *format++;\n         }\n \n         /* specifier */\n         if (*format == '[')\n         {\n            /* Fix 2: bounds-check subfmt and guard against missing ']' */\n            *subfmtiter++ = *format++; /* '[' */\n \n            /* handle negation */\n            if (*format == '^' && subfmtiter < subfmtend)\n               *subfmtiter++ = *format++;\n \n            /* handle literal ']' as first character in scanset */\n            if (*format == ']' && subfmtiter < subfmtend)\n               *subfmtiter++ = *format++;\n \n            while (*format && *format != ']' && subfmtiter < subfmtend)\n               *subfmtiter++ = *format++;\n \n            if (*format == ']')\n               *subfmtiter++ = *format++;\n            else\n               break; /* malformed format string — missing ']' */\n         }\n         else if (*format)\n            *subfmtiter++ = *format++;\n         else\n            break; /* format string ended after '%' + modifiers with no specifier */\n \n         /* append %n to measure consumed characters */\n         *subfmtiter++ = '%';\n         *subfmtiter++ = 'n';\n         *subfmtiter   = '\\0';\n \n         if (asterisk)\n         {\n            int v = sscanf(bufiter, subfmt, &sublen);\n            if (v == EOF)\n               break;\n            /* Fix 1: do NOT increment ret for suppressed assignments */\n            if (sublen == 0)\n               break; /* no input consumed — stop */\n         }\n         else\n         {\n            int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);\n            if (v == EOF)\n               break;\n            if (v != 1)\n               break;\n            ret++;  /* Fix 1: only increment for actual assignments */\n         }\n \n         bufiter += sublen;\n      }\n      else if (isspace((unsigned char)*format))\n      {\n         /* a single whitespace in format matches zero or more in input */\n         while (isspace((unsigned char)*bufiter))\n            bufiter++;\n         /* skip all contiguous whitespace in format too */\n         while (isspace((unsigned char)*format))\n            format++;\n      }\n      else\n      {\n         if (*bufiter != *format)\n            break;\n         bufiter++;\n         format++;\n      }\n   }\n \n   va_end(args_copy);\n \n   filestream_seek(stream, startpos + (bufiter - buf),\n         RETRO_VFS_SEEK_POSITION_START);\n \n   return ret;\n}\n\nint filestream_scanf(RFILE *stream, const char* format, ...)\n{\n   int ret;\n   va_list vl;\n   va_start(vl, format);\n   ret = filestream_vscanf(stream, format, &vl);\n   va_end(vl);\n   return ret;\n}\n\nint64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)\n{\n   int64_t output;\n\n   if (filestream_seek_cb)\n      output = filestream_seek_cb(stream->hfile, offset, seek_position);\n   else\n      output = retro_vfs_file_seek_impl(\n            (libretro_vfs_implementation_file*)stream->hfile,\n            offset, seek_position);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nint filestream_eof(RFILE *stream)\n{\n   return filestream_tell(stream) == filestream_get_size(stream) ? EOF : 0;\n}\n\nint64_t filestream_tell(RFILE *stream)\n{\n   int64_t output;\n\n   if (filestream_tell_cb)\n      output = filestream_tell_cb(stream->hfile);\n   else\n      output = retro_vfs_file_tell_impl(\n            (libretro_vfs_implementation_file*)stream->hfile);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nvoid filestream_rewind(RFILE *stream)\n{\n   if (!stream)\n      return;\n   filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);\n   stream->err_flag = false;\n}\n\nint64_t filestream_read(RFILE *stream, void *s, int64_t len)\n{\n   int64_t output;\n\n   if (filestream_read_cb)\n      output = filestream_read_cb(stream->hfile, s, len);\n   else\n      output = retro_vfs_file_read_impl(\n            (libretro_vfs_implementation_file*)stream->hfile, s, len);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nint filestream_flush(RFILE *stream)\n{\n   int output;\n\n   if (filestream_flush_cb)\n      output = filestream_flush_cb(stream->hfile);\n   else\n      output = retro_vfs_file_flush_impl(\n            (libretro_vfs_implementation_file*)stream->hfile);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nint filestream_delete(const char *path)\n{\n   if (filestream_remove_cb)\n      return filestream_remove_cb(path);\n\n   return retro_vfs_file_remove_impl(path);\n}\n\nint filestream_rename(const char *old_path, const char *new_path)\n{\n   if (filestream_rename_cb)\n      return filestream_rename_cb(old_path, new_path);\n\n   return retro_vfs_file_rename_impl(old_path, new_path);\n}\n\nint filestream_copy(const char *src, const char *dst)\n{\n   char buf[256] = {0};\n   int64_t n     = 0;\n   int ret       = 0;\n   char path_dst[PATH_MAX_LENGTH] = {0};\n\n   RFILE *fp_src = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   RFILE *fp_dst = filestream_open(dst, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n   if (!fp_src || !fp_dst)\n      ret = -1;\n\n   if (ret < 0)\n      goto close;\n\n   snprintf(path_dst, sizeof(path_dst), \"%s\", dst);\n   path_basedir(path_dst);\n\n   if (!path_is_directory(path_dst))\n      path_mkdir(path_dst);\n\n   while ((n = filestream_read(fp_src, buf, sizeof(buf))) > 0 && ret == 0)\n   {\n      if (filestream_write(fp_dst, buf, n) != n)\n         ret = -1;\n   }\n\nclose:\n   if (fp_src)\n      filestream_close(fp_src);\n   if (fp_dst)\n      filestream_close(fp_dst);\n   return ret;\n}\n\nint filestream_cmp(const char *src, const char *dst)\n{\n   int ret           = 0;\n   RFILE *fp_src     = filestream_open(src, RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   RFILE *fp_dst     = filestream_open(dst, RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n   if (!fp_src || !fp_dst || filestream_get_size(fp_src) != filestream_get_size(fp_dst))\n      ret = -1;\n\n   if (ret >= 0)\n   {\n      char buf_src[256] = {0};\n      char buf_dst[256] = {0};\n      while ((filestream_read(fp_src, buf_src, sizeof(buf_src))) > 0 && ret == 0)\n      {\n         filestream_read(fp_dst, buf_dst, sizeof(buf_dst));\n         ret = memcmp(buf_src, buf_dst, sizeof(buf_src));\n      }\n   }\n\n   if (fp_src)\n   {\n      filestream_close(fp_src);\n      fp_src = NULL;\n   }\n   if (fp_dst)\n   {\n      filestream_close(fp_dst);\n      fp_dst = NULL;\n   }\n   return ret;\n}\n\nconst char* filestream_get_path(RFILE *stream)\n{\n   if (filestream_get_path_cb)\n      return filestream_get_path_cb(stream->hfile);\n\n   return retro_vfs_file_get_path_impl(\n         (libretro_vfs_implementation_file*)stream->hfile);\n}\n\nint64_t filestream_write(RFILE *stream, const void *s, int64_t len)\n{\n   int64_t output;\n\n   if (filestream_write_cb)\n      output = filestream_write_cb(stream->hfile, s, len);\n   else\n      output = retro_vfs_file_write_impl(\n            (libretro_vfs_implementation_file*)stream->hfile, s, len);\n\n   if (output == VFS_ERROR_RETURN_VALUE)\n      stream->err_flag = true;\n\n   return output;\n}\n\nint filestream_putc(RFILE *stream, int c)\n{\n   char c_char = (char)c;\n   if (!stream)\n      return EOF;\n   return filestream_write(stream, &c_char, 1) == 1\n      ? (int)(unsigned char)c\n      : EOF;\n}\n\nint filestream_vprintf(RFILE *stream, const char* format, va_list args)\n{\n   static char buffer[8 * 1024];\n   int _len = vsnprintf(buffer, sizeof(buffer),\n         format, args);\n   if (_len < 0)\n      return -1;\n   else if (_len == 0)\n      return 0;\n   return (int)filestream_write(stream, buffer, _len);\n}\n\nint filestream_printf(RFILE *stream, const char* format, ...)\n{\n   va_list vl;\n   int ret;\n   va_start(vl, format);\n   ret = filestream_vprintf(stream, format, vl);\n   va_end(vl);\n   return ret;\n}\n\nint filestream_error(RFILE *stream)\n{\n   return (stream && stream->err_flag);\n}\n\nint filestream_close(RFILE *stream)\n{\n   int output;\n   struct retro_vfs_file_handle* fp = stream->hfile;\n\n   if (filestream_close_cb)\n      output = filestream_close_cb(fp);\n   else\n      output = retro_vfs_file_close_impl(\n            (libretro_vfs_implementation_file*)fp);\n\n   if (output == 0)\n      free(stream);\n\n   return output;\n}\n\nint64_t filestream_read_file(const char *path, void **buf, int64_t *len)\n{\n   int64_t ret              = 0;\n   int64_t content_buf_size = 0;\n   void *content_buf        = NULL;\n   RFILE *file              = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_READ,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n\n   if (!file)\n   {\n      *buf = NULL;\n      return 0;\n   }\n\n   if ((content_buf_size = filestream_get_size(file)) < 0)\n      goto error;\n\n   /* Reject sizes that would not survive the cast to size_t for\n    * the malloc below.  Pre-patch the only check here was a\n    * tautological '(int64_t)(uint64_t)X != X' (which is false\n    * for any positive int64_t), and on 32-bit hosts any file\n    * larger than ~4 GiB silently truncated through (size_t),\n    * the malloc was undersized, and the filestream_read below\n    * overran it. */\n   if ((uint64_t)content_buf_size + 1 > (uint64_t)((size_t)-1))\n      goto error;\n\n   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))\n      goto error;\n\n   if ((ret = filestream_read(file, content_buf, (int64_t)content_buf_size)) <\n         0)\n      goto error;\n\n   if (filestream_close(file) != 0)\n      free(file);\n\n   *buf    = content_buf;\n\n   /* Allow for easy reading of strings to be safe.\n    * Will only work with sane character formatting (Unix). */\n   ((char*)content_buf)[ret] = '\\0';\n\n   if (len)\n      *len = ret;\n\n   return 1;\n\nerror:\n   if (filestream_close(file) != 0)\n      free(file);\n   if (content_buf)\n      free(content_buf);\n   if (len)\n      *len = -1;\n   *buf = NULL;\n   return 0;\n}\n\nbool filestream_write_file(const char *path, const void *data, int64_t size)\n{\n   int64_t ret   = 0;\n   RFILE *file   = filestream_open(path,\n         RETRO_VFS_FILE_ACCESS_WRITE,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   if (!file)\n      return false;\n   ret = filestream_write(file, data, size);\n   if (filestream_close(file) != 0)\n      free(file);\n   return (ret == size);\n}\n\nchar *filestream_getline(RFILE *stream)\n{\n   char  *newline     = NULL;\n   char  *newline_tmp = NULL;\n   size_t cur_size    = 256;\n   size_t idx         = 0;\n   int    in;\n\n   if (!stream)\n      return NULL;\n\n   newline = (char*)malloc(cur_size + 1);\n   if (!newline)\n      return NULL;\n\n   in = filestream_getc(stream);\n   if (in == EOF)\n   {\n      free(newline);\n      return NULL;\n   }\n\n   while (in != EOF && in != '\\n')\n   {\n      newline[idx++] = (char)in;\n      if (idx == cur_size)\n      {\n         cur_size   *= 2;\n         newline_tmp = (char*)realloc(newline, cur_size + 1);\n         if (!newline_tmp)\n         {\n            free(newline);\n            return NULL;\n         }\n         newline = newline_tmp;\n      }\n      in = filestream_getc(stream);\n   }\n\n   /* Shrink to fit if we overallocated significantly */\n   if (cur_size > idx + 64)\n   {\n      newline_tmp = (char*)realloc(newline, idx + 1);\n      if (newline_tmp)\n         newline = newline_tmp;\n   }\n\n   newline[idx] = '\\0';\n   return newline;\n}\n\nlibretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)\n{\n   return (libretro_vfs_implementation_file*)stream->hfile;\n}\n"
  },
  {
    "path": "streams/file_stream_transforms.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (file_stream_transforms.c).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <string.h>\n#include <stdarg.h>\n\n#include <libretro.h>\n#include <streams/file_stream.h>\n\nRFILE* rfopen(const char *path, const char *mode)\n{\n   RFILE          *output  = NULL;\n   unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;\n   bool position_to_end    = false;\n\n   if (strchr(mode, 'r'))\n   {\n      retro_mode = RETRO_VFS_FILE_ACCESS_READ;\n      if (strchr(mode, '+'))\n         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE\n                    | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;\n   }\n   else if (strchr(mode, 'w'))\n   {\n      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;\n      if (strchr(mode, '+'))\n         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;\n   }\n   else if (strchr(mode, 'a'))\n   {\n      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE\n                 | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;\n      position_to_end = true;\n      if (strchr(mode, '+'))\n         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE\n                    | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;\n   }\n\n   output = filestream_open(path, retro_mode,\n         RETRO_VFS_FILE_ACCESS_HINT_NONE);\n   if (output && position_to_end)\n      filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);\n\n   return output;\n}\n\nint rfclose(RFILE* stream)\n{\n   if (!stream)\n      return EOF;\n\n   return filestream_close(stream);\n}\n\nint64_t rftell(RFILE* stream)\n{\n   if (!stream)\n      return -1;\n\n   return filestream_tell(stream);\n}\n\nint64_t rfseek(RFILE* stream, int64_t offset, int origin)\n{\n   int seek_position = -1;\n\n   if (!stream)\n      return -1;\n\n   switch (origin)\n   {\n      case SEEK_SET:\n         seek_position = RETRO_VFS_SEEK_POSITION_START;\n         break;\n      case SEEK_CUR:\n         seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;\n         break;\n      case SEEK_END:\n         seek_position = RETRO_VFS_SEEK_POSITION_END;\n         break;\n   }\n\n   return filestream_seek(stream, offset, seek_position);\n}\n\nint64_t rfread(void* buffer,\n   size_t elem_size, size_t elem_count, RFILE* stream)\n{\n   if (!stream || (elem_size == 0) || (elem_count == 0))\n      return 0;\n\n   return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);\n}\n\nchar *rfgets(char *s, int maxCount, RFILE* stream)\n{\n   if (!stream)\n      return NULL;\n   return filestream_gets(stream, s, maxCount);\n}\n\nint rfgetc(RFILE* stream)\n{\n   if (!stream)\n      return EOF;\n\n   return filestream_getc(stream);\n}\n\nint64_t rfwrite(void const* buffer,\n   size_t elem_size, size_t elem_count, RFILE* stream)\n{\n   if (!stream || (elem_size == 0) || (elem_count == 0))\n      return 0;\n\n   return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);\n}\n\nint rfputc(int character, RFILE * stream)\n{\n   if (!stream)\n      return EOF;\n\n   return filestream_putc(stream, character);\n}\n\nint64_t rfflush(RFILE * stream)\n{\n   if (!stream)\n      return EOF;\n\n   return filestream_flush(stream);\n}\n\nint rfprintf(RFILE * stream, const char * format, ...)\n{\n   int ret;\n   va_list vl;\n\n   if (!stream)\n      return -1;\n\n   va_start(vl, format);\n   ret = filestream_vprintf(stream, format, vl);\n   va_end(vl);\n   return ret;\n}\n\nint rferror(RFILE* stream)\n{\n   return filestream_error(stream);\n}\n\nint rfeof(RFILE* stream)\n{\n   return filestream_eof(stream);\n}\n\nint rfscanf(RFILE * stream, const char * format, ...)\n{\n   int ret;\n   va_list vl;\n\n   if (!stream)\n      return 0;\n\n   va_start(vl, format);\n   ret = filestream_vscanf(stream, format, &vl);\n   va_end(vl);\n   return ret;\n}\n"
  },
  {
    "path": "streams/interface_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (interface_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n\n#include <streams/interface_stream.h>\n#include <streams/file_stream.h>\n#include <streams/memory_stream.h>\n#ifdef HAVE_CHD\n#include <streams/chd_stream.h>\n#endif\n#if defined(HAVE_ZLIB)\n#include <streams/rzip_stream.h>\n#endif\n#include <encodings/crc32.h>\n\nstruct intfstream_internal\n{\n   struct\n   {\n      RFILE *fp;\n   } file;\n\n   struct\n   {\n      memstream_t *fp;\n      struct\n      {\n         uint8_t *data;\n         uint64_t size;\n      } buf;\n      bool writable;\n   } memory;\n#ifdef HAVE_CHD\n   struct\n   {\n      chdstream_t *fp;\n      int32_t track;\n   } chd;\n#endif\n#if defined(HAVE_ZLIB)\n   struct\n   {\n      rzipstream_t *fp;\n   } rzip;\n#endif\n   enum intfstream_type type;\n};\n\nint64_t intfstream_get_size(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return 0;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_get_size(intf->file.fp);\n      case INTFSTREAM_MEMORY:\n         return intf->memory.buf.size;\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n        return chdstream_get_size(intf->chd.fp);\n#else\n        break;\n#endif\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_get_size(intf->rzip.fp);\n#else\n         break;\n#endif\n   }\n\n   return 0;\n}\n\nbool intfstream_resize(intfstream_internal_t *intf, intfstream_info_t *info)\n{\n   if (!intf || !info)\n      return false;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         break;\n      case INTFSTREAM_MEMORY:\n         intf->memory.buf.data = info->memory.buf.data;\n         intf->memory.buf.size = info->memory.buf.size;\n\n         memstream_set_buffer(intf->memory.buf.data,\n               intf->memory.buf.size);\n         break;\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n#endif\n         break;\n      case INTFSTREAM_RZIP:\n         /* Unsupported */\n         return false;\n   }\n\n   return true;\n}\n\nbool intfstream_open(intfstream_internal_t *intf, const char *path,\n      unsigned mode, unsigned hints)\n{\n   if (!intf)\n      return false;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         intf->file.fp = filestream_open(path, mode, hints);\n         if (!intf->file.fp)\n            return false;\n         break;\n      case INTFSTREAM_MEMORY:\n         intf->memory.fp = memstream_open(intf->memory.writable);\n         if (!intf->memory.fp)\n            return false;\n         break;\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         intf->chd.fp = chdstream_open(path, intf->chd.track);\n         if (!intf->chd.fp)\n            return false;\n         break;\n#else\n         return false;\n#endif\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         intf->rzip.fp = rzipstream_open(path, mode);\n         if (!intf->rzip.fp)\n            return false;\n         break;\n#else\n         return false;\n#endif\n   }\n\n   return true;\n}\n\nint intfstream_flush(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return -1;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_flush(intf->file.fp);\n      case INTFSTREAM_MEMORY:\n      case INTFSTREAM_CHD:\n      case INTFSTREAM_RZIP:\n         /* Should we stub this for these interfaces? */\n         break;\n   }\n\n   return 0;\n}\n\nint intfstream_close(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return -1;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         if (intf->file.fp)\n            return filestream_close(intf->file.fp);\n         return 0;\n      case INTFSTREAM_MEMORY:\n         if (intf->memory.fp)\n            memstream_close(intf->memory.fp);\n         return 0;\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         if (intf->chd.fp)\n            chdstream_close(intf->chd.fp);\n#endif\n         return 0;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         if (intf->rzip.fp)\n            return rzipstream_close(intf->rzip.fp);\n#endif\n         return 0;\n   }\n\n   return -1;\n}\n\nvoid *intfstream_init(intfstream_info_t *info)\n{\n   intfstream_internal_t *intf = NULL;\n   if (!info)\n      return NULL;\n\n   if (!(intf = (intfstream_internal_t*)malloc(sizeof(*intf))))\n      return NULL;\n\n   intf->type            = info->type;\n   intf->file.fp         = NULL;\n   intf->memory.buf.data = NULL;\n   intf->memory.buf.size = 0;\n   intf->memory.fp       = NULL;\n   intf->memory.writable = false;\n#ifdef HAVE_CHD\n   intf->chd.track       = 0;\n   intf->chd.fp          = NULL;\n#endif\n#ifdef HAVE_ZLIB\n   intf->rzip.fp         = NULL;\n#endif\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         break;\n      case INTFSTREAM_MEMORY:\n         intf->memory.writable = info->memory.writable;\n         if (!intfstream_resize(intf, info))\n         {\n            free(intf);\n            return NULL;\n         }\n         break;\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         intf->chd.track = info->chd.track;\n         break;\n#else\n         free(intf);\n         return NULL;\n#endif\n      case INTFSTREAM_RZIP:\n         break;\n   }\n\n   return intf;\n}\n\nint64_t intfstream_seek(\n      intfstream_internal_t *intf, int64_t offset, int whence)\n{\n   if (!intf)\n      return -1;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         {\n            int seek_position = 0;\n            switch (whence)\n            {\n               case SEEK_SET:\n                  seek_position = RETRO_VFS_SEEK_POSITION_START;\n                  break;\n               case SEEK_CUR:\n                  seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;\n                  break;\n               case SEEK_END:\n                  seek_position = RETRO_VFS_SEEK_POSITION_END;\n                  break;\n            }\n            return (int64_t)filestream_seek(intf->file.fp, (int64_t)offset,\n                  seek_position);\n         }\n      case INTFSTREAM_MEMORY:\n         return (int64_t)memstream_seek(intf->memory.fp, offset, whence);\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         return (int64_t)chdstream_seek(intf->chd.fp, offset, whence);\n#else\n         break;\n#endif\n      case INTFSTREAM_RZIP:\n         /* Unsupported */\n         break;\n   }\n\n   return -1;\n}\n\nint64_t intfstream_truncate(intfstream_internal_t *intf, uint64_t len)\n{\n   if (!intf)\n      return 0;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_truncate(intf->file.fp, len);\n      case INTFSTREAM_MEMORY:\n         break;\n      case INTFSTREAM_CHD:\n         break;\n      case INTFSTREAM_RZIP:\n         break;\n   }\n\n   return 0;\n}\n\nint64_t intfstream_read(intfstream_internal_t *intf, void *s, uint64_t len)\n{\n   if (!intf)\n      return 0;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_read(intf->file.fp, s, len);\n      case INTFSTREAM_MEMORY:\n         return memstream_read(intf->memory.fp, s, len);\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         return chdstream_read(intf->chd.fp, s, len);\n#else\n         break;\n#endif\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_read(intf->rzip.fp, s, len);\n#else\n         break;\n#endif\n   }\n\n   return -1;\n}\n\nint64_t intfstream_write(intfstream_internal_t *intf,\n      const void *s, uint64_t len)\n{\n   if (!intf)\n      return 0;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_write(intf->file.fp, s, len);\n      case INTFSTREAM_MEMORY:\n         return memstream_write(intf->memory.fp, s, len);\n      case INTFSTREAM_CHD:\n         return -1;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_write(intf->rzip.fp, s, len);\n#else\n         return -1;\n#endif\n   }\n\n   return 0;\n}\n\nint intfstream_printf(intfstream_internal_t *intf,\n      const char* format, ...)\n{\n   int ret;\n   va_list vl;\n\n   if (!intf)\n      return 0;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         va_start(vl, format);\n         ret = filestream_vprintf(intf->file.fp, format, vl);\n         va_end(vl);\n         return ret;\n      case INTFSTREAM_MEMORY:\n         return -1;\n      case INTFSTREAM_CHD:\n         return -1;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         va_start(vl, format);\n         ret = rzipstream_vprintf(intf->rzip.fp, format, vl);\n         va_end(vl);\n         return ret;\n#else\n         return -1;\n#endif\n   }\n\n   return 0;\n}\n\nint64_t intfstream_get_ptr(intfstream_internal_t* intf)\n{\n   if (!intf)\n      return 0;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return -1;\n      case INTFSTREAM_MEMORY:\n         return memstream_get_ptr(intf->memory.fp);\n      case INTFSTREAM_CHD:\n         return -1;\n      case INTFSTREAM_RZIP:\n         return -1;\n   }\n\n   return 0;\n}\n\nchar *intfstream_gets(intfstream_internal_t *intf,\n      char *s, uint64_t len)\n{\n   if (!intf)\n      return NULL;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_gets(intf->file.fp,\n               s, (size_t)len);\n      case INTFSTREAM_MEMORY:\n         return memstream_gets(intf->memory.fp,\n               s, (size_t)len);\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         return chdstream_gets(intf->chd.fp, s, len);\n#else\n         break;\n#endif\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_gets(intf->rzip.fp, s, (size_t)len);\n#else\n         break;\n#endif\n   }\n\n   return NULL;\n}\n\nint intfstream_getc(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return -1;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_getc(intf->file.fp);\n      case INTFSTREAM_MEMORY:\n         return memstream_getc(intf->memory.fp);\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         return chdstream_getc(intf->chd.fp);\n#else\n         break;\n#endif\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_getc(intf->rzip.fp);\n#else\n         break;\n#endif\n   }\n\n   return -1;\n}\n\nint64_t intfstream_tell(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return -1;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return (int64_t)filestream_tell(intf->file.fp);\n      case INTFSTREAM_MEMORY:\n         return (int64_t)memstream_pos(intf->memory.fp);\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         return (int64_t)chdstream_tell(intf->chd.fp);\n#else\n         break;\n#endif\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return (int64_t)rzipstream_tell(intf->rzip.fp);\n#else\n         break;\n#endif\n   }\n\n   return -1;\n}\n\nint intfstream_eof(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return -1;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return filestream_eof(intf->file.fp);\n      case INTFSTREAM_MEMORY:\n         /* TODO: Add this functionality to\n          * memory_stream interface */\n         break;\n      case INTFSTREAM_CHD:\n         /* TODO: Add this functionality to\n          * chd_stream interface */\n         break;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_eof(intf->rzip.fp);\n#else\n         break;\n#endif\n   }\n\n   return -1;\n}\n\nvoid intfstream_rewind(intfstream_internal_t *intf)\n{\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         filestream_rewind(intf->file.fp);\n         break;\n      case INTFSTREAM_MEMORY:\n         memstream_rewind(intf->memory.fp);\n         break;\n      case INTFSTREAM_CHD:\n#ifdef HAVE_CHD\n         chdstream_rewind(intf->chd.fp);\n#endif\n         break;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         rzipstream_rewind(intf->rzip.fp);\n#endif\n         break;\n   }\n}\n\nvoid intfstream_putc(intfstream_internal_t *intf, int c)\n{\n   if (!intf)\n      return;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         filestream_putc(intf->file.fp, c);\n         break;\n      case INTFSTREAM_MEMORY:\n         memstream_putc(intf->memory.fp, c);\n         break;\n      case INTFSTREAM_CHD:\n         break;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         rzipstream_putc(intf->rzip.fp, c);\n#else\n         break;\n#endif\n   }\n}\n\nuint32_t intfstream_get_offset_to_start(intfstream_internal_t *intf)\n{\n   if (intf)\n   {\n#ifdef HAVE_CHD\n      if (intf->type == INTFSTREAM_CHD)\n         return chdstream_get_track_start(intf->chd.fp);\n#endif\n   }\n\n   return 0;\n}\n\nuint32_t intfstream_get_frame_size(intfstream_internal_t *intf)\n{\n   if (intf)\n   {\n#ifdef HAVE_CHD\n      if (intf->type == INTFSTREAM_CHD)\n         return chdstream_get_frame_size(intf->chd.fp);\n#endif\n   }\n\n   return 0;\n}\n\nuint32_t intfstream_get_first_sector(intfstream_internal_t* intf)\n{\n   if (intf)\n   {\n#ifdef HAVE_CHD\n      if (intf->type == INTFSTREAM_CHD)\n         return chdstream_get_first_track_sector(intf->chd.fp);\n#endif\n   }\n\n   return 0;\n}\n\nbool intfstream_is_compressed(intfstream_internal_t *intf)\n{\n   if (!intf)\n      return false;\n\n   switch (intf->type)\n   {\n      case INTFSTREAM_FILE:\n         return false;\n      case INTFSTREAM_MEMORY:\n         return false;\n      case INTFSTREAM_CHD:\n         return true;\n      case INTFSTREAM_RZIP:\n#if defined(HAVE_ZLIB)\n         return rzipstream_is_compressed(intf->rzip.fp);\n#else\n         break;\n#endif\n   }\n\n   return false;\n}\n\nbool intfstream_get_crc(intfstream_internal_t *intf, uint32_t *crc)\n{\n   int64_t data_read    = 0;\n   uint32_t accumulator = 0;\n   uint8_t buffer[4096];\n\n   if (!intf || !crc)\n      return false;\n\n   /* Ensure we start at the beginning of the file */\n   intfstream_rewind(intf);\n\n   while ((data_read = intfstream_read(intf, buffer, sizeof(buffer))) > 0)\n      accumulator = encoding_crc32(accumulator, buffer, (size_t)data_read);\n\n   if (data_read < 0)\n      return false;\n\n   *crc = accumulator;\n\n   /* Reset file to the beginning */\n   intfstream_rewind(intf);\n\n   return true;\n}\n\nintfstream_t* intfstream_open_file(const char *path,\n      unsigned mode, unsigned hints)\n{\n   intfstream_info_t info;\n   intfstream_t *fd = NULL;\n\n   info.type        = INTFSTREAM_FILE;\n   fd               = (intfstream_t*)intfstream_init(&info);\n\n   if (!fd)\n      return NULL;\n\n   if (intfstream_open(fd, path, mode, hints))\n      return fd;\n\n   intfstream_close(fd);\n   free(fd);\n   return NULL;\n}\n\nintfstream_t *intfstream_open_memory(void *data,\n      unsigned mode, unsigned hints, uint64_t size)\n{\n   intfstream_info_t info;\n   intfstream_t *fd     = NULL;\n\n   info.type            = INTFSTREAM_MEMORY;\n   info.memory.buf.data = (uint8_t*)data;\n   info.memory.buf.size = size;\n   info.memory.writable = (mode & RETRO_VFS_FILE_ACCESS_WRITE) != 0;\n\n   if (!(fd = (intfstream_t*)intfstream_init(&info)))\n      return NULL;\n\n   if (intfstream_open(fd, NULL, mode, hints))\n      return fd;\n\n   intfstream_close(fd);\n   free(fd);\n   return NULL;\n}\n\nintfstream_t *intfstream_open_writable_memory(void *data,\n      unsigned mode, unsigned hints, uint64_t size)\n{\n   return intfstream_open_memory(data, mode | RETRO_VFS_FILE_ACCESS_WRITE, hints, size);\n}\n\nintfstream_t *intfstream_open_chd_track(const char *path,\n      unsigned mode, unsigned hints, int32_t track)\n{\n   intfstream_info_t info;\n   intfstream_t *fd = NULL;\n\n   info.type        = INTFSTREAM_CHD;\n   info.chd.track   = track;\n\n   if (!(fd = (intfstream_t*)intfstream_init(&info)))\n      return NULL;\n\n   if (intfstream_open(fd, path, mode, hints))\n      return fd;\n\n   intfstream_close(fd);\n   free(fd);\n   return NULL;\n}\n\nintfstream_t* intfstream_open_rzip_file(const char *path,\n      unsigned mode)\n{\n   intfstream_info_t info;\n   intfstream_t *fd = NULL;\n\n   info.type        = INTFSTREAM_RZIP;\n   fd               = (intfstream_t*)intfstream_init(&info);\n\n   if (!fd)\n      return NULL;\n\n   if (intfstream_open(fd, path, mode, RETRO_VFS_FILE_ACCESS_HINT_NONE))\n      return fd;\n\n   intfstream_close(fd);\n   free(fd);\n   return NULL;\n}\n"
  },
  {
    "path": "streams/memory_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (memory_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <streams/memory_stream.h>\n\n/* TODO/FIXME - static globals */\nstatic uint8_t* g_buffer      = NULL;\nstatic uint64_t g_size         = 0;\nstatic uint64_t last_file_size = 0;\n\nstruct memstream\n{\n   uint64_t size;\n   uint64_t ptr;\n   uint64_t max_ptr;\n   uint8_t *buf;\n   unsigned writing;\n};\n\nvoid memstream_set_buffer(uint8_t *s, uint64_t len)\n{\n   g_buffer = s;\n   g_size   = len;\n}\n\nmemstream_t *memstream_open(unsigned writing)\n{\n   memstream_t *stream;\n   if (!g_buffer || !g_size)\n      return NULL;\n\n   stream = (memstream_t*)malloc(sizeof(*stream));\n\n   if (!stream)\n      return NULL;\n\n   stream->buf       = g_buffer;\n   stream->size      = g_size;\n   stream->ptr       = 0;\n   stream->max_ptr   = 0;\n   stream->writing   = writing;\n\n   g_buffer          = NULL;\n   g_size            = 0;\n\n   return stream;\n}\n\nvoid memstream_close(memstream_t *stream)\n{\n   if (!stream)\n      return;\n\n   last_file_size = stream->writing ? stream->max_ptr : stream->size;\n   free(stream);\n}\n\nuint64_t memstream_get_ptr(memstream_t *stream)\n{\n   return stream->ptr;\n}\n\nuint64_t memstream_read(memstream_t *stream, void *data, uint64_t bytes)\n{\n   uint64_t avail = 0;\n\n   if (!stream)\n      return 0;\n\n   avail               = stream->size - stream->ptr;\n   if (bytes > avail)\n      bytes            = avail;\n\n   memcpy(data, stream->buf + stream->ptr, (size_t)bytes);\n   stream->ptr        += bytes;\n   if (stream->ptr > stream->max_ptr)\n      stream->max_ptr  = stream->ptr;\n   return bytes;\n}\n\nuint64_t memstream_write(memstream_t *stream,\n      const void *data, uint64_t bytes)\n{\n   uint64_t avail = 0;\n\n   if (!stream)\n      return 0;\n\n   avail = stream->size - stream->ptr;\n   if (bytes > avail)\n      bytes = avail;\n\n   memcpy(stream->buf + stream->ptr, data, (size_t)bytes);\n   stream->ptr += bytes;\n   if (stream->ptr > stream->max_ptr)\n      stream->max_ptr = stream->ptr;\n   return bytes;\n}\n\nint64_t memstream_seek(memstream_t *stream, int64_t offset, int whence)\n{\n   uint64_t ptr;\n\n   switch (whence)\n   {\n      case SEEK_SET:\n         ptr = offset;\n         break;\n      case SEEK_CUR:\n         ptr = stream->ptr + offset;\n         break;\n      case SEEK_END:\n         ptr = (stream->writing ? stream->max_ptr : stream->size) + offset;\n         break;\n      default:\n         return -1;\n   }\n\n   if (ptr <= stream->size)\n   {\n      stream->ptr = ptr;\n      return 0;\n   }\n\n   return -1;\n}\n\nvoid memstream_rewind(memstream_t *stream)\n{\n   memstream_seek(stream, 0L, SEEK_SET);\n}\n\nuint64_t memstream_pos(memstream_t *stream) { return stream->ptr; }\nchar *memstream_gets(memstream_t *stream, char *s, size_t len) { return NULL; }\nuint64_t memstream_get_last_size(void) { return last_file_size; }\n\nint memstream_getc(memstream_t *stream)\n{\n   int ret = 0;\n   if (stream->ptr >= stream->size)\n      return EOF;\n   ret = stream->buf[stream->ptr++];\n\n   if (stream->ptr > stream->max_ptr)\n      stream->max_ptr = stream->ptr;\n\n   return ret;\n}\n\nvoid memstream_putc(memstream_t *stream, int c)\n{\n   if (stream->ptr < stream->size)\n      stream->buf[stream->ptr++] = c;\n\n   if (stream->ptr > stream->max_ptr)\n      stream->max_ptr = stream->ptr;\n}\n"
  },
  {
    "path": "streams/network_stream.c",
    "content": "/* Copyright  (C) 2022 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (network_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <retro_endianness.h>\n\n#include <streams/network_stream.h>\n\nbool netstream_open(netstream_t *stream, void *buf, size_t len, size_t used)\n{\n   if (buf)\n   {\n      /* Pre-allocated buffer must have a non-zero size. */\n      if (!len || used > len)\n         return false;\n   }\n   else\n   {\n      if (len)\n      {\n         buf = malloc(len);\n         if (!buf)\n            return false;\n      }\n\n      used = 0;\n   }\n\n   stream->buf  = buf;\n   stream->size = len;\n   stream->used = used;\n   stream->pos  = 0;\n\n   return true;\n}\n\nvoid netstream_close(netstream_t *stream, bool dealloc)\n{\n   if (dealloc)\n      free(stream->buf);\n   memset(stream, 0, sizeof(*stream));\n}\n\nvoid netstream_reset(netstream_t *stream)\n{\n   stream->pos  = 0;\n   stream->used = 0;\n}\n\nbool netstream_truncate(netstream_t *stream, size_t used)\n{\n   if (used > stream->size)\n      return false;\n\n   stream->used = used;\n\n   /* If the current stream position is past our new end of stream,\n      set the current position to the end of the stream. */\n   if (stream->pos > used)\n      stream->pos = used;\n\n   return true;\n}\n\nvoid netstream_data(netstream_t *stream, void **data, size_t *len)\n{\n   *data = stream->buf;\n   *len  = stream->used;\n}\n\nbool netstream_eof(netstream_t *stream)\n{\n   return stream->pos >= stream->used;\n}\n\nsize_t netstream_tell(netstream_t *stream)\n{\n   return stream->pos;\n}\n\nbool netstream_seek(netstream_t *stream, long offset, int origin)\n{\n   long pos  = (long)stream->pos;\n   long used = (long)stream->used;\n\n   switch (origin)\n   {\n      case NETSTREAM_SEEK_SET:\n         pos  = offset;\n         break;\n      case NETSTREAM_SEEK_CUR:\n         pos += offset;\n         break;\n      case NETSTREAM_SEEK_END:\n         pos  = used + offset;\n         break;\n      default:\n         return false;\n   }\n\n   if (pos < 0 || pos > used)\n      return false;\n\n   stream->pos = (size_t)pos;\n\n   return true;\n}\n\nbool netstream_read(netstream_t *stream, void *data, size_t len)\n{\n   size_t remaining = stream->used - stream->pos;\n\n   if (!data || !remaining || len > remaining)\n      return false;\n\n   /* If len is 0, read all remaining bytes. */\n   if (!len)\n      len = remaining;\n\n   memcpy(data, (uint8_t*)stream->buf + stream->pos, len);\n\n   stream->pos += len;\n\n   return true;\n}\n\n/* This one doesn't require any swapping. */\nbool netstream_read_byte(netstream_t *stream, uint8_t *data)\n{\n   return netstream_read(stream, data, sizeof(*data));\n}\n\n#define NETSTREAM_READ_TYPE(name, type, swap) \\\nbool netstream_read_##name(netstream_t *stream, type *data) \\\n{ \\\n   if (!netstream_read(stream, data, sizeof(*data))) \\\n      return false; \\\n   *data = swap(*data); \\\n   return true; \\\n}\n\nNETSTREAM_READ_TYPE(word,  uint16_t, retro_be_to_cpu16)\nNETSTREAM_READ_TYPE(dword, uint32_t, retro_be_to_cpu32)\nNETSTREAM_READ_TYPE(qword, uint64_t, retro_be_to_cpu64)\n\n#undef NETSTREAM_READ_TYPE\n\n#ifdef __STDC_IEC_559__\n#define NETSTREAM_READ_TYPE(name, type, type_alt, swap) \\\nbool netstream_read_##name(netstream_t *stream, type *data) \\\n{ \\\n   type_alt *data_alt = (type_alt*)data; \\\n   if (!netstream_read(stream, data, sizeof(*data))) \\\n      return false; \\\n   *data_alt = swap(*data_alt); \\\n   return true; \\\n}\n\nNETSTREAM_READ_TYPE(float,  float,  uint32_t, retro_be_to_cpu32)\nNETSTREAM_READ_TYPE(double, double, uint64_t, retro_be_to_cpu64)\n\n#undef NETSTREAM_READ_TYPE\n#endif\n\nint netstream_read_string(netstream_t *stream, char *s, size_t len)\n{\n   char c;\n   int ret = 0;\n\n   if (!s || !len)\n      return -1;\n\n   for (; --len; ret++)\n   {\n      if (!netstream_read(stream, &c, sizeof(c)))\n         return -1;\n\n      *s++ = c;\n\n      if (!c)\n         break;\n   }\n\n   if (!len)\n   {\n      *s = '\\0';\n\n      for (;; ret++)\n      {\n         if (!netstream_read(stream, &c, sizeof(c)))\n            return -1;\n         if (!c)\n            break;\n      }\n   }\n\n   return ret;\n}\n\nbool netstream_read_fixed_string(netstream_t *stream, char *s, size_t len)\n{\n   if (!len)\n      return false;\n\n   if (!netstream_read(stream, s, len))\n      return false;\n\n   /* Ensure the string is always null-terminated. */\n   s[len - 1] = '\\0';\n\n   return true;\n}\n\nbool netstream_write(netstream_t *stream, const void *data, size_t len)\n{\n   size_t remaining = stream->size - stream->pos;\n\n   if (!data || !len)\n      return false;\n\n   if (len > remaining)\n   {\n      if (!stream->size)\n      {\n         if (stream->buf)\n            free(stream->buf);\n         stream->buf  = malloc(len);\n         if (!stream->buf)\n            return false;\n         stream->size = len;\n      }\n      else\n      {\n         size_t _len = stream->size + (len - remaining);\n         void   *buf = realloc(stream->buf, _len);\n\n         if (!buf)\n            return false;\n\n         stream->buf  = buf;\n         stream->size = _len;\n      }\n   }\n\n   memcpy((uint8_t*)stream->buf + stream->pos, data, len);\n\n   stream->pos += len;\n\n   if (stream->pos > stream->used)\n      stream->used = stream->pos;\n\n   return true;\n}\n\n/* This one doesn't require any swapping. */\nbool netstream_write_byte(netstream_t *stream, uint8_t data)\n{\n   return netstream_write(stream, &data, sizeof(data));\n}\n\n#define NETSTREAM_WRITE_TYPE(name, type, swap) \\\nbool netstream_write_##name(netstream_t *stream, type data) \\\n{ \\\n   data = swap(data); \\\n   return netstream_write(stream, &data, sizeof(data)); \\\n}\n\nNETSTREAM_WRITE_TYPE(word,  uint16_t, retro_cpu_to_be16)\nNETSTREAM_WRITE_TYPE(dword, uint32_t, retro_cpu_to_be32)\nNETSTREAM_WRITE_TYPE(qword, uint64_t, retro_cpu_to_be64)\n\n#undef NETSTREAM_WRITE_TYPE\n\n#ifdef __STDC_IEC_559__\n#define NETSTREAM_WRITE_TYPE(name, type, type_alt, swap) \\\nbool netstream_write_##name(netstream_t *stream, type data) \\\n{ \\\n   type_alt *data_alt = (type_alt*)&data; \\\n   *data_alt = swap(*data_alt); \\\n   return netstream_write(stream, &data, sizeof(data)); \\\n}\n\nNETSTREAM_WRITE_TYPE(float,  float,  uint32_t, retro_cpu_to_be32)\nNETSTREAM_WRITE_TYPE(double, double, uint64_t, retro_cpu_to_be64)\n\n#undef NETSTREAM_WRITE_TYPE\n#endif\n\nbool netstream_write_string(netstream_t *stream, const char *s)\n{\n   if (!s)\n      return false;\n\n   return netstream_write(stream, s, strlen(s) + 1);\n}\n\nbool netstream_write_fixed_string(netstream_t *stream, const char *s,\n      size_t len)\n{\n   char end = '\\0';\n\n   if (!netstream_write(stream, s, len))\n      return false;\n\n   /* Ensure the string is always null-terminated. */\n   netstream_seek(stream, -1, NETSTREAM_SEEK_CUR);\n   netstream_write(stream, &end, sizeof(end));\n\n   return true;\n}\n"
  },
  {
    "path": "streams/rzip_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rzip_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <string.h>\n#include <file/file_path.h>\n\n#include <streams/file_stream.h>\n#include <streams/trans_stream.h>\n\n#include <streams/rzip_stream.h>\n\n/* Current RZIP file format version */\n#define RZIP_VERSION 1\n\n/* Compression level\n * > zlib default of 6 provides the best\n *   balance between file size and\n *   compression speed */\n#define RZIP_COMPRESSION_LEVEL 6\n\n/* Default chunk size: 128kb */\n#define RZIP_DEFAULT_CHUNK_SIZE 131072\n\n/* Upper bound on the per-chunk buffer size a crafted RZIP file is\n * allowed to request.  The default is 128 KiB; 64 MiB gives plenty\n * of headroom for legitimate archives while preventing a malformed\n * file from allocating gigabytes. */\n#define RZIP_MAX_CHUNK_SIZE (64 * 1024 * 1024)\n\n/* Header sizes (in bytes) */\n#define RZIP_HEADER_SIZE 20\n#define RZIP_CHUNK_HEADER_SIZE 4\n\n/* Holds all metadata for an RZIP file stream */\nstruct rzipstream\n{\n   uint64_t size;\n   /* virtual_ptr: Used to track how much\n    * uncompressed data has been read */\n   uint64_t virtual_ptr;\n   RFILE* file;\n   const struct trans_stream_backend *deflate_backend;\n   void *deflate_stream;\n   const struct trans_stream_backend *inflate_backend;\n   void *inflate_stream;\n   uint8_t *in_buf;\n   uint8_t *out_buf;\n   uint32_t in_buf_size;\n   uint32_t in_buf_ptr;\n   uint32_t out_buf_size;\n   uint32_t out_buf_ptr;\n   uint32_t out_buf_occupancy;\n   uint32_t chunk_size;\n   bool is_compressed;\n   bool is_writing;\n};\n\n/* Header Functions */\n\n/* Reads header information from RZIP file\n * > Detects whether file is compressed or\n *   uncompressed data\n * > If compressed, extracts uncompressed\n *   file/chunk sizes */\nstatic bool rzipstream_read_file_header(rzipstream_t *stream)\n{\n   unsigned i;\n   int64_t length;\n   uint8_t header_bytes[RZIP_HEADER_SIZE];\n\n   if (!stream)\n      return false;\n\n   for (i = 0; i < RZIP_HEADER_SIZE; i++)\n      header_bytes[i] = 0;\n\n   /* Attempt to read header bytes */\n   if ((length = filestream_read(stream->file,\n        header_bytes, sizeof(header_bytes))) <= 0)\n      return false;\n\n   /* If file length is less than header size\n    * then assume this is uncompressed data */\n\n   /* Check 'magic numbers' - first 8 bytes\n    * of header */\n   if (\n          (length       < RZIP_HEADER_SIZE)\n       || (header_bytes[0] !=           35)  /* # */\n       || (header_bytes[1] !=           82)  /* R */\n       || (header_bytes[2] !=           90)  /* Z */\n       || (header_bytes[3] !=           73)  /* I */\n       || (header_bytes[4] !=           80)  /* P */\n       || (header_bytes[5] !=          118)  /* v */\n       || (header_bytes[6] != RZIP_VERSION)  /* file format version number */\n       || (header_bytes[7] !=           35)) /* # */\n   {\n      /* Reset file to start */\n      filestream_seek(stream->file, 0, SEEK_SET);\n      /* Get 'raw' file size */\n      stream->size          = filestream_get_size(stream->file);\n      stream->is_compressed = false;\n      return true;\n   }\n\n   /* Get uncompressed chunk size - next 4 bytes */\n   if ((stream->chunk_size = (\n                            (uint32_t)header_bytes[11] << 24)\n                         | ((uint32_t)header_bytes[10] << 16)\n                         | ((uint32_t)header_bytes[9]  << 8)\n                         |  (uint32_t)header_bytes[8]) == 0)\n      return false;\n\n   /* Sanity-cap the declared chunk size.  Without this, a malformed\n    * RZIP can request a multi-gigabyte allocation on every chunk\n    * read -- and with the derived in_buf_size/out_buf_size multipliers\n    * that compounds to several times more. */\n   if (stream->chunk_size > RZIP_MAX_CHUNK_SIZE)\n      return false;\n\n   /* Get total uncompressed data size - next 8 bytes */\n   if ((stream->size = (\n                      (uint64_t)header_bytes[19] << 56)\n                   | ((uint64_t)header_bytes[18] << 48)\n                   | ((uint64_t)header_bytes[17] << 40)\n                   | ((uint64_t)header_bytes[16] << 32)\n                   | ((uint64_t)header_bytes[15] << 24)\n                   | ((uint64_t)header_bytes[14] << 16)\n                   | ((uint64_t)header_bytes[13] <<  8)\n                   |  (uint64_t)header_bytes[12]) == 0)\n      return false;\n\n   stream->is_compressed = true;\n   return true;\n}\n\n/* Writes header information to RZIP file\n * > ID 'magic numbers' + uncompressed\n *   file/chunk sizes */\nstatic bool rzipstream_write_file_header(rzipstream_t *stream)\n{\n   unsigned i;\n   uint8_t header_bytes[RZIP_HEADER_SIZE];\n\n   if (!stream)\n      return false;\n\n   /* Populate header array */\n   for (i = 0; i < RZIP_HEADER_SIZE; i++)\n      header_bytes[i] = 0;\n\n   /* > 'Magic numbers' - first 8 bytes */\n   header_bytes[0]    =        35;    /* # */\n   header_bytes[1]    =        82;    /* R */\n   header_bytes[2]    =        90;    /* Z */\n   header_bytes[3]    =        73;    /* I */\n   header_bytes[4]    =        80;    /* P */\n   header_bytes[5]    =       118;    /* v */\n   header_bytes[6]    = RZIP_VERSION; /* file format version number */\n   header_bytes[7]    =        35;    /* # */\n\n   /* > Uncompressed chunk size - next 4 bytes */\n   header_bytes[11]   = (stream->chunk_size >> 24) & 0xFF;\n   header_bytes[10]   = (stream->chunk_size >> 16) & 0xFF;\n   header_bytes[9]    = (stream->chunk_size >>  8) & 0xFF;\n   header_bytes[8]    =  stream->chunk_size        & 0xFF;\n\n   /* > Total uncompressed data size - next 8 bytes */\n   header_bytes[19]   = (stream->size >> 56) & 0xFF;\n   header_bytes[18]   = (stream->size >> 48) & 0xFF;\n   header_bytes[17]   = (stream->size >> 40) & 0xFF;\n   header_bytes[16]   = (stream->size >> 32) & 0xFF;\n   header_bytes[15]   = (stream->size >> 24) & 0xFF;\n   header_bytes[14]   = (stream->size >> 16) & 0xFF;\n   header_bytes[13]   = (stream->size >>  8) & 0xFF;\n   header_bytes[12]   =  stream->size        & 0xFF;\n\n   /* Reset file to start */\n   filestream_seek(stream->file, 0, SEEK_SET);\n\n   /* Write header bytes */\n   return (filestream_write(stream->file,\n         header_bytes, sizeof(header_bytes)) == RZIP_HEADER_SIZE);\n}\n\n/* Stream Initialisation/De-initialisation */\n\n/* Initialises all members of an rzipstream_t struct,\n * reading config from existing file header if available */\nstatic bool rzipstream_init_stream(\n      rzipstream_t *stream, const char *path, bool is_writing)\n{\n   unsigned file_mode;\n\n   if (!stream)\n      return false;\n\n   /* Ensure stream has valid initial values */\n   stream->size              = 0;\n   stream->chunk_size        = RZIP_DEFAULT_CHUNK_SIZE;\n   stream->file              = NULL;\n   stream->deflate_backend   = NULL;\n   stream->deflate_stream    = NULL;\n   stream->inflate_backend   = NULL;\n   stream->inflate_stream    = NULL;\n   stream->in_buf            = NULL;\n   stream->in_buf_size       = 0;\n   stream->in_buf_ptr        = 0;\n   stream->out_buf           = NULL;\n   stream->out_buf_size      = 0;\n   stream->out_buf_ptr       = 0;\n   stream->out_buf_occupancy = 0;\n\n   /* Check whether this is a read or write stream */\n   stream->is_writing = is_writing;\n   if (stream->is_writing)\n   {\n      /* Written files are always compressed */\n      stream->is_compressed = true;\n      file_mode             = RETRO_VFS_FILE_ACCESS_WRITE;\n   }\n   /* For read files, must get compression status\n    * from file itself... */\n   else\n      file_mode             = RETRO_VFS_FILE_ACCESS_READ;\n\n   /* Open file */\n   if (!(stream->file = filestream_open(\n         path, file_mode, RETRO_VFS_FILE_ACCESS_HINT_NONE)))\n      return false;\n\n   /* If file is open for writing, output header\n    * (Size component cannot be written until\n    * file is closed...) */\n   if (stream->is_writing)\n   {\n      /* Note: could just write zeros here, but\n       * still want to identify this as an RZIP\n       * file if writing fails partway through */\n      if (!rzipstream_write_file_header(stream))\n         return false;\n   }\n   /* If file is open for reading, parse any existing\n    * header */\n   else if (!rzipstream_read_file_header(stream))\n      return false;\n\n   /* Initialise appropriate transform stream\n    * and determine associated buffer sizes */\n   if (stream->is_writing)\n   {\n      /* Compression */\n      if (!(stream->deflate_backend = trans_stream_get_zlib_deflate_backend()))\n         return false;\n\n      if (!(stream->deflate_stream = stream->deflate_backend->stream_new()))\n         return false;\n\n      /* Set compression level */\n      if (!stream->deflate_backend->define(\n            stream->deflate_stream, \"level\", RZIP_COMPRESSION_LEVEL))\n         return false;\n\n      /* Buffers\n       * > Input: uncompressed\n       * > Output: compressed */\n      stream->in_buf_size  = stream->chunk_size;\n      stream->out_buf_size = stream->chunk_size * 2;\n      /* > Account for minimum zlib overhead\n       *   of 11 bytes... */\n      stream->out_buf_size =\n            (stream->out_buf_size < (stream->in_buf_size + 11)) ?\n                  stream->out_buf_size + 11 :\n                  stream->out_buf_size;\n\n      /* Redundant safety check */\n      if (   (stream->in_buf_size  == 0)\n          || (stream->out_buf_size == 0))\n         return false;\n   }\n   /* When reading, don't need an inflate transform\n    * stream (or buffers) if source file is uncompressed */\n   else if (stream->is_compressed)\n   {\n      /* Decompression */\n      if (!(stream->inflate_backend = trans_stream_get_zlib_inflate_backend()))\n         return false;\n\n      if (!(stream->inflate_stream = stream->inflate_backend->stream_new()))\n         return false;\n\n      /* Buffers\n       * > Input: compressed\n       * > Output: uncompressed\n       * Note 1: Actual compressed chunk sizes are read\n       *         from the file - just allocate a sensible\n       *         default to minimise memory reallocations\n       * Note 2: If file header is valid, output buffer\n       *         should have a size of exactly stream->chunk_size.\n       *         Allocate some additional space, just for\n       *         redundant safety... */\n      stream->in_buf_size  = stream->chunk_size * 2;\n      stream->out_buf_size = stream->chunk_size + (stream->chunk_size >> 2);\n\n      /* Redundant safety check */\n      if (   (stream->in_buf_size  == 0)\n          || (stream->out_buf_size == 0))\n         return false;\n   }\n\n   /* Allocate buffers */\n   if (stream->in_buf_size > 0)\n   {\n      if (!(stream->in_buf = (uint8_t *)calloc(stream->in_buf_size, 1)))\n         return false;\n   }\n\n   if (stream->out_buf_size > 0)\n   {\n      if (!(stream->out_buf = (uint8_t *)calloc(stream->out_buf_size, 1)))\n         return false;\n   }\n\n   return true;\n}\n\n/* free()'s all members of an rzipstream_t struct\n * > Also closes associated file, if currently open */\nstatic int rzipstream_free_stream(rzipstream_t *stream)\n{\n   int ret = 0;\n\n   if (!stream)\n      return -1;\n\n   /* Free transform streams */\n   if (stream->deflate_stream && stream->deflate_backend)\n      stream->deflate_backend->stream_free(stream->deflate_stream);\n\n   stream->deflate_stream  = NULL;\n   stream->deflate_backend = NULL;\n\n   if (stream->inflate_stream && stream->inflate_backend)\n      stream->inflate_backend->stream_free(stream->inflate_stream);\n\n   stream->inflate_stream  = NULL;\n   stream->inflate_backend = NULL;\n\n   /* Free buffers */\n   if (stream->in_buf)\n      free(stream->in_buf);\n   stream->in_buf = NULL;\n\n   if (stream->out_buf)\n      free(stream->out_buf);\n   stream->out_buf = NULL;\n\n   /* Close file */\n   if (stream->file)\n      ret = filestream_close(stream->file);\n   stream->file = NULL;\n\n   free(stream);\n\n   return ret;\n}\n\n/* File Open */\n\n/* Opens a new or existing RZIP file\n * > Supported 'mode' values are:\n *   - RETRO_VFS_FILE_ACCESS_READ\n *   - RETRO_VFS_FILE_ACCESS_WRITE\n * > When reading, 'path' may reference compressed\n *   or uncompressed data\n * Returns NULL if arguments are invalid, file\n * is invalid or an IO error occurs */\nrzipstream_t* rzipstream_open(const char *path, unsigned mode)\n{\n   rzipstream_t *stream = NULL;\n\n   /* Sanity check\n    * > Only RETRO_VFS_FILE_ACCESS_READ and\n    *   RETRO_VFS_FILE_ACCESS_WRITE are supported */\n   if (\n          (   (mode != RETRO_VFS_FILE_ACCESS_READ)\n           && (mode != RETRO_VFS_FILE_ACCESS_WRITE)))\n      return NULL;\n\n   /* If opening in read mode, ensure file exists */\n   if (   (mode == RETRO_VFS_FILE_ACCESS_READ)\n       && !path_is_valid(path))\n      return NULL;\n\n   /* Allocate stream object */\n   if (!(stream = (rzipstream_t*)malloc(sizeof(*stream))))\n      return NULL;\n\n   stream->is_compressed   = false;\n   stream->is_writing      = false;\n   stream->size            = 0;\n   stream->chunk_size      = 0;\n   stream->virtual_ptr     = 0;\n   stream->file            = NULL;\n   stream->deflate_backend = NULL;\n   stream->deflate_stream  = NULL;\n   stream->inflate_backend = NULL;\n   stream->inflate_stream  = NULL;\n   stream->in_buf          = NULL;\n   stream->in_buf_size     = 0;\n   stream->in_buf_ptr      = 0;\n   stream->out_buf         = NULL;\n   stream->out_buf_size    = 0;\n   stream->out_buf_ptr     = 0;\n   stream->out_buf_occupancy = 0;\n\n   /* Initialise stream */\n   if (!rzipstream_init_stream(\n         stream, path,\n         (mode == RETRO_VFS_FILE_ACCESS_WRITE)))\n   {\n      rzipstream_free_stream(stream);\n      return NULL;\n   }\n\n   return stream;\n}\n\n/* File Read */\n\n/* Reads and decompresses the next chunk of data\n * in the RZIP file */\nstatic bool rzipstream_read_chunk(rzipstream_t *stream)\n{\n   unsigned i;\n   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];\n   uint32_t compressed_chunk_size;\n   uint32_t inflate_read;\n   uint32_t inflate_written;\n\n   if (!stream || !stream->inflate_backend || !stream->inflate_stream)\n      return false;\n\n   for (i = 0; i < RZIP_CHUNK_HEADER_SIZE; i++)\n      chunk_header_bytes[i] = 0;\n\n   /* Attempt to read chunk header bytes */\n   if (filestream_read(\n         stream->file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=\n         RZIP_CHUNK_HEADER_SIZE)\n      return false;\n\n   /* Get size of next compressed chunk */\n   compressed_chunk_size = ( (uint32_t)chunk_header_bytes[3]  << 24)\n                           | ((uint32_t)chunk_header_bytes[2] << 16)\n                           | ((uint32_t)chunk_header_bytes[1] <<  8)\n                           | (uint32_t)chunk_header_bytes[0];\n   if (compressed_chunk_size == 0)\n      return false;\n\n   /* A compressed chunk cannot legitimately exceed its uncompressed\n    * counterpart by more than zlib's small worst-case overhead.  Cap\n    * at twice the declared chunk_size (which is itself already\n    * sanity-capped on header read) to reject malformed inputs that\n    * would otherwise provoke multi-gigabyte calloc() calls on each\n    * chunk read. */\n   if (compressed_chunk_size > stream->chunk_size * 2)\n      return false;\n\n   /* Resize input buffer, if required */\n   if (compressed_chunk_size > stream->in_buf_size)\n   {\n      free(stream->in_buf);\n      stream->in_buf      = NULL;\n\n      stream->in_buf_size = compressed_chunk_size;\n      stream->in_buf      = (uint8_t *)calloc(stream->in_buf_size, 1);\n      if (!stream->in_buf)\n         return false;\n\n      /* Note: Uncompressed data size is fixed, and read\n       * from the file header - we therefore don't attempt\n       * to resize the output buffer (if it's too small, then\n       * that's an error condition) */\n   }\n\n   /* Read compressed chunk from file */\n   if (filestream_read(\n         stream->file, stream->in_buf, compressed_chunk_size) !=\n         compressed_chunk_size)\n      return false;\n\n   /* Decompress chunk data */\n   stream->inflate_backend->set_in(\n         stream->inflate_stream,\n         stream->in_buf, compressed_chunk_size);\n\n   stream->inflate_backend->set_out(\n         stream->inflate_stream,\n         stream->out_buf, stream->out_buf_size);\n\n   /* Note: We have to set 'flush == true' here, otherwise we\n    * can't guarantee that the entire chunk will be written\n    * to the output buffer - this is inefficient, but not\n    * much we can do... */\n   if (!stream->inflate_backend->trans(\n         stream->inflate_stream, true,\n         &inflate_read, &inflate_written, NULL))\n      return false;\n\n   /* Error checking */\n   if (inflate_read != compressed_chunk_size)\n      return false;\n\n   if (   (inflate_written == 0)\n       || (inflate_written > stream->out_buf_size))\n      return false;\n\n   /* Record current output buffer occupancy\n    * and reset pointer */\n   stream->out_buf_occupancy = inflate_written;\n   stream->out_buf_ptr       = 0;\n\n   return true;\n}\n\n/* Reads (a maximum of) 'len' bytes from an RZIP file.\n * Returns actual number of bytes read, or -1 in\n * the event of an error */\nint64_t rzipstream_read(rzipstream_t *stream, void *data, int64_t len)\n{\n   int64_t _len      = len;\n   uint8_t *data_ptr = (uint8_t *)data;\n   int64_t data_read = 0;\n\n   if (!stream || stream->is_writing || !data)\n      return -1;\n\n   /* If we are reading uncompressed data, simply\n    * 'pass on' the direct file access request */\n   if (!stream->is_compressed)\n      return filestream_read(stream->file, data, len);\n\n   /* Process input data */\n   while (_len > 0)\n   {\n      int64_t read_size = 0;\n\n      /* Check whether we have reached the end\n       * of the file */\n      if (stream->virtual_ptr >= stream->size)\n         return data_read;\n\n      /* If everything in the output buffer has already\n       * been read, grab and extract the next chunk\n       * from disk */\n      if (stream->out_buf_ptr >= stream->out_buf_occupancy)\n         if (!rzipstream_read_chunk(stream))\n            return -1;\n\n      /* Get amount of data to 'read out' this loop\n       * > i.e. minimum of remaining output buffer\n       *   occupancy and remaining 'read data' size */\n      if ((read_size = stream->out_buf_occupancy - stream->out_buf_ptr) >\n            _len)\n         read_size = _len;\n\n      /* Copy as much cached data as possible into\n       * the read buffer */\n      memcpy(data_ptr, stream->out_buf + stream->out_buf_ptr, (size_t)read_size);\n\n      /* Increment pointers and remaining length */\n      stream->out_buf_ptr += read_size;\n      data_ptr            += read_size;\n      _len                -= read_size;\n\n      stream->virtual_ptr += read_size;\n\n      data_read           += read_size;\n   }\n\n   return data_read;\n}\n\n/* Reads next character from an RZIP file.\n * Returns character value, or EOF if no data\n * remains.\n * Note: Always returns EOF if file is open\n * for writing. */\nint rzipstream_getc(rzipstream_t *stream)\n{\n   char c = 0;\n\n   if (!stream || stream->is_writing)\n      return EOF;\n\n   /* Attempt to read a single character */\n   if (rzipstream_read(stream, &c, 1) == 1)\n      return (int)(unsigned char)c;\n\n   return EOF;\n}\n\n/* Reads one line from an RZIP file and stores it\n * in the character array pointed to by 's'.\n * It stops reading when either (len-1) characters\n * are read, the newline character is read, or the\n * end-of-file is reached, whichever comes first.\n * On success, returns 's'. In the event of an error,\n * or if end-of-file is reached and no characters\n * have been read, returns NULL. */\nchar* rzipstream_gets(rzipstream_t *stream, char *s, size_t len)\n{\n   size_t str_len;\n   int c         = 0;\n   char *str_ptr = s;\n\n   if (!stream || stream->is_writing || (len == 0))\n      return NULL;\n\n   /* Read bytes until newline or EOF is reached,\n    * or string buffer is full */\n   for (str_len = (len - 1); str_len > 0; str_len--)\n   {\n      /* Get next character */\n      c = rzipstream_getc(stream);\n\n      /* Check for newline and EOF */\n      if (c == EOF)\n         break;\n\n      /* Copy character to string buffer */\n      *str_ptr++ = c;\n\n      /* Check for newline and EOF */\n      if (c == '\\n')\n          break;\n   }\n\n   /* Add NUL termination */\n   *str_ptr = '\\0';\n\n   /* Check whether EOF has been reached without\n    * reading any characters */\n   if ((str_ptr == s) && (c == EOF))\n      return NULL;\n\n   return (s);\n}\n\n/* Reads all data from file specified by 'path' and\n * copies it to 'buf'.\n * - 'buf' will be allocated and must be free()'d manually.\n * - Allocated 'buf' size is equal to 'len'.\n * Returns false in the event of an error */\nbool rzipstream_read_file(const char *path, void **s, int64_t *len)\n{\n   int64_t bytes_read       = 0;\n   void *content_buf        = NULL;\n   int64_t content_buf_size = 0;\n   rzipstream_t *stream     = NULL;\n\n   if (!s)\n      return false;\n\n   /* Attempt to open file */\n   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_READ)))\n   {\n      *s = NULL;\n      return false;\n   }\n\n   /* Get file size */\n   if ((content_buf_size = rzipstream_get_size(stream)) < 0)\n      goto error;\n\n   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))\n      goto error;\n\n   /* Allocate buffer */\n   if (!(content_buf = malloc((size_t)(content_buf_size + 1))))\n      goto error;\n\n   /* Read file contents */\n   if ((bytes_read = rzipstream_read(stream, content_buf, content_buf_size)) <\n         0)\n      goto error;\n\n   /* Close file */\n   rzipstream_close(stream);\n   stream = NULL;\n\n   /* Add NUL termination for easy/safe handling of strings.\n    * Will only work with sane character formatting (Unix). */\n   ((char*)content_buf)[bytes_read] = '\\0';\n\n   /* Assign buffer */\n   *s = content_buf;\n\n   /* Assign length value, if required */\n   if (len)\n      *len = bytes_read;\n\n   return true;\n\nerror:\n   if (stream)\n      rzipstream_close(stream);\n   stream = NULL;\n\n   if (content_buf)\n      free(content_buf);\n   content_buf = NULL;\n\n   if (len)\n      *len = -1;\n\n   *s = NULL;\n\n   return false;\n}\n\n/* File Write */\n\n/* Compresses currently cached data and writes it\n * as the next RZIP file chunk */\nstatic bool rzipstream_write_chunk(rzipstream_t *stream)\n{\n   unsigned i;\n   uint8_t chunk_header_bytes[RZIP_CHUNK_HEADER_SIZE];\n   uint32_t deflate_read;\n   uint32_t deflate_written;\n\n   if (!stream || !stream->deflate_backend || !stream->deflate_stream)\n      return false;\n\n   for (i = 0; i < RZIP_CHUNK_HEADER_SIZE; i++)\n      chunk_header_bytes[i] = 0;\n\n   /* Compress data currently held in input buffer */\n   stream->deflate_backend->set_in(\n         stream->deflate_stream,\n         stream->in_buf, stream->in_buf_ptr);\n\n   stream->deflate_backend->set_out(\n         stream->deflate_stream,\n         stream->out_buf, stream->out_buf_size);\n\n   /* Note: We have to set 'flush == true' here, otherwise we\n    * can't guarantee that the entire chunk will be written\n    * to the output buffer - this is inefficient, but not\n    * much we can do... */\n   if (!stream->deflate_backend->trans(\n         stream->deflate_stream, true,\n         &deflate_read, &deflate_written, NULL))\n      return false;\n\n   /* Error checking */\n   if (deflate_read != stream->in_buf_ptr)\n      return false;\n\n   if (   (deflate_written == 0)\n       || (deflate_written > stream->out_buf_size))\n      return false;\n\n   /* Write compressed chunk size to file */\n   chunk_header_bytes[3] = (deflate_written >> 24) & 0xFF;\n   chunk_header_bytes[2] = (deflate_written >> 16) & 0xFF;\n   chunk_header_bytes[1] = (deflate_written >>  8) & 0xFF;\n   chunk_header_bytes[0] =  deflate_written        & 0xFF;\n\n   if (filestream_write(\n         stream->file, chunk_header_bytes, sizeof(chunk_header_bytes)) !=\n         RZIP_CHUNK_HEADER_SIZE)\n      return false;\n\n   /* Write compressed data to file */\n   if (filestream_write(\n         stream->file, stream->out_buf, deflate_written) != deflate_written)\n      return false;\n\n   /* Reset input buffer pointer */\n   stream->in_buf_ptr = 0;\n\n   return true;\n}\n\n/* Writes 'len' bytes to an RZIP file.\n * Returns actual number of bytes written, or -1\n * in the event of an error */\nint64_t rzipstream_write(rzipstream_t *stream, const void *data, int64_t len)\n{\n   int64_t _len = len;\n   const uint8_t *data_ptr = (const uint8_t *)data;\n\n   if (!stream || !stream->is_writing || !data)\n      return -1;\n\n   /* Process input data */\n   while (_len > 0)\n   {\n      int64_t cache_size = 0;\n\n      /* If input buffer is full, compress and write to disk */\n      if (stream->in_buf_ptr >= stream->in_buf_size)\n         if (!rzipstream_write_chunk(stream))\n            return -1;\n\n      /* Get amount of data to cache during this loop\n       * > i.e. minimum of space remaining in input buffer\n       *   and remaining 'write data' size */\n      if ((cache_size = stream->in_buf_size - stream->in_buf_ptr) > _len)\n         cache_size = _len;\n\n      /* Copy as much data as possible into\n       * the input buffer */\n      memcpy(stream->in_buf + stream->in_buf_ptr, data_ptr, (size_t)cache_size);\n\n      /* Increment pointers and remaining length */\n      stream->in_buf_ptr  += cache_size;\n      data_ptr            += cache_size;\n      _len                -= cache_size;\n\n      stream->size        += cache_size;\n      stream->virtual_ptr += cache_size;\n   }\n\n   /* We always write the specified number of bytes\n    * (unless rzipstream_write_chunk() fails, in\n    * which we register a complete failure...) */\n   return len;\n}\n\n/* Writes a single character to an RZIP file.\n * Returns character written, or EOF in the event\n * of an error */\nint rzipstream_putc(rzipstream_t *stream, int c)\n{\n   char c_char = (char)c;\n   if (   stream && stream->is_writing\n         && (rzipstream_write(stream, &c_char, 1) == 1))\n      return (int)(unsigned char)c;\n   return EOF;\n}\n\n/* Writes a variable argument list to an RZIP file.\n * Ugly 'internal' function, required to enable\n * 'printf' support in the higher level 'interface_stream'.\n * Returns actual number of bytes written, or -1\n * in the event of an error */\nint rzipstream_vprintf(rzipstream_t *stream, const char* format, va_list args)\n{\n   static char buffer[8 * 1024] = {0};\n   int _len = vsnprintf(buffer,\n         sizeof(buffer), format, args);\n   if (_len < 0)\n      return -1;\n   else if (_len == 0)\n      return 0;\n   return (int)rzipstream_write(stream, buffer, _len);\n}\n\n/* Writes formatted output to an RZIP file.\n * Returns actual number of bytes written, or -1\n * in the event of an error */\nint rzipstream_printf(rzipstream_t *stream, const char* format, ...)\n{\n   va_list vl;\n   int ret = 0;\n\n   /* Initialise variable argument list */\n   va_start(vl, format);\n\n   /* Write variable argument list to file */\n   ret = rzipstream_vprintf(stream, format, vl);\n\n   /* End using variable argument list */\n   va_end(vl);\n\n   return ret;\n}\n\n/* Writes contents of 'data' buffer to file\n * specified by 'path'.\n * Returns false in the event of an error */\nbool rzipstream_write_file(const char *path, const void *data, int64_t len)\n{\n   int64_t bytes_written = 0;\n   rzipstream_t *stream  = NULL;\n\n   if (!data)\n      return false;\n\n   /* Attempt to open file */\n   if (!(stream = rzipstream_open(path, RETRO_VFS_FILE_ACCESS_WRITE)))\n      return false;\n\n   /* Write contents of data buffer to file */\n   bytes_written = rzipstream_write(stream, data, len);\n\n   /* Close file */\n   if (rzipstream_close(stream) == -1)\n      return false;\n\n   /* Check that the correct number of bytes\n    * were written */\n   return (bytes_written == len);\n}\n\n/* File Control */\n\n/* Sets file position to the beginning of the\n * specified RZIP file.\n * Note: It is not recommended to rewind a file\n * that is open for writing, since the caller\n * may end up with a file containing junk data\n * at the end (harmless, but a waste of space). */\nvoid rzipstream_rewind(rzipstream_t *stream)\n{\n   if (!stream)\n      return;\n\n   /* Note: rzipstream_rewind() has no way of\n    * reporting errors (higher level interface\n    * requires a void return type) - so if anything\n    * goes wrong, all we can do is print to stderr\n    * and bail out... */\n\n   /* If we are handling uncompressed data, simply\n    * 'pass on' the direct file access request */\n   if (!stream->is_compressed)\n   {\n      filestream_rewind(stream->file);\n      return;\n   }\n\n   /* If no file access has yet occurred, file is\n    * already at the beginning -> do nothing */\n   if (stream->virtual_ptr == 0)\n      return;\n\n   /* Check whether we are reading or writing */\n   if (stream->is_writing)\n   {\n      /* Reset file position to first chunk location */\n      filestream_seek(stream->file, RZIP_HEADER_SIZE, SEEK_SET);\n      if (filestream_error(stream->file))\n         return;\n\n      /* Reset pointers */\n      stream->virtual_ptr = 0;\n      stream->in_buf_ptr  = 0;\n\n      /* Reset file size */\n      stream->size        = 0;\n   }\n   else\n   {\n      /* Check whether first file chunk is currently\n       * buffered in memory */\n      if ((stream->virtual_ptr < stream->chunk_size) &&\n          (stream->out_buf_ptr < stream->out_buf_occupancy))\n      {\n         /* It is: No file access is therefore required\n          * > Just reset pointers */\n         stream->virtual_ptr = 0;\n         stream->out_buf_ptr = 0;\n      }\n      else\n      {\n         /* It isn't: Have to re-read the first chunk\n          * from disk... */\n\n         /* Reset file position to first chunk location */\n         filestream_seek(stream->file, RZIP_HEADER_SIZE, SEEK_SET);\n         if (filestream_error(stream->file))\n            return;\n\n         /* Read chunk */\n         if (!rzipstream_read_chunk(stream))\n            return;\n\n         /* Reset pointers */\n         stream->virtual_ptr = 0;\n         stream->out_buf_ptr = 0;\n      }\n   }\n}\n\n/* File Status */\n\n/* Returns total size (in bytes) of the *uncompressed*\n * data in an RZIP file.\n * (If reading an uncompressed file, this corresponds\n * to the 'physical' file size in bytes)\n * Returns -1 in the event of a error. */\nint64_t rzipstream_get_size(rzipstream_t *stream)\n{\n   if (!stream)\n      return -1;\n\n   if (stream->is_compressed)\n      return stream->size;\n   return filestream_get_size(stream->file);\n}\n\n/* Returns EOF when no further *uncompressed* data\n * can be read from an RZIP file. */\nint rzipstream_eof(rzipstream_t *stream)\n{\n   if (!stream)\n      return -1;\n\n   if (stream->is_compressed)\n      return (stream->virtual_ptr >= stream->size) ?\n            EOF : 0;\n   return filestream_eof(stream->file);\n}\n\n/* Returns the offset of the current byte of *uncompressed*\n * data relative to the beginning of an RZIP file.\n * Returns -1 in the event of a error. */\nint64_t rzipstream_tell(rzipstream_t *stream)\n{\n   if (!stream)\n      return -1;\n\n   if (stream->is_compressed)\n      return (int64_t)stream->virtual_ptr;\n   return filestream_tell(stream->file);\n}\n\n/* Returns true if specified RZIP file contains\n * compressed content */\nbool rzipstream_is_compressed(rzipstream_t *stream)\n{\n   return stream && stream->is_compressed;\n}\n\n/* File Close */\n\n/* Closes RZIP file. If file is open for writing,\n * flushes any remaining buffered data to disk.\n * Returns -1 in the event of a error. */\nint rzipstream_close(rzipstream_t *stream)\n{\n   if (!stream)\n      return -1;\n\n   /* If we are writing, ensure that any\n    * remaining uncompressed data is flushed to\n    * disk and update file header */\n   if (stream->is_writing)\n   {\n      if (    ((stream->in_buf_ptr > 0)\n            && !rzipstream_write_chunk(stream))\n            || !rzipstream_write_file_header(stream))\n      {\n         /* Stream must be free()'d regardless */\n         rzipstream_free_stream(stream);\n         return -1;\n      }\n   }\n\n   /* Free stream\n    * > This also closes the file */\n   return rzipstream_free_stream(stream);\n}\n"
  },
  {
    "path": "streams/stdin_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (stdin_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <stdio.h>\n#include <stdint.h>\n#include <stddef.h>\n#include <string.h>\n#include <ctype.h>\n\n#ifdef _WIN32\n#ifndef _XBOX\n#include <windows.h>\n#endif\n#include <direct.h>\n#else\n#include <unistd.h>\n#endif\n\n#include <boolean.h>\n#include <retro_environment.h>\n#include <streams/stdin_stream.h>\n\n#if (defined(_WIN32) && defined(_XBOX)) || defined(__WINRT__) || !defined(__PSL1GHT__) && defined(__PS3__)\nsize_t read_stdin(char *s, size_t len) { return 0; } /* not implemented */\n#elif defined(_WIN32)\nsize_t read_stdin(char *s, size_t len)\n{\n   DWORD i;\n   DWORD has_read = 0;\n   DWORD avail    = 0;\n   bool echo      = false;\n   HANDLE hnd     = GetStdHandle(STD_INPUT_HANDLE);\n\n   if (hnd == INVALID_HANDLE_VALUE)\n      return 0;\n\n   /* Check first if we're a pipe\n    * (not console). */\n\n   /* If not a pipe, check if we're running in a console. */\n   if (!PeekNamedPipe(hnd, NULL, 0, NULL, &avail, NULL))\n   {\n      INPUT_RECORD recs[256];\n      bool has_key   = false;\n      DWORD mode     = 0;\n      DWORD has_read = 0;\n\n      if (!GetConsoleMode(hnd, &mode))\n         return 0;\n\n      if ((mode & (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))\n            && !SetConsoleMode(hnd,\n               mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT)))\n         return 0;\n\n      /* Win32, Y U NO SANE NONBLOCK READ!? */\n      if (!PeekConsoleInput(hnd, recs,\n               sizeof(recs) / sizeof(recs[0]), &has_read))\n         return 0;\n\n      for (i = 0; i < has_read; i++)\n      {\n         /* Very crude, but should get the job done. */\n         if (recs[i].EventType == KEY_EVENT &&\n               recs[i].Event.KeyEvent.bKeyDown &&\n               (isgraph(recs[i].Event.KeyEvent.wVirtualKeyCode) ||\n                recs[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN))\n         {\n            has_key = true;\n            echo    = true;\n            avail   = len;\n            break;\n         }\n      }\n\n      if (!has_key)\n      {\n         FlushConsoleInputBuffer(hnd);\n         return 0;\n      }\n   }\n\n   if (!avail)\n      return 0;\n\n   if (avail > len)\n      avail = len;\n\n   if (!ReadFile(hnd, s, avail, &has_read, NULL))\n      return 0;\n\n   for (i = 0; i < has_read; i++)\n      if (s[i] == '\\r')\n         s[i] = '\\n';\n\n   /* Console won't echo for us while in non-line mode,\n    * so do it manually ... */\n   if (echo)\n   {\n      HANDLE hnd_out = GetStdHandle(STD_OUTPUT_HANDLE);\n      if (hnd_out != INVALID_HANDLE_VALUE)\n      {\n         DWORD has_written;\n         WriteConsole(hnd_out, s, has_read, &has_written, NULL);\n      }\n   }\n   return has_read;\n}\n#else\nsize_t read_stdin(char *s, size_t len)\n{\n   size_t has_read = 0;\n   while (len)\n   {\n      ssize_t ret = read(STDIN_FILENO, s, len);\n      if (ret <= 0)\n         break;\n      s        += ret;\n      has_read += ret;\n      len      -= ret;\n   }\n   return has_read;\n}\n#endif\n"
  },
  {
    "path": "streams/trans_stream.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (trans_stream.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <streams/trans_stream.h>\n\n/**\n * trans_stream_trans_full:\n * @data                        : (optional) existing stream data, or a target\n *                                for the new stream data to be saved\n * @in                          : input data\n * @in_size                     : input size\n * @s                           : output data\n * @len                         : output size\n * @err                         : (optional) output for error code\n *\n * Perform a full transcoding from a source to a destination.\n */\nbool trans_stream_trans_full(\n    struct trans_stream_backend *backend, void **data,\n    const uint8_t *in, uint32_t in_size,\n    uint8_t *s, uint32_t len,\n    enum trans_stream_error *err)\n{\n   void *rdata;\n   bool ret;\n   uint32_t rd, wn;\n\n   if (data && *data)\n      rdata = *data;\n   else\n   {\n      if (!(rdata = backend->stream_new()))\n      {\n         if (err)\n            *err = TRANS_STREAM_ERROR_ALLOCATION_FAILURE;\n         return false;\n      }\n   }\n\n   backend->set_in(rdata, in, in_size);\n   backend->set_out(rdata, s, len);\n   ret = backend->trans(rdata, true, &rd, &wn, err);\n\n   if (data)\n      *data = rdata;\n   else\n      backend->stream_free(rdata);\n\n   return ret;\n}\n\nconst struct trans_stream_backend* trans_stream_get_zlib_deflate_backend(void)\n{\n#if HAVE_ZLIB\n   return &zlib_deflate_backend;\n#else\n   return NULL;\n#endif\n}\n\nconst struct trans_stream_backend* trans_stream_get_zlib_inflate_backend(void)\n{\n#if HAVE_ZLIB\n   return &zlib_inflate_backend;\n#else\n   return NULL;\n#endif\n}\n\nconst struct trans_stream_backend* trans_stream_get_pipe_backend(void)\n{\n   return &pipe_backend;\n}\n"
  },
  {
    "path": "streams/trans_stream_pipe.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (trans_stream_pipe.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <streams/trans_stream.h>\n\nstruct pipe_trans_stream\n{\n   const uint8_t *in;\n   uint8_t *out;\n   uint32_t in_size, out_size;\n};\n\nstatic void *pipe_stream_new(void)\n{\n   struct pipe_trans_stream *stream =\n      (struct pipe_trans_stream*)malloc(sizeof(*stream));\n   if (!stream)\n      return NULL;\n\n   stream->in                       = NULL;\n   stream->out                      = NULL;\n   stream->in_size                  = 0;\n   stream->out_size                 = 0;\n\n   return stream;\n}\n\nstatic void pipe_stream_free(void *data)\n{\n   free(data);\n}\n\nstatic void pipe_set_in(void *data, const uint8_t *in, uint32_t in_size)\n{\n   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;\n\n   if (!p)\n      return;\n\n   p->in                       = in;\n   p->in_size                  = in_size;\n}\n\nstatic void pipe_set_out(void *data, uint8_t *out, uint32_t out_size)\n{\n   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;\n\n   if (!p)\n      return;\n\n   p->out                      = out;\n   p->out_size                 = out_size;\n}\n\nstatic bool pipe_trans(void *data, bool flush,\n   uint32_t *rd, uint32_t *wn, enum trans_stream_error *err)\n{\n   struct pipe_trans_stream *p = (struct pipe_trans_stream *) data;\n\n   if (p->out_size < p->in_size)\n   {\n      memcpy(p->out, p->in, p->out_size);\n      *rd     = *wn = p->out_size;\n      p->in  += p->out_size;\n      p->out += p->out_size;\n      *err    = TRANS_STREAM_ERROR_BUFFER_FULL;\n      return false;\n   }\n\n   memcpy(p->out, p->in, p->in_size);\n   *rd     = *wn = p->in_size;\n   p->in  += p->in_size;\n   p->out += p->in_size;\n   *err    = TRANS_STREAM_ERROR_NONE;\n   return true;\n}\n\nconst struct trans_stream_backend pipe_backend = {\n   \"pipe\",\n   &pipe_backend,\n   pipe_stream_new,\n   pipe_stream_free,\n   NULL,\n   pipe_set_in,\n   pipe_set_out,\n   pipe_trans\n};\n"
  },
  {
    "path": "streams/trans_stream_zlib.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (trans_stream_zlib.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <zlib.h>\n#include <streams/trans_stream.h>\n\nstruct zlib_trans_stream\n{\n   z_stream z;\n   int window_bits;\n   int level;\n   bool inited;\n};\n\nstatic void *zlib_deflate_stream_new(void)\n{\n   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)\n      malloc(sizeof(*ret));\n   if (!ret)\n      return NULL;\n   ret->inited      = false;\n   ret->level       = 9;\n   ret->window_bits = 15;\n\n   ret->z.next_in   = NULL;\n   ret->z.avail_in  = 0;\n   ret->z.total_in  = 0;\n   ret->z.next_out  = NULL;\n   ret->z.avail_out = 0;\n   ret->z.total_out = 0;\n\n   ret->z.msg       = NULL;\n   ret->z.state     = NULL;\n\n   ret->z.zalloc    = NULL;\n   ret->z.zfree     = NULL;\n   ret->z.opaque    = NULL;\n\n   ret->z.data_type = 0;\n   ret->z.adler     = 0;\n   ret->z.reserved  = 0;\n   return (void *)ret;\n}\n\nstatic void *zlib_inflate_stream_new(void)\n{\n   struct zlib_trans_stream *ret = (struct zlib_trans_stream*)\n      malloc(sizeof(*ret));\n   if (!ret)\n      return NULL;\n   ret->inited      = false;\n   ret->window_bits = MAX_WBITS;\n\n   ret->z.next_in   = NULL;\n   ret->z.avail_in  = 0;\n   ret->z.total_in  = 0;\n   ret->z.next_out  = NULL;\n   ret->z.avail_out = 0;\n   ret->z.total_out = 0;\n\n   ret->z.msg       = NULL;\n   ret->z.state     = NULL;\n\n   ret->z.zalloc    = NULL;\n   ret->z.zfree     = NULL;\n   ret->z.opaque    = NULL;\n\n   ret->z.data_type = 0;\n   ret->z.adler     = 0;\n   ret->z.reserved  = 0;\n   return (void *)ret;\n}\n\nstatic void zlib_deflate_stream_free(void *data)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;\n   if (!z)\n      return;\n   if (z->inited)\n      deflateEnd(&z->z);\n   free(z);\n}\n\nstatic void zlib_inflate_stream_free(void *data)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;\n   if (!z)\n      return;\n   if (z->inited)\n      inflateEnd(&z->z);\n   if (z)\n      free(z);\n}\n\nstatic bool zlib_deflate_define(void *data, const char *prop, uint32_t val)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream*)data;\n   if (!data)\n      return false;\n\n   if (strcmp(prop, \"level\") == 0)\n      z->level = (int) val;\n   else if (strcmp(prop, \"window_bits\") == 0)\n      z->window_bits = (int) val;\n   else\n      return false;\n\n   return true;\n}\n\nstatic bool zlib_inflate_define(void *data, const char *prop, uint32_t val)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream*)data;\n   if (!data)\n      return false;\n\n   if (strcmp(prop, \"window_bits\") == 0)\n   {\n      z->window_bits = (int) val;\n      return true;\n   }\n   return false;\n}\n\nstatic void zlib_deflate_set_in(void *data, const uint8_t *in, uint32_t in_size)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;\n\n   if (!z)\n      return;\n\n   z->z.next_in                = (uint8_t *) in;\n   z->z.avail_in               = in_size;\n\n   if (!z->inited)\n   {\n      deflateInit2(&z->z, z->level, Z_DEFLATED , z->window_bits, 8,  Z_DEFAULT_STRATEGY );\n      z->inited = true;\n   }\n}\n\nstatic void zlib_inflate_set_in(void *data, const uint8_t *in, uint32_t in_size)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;\n\n   if (!z)\n      return;\n\n   z->z.next_in                = (uint8_t *) in;\n   z->z.avail_in               = in_size;\n   if (!z->inited)\n   {\n      inflateInit2(&z->z, z->window_bits);\n      z->inited = true;\n   }\n}\n\nstatic void zlib_set_out(void *data, uint8_t *out, uint32_t out_size)\n{\n   struct zlib_trans_stream *z = (struct zlib_trans_stream *) data;\n\n   if (!z)\n      return;\n\n   z->z.next_out               = out;\n   z->z.avail_out              = out_size;\n}\n\nstatic bool zlib_deflate_trans(\n   void *data, bool flush,\n   uint32_t *rd, uint32_t *wn,\n   enum trans_stream_error *err)\n{\n   int zret                     = 0;\n   bool ret                     = false;\n   uint32_t pre_avail_in        = 0;\n   uint32_t pre_avail_out       = 0;\n   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;\n   z_stream                  *z = &zt->z;\n\n   if (!zt->inited)\n   {\n      deflateInit2(z, zt->level, Z_DEFLATED , zt->window_bits, 8,  Z_DEFAULT_STRATEGY );\n      zt->inited = true;\n   }\n\n   pre_avail_in  = z->avail_in;\n   pre_avail_out = z->avail_out;\n   zret          = deflate(z, flush ? Z_FINISH : Z_NO_FLUSH);\n\n   if (zret == Z_OK)\n   {\n      if (err)\n         *err = TRANS_STREAM_ERROR_AGAIN;\n   }\n   else if (zret == Z_STREAM_END)\n   {\n      if (err)\n         *err = TRANS_STREAM_ERROR_NONE;\n   }\n   else\n   {\n      if (err)\n         *err = TRANS_STREAM_ERROR_OTHER;\n      return false;\n   }\n   ret = true;\n\n   if (z->avail_out == 0)\n   {\n      /* Filled buffer, maybe an error */\n      if (z->avail_in != 0)\n      {\n         ret = false;\n         if (err)\n            *err = TRANS_STREAM_ERROR_BUFFER_FULL;\n      }\n   }\n\n   *rd = pre_avail_in - z->avail_in;\n   *wn = pre_avail_out - z->avail_out;\n\n   if (flush && zret == Z_STREAM_END)\n   {\n      deflateEnd(z);\n      zt->inited = false;\n   }\n\n   return ret;\n}\n\nstatic bool zlib_inflate_trans(\n   void *data, bool flush,\n   uint32_t *rd, uint32_t *wn,\n   enum trans_stream_error *err)\n{\n   int zret;\n   bool ret                     = false;\n   uint32_t pre_avail_in        = 0;\n   uint32_t pre_avail_out       = 0;\n   struct zlib_trans_stream *zt = (struct zlib_trans_stream *) data;\n   z_stream                  *z = &zt->z;\n\n   if (!zt->inited)\n   {\n      inflateInit2(z, zt->window_bits);\n      zt->inited = true;\n   }\n\n   pre_avail_in  = z->avail_in;\n   pre_avail_out = z->avail_out;\n   zret          = inflate(z, flush ? Z_FINISH : Z_NO_FLUSH);\n\n   if (zret == Z_OK)\n   {\n      if (err)\n         *err = TRANS_STREAM_ERROR_AGAIN;\n   }\n   else if (zret == Z_STREAM_END)\n   {\n      if (err)\n         *err = TRANS_STREAM_ERROR_NONE;\n   }\n   else\n   {\n      if (err)\n         *err = TRANS_STREAM_ERROR_OTHER;\n      return false;\n   }\n   ret = true;\n\n   if (z->avail_out == 0)\n   {\n      /* Filled buffer, maybe an error */\n      if (z->avail_in != 0)\n      {\n         ret = false;\n         if (err)\n            *err = TRANS_STREAM_ERROR_BUFFER_FULL;\n      }\n   }\n\n   *rd = pre_avail_in - z->avail_in;\n   *wn = pre_avail_out - z->avail_out;\n\n   if (flush && zret == Z_STREAM_END)\n   {\n      inflateEnd(z);\n      zt->inited = false;\n   }\n\n   return ret;\n}\n\nconst struct trans_stream_backend zlib_deflate_backend = {\n   \"zlib_deflate\",\n   &zlib_inflate_backend,\n   zlib_deflate_stream_new,\n   zlib_deflate_stream_free,\n   zlib_deflate_define,\n   zlib_deflate_set_in,\n   zlib_set_out,\n   zlib_deflate_trans\n};\n\nconst struct trans_stream_backend zlib_inflate_backend = {\n   \"zlib_inflate\",\n   &zlib_deflate_backend,\n   zlib_inflate_stream_new,\n   zlib_inflate_stream_free,\n   zlib_inflate_define,\n   zlib_inflate_set_in,\n   zlib_set_out,\n   zlib_inflate_trans\n};\n"
  },
  {
    "path": "string/stdstring.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (stdstring.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdint.h>\n#include <ctype.h>\n#include <string.h>\n\n#include <compat/strl.h>\n#include <string/stdstring.h>\n#include <encodings/utf.h>\n\nconst uint8_t lr_char_props[256] = {\n\t/*x0   x1   x2   x3   x4   x5   x6   x7   x8   x9   xA   xB   xC   xD   xE   xF */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x                  */\n\t0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x  !\"#$%&'()*+,-./ */\n\t0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */\n\t0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */\n\t0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\\]^_ */\n\t0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */\n\t0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex                  */\n\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx                  */\n};\n\nchar *string_to_upper(char *s)\n{\n   char *cs = (char *)s;\n   for ( ; *cs != '\\0'; cs++)\n      *cs = toupper((unsigned char)*cs);\n   return s;\n}\n\nchar *string_to_lower(char *s)\n{\n   char *cs = (char *)s;\n   for ( ; *cs != '\\0'; cs++)\n      *cs = tolower((unsigned char)*cs);\n   return s;\n}\n\nchar *string_ucwords(char *s)\n{\n   char *cs = (char *)s;\n\n   if (!s || *s == '\\0')\n      return s;\n\n   for ( ; *cs != '\\0'; cs++)\n   {\n      if (*cs == ' ' && *(cs + 1) != '\\0')\n         *(cs+1) = toupper((unsigned char)*(cs+1));\n   }\n\n   s[0] = toupper((unsigned char)s[0]);\n   return s;\n}\n\nchar *string_replace_substring(\n      const char *in,          size_t in_len,\n      const char *pattern,     size_t pattern_len,\n      const char *replacement, size_t replacement_len)\n{\n   size_t _len;\n   size_t numhits     = 0;\n   const char *inat   = NULL;\n   const char *inprev = NULL;\n   char          *out = NULL;\n   char        *outat = NULL;\n\n   /* if either pattern or replacement is NULL,\n    * duplicate in and let caller handle it. */\n   if (!pattern || !replacement)\n      return strdup(in);\n\n   inat            = in;\n\n   while ((inat = strstr(inat, pattern)))\n   {\n      inat += pattern_len;\n      numhits++;\n   }\n\n   _len = in_len - pattern_len * numhits + replacement_len*numhits;\n\n   if (!(out = (char *)malloc(_len + 1)))\n      return NULL;\n\n   outat           = out;\n   inat            = in;\n   inprev          = in;\n\n   while ((inat = strstr(inat, pattern)))\n   {\n      memcpy(outat, inprev, inat-inprev);\n      outat += inat-inprev;\n      memcpy(outat, replacement, replacement_len);\n      outat += replacement_len;\n      inat  += pattern_len;\n      inprev = inat;\n   }\n\n   _len = (in + in_len) - inprev;\n   strlcpy(outat, inprev, _len + 1);\n\n   return out;\n}\n\n/**\n * string_trim_whitespace_left:\n *\n * Remove leading whitespaces\n **/\nchar *string_trim_whitespace_left(char *const s)\n{\n   if (s && *s)\n   {\n      char *current  = s;\n      while (*current && (*current == ' ' || *current == '\\t' || *current == '\\n' || *current == '\\r' || *current == '\\v' || *current == '\\f'))\n         ++current;\n      if (s != current)\n      {\n         size_t _len = strlen(current);\n         memmove(s, current, _len + 1);\n      }\n   }\n   return s;\n}\n\n/**\n * string_trim_whitespace_right:\n *\n * Remove trailing whitespaces\n **/\nchar *string_trim_whitespace_right(char *const s)\n{\n   if (s && *s)\n   {\n      size_t _len    = strlen(s);\n      char  *current = s + _len - 1;\n\n      while (current != s && ISSPACE((unsigned char)*current))\n      {\n         --current;\n         --_len;\n      }\n\n      current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\\0';\n   }\n\n   return s;\n}\n\n/**\n * string_trim_whitespace:\n *\n * Remove leading and trailing whitespaces\n **/\nchar *string_trim_whitespace(char *const s)\n{\n   string_trim_whitespace_right(s);  /* order matters */\n   string_trim_whitespace_left(s);\n\n   return s;\n}\n\n/**\n * word_wrap:\n * @s                  : pointer to destination buffer.\n * @len                : size of destination buffer.\n * @src                : pointer to input string.\n * @line_width         : max number of characters per line.\n * @wideglyph_width    : not used, but is necessary to keep\n *                       compatibility with word_wrap_wideglyph().\n * @max_lines          : max lines of destination string.\n *                       0 means no limit.\n *\n * Wraps string specified by @src to destination buffer\n * specified by @s and @len.\n * This function assumes that all glyphs in the string\n * have an on-screen pixel width similar to that of\n * regular Latin characters - i.e. it will not wrap\n * correctly any text containing so-called 'wide' Unicode\n * characters (e.g. CJK languages, emojis, etc.).\n **/\nsize_t word_wrap(\n      char *s,         size_t len,\n      const char *src, size_t src_len,\n      int line_width,  int wideglyph_width, unsigned max_lines)\n{\n   char *last_space    = NULL;\n   unsigned counter    = 0;\n   unsigned lines      = 1;\n   const char *src_end = src + src_len;\n   char *s_start       = s;\n   size_t _len         = len;\n\n   /* Prevent buffer overflow */\n   if (len < src_len + 1)\n      return 0;\n\n   /* Early return if src string length is less\n    * than line width */\n   if (src_len < (size_t)line_width)\n      return strlcpy(s, src, len);\n\n   while (*src != '\\0')\n   {\n      unsigned char_len = (unsigned)(utf8skip(src, 1) - src);\n      counter++;\n\n      if (*src == ' ')\n         last_space = s; /* Remember the location of the whitespace */\n      else if (*src == '\\n')\n      {\n         /* If newlines embedded in the input,\n          * reset the index */\n         lines++;\n         counter   = 0;\n\n         /* Early return if remaining src string\n          * length is less than line width */\n         if (src_end - src <= line_width)\n         {\n            _len = len - (size_t)(s - s_start);\n            return (size_t)(s - s_start) + strlcpy(s, src, _len);\n         }\n      }\n\n      while (char_len--)\n         *s++ = *src++;\n\n      if (counter >= (unsigned)line_width)\n      {\n         counter = 0;\n\n         if (last_space && (max_lines == 0 || lines < max_lines))\n         {\n            /* Replace nearest (previous) whitespace\n             * with newline character */\n            *last_space = '\\n';\n            lines++;\n\n            src        -= s - last_space - 1;\n            s           = last_space + 1;\n            last_space  = NULL;\n\n            /* Early return if remaining src string\n             * length is less than line width */\n            if (src_end - src < line_width)\n            {\n               _len = len - (size_t)(s - s_start);\n               return (size_t)(s - s_start) + strlcpy(s, src, _len);\n            }\n         }\n      }\n   }\n\n   *s = '\\0';\n   return (size_t)(s - s_start);\n}\n\n/**\n * word_wrap_wideglyph:\n * @dst                : pointer to destination buffer.\n * @len                : size of destination buffer.\n * @src                : pointer to input string.\n * @line_width         : max number of characters per line.\n * @wideglyph_width    : effective width of 'wide' Unicode glyphs.\n *                       the value here is normalised relative to the\n *                       typical on-screen pixel width of a regular\n *                       Latin character:\n *                       - a regular Latin character is defined to\n *                         have an effective width of 100\n *                       - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)\n *                       - e.g. if 'wide' Unicode characters in 'src'\n *                         have an on-screen pixel width twice that of\n *                         regular Latin characters, wideglyph_width\n *                         would be 200\n * @max_lines          : max lines of destination string.\n *                       0 means no limit.\n *\n * Wraps string specified by @src to destination buffer\n * specified by @dst and @len.\n * This function assumes that all glyphs in the string\n * are:\n * - EITHER 'non-wide' Unicode glyphs, with an on-screen\n *   pixel width similar to that of regular Latin characters\n * - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)\n *   with an on-screen pixel width defined by @wideglyph_width\n * Note that wrapping may occur in inappropriate locations\n * if @src string contains 'wide' Unicode characters whose\n * on-screen pixel width deviates greatly from the set\n * @wideglyph_width value.\n **/\nsize_t word_wrap_wideglyph(char *s, size_t len,\n      const char *src, size_t src_len, int line_width,\n      int wideglyph_width, unsigned max_lines)\n{\n   char *lastspace                   = NULL;\n   char *lastwideglyph               = NULL;\n   const char *src_end               = src + src_len;\n   char *s_start                     = s;\n   unsigned lines                    = 1;\n   /* 'line_width' means max numbers of characters per line,\n    * but this metric is only meaningful when dealing with\n    * 'regular' glyphs that have an on-screen pixel width\n    * similar to that of regular Latin characters.\n    * When handing so-called 'wide' Unicode glyphs, it is\n    * necessary to consider the actual on-screen pixel width\n    * of each character.\n    * In order to do this, we create a distinction between\n    * regular Latin 'non-wide' glyphs and 'wide' glyphs, and\n    * normalise all values relative to the on-screen pixel\n    * width of regular Latin characters:\n    * - Regular 'non-wide' glyphs have a normalised width of 100\n    * - 'line_width' is therefore normalised to 100 * (width_in_characters)\n    * - 'wide' glyphs have a normalised width of\n    *   100 * (wide_character_pixel_width / latin_character_pixel_width)\n    * - When a character is detected, the position in the current\n    *   line is incremented by the regular normalised width of 100\n    * - If that character is then determined to be a 'wide'\n    *   glyph, the position in the current line is further incremented\n    *   by the difference between the normalised 'wide' and 'non-wide'\n    *   width values */\n   unsigned counter_normalized       = 0;\n   int line_width_normalized         = line_width * 100;\n   int additional_counter_normalized = wideglyph_width - 100;\n\n   /* Early return if src string length is less\n    * than line width.\n    *\n    * NOTE on the strlcpy clamp: strlcpy returns strlen(src),\n    * which exceeds bytes-actually-written if the destination\n    * was too small (truncation case).  Callers (xmb, ozone,\n    * materialui messagebox helpers) use the returned value as\n    * the length argument to memchr() over the destination\n    * buffer; an inflated return walks memchr past the buffer\n    * end into adjacent stack memory.  Clamp the return to the\n    * true bytes-written count: min(strlen(src), len - 1). */\n   if (src_end - src < line_width)\n   {\n      size_t copied = strlcpy(s, src, len);\n      if (copied >= len)\n         copied = (len > 0) ? len - 1 : 0;\n      return copied;\n   }\n\n   while (*src != '\\0')\n   {\n      size_t remaining;\n      unsigned char_len   = (unsigned)(utf8skip(src, 1) - src);\n      counter_normalized += 100;\n\n      /* Prevent buffer overflow.  `remaining` is computed from\n       * the original `len` and the current write offset rather\n       * than tracking it via `len -= char_len` -- the rewinds\n       * at lastspace/lastwideglyph below move `s` backwards\n       * without a matching `len += ...`, which would otherwise\n       * desync the two and break the buffer-space accounting\n       * for the early-return strlcpys. */\n      remaining = len - (size_t)(s - s_start);\n      if (char_len >= remaining)\n         break;\n\n      if (*src == ' ')\n         lastspace          = s; /* Remember the location of the whitespace */\n      else if (*src == '\\n')\n      {\n         /* If newlines embedded in the input,\n          * reset the index */\n         lines++;\n         counter_normalized = 0;\n\n         /* Early return if remaining src string\n          * length is less than line width */\n         if (src_end - src <= line_width)\n         {\n            size_t copied = strlcpy(s, src, remaining);\n            if (copied >= remaining)\n               copied = (remaining > 0) ? remaining - 1 : 0;\n            return (size_t)(s - s_start) + copied;\n         }\n      }\n      else if (char_len >= 3)\n      {\n         /* Remember the location of the first byte\n          * whose length as UTF-8 >= 3*/\n         lastwideglyph       = s;\n         counter_normalized += additional_counter_normalized;\n      }\n\n      while (char_len--)\n         *s++ = *src++;\n\n      if (counter_normalized >= (unsigned)line_width_normalized)\n      {\n         counter_normalized = 0;\n\n         if (max_lines != 0 && lines >= max_lines)\n            continue;\n         else if (lastwideglyph \n              && (!lastspace || lastwideglyph > lastspace))\n         {\n            /* Insert newline character */\n            *lastwideglyph = '\\n';\n            lines++;\n            src           -= s - lastwideglyph;\n            s              = lastwideglyph + 1;\n            lastwideglyph  = NULL;\n\n            /* Early return if remaining src string\n             * length is less than line width */\n            if (src_end - src <= line_width)\n            {\n               size_t copied;\n               remaining = len - (size_t)(s - s_start);\n               copied    = strlcpy(s, src, remaining);\n               if (copied >= remaining)\n                  copied = (remaining > 0) ? remaining - 1 : 0;\n               return (size_t)(s - s_start) + copied;\n            }\n         }\n         else if (lastspace)\n         {\n            /* Replace nearest (previous) whitespace\n             * with newline character */\n            *lastspace = '\\n';\n            lines++;\n            src       -= s - lastspace - 1;\n            s          = lastspace + 1;\n            lastspace  = NULL;\n\n            /* Early return if remaining src string\n             * length is less than line width */\n            if (src_end - src < line_width)\n            {\n               size_t copied;\n               remaining = len - (size_t)(s - s_start);\n               copied    = strlcpy(s, src, remaining);\n               if (copied >= remaining)\n                  copied = (remaining > 0) ? remaining - 1 : 0;\n               return (size_t)(s - s_start) + copied;\n            }\n         }\n      }\n   }\n\n   *s = '\\0';\n   return (size_t)(s - s_start);\n}\n\n/**\n * string_tokenize:\n *\n * Splits string into tokens separated by @delim\n * > Returned token string must be free()'d\n * > Returns NULL if token is not found\n * > After each call, @str is set to the position after the\n *   last found token\n * > Tokens *include* empty strings\n * Usage example:\n *    char *str      = \"1,2,3,4,5,6,7,,,10,\";\n *    char **str_ptr = &str;\n *    char *token    = NULL;\n *    while ((token = string_tokenize(str_ptr, \",\")))\n *    {\n *        printf(\"%s\\n\", token);\n *        free(token);\n *        token = NULL;\n *    }\n **/\nchar* string_tokenize(char **str, const char *delim)\n{\n   /* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */\n   char *str_ptr    = NULL;\n   char *delim_ptr  = NULL;\n   char *token      = NULL;\n   size_t _len      = 0;\n   size_t delim_len = 0;\n\n   /* Sanity checks */\n   if (!str || !delim || !*delim)\n      return NULL;\n\n   /* Note: we don't check if string is empty here,\n    * empty strings are valid */\n   if (!(str_ptr = *str))\n      return NULL;\n\n   delim_len = strlen(delim);\n\n   /* Search for delimiter */\n   if ((delim_ptr = strstr(str_ptr, delim)))\n      _len = delim_ptr - str_ptr;\n   else\n      _len = strlen(str_ptr);\n\n   /* Allocate token string */\n   if (!(token = (char *)malloc((_len + 1) * sizeof(char))))\n      return NULL;\n\n   /* Copy token.  strlcpy already NUL-terminates within the\n    * `_len + 1` byte limit -- _len is bounded above by\n    * strlen(str_ptr) (computed at lines 489-492), so the\n    * terminator lands exactly at token[_len] without needing\n    * a separate write here.  The redundant token[_len] = '\\0'\n    * also tripped -Wstringop-overflow under some gcc\n    * configurations (the analyser couldn't constrain _len\n    * relative to the malloc'd size). */\n   strlcpy(token, str_ptr, (_len + 1) * sizeof(char));\n   /* Update input string pointer */\n   *str = delim_ptr ? delim_ptr + delim_len : NULL;\n   return token;\n}\n\n/**\n * string_remove_all_chars:\n * @s                 : input string (must be non-NULL, otherwise UB)\n *\n * Leaf function.\n *\n * Removes every instance of character @c from @s\n *\n * Returns the length of the resulting string.\n **/\nsize_t string_remove_all_chars(char *s, char c)\n{\n   char *dst = s;\n   char *src = s;\n   while (*src)\n   {\n      /* Only write if the character is not the one to remove */\n      if (*src != c)\n         *dst++ = *src;\n      src++;\n   }\n   *dst = '\\0';\n   return (size_t)(dst - s);\n}\n\n/**\n * string_replace_all_chars:\n * @s                  : input string (must be non-NULL, otherwise UB)\n * @find               : character to find\n * @replace            : character to replace @find with\n *\n * Replaces every instance of character @find in @s\n * with character @replace\n **/\nvoid string_replace_all_chars(char *s, char find, char replace)\n{\n   char *str_ptr = s;\n   while ((str_ptr = strchr(str_ptr, find)))\n      *str_ptr++ = replace;\n}\n\n/**\n * string_to_unsigned:\n * @str                : input string\n *\n * Converts string to unsigned integer.\n *\n * @return 0 if string is invalid, otherwise > 0\n **/\nunsigned string_to_unsigned(const char *str)\n{\n   const char *ptr = NULL;\n\n   if (!str || !*str)\n      return 0;\n\n   for (ptr = str; *ptr != '\\0'; ptr++)\n   {\n      if (!ISDIGIT((unsigned char)*ptr))\n         return 0;\n   }\n\n   return (unsigned)strtoul(str, NULL, 10);\n}\n\n/**\n * string_hex_to_unsigned:\n * @str                : input string (must be non-NULL, otherwise UB)\n *\n * Converts hexadecimal string to unsigned integer.\n * Handles optional leading '0x'.\n *\n * @return 0 if string is invalid, otherwise > 0\n **/\nunsigned string_hex_to_unsigned(const char *str)\n{\n   const char *hex_str = str;\n   const char *ptr     = NULL;\n\n   if (!str || !*str)\n      return 0;\n\n   /* Remove leading '0x', if present */\n   if (   str[0] == '0'\n       && (str[1] == 'x' || str[1] == 'X'))\n   {\n      hex_str = str + 2;\n      if (!hex_str || !*hex_str)\n         return 0;\n   }\n\n   /* Check for valid characters */\n   for (ptr = hex_str; *ptr != '\\0'; ptr++)\n   {\n      if (!isxdigit((unsigned char)*ptr))\n         return 0;\n   }\n\n   return (unsigned)strtoul(hex_str, NULL, 16);\n}\n\n/**\n * string_count_occurrences_single_character:\n *\n * Leaf function.\n *\n * Get the total number of occurrences of character @c in @str.\n *\n * @return Total number of occurrences of character @c\n */\nint string_count_occurrences_single_character(const char *str, char c)\n{\n   int count = 0;\n\n   for (; *str; str++)\n      if (*str == c)\n         count++;\n\n   return count;\n}\n\n/**\n * string_replace_whitespace_with_single_character:\n *\n * Leaf function.\n *\n * Replaces all spaces with given character @c.\n **/\nvoid string_replace_whitespace_with_single_character(char *s, char c)\n{\n   for (; *s; s++)\n      if (ISSPACE((unsigned char)*s))\n         *s = c;\n}\n\n/**\n * string_replace_multi_space_with_single_space:\n *\n * Leaf function.\n *\n * Replaces multiple spaces with a single space in a string.\n **/\nvoid string_replace_multi_space_with_single_space(char *s)\n{\n   char *str_trimmed  = s;\n   bool prev_is_space = false;\n   bool curr_is_space = false;\n\n   for (; *s; s++)\n   {\n      curr_is_space  = ISSPACE((unsigned char)*s);\n      if (prev_is_space && curr_is_space)\n         continue;\n      *str_trimmed++ = *s;\n      prev_is_space  = curr_is_space;\n   }\n   *str_trimmed = '\\0';\n}\n\n/**\n * string_remove_all_whitespace:\n *\n * Leaf function.\n *\n * Remove all spaces from the given string.\n * Returns the length of the resulting string.\n **/\nsize_t string_remove_all_whitespace(char *s, const char *str)\n{\n   char *start = (char*)s;\n   for (; *str; str++)\n      if (!ISSPACE((unsigned char)*str))\n         *s++ = *str;\n   *s = '\\0';\n   return s - start;\n}\n\n/**\n * strlcpy_append:\n *\n * See header (libretro-common/include/string/stdstring.h) for the\n * full contract.  Bound-checked append; advances *pos by\n * strlen(@src) on success, returns -1 on truncation.\n *\n * Truncation is signalled when *pos >= len already, or when\n * strlcpy returns a value >= the remaining capacity.  In either\n * case the destination is left NUL-terminated (strlcpy guarantees\n * this when its size argument is non-zero) and *pos is clamped to\n * len - 1 so subsequent calls in a chain become no-ops that also\n * return -1.\n **/\nint strlcpy_append(char *s, size_t len, size_t *pos, const char *src)\n{\n   size_t remaining;\n   size_t n;\n\n   if (!s || !pos || !src || len == 0)\n      return -1;\n\n   if (*pos >= len)\n   {\n      /* Already saturated; clamp and report truncation. */\n      *pos = len - 1;\n      return -1;\n   }\n\n   remaining = len - *pos;\n   n         = strlcpy(s + *pos, src, remaining);\n\n   if (n >= remaining)\n   {\n      /* strlcpy truncated.  s + len - 1 is NUL-terminated by\n       * strlcpy's contract.  Clamp *pos so subsequent appends\n       * short-circuit. */\n      *pos = len - 1;\n      return -1;\n   }\n\n   *pos += n;\n   return 0;\n}\n\n/**\n * Retrieve the last occurrence of the given character in a string.\n */\nint string_index_last_occurance(const char *str, char c)\n{\n   const char *pos = strrchr(str, c);\n   if (pos)\n      return (int)(pos - str);\n   return -1;\n}\n\n/**\n * string_find_index_substring_string:\n * @str                : input string (must be non-NULL, otherwise UB)\n * @substr             : substring to find in @str\n *\n * Find the position of substring @substr in string @str.\n **/\nint string_find_index_substring_string(const char *str, const char *substr)\n{\n   const char *pos = strstr(str, substr);\n   if (pos)\n      return (int)(pos - str);\n   return -1;\n}\n\n/**\n * string_copy_only_ascii:\n *\n * Leaf function.\n *\n * Strips non-ASCII characters from a string.\n **/\nvoid string_copy_only_ascii(char *s, const char *str)\n{\n   for (; *str; str++)\n      if (*str > 0x1F && *str < 0x7F)\n         *s++ = *str;\n   *s = '\\0';\n}\n\n/**\n * string_ext_list_find:\n *\n * Checks whether a single extension token already exists\n * in a '|'-delimited string. Exact token matching only.\n **/\nbool string_ext_list_find(const char *delim_str, size_t delim_len,\n      const char *ext, size_t ext_len)\n{\n   const char *p   = delim_str;\n   const char *end = delim_str + delim_len;\n\n   while (p < end)\n   {\n      const char *tok_end = (const char*)memchr(p, '|', end - p);\n      size_t tok_len;\n\n      if (!tok_end)\n         tok_end = end;\n\n      tok_len = tok_end - p;\n\n      if (tok_len == ext_len && memcmp(p, ext, ext_len) == 0)\n         return true;\n\n      p = tok_end + 1;\n   }\n\n   return false;\n}\n\n/**\n * string_ext_list_append_dedup:\n *\n * Appends a single extension to a '|'-delimited destination buffer,\n * but only if that extension is not already present.\n **/\nvoid string_ext_list_append_dedup(char *dst, size_t *dst_len,\n      size_t dst_size, const char *ext, size_t ext_len)\n{\n   if (ext_len == 0)\n      return;\n   if (string_ext_list_find(dst, *dst_len, ext, ext_len))\n      return;\n   if (*dst_len + 1 + ext_len + 1 > dst_size)\n      return;\n\n   if (*dst_len > 0)\n      dst[(*dst_len)++] = '|';\n\n   memcpy(dst + *dst_len, ext, ext_len);\n   *dst_len += ext_len;\n   dst[*dst_len] = '\\0';\n}\n\n/**\n * string_ext_list_merge_dedup:\n *\n * Splits a '|'-delimited source string and appends each unique\n * extension to the destination buffer via string_ext_list_append_dedup.\n **/\nvoid string_ext_list_merge_dedup(char *dst, size_t *dst_len,\n      size_t dst_size, const char *src)\n{\n   const char *p;\n   const char *end;\n\n   if (!src || !*src)\n      return;\n\n   end = src + strlen(src);\n   p   = src;\n\n   while (p < end)\n   {\n      const char *tok_end = (const char*)memchr(p, '|', end - p);\n      size_t tok_len;\n\n      if (!tok_end)\n         tok_end = end;\n\n      tok_len = tok_end - p;\n\n      if (tok_len > 0)\n         string_ext_list_append_dedup(dst, dst_len, dst_size, p, tok_len);\n\n      p = tok_end + 1;\n   }\n}\n"
  },
  {
    "path": "test/formats/test_rpng.c",
    "content": "/* Copyright  (C) 2026 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (test_rpng.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Regression coverage for rpng_process_ihdr's dimension and\n * size guards.\n *\n * The picture is two-layer:\n *\n *  - On all hosts a 4 GiB output guard (width*height*4) plus a\n *    4 GiB pass_size guard reject images whose decoded buffer\n *    cannot be addressed.  Together with the (size_t) casts at\n *    the per-row malloc sites these prevent the original heap\n *    overflow on any platform regardless of dimensions.\n *\n *  - On 32-bit hosts an additional 0x4000 (16384) dimension cap\n *    rejects images that would demand more than a few hundred MB\n *    of decoded pixels.  These would fail to allocate anyway on\n *    a 32-bit address space, but a tight cap turns the failure\n *    into a clean reject rather than a partially-set-up parser\n *    state.  64-bit hosts do not cap here, allowing legitimate\n *    large images (cf. IrfanView's tens-of-thousands-pixel\n *    routine support).\n *\n * Tests below are platform-gated to match.  The strict\n * regression cases (the 0x4001 / 30000-squared bug shapes) only\n * fire on 32-bit; 64-bit gets the looser sanity coverage. */\n\n#include <check.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <formats/rpng.h>\n\n#define SUITE_NAME \"rpng\"\n\n/* PNG file signature, replicated from rpng_internal.h (which is\n * not part of the public install set). */\nstatic const uint8_t png_magic[8] = {\n   0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a,\n};\n\n/* Build a minimal valid-shape PNG buffer containing the file\n * signature and a single IHDR chunk with the supplied dimensions,\n * followed by a trailing-padding chunk-header so that\n * rpng_iterate_image's post-IHDR pointer-advance check does not\n * push past buff_end on the same call (a successful IHDR-accept\n * call must leave buff_data <= buff_end so a subsequent iterate\n * could read the next chunk).  The CRC is set to zero - rpng's\n * iterate path does not validate IHDR CRC, so this is sufficient\n * to exercise rpng_process_ihdr. */\nstatic size_t make_ihdr_only_png(uint8_t *out, size_t out_size,\n      uint32_t width, uint32_t height,\n      uint8_t depth, uint8_t color_type)\n{\n   /* 8 (magic) + 4 (length) + 4 (type) + 13 (IHDR data) + 4 (CRC)\n    * + 8 (room for next chunk header) = 41 */\n   size_t len = 0;\n   if (out_size < 41)\n      return 0;\n\n   memcpy(out + len, png_magic, 8);\n   len += 8;\n\n   /* IHDR chunk length = 13, big-endian */\n   out[len++] = 0; out[len++] = 0; out[len++] = 0; out[len++] = 13;\n\n   /* \"IHDR\" */\n   out[len++] = 'I'; out[len++] = 'H'; out[len++] = 'D'; out[len++] = 'R';\n\n   /* width, big-endian */\n   out[len++] = (uint8_t)(width  >> 24);\n   out[len++] = (uint8_t)(width  >> 16);\n   out[len++] = (uint8_t)(width  >>  8);\n   out[len++] = (uint8_t)(width  >>  0);\n\n   /* height, big-endian */\n   out[len++] = (uint8_t)(height >> 24);\n   out[len++] = (uint8_t)(height >> 16);\n   out[len++] = (uint8_t)(height >>  8);\n   out[len++] = (uint8_t)(height >>  0);\n\n   out[len++] = depth;\n   out[len++] = color_type;\n   out[len++] = 0; /* compression */\n   out[len++] = 0; /* filter */\n   out[len++] = 0; /* interlace */\n\n   /* CRC placeholder; rpng_iterate_image does not validate it */\n   out[len++] = 0; out[len++] = 0; out[len++] = 0; out[len++] = 0;\n\n   /* Trailing 8 bytes so the post-IHDR pointer advance leaves\n    * buff_data <= buff_end (rpng_iterate_image returns false if\n    * the advance pushes past the end).  Contents do not matter -\n    * the test does not call rpng_iterate_image again. */\n   out[len++] = 0; out[len++] = 0; out[len++] = 0; out[len++] = 0;\n   out[len++] = 0; out[len++] = 0; out[len++] = 0; out[len++] = 0;\n\n   return len;\n}\n\n/* Helper: try to parse an IHDR-only PNG with the supplied\n * dimensions and depth/color_type, returning the result of\n * rpng_iterate_image. */\nstatic bool try_iterate(uint32_t w, uint32_t h, uint8_t depth, uint8_t ctype)\n{\n   uint8_t buf[64];\n   size_t  len;\n   rpng_t *rpng;\n   bool    ret;\n\n   len = make_ihdr_only_png(buf, sizeof(buf), w, h, depth, ctype);\n   ck_assert(len > 0);\n\n   rpng = rpng_alloc();\n   ck_assert(rpng != NULL);\n   ck_assert(rpng_set_buf_ptr(rpng, buf, len));\n   ck_assert(rpng_start(rpng));\n\n   ret = rpng_iterate_image(rpng);\n\n   rpng_free(rpng);\n   return ret;\n}\n\nSTART_TEST (test_rpng_ihdr_dimension_cap_accept_at_limit)\n{\n   /* 0x4000 == 16384.  Inclusive accept on every platform: on\n    * 32-bit this is the boundary of the dimension cap; on 64-bit\n    * there is no dimension cap and 16384x16384 RGBA8 is well\n    * under the 4 GiB output guard. */\n   ck_assert(try_iterate(0x4000u, 0x4000u, 8, 6));\n}\nEND_TEST\n\n#if SIZE_MAX <= 0xFFFFFFFFu\nSTART_TEST (test_rpng_ihdr_dimension_cap_reject_just_over_32bit)\n{\n   /* 0x4001 must be rejected on 32-bit.  The pre-existing 4 GiB\n    * output guard does not catch 16385x16385 RGBA8 (~1.07 GiB),\n    * so the 0x4000 cap is what rejects it here.  This case does\n    * NOT reproduce on 64-bit, where 16385x16385 is a legitimate\n    * (large) image. */\n   ck_assert(!try_iterate(0x4001u, 0x4000u, 8, 6));\n   ck_assert(!try_iterate(0x4000u, 0x4001u, 8, 6));\n   ck_assert(!try_iterate(0x4001u, 0x4001u, 8, 6));\n}\nEND_TEST\n\nSTART_TEST (test_rpng_ihdr_dimension_cap_reject_30000_squared_32bit)\n{\n   /* 30000x30000 RGBA8 is the historical worst case on 32-bit:\n    * 3.35 GiB of decoded pixels, which on a 32-bit address space\n    * cannot be allocated and pre-patch corrupted the heap when\n    * the uint32 multiplication width*height*sizeof(uint32_t)\n    * wrapped.  The 0x4000 cap catches this.  On 64-bit this is a\n    * legitimate-but-large image, accepted by the IHDR guards. */\n   ck_assert(!try_iterate(30000u, 30000u, 8, 6));\n}\nEND_TEST\n#endif\n\nSTART_TEST (test_rpng_ihdr_size_cap_reject_uint32_max)\n{\n   /* PNG-spec maximum dimensions.  Rejected on every platform:\n    * on 32-bit the 0x4000 cap catches it first; on 64-bit the\n    * 4 GiB output guard does (the math overflows even with\n    * 64-bit width arithmetic). */\n   ck_assert(!try_iterate(0x7FFFFFFFu, 0x7FFFFFFFu, 8, 6));\n   ck_assert(!try_iterate(0x7FFFFFFFu, 1u, 8, 6));\n   ck_assert(!try_iterate(1u, 0x7FFFFFFFu, 8, 6));\n}\nEND_TEST\n\nSTART_TEST (test_rpng_ihdr_dimension_cap_accept_small)\n{\n   /* Sanity: small valid dimensions still parse on every\n    * platform. */\n   ck_assert(try_iterate(16u, 16u, 8, 6));\n   ck_assert(try_iterate(1u, 1u, 8, 6));\n   /* Other supported color/depth combinations at the 0x4000\n    * boundary.  16384x16384 RGBA-16 is 2 GiB output -- under the\n    * 4 GiB cap on every platform. */\n   ck_assert(try_iterate(0x4000u, 0x4000u, 8, 2));   /* RGB */\n   ck_assert(try_iterate(0x4000u, 0x4000u, 16, 6));  /* RGBA-16 */\n}\nEND_TEST\n\nSTART_TEST (test_rpng_ihdr_zero_dimensions_rejected)\n{\n   /* Pre-existing behavior: zero dimensions are rejected.\n    * Verify the cap patch did not regress this. */\n   ck_assert(!try_iterate(0u, 16u, 8, 6));\n   ck_assert(!try_iterate(16u, 0u, 8, 6));\n}\nEND_TEST\n\nSuite *create_suite(void)\n{\n   Suite *s = suite_create(SUITE_NAME);\n\n   TCase *tc_core = tcase_create(\"Core\");\n   tcase_add_test(tc_core, test_rpng_ihdr_dimension_cap_accept_at_limit);\n#if SIZE_MAX <= 0xFFFFFFFFu\n   tcase_add_test(tc_core, test_rpng_ihdr_dimension_cap_reject_just_over_32bit);\n   tcase_add_test(tc_core, test_rpng_ihdr_dimension_cap_reject_30000_squared_32bit);\n#endif\n   tcase_add_test(tc_core, test_rpng_ihdr_size_cap_reject_uint32_max);\n   tcase_add_test(tc_core, test_rpng_ihdr_dimension_cap_accept_small);\n   tcase_add_test(tc_core, test_rpng_ihdr_zero_dimensions_rejected);\n   suite_add_tcase(s, tc_core);\n\n   return s;\n}\n\nint main(void)\n{\n   int num_fail;\n   Suite *s = create_suite();\n   SRunner *sr = srunner_create(s);\n   srunner_run_all(sr, CK_NORMAL);\n   num_fail = srunner_ntests_failed(sr);\n   srunner_free(sr);\n   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/hash/test_hash.c",
    "content": "/* Copyright  (C) 2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (test_hash.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <check.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <lrc_hash.h>\n\n#define SUITE_NAME \"hash\"\n\nSTART_TEST (test_sha256)\n{\n   char output[65];\n   sha256_hash(output, (uint8_t*)\"abc\", 3);\n   ck_assert(!strcmp(output,\n      \"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad\"));\n}\nEND_TEST\n\nSTART_TEST (test_sha1)\n{\n   char output[41];\n   char tmpfile[512];\n   FILE *fd;\n   tmpnam(tmpfile);\n   fd = fopen(tmpfile, \"wb\");\n   ck_assert(fd != NULL);\n   fwrite(\"abc\", 1, 3, fd);\n   fclose(fd);\n   sha1_calculate(tmpfile, output);\n\n   ck_assert(!strcmp(output,\n      \"A9993E364706816ABA3E25717850C26C9CD0D89D\"));\n}\nEND_TEST\n\nSTART_TEST (test_djb2)\n{\n   ck_assert_uint_eq(djb2_calculate(\"retroarch\"), 0xFADF3BCF);\n}\nEND_TEST\n\nSuite *create_suite(void)\n{\n   Suite *s = suite_create(SUITE_NAME);\n\n   TCase *tc_core = tcase_create(\"Core\");\n   tcase_add_test(tc_core, test_sha256);\n   tcase_add_test(tc_core, test_sha1);\n   tcase_add_test(tc_core, test_djb2);\n   suite_add_tcase(s, tc_core);\n\n   return s;\n}\n\nint main(void)\n{\n   int num_fail;\n   Suite *s = create_suite();\n   SRunner *sr = srunner_create(s);\n   srunner_run_all(sr, CK_NORMAL);\n   num_fail = srunner_ntests_failed(sr);\n   srunner_free(sr);\n   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/lists/test_linked_list.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (test_linked_list.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <check.h>\n#include <stdarg.h>\n#include <stdlib.h>\n\n#include <lists/linked_list.h>\n\n#define SUITE_NAME \"Linked List\"\n\nstatic char *_value_1 = \"value1\";\nstatic char *_value_2 = \"value2\";\nstatic char *_value_3 = \"value3\";\n\nSTART_TEST (test_linked_list_create)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_nonnull(list);\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_free)\n{\n   linked_list_t *queue = linked_list_new();\n   linked_list_free(queue, NULL);\n   linked_list_free(NULL, NULL);\n}\nEND_TEST\n\nstatic int _free_alloced_value_count;\nstatic void _free_alloced_value(void *value)\n{\n   _free_alloced_value_count++;\n   free(value);\n}\n\nSTART_TEST (test_linked_list_free_with_fn)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, malloc(1));\n   linked_list_add(list, malloc(1));\n   linked_list_add(list, malloc(1));\n\n   _free_alloced_value_count = 0;\n   linked_list_free(list, &_free_alloced_value);\n\n   ck_assert_int_eq(3, _free_alloced_value_count);\n}\nEND_TEST\n\nstatic void _verify_list(linked_list_t *list, int size, ...)\n{\n   va_list values_list;\n   void **values;\n   int i;\n   linked_list_iterator_t *iterator;\n\n   values = (void **)malloc(size * sizeof(void *));\n\n   ck_assert_int_eq(linked_list_size(list), size);\n\n   va_start(values_list, size);\n   for (i = 0; i < size; i++)\n   {\n      values[i] = va_arg(values_list, void *);\n      ck_assert_ptr_eq(values[i], linked_list_get(list, i));\n   }\n   va_end(values_list);\n\n   iterator = linked_list_iterator(list, true);\n   for (i = 0; i < size; i++)\n   {\n      ck_assert_ptr_nonnull(iterator);\n      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));\n      iterator = linked_list_iterator_next(iterator);\n   }\n   ck_assert_ptr_null(iterator);\n\n   iterator = linked_list_iterator(list, false);\n   for (i = size - 1; i >= 0; i--)\n   {\n      ck_assert_ptr_nonnull(iterator);\n      ck_assert_ptr_eq(values[i], linked_list_iterator_value(iterator));\n      iterator = linked_list_iterator_next(iterator);\n   }\n   ck_assert_ptr_null(iterator);\n\n   free(values);\n}\n\nSTART_TEST (test_linked_list_add)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_insert_empty)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_insert(list, 0, _value_1);\n\n   ck_assert_int_eq(linked_list_size(list), 1);\n   ck_assert_ptr_eq(linked_list_get(list, 0), _value_1);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_insert_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n   linked_list_insert(list, 0, _value_1);\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_insert_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_3);\n   linked_list_insert(list, 1, _value_2);\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_insert_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_insert(list, 2, _value_3);\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_insert_invalid)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_insert(list, 2, _value_1);\n\n   ck_assert_int_eq(linked_list_size(list), 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_insert_null)\n{\n   linked_list_insert(NULL, 0, _value_1);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_invalid)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_get(list, 2));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_null)\n{\n   ck_assert_ptr_null(linked_list_get(NULL, 0));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_first_matching_null)\n{\n   ck_assert_ptr_null(linked_list_get_first_matching(NULL, NULL, NULL));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_first_matching_function_null)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_get_first_matching(list, NULL, NULL));\n\n   linked_list_free(list, NULL);\n}\n\nbool _matches_function(void *value, void *state)\n{\n   ck_assert_ptr_eq(_value_1, state);\n   return value == _value_2;\n}\n\nSTART_TEST (test_linked_list_get_first_matching_no_match)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_get_first_matching(list, &_matches_function, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_first_matching_with_match)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(_value_2, linked_list_get_first_matching(list, &_matches_function, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_last_matching_null)\n{\n   ck_assert_ptr_null(linked_list_get_last_matching(NULL, NULL, NULL));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_last_matching_function_null)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_get_last_matching(list, NULL, NULL));\n\n   linked_list_free(list, NULL);\n}\n\nSTART_TEST (test_linked_list_get_last_matching_no_match)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_get_last_matching(list, &_matches_function, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_get_last_matching_with_match)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(_value_2, linked_list_get_last_matching(list, &_matches_function, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_null)\n{\n   ck_assert_ptr_null(linked_list_remove_at(NULL, 0));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_remove_at(list, 0));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_invalid)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_at(list, 3);\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_at(list, 0);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_at(list, 1);\n\n   _verify_list(list, 2, _value_1, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_at(list, 2);\n\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_at_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   linked_list_remove_at(list, 0);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_null)\n{\n   ck_assert_ptr_null(linked_list_remove_first(NULL, _value_1));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_remove_first(list, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_not_found)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_null(linked_list_remove_first(list, \"foo\"));\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_first(list, _value_2), _value_2);\n\n   _verify_list(list, 2, _value_1, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_first(list, _value_3), _value_3);\n\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_multiple)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_first(list, _value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_1);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_null)\n{\n   ck_assert_ptr_null(linked_list_remove_last(NULL, _value_1));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_remove_last(list, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_not_found)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_null(linked_list_remove_last(list, \"foo\"));\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_last(list, _value_2), _value_2);\n\n   _verify_list(list, 2, _value_1, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_last(list, _value_3), _value_3);\n\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_multiple)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_last(list, _value_1), _value_1);\n\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_null)\n{\n   ck_assert_ptr_null(linked_list_remove_all(NULL, _value_1));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_remove_all(list, _value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_not_found)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_null(linked_list_remove_all(list, \"foo\"));\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_all(list, _value_2), _value_2);\n\n   _verify_list(list, 2, _value_1, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_all(list, _value_3), _value_3);\n\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_multiple)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_all(list, _value_1), _value_1);\n\n   _verify_list(list, 1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nbool _match_value_1(void *value)\n{\n   return _value_1 == value;\n}\n\nbool _no_match(void *value)\n{\n   return false;\n}\n\nSTART_TEST (test_linked_list_remove_first_matching_null)\n{\n   ck_assert_ptr_null(linked_list_remove_first_matching(NULL, &_match_value_1));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_remove_first_matching(list, &_match_value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_not_found)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_null(linked_list_remove_first_matching(list, &_no_match));\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_first_matching_multiple)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_first_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_1);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_null)\n{\n   ck_assert_ptr_null(linked_list_remove_last_matching(NULL, &_match_value_1));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_ptr_null(linked_list_remove_last_matching(list, &_match_value_1));\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_not_found)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_null(linked_list_remove_last_matching(list, &_no_match));\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_3);\n\n   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_last_matching_multiple)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n\n   ck_assert_ptr_eq(linked_list_remove_last_matching(list, &_match_value_1), _value_1);\n\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_null)\n{\n   linked_list_remove_all_matching(NULL, &_match_value_1);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_empty)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_remove_all_matching(list, &_match_value_1);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_not_found)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_all_matching(list, &_no_match);\n\n   _verify_list(list, 3, _value_1, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_all_matching(list, &_match_value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_3);\n\n   linked_list_remove_all_matching(list, &_match_value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n   linked_list_add(list, _value_1);\n\n   linked_list_remove_all_matching(list, &_match_value_1);\n\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_only)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n\n   linked_list_remove_all_matching(list, &_match_value_1);\n\n   _verify_list(list, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_remove_all_matching_multiple)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_1);\n\n   linked_list_remove_all_matching(list, &_match_value_1);\n\n   _verify_list(list, 1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_set_at_null)\n{\n   ck_assert_int_eq(linked_list_set_at(NULL, 0, _value_1) == true, 0);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_set_at_empty)\n{\n   linked_list_t *list = linked_list_new();\n   ck_assert_int_eq(linked_list_set_at(list, 0, _value_1) == true, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_set_at_invalid)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   ck_assert_int_eq(linked_list_set_at(list, 1, _value_2) == true, 0);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nstatic char *_replacement_value = \"foo\";\n\nSTART_TEST (test_linked_list_set_at_first)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_int_eq(linked_list_set_at(list, 0, _replacement_value) == false, 0);\n\n   _verify_list(list, 3, _replacement_value, _value_2, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_set_at_middle)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_int_eq(linked_list_set_at(list, 1, _replacement_value) == false, 0);\n\n   _verify_list(list, 3, _value_1, _replacement_value, _value_3);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_set_at_last)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   ck_assert_int_eq(linked_list_set_at(list, 2, _replacement_value) == false, 0);\n\n   _verify_list(list, 3, _value_1, _value_2, _replacement_value);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_iterator_remove_null)\n{\n   ck_assert_ptr_null(linked_list_iterator_remove(NULL));\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_iterator_remove_first)\n{\n   linked_list_t *list;\n   linked_list_iterator_t *iterator;\n\n   list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   iterator = linked_list_iterator(list, true);\n   iterator = linked_list_iterator_remove(iterator);\n\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_2);\n   _verify_list(list, 2, _value_2, _value_3);\n\n   linked_list_iterator_free(iterator);\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_iterator_remove_middle)\n{\n   linked_list_t *list;\n   linked_list_iterator_t *iterator;\n\n   list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   iterator = linked_list_iterator(list, true);\n   iterator = linked_list_iterator_next(iterator);\n   iterator = linked_list_iterator_remove(iterator);\n\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(linked_list_iterator_value(iterator), _value_3);\n   _verify_list(list, 2, _value_1, _value_3);\n\n   linked_list_iterator_free(iterator);\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_iterator_remove_last)\n{\n   linked_list_t *list;\n   linked_list_iterator_t *iterator;\n\n   list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   iterator = linked_list_iterator(list, true);\n   iterator = linked_list_iterator_next(iterator);\n   iterator = linked_list_iterator_next(iterator);\n   iterator = linked_list_iterator_remove(iterator);\n\n   ck_assert_ptr_null(iterator);\n   _verify_list(list, 2, _value_1, _value_2);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_iterator_free_null)\n{\n   linked_list_iterator_free(NULL);\n}\nEND_TEST\n\nstatic size_t _foreach_count;\nstatic void _foreach_fn(size_t index, void *value)\n{\n   _foreach_count++;\n}\n\nSTART_TEST (test_linked_list_foreach_null_list)\n{\n   linked_list_foreach(NULL, _foreach_fn);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_foreach_null_fn)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   linked_list_foreach(list, NULL);\n\n   linked_list_free(list, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_linked_list_foreach_valid)\n{\n   linked_list_t *list = linked_list_new();\n   linked_list_add(list, _value_1);\n   linked_list_add(list, _value_2);\n   linked_list_add(list, _value_3);\n\n   _foreach_count = 0;\n   linked_list_foreach(list, &_foreach_fn);\n   ck_assert_uint_eq(3, _foreach_count);\n\n   linked_list_free(list, NULL);\n}\n\nSuite *create_suite(void)\n{\n   Suite *s = suite_create(SUITE_NAME);\n\n   TCase *tc_core = tcase_create(\"Core\");\n   tcase_add_test(tc_core, test_linked_list_create);\n   tcase_add_test(tc_core, test_linked_list_free);\n   tcase_add_test(tc_core, test_linked_list_free_with_fn);\n   tcase_add_test(tc_core, test_linked_list_add);\n   tcase_add_test(tc_core, test_linked_list_insert_empty);\n   tcase_add_test(tc_core, test_linked_list_insert_first);\n   tcase_add_test(tc_core, test_linked_list_insert_middle);\n   tcase_add_test(tc_core, test_linked_list_insert_last);\n   tcase_add_test(tc_core, test_linked_list_insert_invalid);\n   tcase_add_test(tc_core, test_linked_list_insert_null);\n   tcase_add_test(tc_core, test_linked_list_get_invalid);\n   tcase_add_test(tc_core, test_linked_list_get_null);\n   tcase_add_test(tc_core, test_linked_list_get_first_matching_null);\n   tcase_add_test(tc_core, test_linked_list_get_first_matching_function_null);\n   tcase_add_test(tc_core, test_linked_list_get_first_matching_no_match);\n   tcase_add_test(tc_core, test_linked_list_get_first_matching_with_match);\n   tcase_add_test(tc_core, test_linked_list_get_last_matching_null);\n   tcase_add_test(tc_core, test_linked_list_get_last_matching_function_null);\n   tcase_add_test(tc_core, test_linked_list_get_last_matching_no_match);\n   tcase_add_test(tc_core, test_linked_list_get_last_matching_with_match);\n   tcase_add_test(tc_core, test_linked_list_remove_at_null);\n   tcase_add_test(tc_core, test_linked_list_remove_at_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_at_invalid);\n   tcase_add_test(tc_core, test_linked_list_remove_at_first);\n   tcase_add_test(tc_core, test_linked_list_remove_at_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_at_last);\n   tcase_add_test(tc_core, test_linked_list_remove_at_only);\n   tcase_add_test(tc_core, test_linked_list_remove_first_null);\n   tcase_add_test(tc_core, test_linked_list_remove_first_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_first_not_found);\n   tcase_add_test(tc_core, test_linked_list_remove_first_first);\n   tcase_add_test(tc_core, test_linked_list_remove_first_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_first_last);\n   tcase_add_test(tc_core, test_linked_list_remove_first_only);\n   tcase_add_test(tc_core, test_linked_list_remove_first_multiple);\n   tcase_add_test(tc_core, test_linked_list_remove_last_null);\n   tcase_add_test(tc_core, test_linked_list_remove_last_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_last_not_found);\n   tcase_add_test(tc_core, test_linked_list_remove_last_first);\n   tcase_add_test(tc_core, test_linked_list_remove_last_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_last_last);\n   tcase_add_test(tc_core, test_linked_list_remove_last_only);\n   tcase_add_test(tc_core, test_linked_list_remove_last_multiple);\n   tcase_add_test(tc_core, test_linked_list_remove_all_null);\n   tcase_add_test(tc_core, test_linked_list_remove_all_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_all_not_found);\n   tcase_add_test(tc_core, test_linked_list_remove_all_first);\n   tcase_add_test(tc_core, test_linked_list_remove_all_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_all_last);\n   tcase_add_test(tc_core, test_linked_list_remove_all_only);\n   tcase_add_test(tc_core, test_linked_list_remove_all_multiple);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_null);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_not_found);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_first);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_last);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_only);\n   tcase_add_test(tc_core, test_linked_list_remove_first_matching_multiple);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_null);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_not_found);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_first);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_last);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_only);\n   tcase_add_test(tc_core, test_linked_list_remove_last_matching_multiple);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_null);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_empty);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_not_found);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_first);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_middle);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_last);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_only);\n   tcase_add_test(tc_core, test_linked_list_remove_all_matching_multiple);\n   tcase_add_test(tc_core, test_linked_list_set_at_null);\n   tcase_add_test(tc_core, test_linked_list_set_at_empty);\n   tcase_add_test(tc_core, test_linked_list_set_at_invalid);\n   tcase_add_test(tc_core, test_linked_list_set_at_first);\n   tcase_add_test(tc_core, test_linked_list_set_at_middle);\n   tcase_add_test(tc_core, test_linked_list_set_at_last);\n   tcase_add_test(tc_core, test_linked_list_iterator_remove_null);\n   tcase_add_test(tc_core, test_linked_list_iterator_remove_first);\n   tcase_add_test(tc_core, test_linked_list_iterator_remove_middle);\n   tcase_add_test(tc_core, test_linked_list_iterator_remove_last);\n   tcase_add_test(tc_core, test_linked_list_iterator_free_null);\n   tcase_add_test(tc_core, test_linked_list_foreach_null_list);\n   tcase_add_test(tc_core, test_linked_list_foreach_null_fn);\n   tcase_add_test(tc_core, test_linked_list_foreach_valid);\n   suite_add_tcase(s, tc_core);\n\n   return s;\n}\n\nint main(void)\n{\n   int num_fail;\n   Suite *s = create_suite();\n   SRunner *sr = srunner_create(s);\n   srunner_run_all(sr, CK_NORMAL);\n   num_fail = srunner_ntests_failed(sr);\n   srunner_free(sr);\n   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/queues/test_generic_queue.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (test_generic_queue.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n#include <check.h>\n#include <stdarg.h>\n#include <stdlib.h>\n\n#include <queues/generic_queue.h>\n\n#define SUITE_NAME \"Generic Queue\"\n\nstatic char *_value_1 = \"value1\";\nstatic char *_value_2 = \"value2\";\nstatic char *_value_3 = \"value3\";\n\nSTART_TEST (test_generic_queue_create)\n{\n   generic_queue_t *queue = generic_queue_new();\n   ck_assert_ptr_nonnull(queue);\n   generic_queue_free(queue, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_free)\n{\n   generic_queue_t *queue = generic_queue_new();\n   generic_queue_free(queue, NULL);\n   generic_queue_free(NULL, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_push_pop)\n{\n   generic_queue_t *queue;\n   char *value;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   ck_assert_int_eq(generic_queue_length(queue), 1);\n   value = (char *) generic_queue_pop(queue);\n   ck_assert_ptr_eq(value, _value_1);\n   ck_assert_int_eq(generic_queue_length(queue), 0);\n\n   generic_queue_push(queue, _value_2);\n   ck_assert_int_eq(generic_queue_length(queue), 1);\n   generic_queue_push(queue, _value_3);\n   ck_assert_int_eq(generic_queue_length(queue), 2);\n   value = (char *) generic_queue_pop(queue);\n   ck_assert_ptr_eq(value, _value_3);\n   ck_assert_int_eq(generic_queue_length(queue), 1);\n   value = (char *) generic_queue_pop(queue);\n   ck_assert_ptr_eq(value, _value_2);\n   ck_assert_int_eq(generic_queue_length(queue), 0);\n\n   generic_queue_free(queue, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_peek)\n{\n   generic_queue_t *queue;\n\n   queue = generic_queue_new();\n   ck_assert_ptr_null(generic_queue_peek(queue));\n   ck_assert_ptr_null(generic_queue_peek_first(queue));\n\n   generic_queue_push(queue, _value_1);\n   ck_assert_ptr_eq(_value_1, generic_queue_peek(queue));\n   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));\n\n   generic_queue_push(queue, _value_2);\n   ck_assert_ptr_eq(_value_2, generic_queue_peek(queue));\n   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));\n\n   generic_queue_push(queue, _value_3);\n   ck_assert_ptr_eq(_value_3, generic_queue_peek(queue));\n   ck_assert_ptr_eq(_value_1, generic_queue_peek_first(queue));\n\n   generic_queue_free(queue, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_shift_unshift)\n{\n   generic_queue_t *queue;\n   char *value;\n\n   queue = generic_queue_new();\n   generic_queue_shift(queue, _value_1);\n   ck_assert_int_eq(generic_queue_length(queue), 1);\n   value = (char *) generic_queue_unshift(queue);\n   ck_assert_ptr_eq(value, _value_1);\n   ck_assert_int_eq(generic_queue_length(queue), 0);\n\n   generic_queue_shift(queue, _value_2);\n   ck_assert_int_eq(generic_queue_length(queue), 1);\n   generic_queue_shift(queue, _value_3);\n   ck_assert_int_eq(generic_queue_length(queue), 2);\n   value = (char *) generic_queue_unshift(queue);\n   ck_assert_ptr_eq(value, _value_3);\n   ck_assert_int_eq(generic_queue_length(queue), 1);\n   value = (char *) generic_queue_unshift(queue);\n   ck_assert_ptr_eq(value, _value_2);\n   ck_assert_int_eq(generic_queue_length(queue), 0);\n\n   generic_queue_free(queue, NULL);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_empty)\n{\n   generic_queue_t *queue;\n\n   queue = generic_queue_new();\n   ck_assert_ptr_null(generic_queue_pop(queue));\n   ck_assert_ptr_null(generic_queue_unshift(queue));\n   generic_queue_free(queue, NULL);\n}\nEND_TEST\n\nvoid _free_value(void *value)\n{\n   return;\n}\n\nSTART_TEST (test_generic_queue_iterator)\n{\n   generic_queue_t *queue;\n   generic_queue_iterator_t *iterator;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   iterator = generic_queue_iterator(queue, true);\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);\n   iterator = generic_queue_iterator_next(iterator);\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);\n   iterator = generic_queue_iterator_next(iterator);\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);\n   iterator = generic_queue_iterator_next(iterator);\n   ck_assert_ptr_null(iterator);\n\n   iterator = generic_queue_iterator(queue, false);\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_3);\n   iterator = generic_queue_iterator_next(iterator);\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_2);\n   iterator = generic_queue_iterator_next(iterator);\n   ck_assert_ptr_nonnull(iterator);\n   ck_assert_ptr_eq(generic_queue_iterator_value(iterator), _value_1);\n   iterator = generic_queue_iterator_next(iterator);\n   ck_assert_ptr_null(iterator);\n\n   generic_queue_free(queue, &_free_value);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_shift_free)\n{\n   generic_queue_t *queue;\n\n   queue = generic_queue_new();\n\n   generic_queue_shift(queue, _value_1);\n   generic_queue_shift(queue, _value_2);\n   generic_queue_shift(queue, _value_3);\n\n   generic_queue_free(queue, &_free_value);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_remove_one)\n{\n   generic_queue_t *queue;\n   generic_queue_iterator_t *iterator;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n\n   iterator = generic_queue_iterator(queue, true);\n   iterator = generic_queue_iterator_remove(iterator);\n   ck_assert_ptr_null(iterator);\n   ck_assert_int_eq(generic_queue_length(queue), 0);\n\n   generic_queue_free(queue, NULL);\n}\nEND_TEST\n\nstatic void _verify_queue_values(generic_queue_t *queue, int count, ...)\n{\n   va_list values_list;\n   void **values;\n   int i;\n   generic_queue_iterator_t *iterator;\n\n   values = (void **)malloc(count * sizeof(void *));\n\n   ck_assert_int_eq(count, generic_queue_length(queue));\n\n   va_start(values_list, count);\n   for (i = 0; i < count; i++)\n      values[i] = va_arg(values_list, void *);\n   va_end(values_list);\n\n   iterator = generic_queue_iterator(queue, true);\n   for (i = 0; i < count; i++)\n   {\n      ck_assert_ptr_nonnull(iterator);\n      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));\n      iterator = generic_queue_iterator_next(iterator);\n   }\n   ck_assert_ptr_null(iterator);\n\n   iterator = generic_queue_iterator(queue, false);\n   for (i = count - 1; i >= 0; i--)\n   {\n      ck_assert_ptr_nonnull(iterator);\n      ck_assert_ptr_eq(values[i], generic_queue_iterator_value(iterator));\n      iterator = generic_queue_iterator_next(iterator);\n   }\n   ck_assert_ptr_null(iterator);\n\n   free(values);\n}\n\nSTART_TEST (test_generic_queue_iterator_remove_first)\n{\n   generic_queue_t *queue;\n   generic_queue_iterator_t *iterator;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   iterator = generic_queue_iterator(queue, true);\n   iterator = generic_queue_iterator_remove(iterator);\n   generic_queue_iterator_free(iterator);\n\n   _verify_queue_values(queue, 2, _value_2, _value_3);\n\n   generic_queue_free(queue, &_free_value);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_iterator_remove_middle)\n{\n   generic_queue_t *queue;\n   generic_queue_iterator_t *iterator;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   iterator = generic_queue_iterator(queue, true);\n   iterator = generic_queue_iterator_next(iterator);\n   iterator = generic_queue_iterator_remove(iterator);\n   generic_queue_iterator_free(iterator);\n\n   _verify_queue_values(queue, 2, _value_1, _value_3);\n\n   generic_queue_free(queue, &_free_value);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_iterator_remove_last)\n{\n   generic_queue_t *queue;\n   generic_queue_iterator_t *iterator;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   iterator = generic_queue_iterator(queue, false);\n   iterator = generic_queue_iterator_remove(iterator);\n   generic_queue_iterator_free(iterator);\n\n   _verify_queue_values(queue, 2, _value_1, _value_2);\n\n   generic_queue_free(queue, &_free_value);\n}\nEND_TEST\n\nSTART_TEST (test_generic_queue_remove_first)\n{\n   generic_queue_t *queue;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   ck_assert_ptr_eq(generic_queue_remove(queue, _value_1), _value_1);\n\n   _verify_queue_values(queue, 2, _value_2, _value_3);\n\n   generic_queue_free(queue, &_free_value);\n}\n\nSTART_TEST (test_generic_queue_remove_middle)\n{\n   generic_queue_t *queue;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   ck_assert_ptr_eq(generic_queue_remove(queue, _value_2), _value_2);\n\n   _verify_queue_values(queue, 2, _value_1, _value_3);\n\n   generic_queue_free(queue, &_free_value);\n}\n\nSTART_TEST (test_generic_queue_remove_last)\n{\n   generic_queue_t *queue;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   generic_queue_push(queue, _value_2);\n   generic_queue_push(queue, _value_3);\n\n   ck_assert_ptr_eq(generic_queue_remove(queue, _value_3), _value_3);\n\n   _verify_queue_values(queue, 2, _value_1, _value_2);\n\n   generic_queue_free(queue, &_free_value);\n}\n\nSTART_TEST (test_generic_queue_iterator_free)\n{\n   generic_queue_t *queue;\n   generic_queue_iterator_t *iterator;\n\n   queue = generic_queue_new();\n   generic_queue_push(queue, _value_1);\n   iterator = generic_queue_iterator(queue, true);\n\n   generic_queue_iterator_free(iterator);\n   generic_queue_iterator_free(NULL);\n\n   generic_queue_free(queue, _free_value);\n}\nEND_TEST\n\nSuite *create_suite(void)\n{\n   Suite *s = suite_create(SUITE_NAME);\n\n   TCase *tc_core = tcase_create(\"Core\");\n   tcase_add_test(tc_core, test_generic_queue_create);\n   tcase_add_test(tc_core, test_generic_queue_free);\n   tcase_add_test(tc_core, test_generic_queue_push_pop);\n   tcase_add_test(tc_core, test_generic_queue_peek);\n   tcase_add_test(tc_core, test_generic_queue_shift_unshift);\n   tcase_add_test(tc_core, test_generic_queue_empty);\n   tcase_add_test(tc_core, test_generic_queue_iterator);\n   tcase_add_test(tc_core, test_generic_queue_shift_free);\n   tcase_add_test(tc_core, test_generic_queue_remove_one);\n   tcase_add_test(tc_core, test_generic_queue_iterator_remove_first);\n   tcase_add_test(tc_core, test_generic_queue_iterator_remove_middle);\n   tcase_add_test(tc_core, test_generic_queue_iterator_remove_last);\n   tcase_add_test(tc_core, test_generic_queue_remove_first);\n   tcase_add_test(tc_core, test_generic_queue_remove_middle);\n   tcase_add_test(tc_core, test_generic_queue_remove_last);\n   tcase_add_test(tc_core, test_generic_queue_iterator_free);\n   suite_add_tcase(s, tc_core);\n\n   return s;\n}\n\nint main(void)\n{\n\tint num_fail;\n\tSuite *s = create_suite();\n\tSRunner *sr = srunner_create(s);\n\tsrunner_run_all(sr, CK_NORMAL);\n\tnum_fail = srunner_ntests_failed(sr);\n\tsrunner_free(sr);\n\treturn (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/string/test_stdstring.c",
    "content": "/* Copyright  (C) 2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (test_stdstring.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <check.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <string/stdstring.h>\n#include <encodings/utf.h>\n\n#define SUITE_NAME \"stdstring\"\n\nSTART_TEST (test_string_filter)\n{\n   char test1[] = \"foo bar some string\";\n   char test2[] = \"\";\n   string_remove_all_chars(test1, 's');\n   string_remove_all_chars(test2, '0');\n   string_remove_all_chars(NULL, 'a');\n   ck_assert(!strcmp(test1, \"foo bar ome tring\"));\n   ck_assert(!strcmp(test2, \"\"));\n}\nEND_TEST\n\nSTART_TEST (test_string_replace)\n{\n   char test1[] = \"foo bar some string\";\n   string_replace_all_chars(test1, 's', 'S');\n   string_replace_all_chars(NULL, 'a', 'A');\n   ck_assert(!strcmp(test1, \"foo bar Some String\"));\n}\nEND_TEST\n\nSTART_TEST (test_string_case)\n{\n   char test1[] = \"foo\";\n   char test2[] = \"01foOo[]_\";\n   ck_assert(!strcmp(string_to_upper(test1), \"FOO\"));\n   ck_assert(!strcmp(string_to_upper(test2), \"01FOOO[]_\"));\n   ck_assert(!strcmp(string_to_lower(test2), \"01fooo[]_\"));\n}\nEND_TEST\n\nSTART_TEST (test_string_char_classify)\n{\n   ck_assert(ISSPACE(' '));\n   ck_assert(ISSPACE('\\n'));\n   ck_assert(ISSPACE('\\r'));\n   ck_assert(ISSPACE('\\t'));\n   ck_assert(!ISSPACE('a'));\n\n   ck_assert(ISALPHA('a'));\n   ck_assert(ISALPHA('Z'));\n   ck_assert(!ISALPHA('5'));\n\n   ck_assert(ISALNUM('a'));\n   ck_assert(ISALNUM('Z'));\n   ck_assert(ISALNUM('5'));\n}\nEND_TEST\n\nSTART_TEST (test_string_num_conv)\n{\n   ck_assert_uint_eq(3, string_to_unsigned(\"3\"));\n   ck_assert_uint_eq(2147483647, string_to_unsigned(\"2147483647\"));\n   ck_assert_uint_eq(0, string_to_unsigned(\"foo\"));\n   ck_assert_uint_eq(0, string_to_unsigned(\"-1\"));\n   ck_assert_uint_eq(0, string_to_unsigned(NULL));\n\n   ck_assert_uint_eq(10, string_hex_to_unsigned(\"0xa\"));\n   ck_assert_uint_eq(10, string_hex_to_unsigned(\"a\"));\n   ck_assert_uint_eq(255, string_hex_to_unsigned(\"FF\"));\n   ck_assert_uint_eq(255, string_hex_to_unsigned(\"0xff\"));\n   ck_assert_uint_eq(0, string_hex_to_unsigned(\"0xfzzf\"));\n   ck_assert_uint_eq(0, string_hex_to_unsigned(\"0x\"));\n   ck_assert_uint_eq(0, string_hex_to_unsigned(\"0xx\"));\n   ck_assert_uint_eq(0, string_hex_to_unsigned(NULL));\n}\nEND_TEST\n\nSTART_TEST (test_string_tokenizer)\n{\n   char *testinput = \"@@1@@2@@3@@@@9@@@\";\n   char **ptr = &testinput;\n   char *token = NULL;\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"1\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"2\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"3\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"9\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token != NULL);\n   ck_assert(!strcmp(token, \"@\"));\n   free(token);\n   token = string_tokenize(ptr, \"@@\");\n   ck_assert(token == NULL);\n}\nEND_TEST\n\nSTART_TEST (test_string_replacesubstr)\n{\n   char *res = string_replace_substring(\"foobaarhellowooorldtest\", \"oo\", \"ooo\");\n   ck_assert(res != NULL);\n   ck_assert(!strcmp(res, \"fooobaarhellowoooorldtest\"));\n   free(res);\n}\nEND_TEST\n\nSTART_TEST (test_string_trim)\n{\n   char test1[] = \"\\t \\t\\nhey there \\n \\n\";\n   char test2[] = \"\\t \\t\\nhey there \\n \\n\";\n   char test3[] = \"\\t \\t\\nhey there \\n \\n\";\n   ck_assert(string_trim_whitespace_left(test1) ==  (char*)test1);\n   ck_assert(!strcmp(test1, \"hey there \\n \\n\"));\n   ck_assert(string_trim_whitespace_right(test2) ==  (char*)test2);\n   ck_assert(!strcmp(test2, \"\\t \\t\\nhey there\"));\n   ck_assert(string_trim_whitespace(test3) ==  (char*)test3);\n   ck_assert(!strcmp(test3, \"hey there\"));\n}\nEND_TEST\n\nSTART_TEST (test_string_comparison)\n{\n   ck_assert(memcmp(\"foo\", \"bar\", 3)   != 0);\n   ck_assert(memcmp(\"foo2\", \"foo2\", 4) == 0);\n   ck_assert(memcmp(\"foo1\", \"foo2\", 4) != 0);\n   ck_assert(memcmp(\"foo1\", \"foo2\", 3) == 0);\n}\nEND_TEST\n\nSTART_TEST (test_word_wrap)\n{\n   const char *testtxt = (\n      \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nec \"\n      \"enim quis orci euismod efficitur at nec arcu. Vivamus imperdiet est \"\n      \"feugiat massa rhoncus porttitor at vitae ante. Nunc a orci vel ipsum \"\n      \"tempor posuere sed a lacus. Ut erat odio, ultrices vitae iaculis \"\n      \"fringilla, iaculis ut eros.\\nSed facilisis viverra lectus et \"\n      \"ullamcorper. Aenean risus ex, ornare eget scelerisque ac, imperdiet eu \"\n      \"ipsum. Morbi pellentesque erat metus, sit amet aliquet libero rutrum \"\n      \"et. Integer non ullamcorper tellus.\");\n   const char *expected = (\n      \"Lorem ipsum dolor sit amet, consectetur\\n\"\n      \"adipiscing elit. Nam nec enim quis orci\\n\"\n      \"euismod efficitur at nec arcu. Vivamus\\n\"\n      \"imperdiet est feugiat massa rhoncus\\n\"\n      \"porttitor at vitae ante. Nunc a orci\\n\"\n      \"vel ipsum tempor posuere sed a lacus.\\n\"\n      \"Ut erat odio, ultrices vitae iaculis\\n\"\n      \"fringilla, iaculis ut eros.\\n\"\n      \"Sed facilisis viverra lectus et\\n\"\n      \"ullamcorper. \"\n      \"Aenean risus ex, ornare eget scelerisque ac, imperdiet eu ipsum. Morbi \"\n      \"pellentesque erat metus, sit amet aliquet libero rutrum et. Integer \"\n      \"non ullamcorper tellus.\");\n\n   char output[1024];\n\n   word_wrap(output, sizeof(output), testtxt, strlen(testtxt), 40, 100, 10);\n   ck_assert(!strcmp(output, expected));\n}\nEND_TEST\n\nSTART_TEST (test_strlcpy)\n{\n   char buf1[8];\n   ck_assert_uint_eq(3, strlcpy(buf1, \"foo\", sizeof(buf1)));\n   ck_assert(!memcmp(buf1, \"foo\", 4));\n   ck_assert_uint_eq(11, strlcpy(buf1, \"foo12345678\", sizeof(buf1)));\n   ck_assert(!memcmp(buf1, \"foo1234\", 8));\n}\nEND_TEST\n\nSTART_TEST (test_strlcat)\n{\n   char buf1[8];\n   buf1[0] = 'f';\n   buf1[1] = '\\0';\n   ck_assert_uint_eq(10, strlcat(buf1, \"ooooooooo\", sizeof(buf1)));\n   ck_assert(!memcmp(buf1, \"foooooo\\0\", 8));\n   ck_assert_uint_eq(13, strlcat(buf1, \"123456\", sizeof(buf1)));\n   ck_assert(!memcmp(buf1, \"foooooo\\0\", 8));\n}\nEND_TEST\n\nSTART_TEST (test_strldup)\n{\n   char buf1[8] = \"foo\";\n   char *tv1 = strldup(buf1, 16);\n   char *tv2 = strldup(buf1, 2);\n   ck_assert(tv1 != (char*)buf1);\n   ck_assert(tv2 != (char*)buf1);\n   ck_assert_uint_eq(strlen(tv2), 1);\n   ck_assert(tv2[0] == 'f' && tv2[1] == 0);\n   free(tv1);\n   free(tv2);\n}\nEND_TEST\n\nSTART_TEST (test_utf8_conv_utf32)\n{\n   uint32_t output[12];\n   const char test1[] = \"aæ⠻จйγチℝ\\xff\";\n   ck_assert_uint_eq(8, utf8_conv_utf32(output, 12, test1, strlen(test1)));\n   ck_assert_uint_eq(97, output[0]);\n   ck_assert_uint_eq(230, output[1]);\n   ck_assert_uint_eq(10299, output[2]);\n   ck_assert_uint_eq(3592, output[3]);\n   ck_assert_uint_eq(1081, output[4]);\n   ck_assert_uint_eq(947, output[5]);\n   ck_assert_uint_eq(12481, output[6]);\n   ck_assert_uint_eq(8477, output[7]);\n}\nEND_TEST\n\nSTART_TEST (test_utf8_util)\n{\n   const char *test1 = \"aæ⠻จ𠀤\";\n   const char **tptr = &test1;\n   char out[64];\n   ck_assert_uint_eq(utf8len(test1), 5);\n   ck_assert_uint_eq(utf8len(NULL), 0);\n   ck_assert(&test1[1 + 2 + 3] == utf8skip(test1, 3));\n\n   ck_assert_uint_eq(97, utf8_walk(tptr));\n   ck_assert_uint_eq(230, utf8_walk(tptr));\n   ck_assert_uint_eq(10299, utf8_walk(tptr));\n   ck_assert_uint_eq(3592, utf8_walk(tptr));\n   ck_assert_uint_eq(131108, utf8_walk(tptr));\n}\nEND_TEST\n\nSTART_TEST (test_utf16_conv)\n{\n   const uint16_t test1[] = {0x0061, 0x00e6, 0x283b, 0x0e08, 0xd840, 0xdc24};\n   char out[64];\n   size_t outlen = sizeof(out);\n   ck_assert(utf16_conv_utf8((uint8_t*)out, &outlen, test1, sizeof(test1) / 2));\n   ck_assert_uint_eq(outlen, 13);\n   ck_assert(!memcmp(out, \"aæ⠻จ𠀤\", 13));\n}\nEND_TEST\n\nSuite *create_suite(void)\n{\n   Suite *s = suite_create(SUITE_NAME);\n\n   TCase *tc_core = tcase_create(\"Core\");\n   tcase_add_test(tc_core, test_string_comparison);\n   tcase_add_test(tc_core, test_string_num_conv);\n   tcase_add_test(tc_core, test_string_char_classify);\n   tcase_add_test(tc_core, test_string_case);\n   tcase_add_test(tc_core, test_string_filter);\n   tcase_add_test(tc_core, test_string_replace);\n   tcase_add_test(tc_core, test_string_tokenizer);\n   tcase_add_test(tc_core, test_string_trim);\n   tcase_add_test(tc_core, test_string_replacesubstr);\n   tcase_add_test(tc_core, test_word_wrap);\n   tcase_add_test(tc_core, test_strlcpy);\n   tcase_add_test(tc_core, test_strlcat);\n   tcase_add_test(tc_core, test_strldup);\n   tcase_add_test(tc_core, test_utf8_conv_utf32);\n   tcase_add_test(tc_core, test_utf16_conv);\n   tcase_add_test(tc_core, test_utf8_util);\n   suite_add_tcase(s, tc_core);\n\n   return s;\n}\n\nint main(void)\n{\n   int num_fail;\n   Suite *s = create_suite();\n   SRunner *sr = srunner_create(s);\n   srunner_run_all(sr, CK_NORMAL);\n   num_fail = srunner_ntests_failed(sr);\n   srunner_free(sr);\n   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "test/utils/test_utils.c",
    "content": "/* Copyright  (C) 2021 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (test_utils.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <check.h>\n#include <stdarg.h>\n#include <stdlib.h>\n#include <stdio.h>\n\n#include <utils/md5.h>\n#include <encodings/crc32.h>\n#include <streams/file_stream.h>\n\n#define SUITE_NAME \"hash\"\n\nSTART_TEST (test_md5)\n{\n   uint8_t output[16];\n   MD5_CTX ctx;\n   MD5_Init(&ctx);\n   MD5_Final(output, &ctx);\n   ck_assert(!memcmp(\n      \"\\xd4\\x1d\\x8c\\xd9\\x8f\\x00\\xb2\\x04\\xe9\\x80\\x09\\x98\\xec\\xf8\\x42\\x7e\",\n      output, 16));\n   MD5_Init(&ctx);\n   MD5_Update(&ctx, \"The quick brown fox jumps over the lazy dog\", 43);\n   MD5_Final(output, &ctx);\n   ck_assert(!memcmp(\n      \"\\x9e\\x10\\x7d\\x9d\\x37\\x2b\\xb6\\x82\\x6b\\xd8\\x1d\\x35\\x42\\xa4\\x19\\xd6\",\n      output, 16));\n   MD5_Init(&ctx);\n   MD5_Update(&ctx, \"The quick brown fox jumps over the lazy dog\", 43);\n   MD5_Update(&ctx, \"The quick brown fox jumps over the lazy dog\", 43);\n   MD5_Update(&ctx, \"The quick brown fox jumps over the lazy dog\", 43);\n   MD5_Final(output, &ctx);\n   ck_assert(!memcmp(\n      \"\\x4e\\x67\\xdb\\x4a\\x7a\\x40\\x6b\\x0c\\xfd\\xad\\xd8\\x87\\xcd\\xe7\\x88\\x8e\",\n      output, 16));\n}\nEND_TEST\n\nSTART_TEST (test_crc32)\n{\n   char buf1[] = \"retroarch\";\n   char buf2[] = \"12345678\";\n   char buf3[] = \"The quick brown fox jumps over the lazy dog\";\n   uint32_t test1 = encoding_crc32(0, (uint8_t*)buf1, strlen(buf1));\n   uint32_t test2 = encoding_crc32(0, (uint8_t*)buf2, strlen(buf2));\n   uint32_t test3 = encoding_crc32(0, (uint8_t*)buf3, strlen(buf3));\n   ck_assert_uint_eq(0x3cae141a, test1);\n   ck_assert_uint_eq(0x9ae0daaf, test2);\n   ck_assert_uint_eq(0x414fa339, test3);\n}\nEND_TEST\n\n#define CRC32_BUFFER_SIZE 1048576\n#define CRC32_MAX_MB 64\n\n/**\n * Calculate a CRC32 from the first part of the given file.\n * \"first part\" being the first (CRC32_BUFFER_SIZE * CRC32_MAX_MB)\n * bytes.\n *\n * Returns: the crc32, or 0 if there was an error.\n */\nstatic uint32_t file_crc32(uint32_t crc, const char *path)\n{\n   unsigned i;\n   RFILE *file        = NULL;\n   unsigned char *buf = NULL;\n   if (!path)\n      return 0;\n\n   if (!(file = filestream_open(path, RETRO_VFS_FILE_ACCESS_READ, 0)))\n      return 0;\n\n   if (!(buf = (unsigned char*)malloc(CRC32_BUFFER_SIZE)))\n   {\n      filestream_close(file);\n      return 0;\n   }\n\n   for (i = 0; i < CRC32_MAX_MB; i++)\n   {\n      int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);\n      if (nread < 0)\t\t\n      {\n         free(buf);\n         filestream_close(file);\n         return 0;\n      }\n\n      crc = encoding_crc32(crc, buf, (size_t)nread);\n      if (filestream_eof(file))\n         break;\n   }\n   free(buf);\n   filestream_close(file);\n   return crc;\n}\n\nSTART_TEST (test_crc32_file)\n{\n   char tmpfile[512];\n   FILE *fd;\n   tmpnam(tmpfile);\n   fd = fopen(tmpfile, \"wb\");\n   ck_assert(fd != NULL);\n   fwrite(\"12345678\", 1, 8, fd);\n   fclose(fd);\n\n   ck_assert_uint_eq(file_crc32(0, tmpfile), 0x9ae0daaf);\n   /* Error checking */\n   ck_assert_uint_eq(file_crc32(0, \"/this/path/should/not/exist\"), 0);\n   ck_assert_uint_eq(file_crc32(0, NULL), 0);\n}\nEND_TEST\n\nSuite *create_suite(void)\n{\n   Suite *s = suite_create(SUITE_NAME);\n\n   TCase *tc_core = tcase_create(\"Core\");\n   tcase_add_test(tc_core, test_md5);\n   tcase_add_test(tc_core, test_crc32);\n   tcase_add_test(tc_core, test_crc32_file);\n   suite_add_tcase(s, tc_core);\n\n   return s;\n}\n\nint main(void)\n{\n   int num_fail;\n   Suite *s = create_suite();\n   SRunner *sr = srunner_create(s);\n   srunner_run_all(sr, CK_NORMAL);\n   num_fail = srunner_ntests_failed(sr);\n   srunner_free(sr);\n   return (num_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE;\n}\n"
  },
  {
    "path": "time/rtime.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n *\n * ---------------------------------------------------------------------------------------\n * The following license statement only applies to this file (rtime.c).\n * ---------------------------------------------------------------------------------------\n *\n * Permission is hereby granted, free of charge,\n * to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation the rights to\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifdef HAVE_THREADS\n#include <rthreads/rthreads.h>\n#include <stdlib.h>\n#endif\n\n#include <string.h>\n#include <time/rtime.h>\n\n#ifdef HAVE_THREADS\n/* TODO/FIXME - global */\nslock_t *rtime_localtime_lock = NULL;\n#endif\n\n/* Must be called before using rtime_localtime() */\nvoid rtime_init(void)\n{\n   rtime_deinit();\n#ifdef HAVE_THREADS\n   if (!rtime_localtime_lock)\n      rtime_localtime_lock = slock_new();\n#endif\n}\n\n/* Must be called upon program termination */\nvoid rtime_deinit(void)\n{\n#ifdef HAVE_THREADS\n   if (rtime_localtime_lock)\n   {\n      slock_free(rtime_localtime_lock);\n      rtime_localtime_lock = NULL;\n   }\n#endif\n}\n\n/* Thread-safe wrapper for localtime() */\nstruct tm *rtime_localtime(const time_t *timep, struct tm *result)\n{\n   struct tm *time_info = NULL;\n\n   /* Lock mutex */\n#ifdef HAVE_THREADS\n   slock_lock(rtime_localtime_lock);\n#endif\n\n   time_info = localtime(timep);\n   if (time_info)\n      memcpy(result, time_info, sizeof(struct tm));\n\n   /* Unlock mutex */\n#ifdef HAVE_THREADS\n   slock_unlock(rtime_localtime_lock);\n#endif\n\n   return result;\n}\n"
  },
  {
    "path": "utils/md5.c",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * (This is a heavily cut-down \"BSD license\".)\n *\n * This differs from Colin Plumb's older public domain implementation in that\n * no exactly 32-bit integer data type is required (any 32-bit or wider\n * unsigned integer data type will do), there's no compile-time endianness\n * configuration, and the function prototypes match OpenSSL's.  No code from\n * Colin Plumb's implementation has been reused; this comment merely compares\n * the properties of the two independent implementations.\n *\n * The primary goals of this implementation are portability and ease of use.\n * It is meant to be fast, but not as fast as possible.  Some known\n * optimizations are not included to reduce source code size and avoid\n * compile-time configuration.\n */\n\n/* On Apple platforms MD5 is provided by CommonCrypto, and lrc_hash.h\n * aliases MD5_CTX / MD5_Init / MD5_Update / MD5_Final to the CC_*\n * equivalents. The Solar Designer implementation below pokes at\n * struct members (a, b, c, d, block) that do not exist on\n * CC_MD5state_st, so it must be skipped entirely on Apple. */\n#ifndef __APPLE__\n\n#include <lrc_hash.h>\n\n#include <stdint.h>\n#include <string.h>\n\n/*\n * The basic MD5 functions.\n *\n * F and G are optimized compared to their RFC 1321 definitions for\n * architectures that lack an AND-NOT instruction, just like in Colin Plumb's\n * implementation.\n */\n#define MD5_F(x, y, z)\t\t\t((z) ^ ((x) & ((y) ^ (z))))\n#define MD5_G(x, y, z)\t\t\t((y) ^ ((z) & ((x) ^ (y))))\n#define MD5_H(x, y, z)\t\t\t(((x) ^ (y)) ^ (z))\n#define MD5_H2(x, y, z)\t\t\t((x) ^ ((y) ^ (z)))\n#define MD5_I(x, y, z)\t\t\t((y) ^ ((x) | ~(z)))\n\n/*\n * The MD5 transformation for all four rounds.\n */\n#define MD5_STEP(f, a, b, c, d, x, t, s) \\\n\t(a) += f((b), (c), (d)) + (x) + (t); \\\n\t(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \\\n\t(a) += (b);\n\n/*\n * MD5_SET reads 4 input bytes in little-endian byte order and stores them\n * in a properly aligned word in host byte order.\n *\n * The check for little-endian architectures that tolerate unaligned\n * memory accesses is just an optimization.  Nothing will break if it\n * doesn't work.\n */\n#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)\n#define MD5_SET(n) \\\n\t(*(uint32_t*)&ptr[(n) * 4])\n#define MD5_GET(n) \\\n\tMD5_SET(n)\n#else\n#define MD5_SET(n) \\\n\t(ctx->block[(n)] = \\\n\t(uint32_t)ptr[(n) * 4] | \\\n\t((uint32_t)ptr[(n) * 4 + 1] << 8) | \\\n\t((uint32_t)ptr[(n) * 4 + 2] << 16) | \\\n\t((uint32_t)ptr[(n) * 4 + 3] << 24))\n#define MD5_GET(n) \\\n\t(ctx->block[(n)])\n#endif\n\n/*\n * This processes one or more 64-byte data blocks, but does NOT update\n * the bit counters.  There are no alignment requirements.\n */\nstatic const void *MD5_body(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tuint32_t saved_a, saved_b, saved_c, saved_d;\n\tconst unsigned char *ptr = (const unsigned char *)data;\n\tuint32_t a = ctx->a;\n\tuint32_t b = ctx->b;\n\tuint32_t c = ctx->c;\n\tuint32_t d = ctx->d;\n\n\tdo {\n\t\tsaved_a = a;\n\t\tsaved_b = b;\n\t\tsaved_c = c;\n\t\tsaved_d = d;\n\n      /* Round 1 */\n\t\tMD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7)\n\t\tMD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12)\n\t\tMD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17)\n\t\tMD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22)\n\t\tMD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7)\n\t\tMD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12)\n\t\tMD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17)\n\t\tMD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22)\n\t\tMD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7)\n\t\tMD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12)\n\t\tMD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17)\n\t\tMD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22)\n\t\tMD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7)\n\t\tMD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12)\n\t\tMD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17)\n\t\tMD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22)\n\n      /* Round 2 */\n\t\tMD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5)\n\t\tMD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9)\n\t\tMD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14)\n\t\tMD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20)\n\t\tMD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5)\n\t\tMD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9)\n\t\tMD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14)\n\t\tMD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20)\n\t\tMD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5)\n\t\tMD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9)\n\t\tMD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14)\n\t\tMD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20)\n\t\tMD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5)\n\t\tMD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9)\n\t\tMD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14)\n\t\tMD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20)\n\n      /* Round 3 */\n\t\tMD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4)\n\t\tMD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11)\n\t\tMD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16)\n\t\tMD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23)\n\t\tMD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4)\n\t\tMD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11)\n\t\tMD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16)\n\t\tMD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23)\n\t\tMD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4)\n\t\tMD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11)\n\t\tMD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16)\n\t\tMD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23)\n\t\tMD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4)\n\t\tMD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11)\n\t\tMD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16)\n\t\tMD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23)\n\n      /* Round 4 */\n\t\tMD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6)\n\t\tMD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10)\n\t\tMD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15)\n\t\tMD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21)\n\t\tMD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6)\n\t\tMD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10)\n\t\tMD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15)\n\t\tMD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21)\n\t\tMD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6)\n\t\tMD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10)\n\t\tMD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15)\n\t\tMD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21)\n\t\tMD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6)\n\t\tMD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10)\n\t\tMD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15)\n\t\tMD5_STEP(MD5_I, b, c, d, a, MD5_GET(9), 0xeb86d391, 21)\n\n\t\ta += saved_a;\n\t\tb += saved_b;\n\t\tc += saved_c;\n\t\td += saved_d;\n\n\t\tptr += 64;\n\t} while (size -= 64);\n\n\tctx->a = a;\n\tctx->b = b;\n\tctx->c = c;\n\tctx->d = d;\n\n\treturn ptr;\n}\n\nvoid MD5_Init(MD5_CTX *ctx)\n{\n\tctx->a = 0x67452301;\n\tctx->b = 0xefcdab89;\n\tctx->c = 0x98badcfe;\n\tctx->d = 0x10325476;\n\n\tctx->lo = 0;\n\tctx->hi = 0;\n}\n\nvoid MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tuint32_t used;\n\tuint32_t saved_lo = ctx->lo;\n\tif ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)\n\t\tctx->hi++;\n\tctx->hi += size >> 29;\n\n\tused = saved_lo & 0x3f;\n\n\tif (used)\n   {\n      unsigned long available = 64 - used;\n\n      if (size < available)\n      {\n         memcpy(&ctx->buffer[used], data, size);\n         return;\n      }\n\n      memcpy(&ctx->buffer[used], data, available);\n      data = (const unsigned char *)data + available;\n      size -= available;\n      MD5_body(ctx, ctx->buffer, 64);\n   }\n\n\tif (size >= 64)\n   {\n      data = MD5_body(ctx, data, size & ~(unsigned long)0x3f);\n      size &= 0x3f;\n   }\n\n\tmemcpy(ctx->buffer, data, size);\n}\n\nvoid MD5_Final(unsigned char *result, MD5_CTX *ctx)\n{\n\tunsigned long available;\n\tunsigned long used = ctx->lo & 0x3f;\n\n\tctx->buffer[used++] = 0x80;\n\n\tavailable = 64 - used;\n\n\tif (available < 8)\n   {\n      memset(&ctx->buffer[used], 0, available);\n      MD5_body(ctx, ctx->buffer, 64);\n      used = 0;\n      available = 64;\n   }\n\n\tmemset(&ctx->buffer[used], 0, available - 8);\n\n\tctx->lo <<= 3;\n\tctx->buffer[56] = ctx->lo;\n\tctx->buffer[57] = ctx->lo >> 8;\n\tctx->buffer[58] = ctx->lo >> 16;\n\tctx->buffer[59] = ctx->lo >> 24;\n\tctx->buffer[60] = ctx->hi;\n\tctx->buffer[61] = ctx->hi >> 8;\n\tctx->buffer[62] = ctx->hi >> 16;\n\tctx->buffer[63] = ctx->hi >> 24;\n\n\tMD5_body(ctx, ctx->buffer, 64);\n\n\tresult[0] = ctx->a;\n\tresult[1] = ctx->a >> 8;\n\tresult[2] = ctx->a >> 16;\n\tresult[3] = ctx->a >> 24;\n\tresult[4] = ctx->b;\n\tresult[5] = ctx->b >> 8;\n\tresult[6] = ctx->b >> 16;\n\tresult[7] = ctx->b >> 24;\n\tresult[8] = ctx->c;\n\tresult[9] = ctx->c >> 8;\n\tresult[10] = ctx->c >> 16;\n\tresult[11] = ctx->c >> 24;\n\tresult[12] = ctx->d;\n\tresult[13] = ctx->d >> 8;\n\tresult[14] = ctx->d >> 16;\n\tresult[15] = ctx->d >> 24;\n\n\tmemset(ctx, 0, sizeof(*ctx));\n}\n\n#endif /* !__APPLE__ */\n"
  },
  {
    "path": "utils/sha1.c",
    "content": "/*\n *  sha1.h\n *\n *  Copyright (C) 1998, 2009\n *  Paul E. Jones <paulej@packetizer.com>\n *  All Rights Reserved\n *\n *****************************************************************************\n *  $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $\n *****************************************************************************\n *\n *  Description:\n *      This class implements the Secure Hashing Standard as defined\n *      in FIPS PUB 180-1 published April 17, 1995.\n *\n *      Many of the variable names in the SHA1Context, especially the\n *      single character names, were used because those were the names\n *      used in the publication.\n *\n *      Please read the file sha1.c for more information.\n *\n */\n\n#include <stdio.h>\n#include <string.h>\n#ifdef WIN32\n#include <io.h>\n#endif\n#include <fcntl.h>\n\n#ifndef _SHA1_H_\n#define _SHA1_H_\n\n/*\n *  This structure will hold context information for the hashing\n *  operation\n */\ntypedef struct SHA1Context\n{\n   unsigned Message_Digest[5]; /* Message Digest (output)          */\n\n   unsigned Length_Low;        /* Message length in bits           */\n   unsigned Length_High;       /* Message length in bits           */\n\n   unsigned char Message_Block[64]; /* 512-bit message blocks      */\n   int Message_Block_Index;    /* Index into message block array   */\n\n   int Computed;               /* Is the digest computed?          */\n   int Corrupted;              /* Is the message digest corruped?  */\n} SHA1Context;\n\n/*\n *  Function Prototypes\n */\nvoid SHA1Reset(SHA1Context *);\nint SHA1Result(SHA1Context *);\nvoid SHA1Input( SHA1Context *,\n      const unsigned char *,\n      unsigned);\n\n#endif\n\n/*\n *  sha1.c\n *\n *  Copyright (C) 1998, 2009\n *  Paul E. Jones <paulej@packetizer.com>\n *  All Rights Reserved\n *\n *****************************************************************************\n *  $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $\n *****************************************************************************\n *\n *  Description:\n *      This file implements the Secure Hashing Standard as defined\n *      in FIPS PUB 180-1 published April 17, 1995.\n *\n *      The Secure Hashing Standard, which uses the Secure Hashing\n *      Algorithm (SHA), produces a 160-bit message digest for a\n *      given data stream.  In theory, it is highly improbable that\n *      two messages will produce the same message digest.  Therefore,\n *      this algorithm can serve as a means of providing a \"fingerprint\"\n *      for a message.\n *\n *  Portability Issues:\n *      SHA-1 is defined in terms of 32-bit \"words\".  This code was\n *      written with the expectation that the processor has at least\n *      a 32-bit machine word size.  If the machine word size is larger,\n *      the code should still function properly.  One caveat to that\n *      is that the input functions taking characters and character\n *      arrays assume that only 8 bits of information are stored in each\n *      character.\n *\n *  Caveats:\n *      SHA-1 is designed to work with messages less than 2^64 bits\n *      long. Although SHA-1 allows a message digest to be generated for\n *      messages of any number of bits less than 2^64, this\n *      implementation only works with messages with a length that is a\n *      multiple of the size of an 8-bit character.\n *\n */\n\n/*#include \"sha1.h\"*/\n\n/*\n *  Define the circular shift macro\n */\n#define SHA1CircularShift(bits,word) \\\n                ((((word) << (bits)) & 0xFFFFFFFF) | \\\n                ((word) >> (32-(bits))))\n\n/* Function prototypes */\nvoid SHA1ProcessMessageBlock(SHA1Context *);\nvoid SHA1PadMessage(SHA1Context *);\n\n/*\n *  SHA1Reset\n *\n *  Description:\n *      This function will initialize the SHA1Context in preparation\n *      for computing a new message digest.\n *\n *  Parameters:\n *      context: [in/out]\n *          The context to reset.\n *\n *  Returns:\n *      Nothing.\n *\n *  Comments:\n *\n */\nvoid SHA1Reset(SHA1Context *context)\n{\n   context->Length_Low             = 0;\n   context->Length_High            = 0;\n   context->Message_Block_Index    = 0;\n\n   context->Message_Digest[0]      = 0x67452301;\n   context->Message_Digest[1]      = 0xEFCDAB89;\n   context->Message_Digest[2]      = 0x98BADCFE;\n   context->Message_Digest[3]      = 0x10325476;\n   context->Message_Digest[4]      = 0xC3D2E1F0;\n\n   context->Computed   = 0;\n   context->Corrupted  = 0;\n}\n\n/*\n *  SHA1Result\n *\n *  Description:\n *      This function will return the 160-bit message digest into the\n *      Message_Digest array within the SHA1Context provided\n *\n *  Parameters:\n *      context: [in/out]\n *          The context to use to calculate the SHA-1 hash.\n *\n *  Returns:\n *      1 if successful, 0 if it failed.\n *\n *  Comments:\n *\n */\nint SHA1Result(SHA1Context *context)\n{\n   if (context->Corrupted)\n      return 0;\n\n   if (!context->Computed)\n   {\n      SHA1PadMessage(context);\n      context->Computed = 1;\n   }\n\n   return 1;\n}\n\n/*\n *  SHA1Input\n *\n *  Description:\n *      This function accepts an array of octets as the next portion of\n *      the message.\n *\n *  Parameters:\n *      context: [in/out]\n *          The SHA-1 context to update\n *      message_array: [in]\n *          An array of characters representing the next portion of the\n *          message.\n *      length: [in]\n *          The length of the message in message_array\n *\n *  Returns:\n *      Nothing.\n *\n *  Comments:\n *\n */\nvoid SHA1Input(     SHA1Context         *context,\n                    const unsigned char *message_array,\n                    unsigned            length)\n{\n   if (!length)\n      return;\n\n   if (context->Computed || context->Corrupted)\n   {\n      context->Corrupted = 1;\n      return;\n   }\n\n   while(length-- && !context->Corrupted)\n   {\n      context->Message_Block[context->Message_Block_Index++] =\n         (*message_array & 0xFF);\n\n      context->Length_Low += 8;\n      /* Force it to 32 bits */\n      context->Length_Low &= 0xFFFFFFFF;\n      if (context->Length_Low == 0)\n      {\n         context->Length_High++;\n         /* Force it to 32 bits */\n         context->Length_High &= 0xFFFFFFFF;\n         /* Message is too long */\n         if (context->Length_High == 0)\n            context->Corrupted = 1;\n      }\n\n      if (context->Message_Block_Index == 64)\n         SHA1ProcessMessageBlock(context);\n\n      message_array++;\n   }\n}\n\n/*\n *  SHA1ProcessMessageBlock\n *\n *  Description:\n *      This function will process the next 512 bits of the message\n *      stored in the Message_Block array.\n *\n *  Parameters:\n *      None.\n *\n *  Returns:\n *      Nothing.\n *\n *  Comments:\n *      Many of the variable names in the SHAContext, especially the\n *      single character names, were used because those were the names\n *      used in the publication.\n *\n *\n */\nvoid SHA1ProcessMessageBlock(SHA1Context *context)\n{\n   const unsigned K[] =            /* Constants defined in SHA-1   */\n   {\n      0x5A827999,\n      0x6ED9EBA1,\n      0x8F1BBCDC,\n      0xCA62C1D6\n   };\n   int         t;                  /* Loop counter                 */\n   unsigned    temp;               /* Temporary word value         */\n   unsigned    W[80];              /* Word sequence                */\n   unsigned    A, B, C, D, E;      /* Word buffers                 */\n\n   /*\n    *  Initialize the first 16 words in the array W\n    */\n   for (t = 0; t < 16; t++)\n   {\n      W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;\n      W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;\n      W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8;\n      W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);\n   }\n\n   for (t = 16; t < 80; t++)\n      W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);\n\n   A = context->Message_Digest[0];\n   B = context->Message_Digest[1];\n   C = context->Message_Digest[2];\n   D = context->Message_Digest[3];\n   E = context->Message_Digest[4];\n\n   for (t = 0; t < 20; t++)\n   {\n      temp =  SHA1CircularShift(5,A) +\n         ((B & C) | ((~B) & D)) + E + W[t] + K[0];\n      temp &= 0xFFFFFFFF;\n      E = D;\n      D = C;\n      C = SHA1CircularShift(30,B);\n      B = A;\n      A = temp;\n   }\n\n   for (t = 20; t < 40; t++)\n   {\n      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];\n      temp &= 0xFFFFFFFF;\n      E = D;\n      D = C;\n      C = SHA1CircularShift(30,B);\n      B = A;\n      A = temp;\n   }\n\n   for (t = 40; t < 60; t++)\n   {\n      temp = SHA1CircularShift(5,A) +\n         ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];\n      temp &= 0xFFFFFFFF;\n      E = D;\n      D = C;\n      C = SHA1CircularShift(30,B);\n      B = A;\n      A = temp;\n   }\n\n   for (t = 60; t < 80; t++)\n   {\n      temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];\n      temp &= 0xFFFFFFFF;\n      E = D;\n      D = C;\n      C = SHA1CircularShift(30,B);\n      B = A;\n      A = temp;\n   }\n\n   context->Message_Digest[0] =\n      (context->Message_Digest[0] + A) & 0xFFFFFFFF;\n   context->Message_Digest[1] =\n      (context->Message_Digest[1] + B) & 0xFFFFFFFF;\n   context->Message_Digest[2] =\n      (context->Message_Digest[2] + C) & 0xFFFFFFFF;\n   context->Message_Digest[3] =\n      (context->Message_Digest[3] + D) & 0xFFFFFFFF;\n   context->Message_Digest[4] =\n      (context->Message_Digest[4] + E) & 0xFFFFFFFF;\n\n   context->Message_Block_Index = 0;\n}\n\n/*\n *  SHA1PadMessage\n *\n *  Description:\n *      According to the standard, the message must be padded to an even\n *      512 bits.  The first padding bit must be a '1'.  The last 64\n *      bits represent the length of the original message.  All bits in\n *      between should be 0.  This function will pad the message\n *      according to those rules by filling the Message_Block array\n *      accordingly.  It will also call SHA1ProcessMessageBlock()\n *      appropriately.  When it returns, it can be assumed that the\n *      message digest has been computed.\n *\n *  Parameters:\n *      context: [in/out]\n *          The context to pad\n *\n *  Returns:\n *      Nothing.\n *\n *  Comments:\n *\n */\nvoid SHA1PadMessage(SHA1Context *context)\n{\n   /*\n    *  Check to see if the current message block is too small to hold\n    *  the initial padding bits and length.  If so, we will pad the\n    *  block, process it, and then continue padding into a second\n    *  block.\n    */\n   if (context->Message_Block_Index > 55)\n   {\n      context->Message_Block[context->Message_Block_Index++] = 0x80;\n      while(context->Message_Block_Index < 64)\n         context->Message_Block[context->Message_Block_Index++] = 0;\n\n      SHA1ProcessMessageBlock(context);\n\n      while(context->Message_Block_Index < 56)\n         context->Message_Block[context->Message_Block_Index++] = 0;\n   }\n   else\n   {\n      context->Message_Block[context->Message_Block_Index++] = 0x80;\n      while(context->Message_Block_Index < 56)\n         context->Message_Block[context->Message_Block_Index++] = 0;\n   }\n\n   /*\n    *  Store the message length as the last 8 octets\n    */\n   context->Message_Block[56] = (context->Length_High >> 24) & 0xFF;\n   context->Message_Block[57] = (context->Length_High >> 16) & 0xFF;\n   context->Message_Block[58] = (context->Length_High >> 8) & 0xFF;\n   context->Message_Block[59] = (context->Length_High) & 0xFF;\n   context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF;\n   context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF;\n   context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF;\n   context->Message_Block[63] = (context->Length_Low) & 0xFF;\n\n   SHA1ProcessMessageBlock(context);\n}\n"
  },
  {
    "path": "vfs/saf/src/com/libretro/common/vfs/VfsImplementationSaf.java",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (VfsImplementationSaf.java).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\npackage com.libretro.common.vfs;\n\nimport android.content.ContentResolver;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.provider.DocumentsContract;\nimport android.provider.DocumentsContract.Document;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.List;\n\npublic final class VfsImplementationSaf\n{\n   private static final String[] QUERY_ARGS_MIME_TYPE = {\n      Document.COLUMN_MIME_TYPE,\n   };\n\n   private static String normalizePath(String path) {\n      try\n      {\n         return new File(\"/\" + path).getCanonicalPath();\n      }\n      catch (IOException e)\n      {\n         return \"/\";\n      }\n   }\n\n   private static String getPathParent(String path) {\n      try\n      {\n         return new File(\"/\" + path).getCanonicalFile().getParent();\n      }\n      catch (IOException e)\n      {\n         return null;\n      }\n   }\n\n   private static String getPathFileName(String path) {\n      try\n      {\n         return new File(\"/\" + path).getCanonicalFile().getName();\n      }\n      catch (IOException e)\n      {\n         return null;\n      }\n   }\n\n   private static boolean isDocument(Uri treeUri) {\n      final List<String> segments = treeUri.getPathSegments();\n      return (\n         (\n            segments.size() >= 2\n               && segments.get(0).equals(\"document\")\n         ) || (\n            segments.size() >= 4\n               && segments.get(0).equals(\"tree\")\n               && segments.get(2).equals(\"document\")\n         )\n      );\n   }\n\n   /**\n    * Open a Storage Access Framework file, returning its file descriptor if successful or -1 if not.\n    * The file is not guaranteed to be seeked to any particular position, so it may be a good idea to seek it immediately after opening.\n    * @param content the content resolver returned by getContentResolver()\n    * @param tree the URI returned by the ACTION_OPEN_DOCUMENT_TREE intent action\n    * @param path path of the file to open, relative to the root directory of the tree\n    * @param read whether or not to open the file with read permissions\n    * @param write whether or not to open the file with write permissions\n    * @param truncate if the file is opened with write permissions, whether or not to delete the contents of the file after opening it\n    */\n   public static int openSafFile(ContentResolver content, String tree, String path, boolean read, boolean write, boolean truncate)\n   {\n      if (Build.VERSION.SDK_INT < 21)\n         return -1;\n      path = normalizePath(path);\n      boolean createdFile = false;\n      while (true)\n      {\n         final Uri treeUri = Uri.parse(tree);\n         if (isDocument(treeUri) && !path.equals(\"/\"))\n            return -1;\n         final Uri fileUri = isDocument(treeUri)\n            ? treeUri\n            : DocumentsContract.buildDocumentUriUsingTree(treeUri, path.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + path);\n         final String mode;\n         if (!write)\n            mode = \"r\";\n         else if (!read)\n         {\n            if (truncate)\n               mode = \"wt\";\n            else\n               mode = \"wa\";\n         }\n         else\n         {\n            if (truncate)\n               mode = \"rwt\";\n            else\n               mode = \"rw\";\n         }\n         try\n         {\n            return content.openFileDescriptor(fileUri, mode).detachFd();\n         }\n         catch (FileNotFoundException | IllegalArgumentException e)\n         {\n            if (createdFile || !write || !truncate || isDocument(treeUri))\n               return -1;\n            createdFile = true;\n            final String parentPath = getPathParent(path);\n            if (parentPath == null)\n               return -1;\n            final Uri parentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, parentPath.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + parentPath);\n            try\n            {\n               DocumentsContract.createDocument(content, parentUri, \"application/octet-stream\", getPathFileName(path));\n            }\n            catch (FileNotFoundException | IllegalArgumentException f)\n            {\n               return -1;\n            }\n         }\n      }\n   }\n\n   /**\n    * Delete a Storage Access Framework file or directory, returning whether or not the operation succeeded.\n    * @param content the content resolver returned by getContentResolver()\n    * @param tree the URI returned by the ACTION_OPEN_DOCUMENT_TREE intent action\n    * @param path path of the file or directory to delete, relative to the root directory of the tree\n    */\n   public static boolean removeSafFile(ContentResolver content, String tree, String path)\n   {\n      if (Build.VERSION.SDK_INT < 21)\n         return false;\n      final Uri treeUri = Uri.parse(tree);\n      path = normalizePath(path);\n      if (isDocument(treeUri) && !path.equals(\"/\"))\n         return false;\n      final Uri fileUri = isDocument(treeUri)\n         ? treeUri\n         : DocumentsContract.buildDocumentUriUsingTree(treeUri, path.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + path);\n      try\n      {\n         DocumentsContract.deleteDocument(content, fileUri);\n      }\n      catch (FileNotFoundException | IllegalArgumentException e)\n      {\n         return false;\n      }\n      return true;\n   }\n\n   public static class SafStat\n   {\n      private static final String[] QUERY_ARGS_WITH_SIZE = {\n         Document.COLUMN_MIME_TYPE,\n         Document.COLUMN_SIZE,\n      };\n\n      private static final String[] QUERY_ARGS_WITHOUT_SIZE = {\n         Document.COLUMN_MIME_TYPE,\n      };\n\n      private boolean isOpen = false;\n      private boolean isDirectory = false;\n      private long size = -1;\n\n      /**\n       * Retrieves metadata about a Storage Access Framework file or directory.\n       * @param content the content resolver returned by getContentResolver()\n       * @param tree the URI returned by the ACTION_OPEN_DOCUMENT_TREE intent action\n       * @param path path of the file or directory to open, relative to the root directory of the tree\n       * @param includeSize whether or not to query the size of the file or directory\n       */\n      public SafStat(ContentResolver content, String tree, String path, boolean includeSize)\n      {\n         if (Build.VERSION.SDK_INT < 21)\n            return;\n         final Uri treeUri = Uri.parse(tree);\n         path = normalizePath(path);\n         if (isDocument(treeUri) && !path.equals(\"/\"))\n            return;\n         final Uri fileUri = isDocument(treeUri)\n            ? treeUri\n            : DocumentsContract.buildDocumentUriUsingTree(treeUri, path.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + path);\n         final Cursor cursor;\n         try\n         {\n            cursor = content.query(fileUri, includeSize ? QUERY_ARGS_WITH_SIZE : QUERY_ARGS_WITHOUT_SIZE, null, null, null);\n         }\n         catch (IllegalArgumentException e)\n         {\n            return;\n         }\n         if (cursor == null)\n            return;\n         try\n         {\n            if (!cursor.moveToNext())\n               return;\n            isDirectory = cursor.getString(0).equals(Document.MIME_TYPE_DIR);\n            size = includeSize ? cursor.getLong(1) : 0;\n            isOpen = true;\n         }\n         finally\n         {\n            cursor.close();\n         }\n      }\n\n      /**\n       * Get whether or not the file or directory was able to be queried.\n       */\n      public boolean getIsOpen()\n      {\n         return isOpen;\n      }\n\n      /**\n       * Get whether or not the file or directory is a directory, or false if there was an error opening the file or directory.\n       */\n      public boolean getIsDirectory()\n      {\n         return isOpen ? isDirectory : false;\n      }\n\n      /**\n       * Get the size of the file or directory, or -1 if there was an error opening the file or directory.\n       * If this object was initialized without includeSize, the size will be 0 if the file or directory was opened successfully or -1 if not.\n       */\n      public long getSize()\n      {\n         return isOpen ? size : -1;\n      }\n   }\n\n   /**\n    * Create a Storage Access Framework directory, returning 0 if it succeeded, -1 if it failed or -2 if the directory already exists.\n    * @param content the content resolver returned by getContentResolver()\n    * @param tree the URI returned by the ACTION_OPEN_DOCUMENT_TREE intent action\n    * @param path path of the directory to create, relative to the root directory of the tree\n    */\n   public static int mkdirSaf(ContentResolver content, String tree, String path)\n   {\n      if (Build.VERSION.SDK_INT < 21)\n         return -1;\n      final Uri treeUri = Uri.parse(tree);\n      path = normalizePath(path);\n      if (isDocument(treeUri))\n         return -1;\n      path = path.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + path;\n      final Uri directoryUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, path);\n      Cursor cursor = null;\n      try\n      {\n         cursor = content.query(directoryUri, QUERY_ARGS_MIME_TYPE, null, null, null);\n      }\n      catch (IllegalArgumentException e)\n      {}\n      if (cursor != null)\n      {\n         try\n         {\n            if (cursor.moveToNext())\n               return cursor.getString(0).equals(Document.MIME_TYPE_DIR) ? -2 : -1;\n         }\n         finally\n         {\n            cursor.close();\n         }\n      }\n      final String parentPath = getPathParent(path);\n      if (parentPath == null)\n         return -1;\n      final Uri parentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, parentPath.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + parentPath);\n      try\n      {\n         if (DocumentsContract.createDocument(content, parentUri, Document.MIME_TYPE_DIR, getPathFileName(path)) == null)\n            return -1;\n      }\n      catch (FileNotFoundException | IllegalArgumentException e)\n      {\n         return -1;\n      }\n      return 0;\n   }\n\n   public static class SafDirectory implements Closeable\n   {\n      private static final String[] QUERY_ARGS = {\n         Document.COLUMN_DOCUMENT_ID,\n         Document.COLUMN_MIME_TYPE,\n      };\n\n      private int prefixLength;\n      private Cursor cursor = null;\n      private String direntName = null;\n      private boolean direntIsDirectory = false;\n\n      /**\n       * Open a Storage Access Framework directory to list its contents.\n       * @param content the content resolver returned by getContentResolver()\n       * @param tree the URI returned by the ACTION_OPEN_DOCUMENT_TREE intent action\n       * @param path path of the directory to open, relative to the root directory of the tree\n       */\n      public SafDirectory(ContentResolver content, String tree, String path)\n      {\n         if (Build.VERSION.SDK_INT < 21)\n            return;\n         final Uri treeUri = Uri.parse(tree);\n         path = normalizePath(path);\n         if (isDocument(treeUri))\n            return;\n         path = path.length() == 1 ? DocumentsContract.getTreeDocumentId(treeUri) : DocumentsContract.getTreeDocumentId(treeUri) + path;\n         prefixLength = path.length();\n         final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, path);\n         try\n         {\n            cursor = content.query(childrenUri, QUERY_ARGS, null, null, null);\n         }\n         catch (IllegalArgumentException e)\n         {}\n      }\n\n      @Override\n      public void close()\n      {\n         if (cursor != null)\n         {\n            cursor.close();\n            cursor = null;\n         }\n      }\n\n      /**\n       * Get the next child (could be a file or directory) of this directory, returning true if successful or false if there are no more children.\n       */\n      public boolean readdir()\n      {\n         if (Build.VERSION.SDK_INT < 21)\n            return false;\n         if (cursor == null)\n            return false;\n         if (cursor.moveToNext())\n         {\n            direntName = cursor.getString(0).substring(prefixLength);\n            // Remove leading slashes\n            int slashIndex = 0;\n            while (slashIndex < direntName.length() && direntName.charAt(slashIndex) == '/')\n               ++slashIndex;\n            direntName = direntName.substring(slashIndex);\n            // Remove trailing slashes\n            slashIndex = direntName.length();\n            while (slashIndex > 0 && direntName.charAt(slashIndex - 1) == '/')\n               --slashIndex;\n            direntName = direntName.substring(0, slashIndex);\n            direntIsDirectory = cursor.getString(1).equals(Document.MIME_TYPE_DIR);\n            return true;\n         }\n         else\n         {\n            direntName = null;\n            direntIsDirectory = false;\n            close();\n            return false;\n         }\n      }\n\n      /**\n       * Return the name of the child that was most recently retrieved by readdir(), or null if readdir() hasn't been called yet or readdir() ran out of children.\n       */\n      public String getDirentName()\n      {\n         return direntName;\n      }\n\n      /**\n       * Return whether or not the child that was most recently retrieved by readdir() is a directory, or false if readdir() hasn't been called yet or readdir() ran out of children.\n       */\n      public boolean getDirentIsDirectory()\n      {\n         return direntIsDirectory;\n      }\n   }\n}\n"
  },
  {
    "path": "vfs/vfs_implementation.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation.c).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <errno.h>\n#include <limits.h>  /* INT_MAX, LONG_MAX -- both C89 */\n#include <sys/types.h>\n\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#if defined(_WIN32)\n#  ifdef _MSC_VER\n#    define setmode _setmode\n#  endif\n#include <sys/stat.h>\n#  ifdef _XBOX\n#    include <xtl.h>\n#    define INVALID_FILE_ATTRIBUTES -1\n#  else\n\n#    include <fcntl.h>\n#    include <direct.h>\n#    include <windows.h>\n#  endif\n#    include <io.h>\n#else\n#  if defined(PSP)\n#    include <pspiofilemgr.h>\n#  endif\n#  include <sys/types.h>\n#  include <sys/stat.h>\n#  if !defined(VITA)\n#  include <dirent.h>\n#  endif\n#  include <unistd.h>\n#  if defined(WIIU)\n#  include <malloc.h>\n#  endif\n#endif\n\n#include <fcntl.h>\n\n/* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */\n#if defined(VITA)\n#  include <psp2/io/fcntl.h>\n#  include <psp2/io/dirent.h>\n#  include <psp2/io/stat.h>\n#elif !defined(_WIN32)\n#  if defined(PSP)\n#    include <pspiofilemgr.h>\n#  endif\n#  include <sys/types.h>\n#  include <sys/stat.h>\n#  include <dirent.h>\n#  include <unistd.h>\n#endif\n\n#if defined(__QNX__) || defined(PSP)\n#include <unistd.h> /* stat() is defined here */\n#endif\n\n#ifdef __APPLE__\n#include <CoreFoundation/CoreFoundation.h>\n#endif\n#ifdef __HAIKU__\n#include <kernel/image.h>\n#endif\n#ifndef __MACH__\n#include <compat/strl.h>\n#include <compat/posix_string.h>\n#endif\n#include <compat/strcasestr.h>\n#include <retro_miscellaneous.h>\n#include <encodings/utf.h>\n\n#if defined(_WIN32)\n#ifndef _XBOX\n#if defined(_MSC_VER) && _MSC_VER <= 1200\n#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)\n#endif\n#endif\n#elif defined(VITA)\n#define SCE_ERROR_ERRNO_EEXIST 0x80010011\n#include <psp2/io/fcntl.h>\n#include <psp2/io/dirent.h>\n#include <psp2/io/stat.h>\n#else\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#endif\n\n\n#if defined(PSP)\n#include <pspkernel.h>\n#endif\n\n#if defined(__PS3__) || defined(__PSL1GHT__)\n#define FS_SUCCEEDED 0\n#define FS_TYPE_DIR 1\n#ifdef __PSL1GHT__\n#include <lv2/sysfs.h>\n#ifndef O_RDONLY\n#define O_RDONLY SYS_O_RDONLY\n#endif\n#ifndef O_WRONLY\n#define O_WRONLY SYS_O_WRONLY\n#endif\n#ifndef O_CREAT\n#define O_CREAT SYS_O_CREAT\n#endif\n#ifndef O_TRUNC\n#define O_TRUNC SYS_O_TRUNC\n#endif\n#ifndef O_RDWR\n#define O_RDWR SYS_O_RDWR\n#endif\n#else\n#include <cell/cell_fs.h>\n#ifndef O_RDONLY\n#define O_RDONLY CELL_FS_O_RDONLY\n#endif\n#ifndef O_WRONLY\n#define O_WRONLY CELL_FS_O_WRONLY\n#endif\n#ifndef O_CREAT\n#define O_CREAT CELL_FS_O_CREAT\n#endif\n#ifndef O_TRUNC\n#define O_TRUNC CELL_FS_O_TRUNC\n#endif\n#ifndef O_RDWR\n#define O_RDWR CELL_FS_O_RDWR\n#endif\n#ifndef sysFsStat\n#define sysFsStat cellFsStat\n#endif\n#ifndef sysFSDirent\n#define sysFSDirent CellFsDirent\n#endif\n#ifndef sysFsOpendir\n#define sysFsOpendir cellFsOpendir\n#endif\n#ifndef sysFsReaddir\n#define sysFsReaddir cellFsReaddir\n#endif\n#ifndef sysFSDirent\n#define sysFSDirent CellFsDirent\n#endif\n#ifndef sysFsClosedir\n#define sysFsClosedir cellFsClosedir\n#endif\n#endif\n#endif\n\n#if defined(VITA)\n#define FIO_S_ISDIR SCE_S_ISDIR\n#endif\n\n#if defined(__QNX__) || defined(PSP)\n#include <unistd.h> /* stat() is defined here */\n#endif\n\n/* Assume W-functions do not work below Win2K and Xbox platforms */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)\n\n#ifndef LEGACY_WIN32\n#define LEGACY_WIN32\n#endif\n\n#endif\n\n#if defined(_WIN32)\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n#define ATLEAST_VC2005\n#endif\n#endif\n\n#include <vfs/vfs_implementation.h>\n#include <libretro.h>\n#if defined(HAVE_MMAP)\n#include <memmap.h>\n#endif\n#include <encodings/utf.h>\n#include <compat/fopen_utf8.h>\n#include <file/file_path.h>\n\n#ifdef HAVE_CDROM\n#include <vfs/vfs_implementation_cdrom.h>\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n#include <vfs/vfs_implementation_saf.h>\n#endif\n\n#ifdef HAVE_SMBCLIENT\n#include \"vfs_implementation_smb.h\"\n#endif\n\n#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)\n#ifndef HAVE_64BIT_OFFSETS\n#define HAVE_64BIT_OFFSETS\n#endif\n#endif\n\n#define RFILE_HINT_UNBUFFERED (1 << 8)\n\n#ifdef HAVE_CDROM\nstatic int path_is_cdrom(const char *p)\n{\n   return (p\n         && p[0] == 'c' && p[1] == 'd' && p[2] == 'r'\n         && p[3] == 'o' && p[4] == 'm' && p[5] == ':'\n         && p[6] == '/' && p[7] == '/' && p[8] != '\\0');\n}\n#endif\n\n#ifdef HAVE_SMBCLIENT\nstatic int path_is_smb(const char *p)\n{\n   return (p\n         && p[0] == 's' && p[1] == 'm' && p[2] == 'b'\n         && p[3] == ':' && p[4] == '/' && p[5] == '/'\n         && p[6] != '\\0');\n}\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\nstatic int path_is_saf(const char *p)\n{\n   return (p\n         && p[0] == 's' && p[1] == 'a' && p[2] == 'f'\n         && p[3] == ':' && p[4] == '/' && p[5] == '/'\n         && p[6] != '\\0');\n}\n#endif\n\nint64_t retro_vfs_file_seek_internal(\n      libretro_vfs_implementation_file *stream,\n      int64_t offset, int whence)\n{\n   int64_t val;\n\n   if (!stream)\n      return -1;\n\n   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n   {\n#ifdef HAVE_CDROM\n      if (stream->scheme == VFS_SCHEME_CDROM)\n         return retro_vfs_file_seek_cdrom(stream, offset, whence);\n#endif\n#ifdef HAVE_SMBCLIENT\n      if (stream->scheme == VFS_SCHEME_SMB)\n         return retro_vfs_file_seek_smb(stream, offset, whence);\n#endif\n#ifdef ATLEAST_VC2005\n      /* VC2005 and up have a special 64-bit fseek */\n      return _fseeki64(stream->fp, offset, whence);\n#elif defined(HAVE_64BIT_OFFSETS)\n      return fseeko(stream->fp, (off_t)offset, whence);\n#else\n      return fseek(stream->fp, (long)offset, whence);\n#endif\n   }\n#ifdef HAVE_MMAP\n   /* Need to check stream->mapped because this function is\n    * called in filestream_open() */\n   if (stream->mapped && (stream->hints &\n         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS))\n   {\n      /* fseek() returns error on under/overflow but\n       * allows cursor > EOF for\n       read-only file descriptors. */\n      /* The file position must never be negative. */\n      switch (whence)\n      {\n         case SEEK_SET:\n            if (offset < 0)\n               return -1;\n\n            stream->mappos = offset;\n            break;\n\n         case SEEK_CUR:\n            if ((int64_t)stream->mappos + offset < 0)\n              return -1;\n\n            stream->mappos += offset;\n            break;\n\n         case SEEK_END:\n            /* RETRO_VFS_SEEK_POSITION_END states offset should be negative.\n             * However, this is impractical because we would be forcing the\n             * end of file to always be off by one.\n             */\n            if (offset > 0 || (int64_t)stream->mapsize + offset < 0)\n               return -1;\n\n            stream->mappos = stream->mapsize + offset;\n            break;\n      }\n      return stream->mappos;\n   }\n#endif\n\n   if ((val = lseek(stream->fd, (off_t)offset, whence)) < 0)\n      return -1;\n\n   return val;\n}\n\n/**\n * retro_vfs_file_open_impl:\n * @path               : path to file\n * @mode               : file mode to use when opening (read/write)\n * @hints              :\n *\n * Opens a file for reading or writing, depending on the requested mode.\n * Returns a pointer to an RFILE if opened successfully, otherwise NULL.\n **/\n\nlibretro_vfs_implementation_file *retro_vfs_file_open_impl(\n      const char *path, unsigned mode, unsigned hints)\n{\n   int                                flags = 0;\n   const char                     *mode_str = NULL;\n   libretro_vfs_implementation_file *stream =\n      (libretro_vfs_implementation_file*)\n      calloc(1, sizeof(*stream));\n\n   if (!stream)\n      return NULL;\n\n   stream->fd                     = -1;\n   stream->hints                  = hints;\n   stream->scheme                 = VFS_SCHEME_NONE;\n\n#ifdef VFS_FRONTEND\n   if (     path\n         && path[0] == 'v'\n         && path[1] == 'f'\n         && path[2] == 's'\n         && path[3] == 'o'\n         && path[4] == 'n'\n         && path[5] == 'l'\n         && path[6] == 'y'\n         && path[7] == ':'\n         && path[8] == '/'\n         && path[9] == '/')\n         path             += sizeof(\"vfsonly://\")-1;\n#endif\n\n#ifdef HAVE_CDROM\n   if (path_is_cdrom(path))\n   {\n      path             += sizeof(\"cdrom://\")-1;\n      stream->scheme    = VFS_SCHEME_CDROM;\n   }\n#endif\n\n#ifdef HAVE_SMBCLIENT\n   if (path_is_smb(path))\n   {\n      stream->scheme    = VFS_SCHEME_SMB;\n   }\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (path_is_saf(path))\n   {\n      stream->scheme    = VFS_SCHEME_SAF;\n   }\n#endif\n\n   if (path)\n      stream->orig_path = strdup(path);\n\n#ifdef HAVE_MMAP\n   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS && mode == RETRO_VFS_FILE_ACCESS_READ)\n      stream->hints |= RFILE_HINT_UNBUFFERED;\n   else\n#endif\n      stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;\n\n   switch (mode)\n   {\n      case RETRO_VFS_FILE_ACCESS_READ:\n         mode_str = \"rb\";\n\n         flags    = O_RDONLY;\n#ifdef _WIN32\n         flags   |= O_BINARY;\n#endif\n         break;\n\n      case RETRO_VFS_FILE_ACCESS_WRITE:\n         mode_str = \"wb\";\n\n         flags    = O_WRONLY | O_CREAT | O_TRUNC;\n#if defined(_WIN32)\n         flags   |= O_BINARY;\n#endif\n         break;\n\n      case RETRO_VFS_FILE_ACCESS_READ_WRITE:\n         mode_str = \"w+b\";\n         flags    = O_RDWR | O_CREAT | O_TRUNC;\n#if defined(_WIN32)\n         flags   |= O_BINARY;\n#endif\n         break;\n\n      case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:\n      case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:\n         mode_str = \"r+b\";\n\n         flags    = O_RDWR;\n#if defined(_WIN32)\n         flags   |= O_BINARY;\n#endif\n         break;\n\n      default:\n         goto error;\n   }\n\n   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n   {\n      FILE *fp;\n      switch (stream->scheme)\n      {\n#ifdef HAVE_CDROM\n         case VFS_SCHEME_CDROM:\n            retro_vfs_file_open_cdrom(stream, path, mode, hints);\n#if defined(_WIN32) && !defined(_XBOX)\n            if (!stream->fh)\n               goto error;\n#else\n            if (!stream->fp)\n               goto error;\n#endif\n            break;\n#endif\n\n#ifdef HAVE_SMBCLIENT\n         case VFS_SCHEME_SMB:\n            if (!retro_vfs_file_open_smb(stream, path, mode, hints))\n               goto error;\n            break;\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n         case VFS_SCHEME_SAF:\n            {\n               struct libretro_vfs_implementation_saf_path_split_result saf_split_result;\n               int fd;\n               if (!retro_vfs_path_split_saf(&saf_split_result, path))\n                  goto error;\n               fd = retro_vfs_file_open_saf(saf_split_result.tree, saf_split_result.path, mode);\n               free(saf_split_result.path);\n               free(saf_split_result.tree);\n               if (fd == -1)\n                  goto error;\n               stream->fp = fdopen(fd, mode_str);\n               if (!stream->fp)\n               {\n                  close(fd);\n                  goto error;\n               }\n            }\n            break;\n#endif\n\n         default:\n            if (!(fp = (FILE*)fopen_utf8(path, mode_str)))\n            {\n#ifdef IOS\n               if (errno == EEXIST)\n               {\n                  retro_vfs_file_remove_impl(path);\n                  fp = (FILE*)fopen_utf8(path, mode_str);\n               }\n               if (!fp)\n#endif\n               goto error;\n            }\n            stream->fp  = fp;\n            break;\n      }\n\n      /* Regarding setvbuf:\n       *\n       * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html\n       *\n       * If the size argument is not zero but buf is NULL,\n       * a buffer of the given size will be allocated immediately, and\n       * released on close. This is an extension to ANSI C.\n       *\n       * Since C89 does not support specifying a NULL buffer\n       * with a non-zero size, we create and track our own buffer for it.\n       */\n      /* TODO: this is only useful for a few platforms,\n       * find which and add ifdef */\n#if defined(_3DS)\n      if (stream->scheme != VFS_SCHEME_CDROM)\n      {\n         stream->buf = (char*)calloc(1, 0x10000);\n         if (stream->fp)\n            setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);\n      }\n#elif defined(WIIU)\n      if (stream->scheme != VFS_SCHEME_CDROM)\n      {\n         const int bufsize = 128 * 1024;\n         stream->buf = (char*)memalign(0x40, bufsize);\n         if (stream->fp)\n            setvbuf(stream->fp, stream->buf, _IOFBF, bufsize);\n      }\n#endif\n   }\n   else\n   {\n      switch (stream->scheme)\n      {\n#if defined(ANDROID) && defined(HAVE_SAF)\n         case VFS_SCHEME_SAF:\n            {\n               struct libretro_vfs_implementation_saf_path_split_result saf_split_result;\n               if (!retro_vfs_path_split_saf(&saf_split_result, path))\n                  goto error;\n               stream->fd = retro_vfs_file_open_saf(saf_split_result.tree, saf_split_result.path, mode);\n               free(saf_split_result.path);\n               free(saf_split_result.tree);\n            }\n            break;\n#endif\n\n         default:\n            {\n#if defined(_WIN32) && !defined(_XBOX)\n#if defined(LEGACY_WIN32)\n               char *path_local    = utf8_to_local_string_alloc(path);\n               stream->fd          = open(path_local, flags, 0);\n               if (path_local)\n                  free(path_local);\n#else\n               wchar_t * path_wide = utf8_to_utf16_string_alloc(path);\n               stream->fd          = _wopen(path_wide, flags, 0);\n               if (path_wide)\n                  free(path_wide);\n#endif\n#else\n               stream->fd          = open(path, flags, S_IRUSR | S_IWUSR);\n#endif\n            }\n            break;\n      }\n\n      if (stream->fd == -1)\n         goto error;\n\n#ifdef HAVE_MMAP\n      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)\n      {\n         stream->mappos  = 0;\n         stream->mapped  = NULL;\n         stream->mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END);\n\n         if (stream->mapsize == (uint64_t)-1)\n            goto error;\n\n         retro_vfs_file_seek_internal(stream, 0, SEEK_SET);\n\n         if ((stream->mapped = (uint8_t*)mmap((void*)0,\n               stream->mapsize, PROT_READ,  MAP_SHARED, stream->fd, 0)) == MAP_FAILED)\n         {\n            stream->mapped = NULL;\n            stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;\n         }\n      }\n#endif\n   }\n#ifdef HAVE_CDROM\n   if (stream->scheme == VFS_SCHEME_CDROM)\n   {\n      retro_vfs_file_seek_cdrom(stream, 0, SEEK_END);\n\n      stream->size = retro_vfs_file_tell_impl(stream);\n\n      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);\n   }\n   else\n#endif\n   {\n      retro_vfs_file_seek_internal(stream, 0, SEEK_END);\n\n      stream->size = retro_vfs_file_tell_impl(stream);\n\n      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);\n   }\n   return stream;\n\nerror:\n   retro_vfs_file_close_impl(stream);\n   return NULL;\n}\n\nint retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)\n{\n   if (!stream)\n      return -1;\n\n#ifdef HAVE_CDROM\n   if (stream->scheme == VFS_SCHEME_CDROM)\n   {\n      retro_vfs_file_close_cdrom(stream);\n      goto end;\n   }\n#endif\n\n#ifdef HAVE_SMBCLIENT\n   if (stream->scheme == VFS_SCHEME_SMB)\n   {\n      retro_vfs_file_close_smb(stream);\n      goto smbend;\n   }\n#endif\n\n   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n   {\n      if (stream->fp)\n         fclose(stream->fp);\n   }\n   else\n   {\n#ifdef HAVE_MMAP\n      if (stream->mapped && (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS))\n         munmap(stream->mapped, stream->mapsize);\n#endif\n   }\n\n   if (stream->fd >= 0)\n      close(stream->fd);\n#ifdef HAVE_CDROM\nend:\n   if (stream->cdrom.cue_buf)\n      free(stream->cdrom.cue_buf);\n#endif\n#ifdef HAVE_SMBCLIENT\nsmbend:\n#endif\n\n   if (stream->buf)\n      free(stream->buf);\n\n   if (stream->orig_path)\n      free(stream->orig_path);\n\n   free(stream);\n\n   return 0;\n}\n\nint retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)\n{\n   if (!stream)\n      return -1;\n#ifdef HAVE_CDROM\n   if (stream->scheme == VFS_SCHEME_CDROM)\n      return retro_vfs_file_error_cdrom(stream);\n#endif\n#ifdef HAVE_SMBCLIENT\n    if (stream->scheme == VFS_SCHEME_SMB)\n        return retro_vfs_file_error_smb(stream);\n#endif\n   if (!stream->fp)\n      return -1;\n   return ferror(stream->fp);\n}\n\nint64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)\n{\n   if (stream)\n      return stream->size;\n   return 0;\n}\n\nint64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t len)\n{\n#ifdef _WIN32\n   /* _chsize takes a long and silently truncates lengths > LONG_MAX\n    * (2 GiB on Windows) -- present on all Windows CRTs including\n    * VC6.  _chsize_s takes __int64 and was added in the Secure CRT\n    * (VS 2005, _MSC_VER 1400).  Prefer the 64-bit variant when\n    * available, and on older MSVC / MinGW with legacy msvcrt fall\n    * back to _chsize only for lengths that fit in long -- return\n    * an error for larger lengths rather than silently truncating\n    * the file. */\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (stream && stream->fp && _chsize_s(_fileno(stream->fp), len) == 0)\n   {\n\t   stream->size = len;\n\t   return 0;\n   }\n#else\n   if (stream && stream->fp && len >= 0 && len <= (int64_t)LONG_MAX\n         && _chsize(_fileno(stream->fp), (long)len) == 0)\n   {\n\t   stream->size = len;\n\t   return 0;\n   }\n#endif\n#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))\n   if (stream && stream->fp && ftruncate(fileno(stream->fp), (off_t)len) == 0)\n   {\n      stream->size = len;\n      return 0;\n   }\n#endif\n   return -1;\n}\n\nint64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)\n{\n   int64_t val;\n\n   if (!stream)\n      return -1;\n\n   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n   {\n#ifdef HAVE_CDROM\n      if (stream->scheme == VFS_SCHEME_CDROM)\n         return retro_vfs_file_tell_cdrom(stream);\n#endif\n#ifdef HAVE_SMBCLIENT\n      if (stream->scheme == VFS_SCHEME_SMB)\n         return retro_vfs_file_tell_smb(stream);\n#endif\n#ifdef ATLEAST_VC2005\n      /* VC2005 and up have a special 64-bit ftell */\n      return _ftelli64(stream->fp);\n#elif defined(HAVE_64BIT_OFFSETS)\n      return ftello(stream->fp);\n#else\n      return ftell(stream->fp);\n#endif\n   }\n#ifdef HAVE_MMAP\n   /* Need to check stream->mapped because this function\n    * is called in filestream_open() */\n   if (stream->mapped && (stream->hints &\n         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS))\n      return stream->mappos;\n#endif\n   if ((val = lseek(stream->fd, 0, SEEK_CUR)) < 0)\n      return -1;\n\n   return val;\n}\n\nint64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,\n      int64_t offset, int seek_position)\n{\n   return retro_vfs_file_seek_internal(stream, offset, seek_position);\n}\n\nint64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,\n      void *s, uint64_t len)\n{\n   if (!stream || !s)\n      return -1;\n\n   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n   {\n#ifdef HAVE_CDROM\n      if (stream->scheme == VFS_SCHEME_CDROM)\n         return retro_vfs_file_read_cdrom(stream, s, len);\n#endif\n#ifdef HAVE_SMBCLIENT\n      if (stream->scheme == VFS_SCHEME_SMB)\n         return retro_vfs_file_read_smb(stream, s, len);\n#endif\n      return fread(s, 1, (size_t)len, stream->fp);\n   }\n#ifdef HAVE_MMAP\n   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)\n   {\n      if (stream->mappos >= stream->mapsize)\n      {\n         /* At or past EOF: 0 bytes is the correct return for\n          * fread-style semantics on a legitimate read that reached\n          * EOF, -1 if we were already past EOF (corrupt state). */\n         if (stream->mappos == stream->mapsize)\n            return 0;\n         return -1;\n      }\n\n      /* Clamp len against the remaining mapped bytes.  Done as an\n       * unsigned subtraction *before* computing mappos+len to avoid\n       * integer overflow: mappos+len can wrap past mapsize when\n       * both operands are large uint64_t values, defeating the\n       * naive \"mappos + len > mapsize\" bound check. */\n      {\n         uint64_t remaining = stream->mapsize - stream->mappos;\n         if (len > remaining)\n            len = remaining;\n      }\n\n      memcpy(s, &stream->mapped[stream->mappos], (size_t)len);\n      stream->mappos += len;\n\n      return (int64_t)len;\n   }\n#endif\n\n   return read(stream->fd, s, (size_t)len);\n}\n\nint64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)\n{\n   int64_t pos = 0;\n   ssize_t ret = -1;\n\n   if (!stream)\n      return -1;\n\n   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n   {\n#ifdef HAVE_SMBCLIENT\n      if (stream->scheme == VFS_SCHEME_SMB)\n      {\n         pos = retro_vfs_file_tell_smb(stream);\n         ret = retro_vfs_file_write_smb(stream, s, len);\n         if (ret != -1 && pos + ret > stream->size)\n            stream->size = pos + ret;\n         return ret;\n      }\n#endif\n      pos = retro_vfs_file_tell_impl(stream);\n      ret = fwrite(s, 1, (size_t)len, stream->fp);\n\n      if (ret > 0 && pos + ret > stream->size)\n         stream->size = pos + ret;\n\n      return ret;\n   }\n#ifdef HAVE_MMAP\n   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)\n      return -1;\n#endif\n\n   pos = retro_vfs_file_tell_impl(stream);\n   ret = write(stream->fd, s, (size_t)len);\n\n   if (ret != -1 && pos + ret > stream->size)\n      stream->size = pos + ret;\n\n   return ret;\n}\n\nint retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)\n{\n   if (!stream)\n      return -1;\n#ifdef HAVE_CDROM\n   if (stream->scheme == VFS_SCHEME_CDROM)\n      return 0;\n#endif\n#ifdef HAVE_SMBCLIENT\n   if (stream->scheme == VFS_SCHEME_SMB)\n      return 0;\n#endif\n   if (stream->fp && fflush(stream->fp) == 0)\n      return 0;\n   return -1;\n}\n\nint retro_vfs_file_remove_impl(const char *path)\n{\n   if (path && *path)\n   {\n      int ret          = -1;\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n      if (path_is_saf(path))\n      {\n         struct libretro_vfs_implementation_saf_path_split_result saf_split_result;\n         if (!retro_vfs_path_split_saf(&saf_split_result, path))\n            return -1;\n         ret = retro_vfs_file_remove_saf(saf_split_result.tree, saf_split_result.path);\n         free(saf_split_result.path);\n         free(saf_split_result.tree);\n         return ret;\n      }\n#endif\n\n#if defined(_WIN32) && !defined(_XBOX)\n      /* Win32 (no Xbox) */\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500\n      char *path_local = NULL;\n      if ((path_local = utf8_to_local_string_alloc(path)))\n      {\n         /* We need to check if path is a directory */\n         if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)\n            ret = _rmdir(path_local);\n         else\n            ret = remove(path_local);\n         free(path_local);\n      }\n#else\n      wchar_t *path_wide = NULL;\n      if ((path_wide = utf8_to_utf16_string_alloc(path)))\n      {\n         /* We need to check if path is a directory */\n         if ((retro_vfs_stat_impl(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0)\n            ret = _wrmdir(path_wide);\n         else\n            ret = _wremove(path_wide);\n         free(path_wide);\n      }\n#endif\n#else\n      ret = remove(path);\n#endif\n      if (ret == 0)\n         return 0;\n   }\n   return -1;\n}\n\nint retro_vfs_file_rename_impl(const char *old_path, const char *new_path)\n{\n#if defined(ANDROID) && defined(HAVE_SAF)\n      if (path_is_saf(old_path) && path_is_saf(new_path))\n      {\n         int ret;\n         struct libretro_vfs_implementation_saf_path_split_result saf_split_result_old, saf_split_result_new;\n         if (!retro_vfs_path_split_saf(&saf_split_result_old, old_path))\n            return -1;\n         if (!retro_vfs_path_split_saf(&saf_split_result_new, new_path))\n         {\n            free(saf_split_result_old.path);\n            free(saf_split_result_old.tree);\n            return -1;\n         }\n         ret = retro_vfs_file_rename_saf(saf_split_result_old.tree, saf_split_result_old.path, saf_split_result_new.tree, saf_split_result_new.path);\n         free(saf_split_result_new.path);\n         free(saf_split_result_new.tree);\n         free(saf_split_result_old.path);\n         free(saf_split_result_old.tree);\n         return ret;\n      }\n#endif\n\n#if defined(_WIN32) && !defined(_XBOX)\n   /* Win32 (no Xbox) */\n   int ret                 = -1;\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500\n   char *old_path_local    = NULL;\n#else\n   wchar_t *old_path_wide  = NULL;\n#endif\n\n   if (!old_path || !*old_path || !new_path || !*new_path)\n      return -1;\n\n#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500\n   old_path_local = utf8_to_local_string_alloc(old_path);\n\n   if (old_path_local)\n   {\n      char *new_path_local = utf8_to_local_string_alloc(new_path);\n\n      if (new_path_local)\n      {\n         if (rename(old_path_local, new_path_local) == 0)\n            ret = 0;\n         free(new_path_local);\n      }\n\n      free(old_path_local);\n   }\n#else\n   old_path_wide = utf8_to_utf16_string_alloc(old_path);\n\n   if (old_path_wide)\n   {\n      wchar_t *new_path_wide = utf8_to_utf16_string_alloc(new_path);\n\n      if (new_path_wide)\n      {\n         if (_wrename(old_path_wide, new_path_wide) == 0)\n            ret = 0;\n         free(new_path_wide);\n      }\n\n      free(old_path_wide);\n   }\n#endif\n   return ret;\n\n#else\n   /* Every other platform */\n   if (!old_path || !*old_path || !new_path || !*new_path)\n      return -1;\n   return rename(old_path, new_path) == 0 ? 0 : -1;\n#endif\n}\n\nconst char *retro_vfs_file_get_path_impl(\n      libretro_vfs_implementation_file *stream)\n{\n   if (!stream)\n      return NULL;\n   return stream->orig_path;\n}\n\nint retro_vfs_stat_64_impl(const char *path, int64_t *size)\n{\n   int ret                   = RETRO_VFS_STAT_IS_VALID;\n\n   if (!path || !*path)\n      return 0;\n\n#ifdef HAVE_SMBCLIENT\n   if (path_is_smb(path))\n      return retro_vfs_stat_smb(path, size);\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (path_is_saf(path))\n   {\n      struct libretro_vfs_implementation_saf_path_split_result saf_split_result;\n      if (!retro_vfs_path_split_saf(&saf_split_result, path))\n         return 0;\n      ret = retro_vfs_stat_saf(saf_split_result.tree, saf_split_result.path, size);\n      free(saf_split_result.path);\n      free(saf_split_result.tree);\n      return ret;\n   }\n#endif\n\n   {\n#if defined(VITA)\n      /* Vita / PSP */\n      SceIoStat stat_buf;\n      int dir_ret;\n      char path_buf[PATH_MAX_LENGTH];\n      size_t _len               = strlcpy(path_buf, path, sizeof(path_buf));\n      if (_len > 0 && path_buf[_len-1] == '/')\n          path_buf[_len-1]      = '\\0';\n\n      dir_ret                   = sceIoGetstat(path_buf, &stat_buf);\n      if (dir_ret < 0)\n         return 0;\n\n      if (size)\n         *size                  = (int64_t)stat_buf.st_size;\n\n      if (FIO_S_ISDIR(stat_buf.st_mode))\n         ret              |= RETRO_VFS_STAT_IS_DIRECTORY;\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n      /* Lowlevel Lv2 */\n      sysFSStat stat_buf;\n\n      if (sysFsStat(path, &stat_buf) < 0)\n         return 0;\n\n      if (size)\n         *size = (int64_t)stat_buf.st_size;\n\n      if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)\n         ret  |= RETRO_VFS_STAT_IS_DIRECTORY;\n#elif defined(_WIN32)\n      /* Windows\n       * Older MSVC _stat may fail on directory paths \n       * with a trailing backslash */\n      struct _stat64 stat_buf;\n      char path_buf[PATH_MAX_LENGTH];\n      const char *stat_path = path;\n      DWORD file_info;\n#if defined(LEGACY_WIN32)\n      char *path_local;\n#else\n      wchar_t *path_wide;\n#endif\n      size_t _len = strlcpy(path_buf, path, sizeof(path_buf));\n\n      if (_len > 0 && _len < sizeof(path_buf))\n      {\n         while (_len > 0 && \n               (path_buf[_len - 1] == '\\\\' || path_buf[_len - 1] == '/'))\n         {\n            /* Keep drive roots like \"C:\\\" intact */\n            if (_len == 3 &&\n                  ((((path_buf[0] >= 'A') && (path_buf[0] <= 'Z')) ||\n                    ((path_buf[0] >= 'a') && (path_buf[0] <= 'z'))) &&\n                   path_buf[1] == ':' && path_buf[2] == '\\\\'))\n               break;\n\n            path_buf[--_len] = '\\0';\n         }\n\n         stat_path = path_buf;\n      }\n#if defined(LEGACY_WIN32)\n      path_local                = utf8_to_local_string_alloc(stat_path);\n\n      if (!path_local)\n         return 0;\n\n      file_info                 = GetFileAttributes(path_local);\n\n      /* Use _stat64 explicitly to match the struct _stat64 buffer\n       * declared above. The bare _stat is a macro that expands to\n       * _stat64i32 on VS2005+ (or _stat32 with _USE_32BIT_TIME_T),\n       * neither of which match struct _stat64 -- passing the wrong\n       * struct silently truncates st_size. _stat64 has been in MSVC\n       * since VS2003 (_MSC_VER >= 1300) and is provided by mingw-w64.\n       * VC6 has no 64-bit time_t at all; _stati64 is the only match. */\n#if defined(_MSC_VER) && _MSC_VER < 1300\n      if (file_info == INVALID_FILE_ATTRIBUTES\n            || _stati64(path_local, (struct _stati64*)&stat_buf) != 0)\n#else\n      if (file_info == INVALID_FILE_ATTRIBUTES\n            || _stat64(path_local, &stat_buf) != 0)\n#endif\n      {\n         free(path_local);\n         return 0;\n      }\n\n      free(path_local);\n#else\n      path_wide                 = utf8_to_utf16_string_alloc(stat_path);\n\n      if (!path_wide)\n         return 0;\n\n      file_info                 = GetFileAttributesW(path_wide);\n\n      if (file_info == INVALID_FILE_ATTRIBUTES\n            || _wstat64(path_wide, &stat_buf) != 0)\n      {\n         free(path_wide);\n         return 0;\n      }\n\n      free(path_wide);\n#endif\n\n      if (size)\n         *size = (int64_t)stat_buf.st_size;\n\n      if (file_info & FILE_ATTRIBUTE_DIRECTORY)\n         ret  |= RETRO_VFS_STAT_IS_DIRECTORY;\n#elif defined(GEKKO)\n      /* On GEKKO platforms, paths cannot have\n       * trailing slashes - we must therefore\n       * remove them */\n      size_t _len;\n      char path_buf[PATH_MAX_LENGTH];\n      struct stat stat_buf;\n\n      _len = strlcpy(path_buf, path, sizeof(path_buf));\n      if (_len > 0 && path_buf[_len - 1] == '/')\n          path_buf[_len - 1] = '\\0';\n\n      if (stat(path_buf, &stat_buf) < 0)\n         return 0;\n\n      if (size)\n         *size = (int64_t)stat_buf.st_size;\n\n      if (S_ISDIR(stat_buf.st_mode))\n         ret |= RETRO_VFS_STAT_IS_DIRECTORY;\n      if (S_ISCHR(stat_buf.st_mode))\n         ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;\n#else\n      /* Every other platform */\n#if defined(_LARGEFILE64_SOURCE)\n      struct stat64 stat_buf;\n      if (stat64(path, &stat_buf) < 0)\n         return 0;\n#else\n      struct stat stat_buf;\n\n      if (stat(path, &stat_buf) < 0)\n         return 0;\n#endif\n\n      if (size)\n         *size = (int64_t)stat_buf.st_size;\n\n      if (S_ISDIR(stat_buf.st_mode))\n         ret |= RETRO_VFS_STAT_IS_DIRECTORY;\n      if (S_ISCHR(stat_buf.st_mode))\n         ret |= RETRO_VFS_STAT_IS_CHARACTER_SPECIAL;\n#endif\n   }\n   return ret;\n}\n\nint retro_vfs_stat_impl(const char *path, int32_t *size)\n{\n   int64_t size64 = 0;\n   int ret = retro_vfs_stat_64_impl(path, size ? &size64 : NULL);\n\n   /* If a file is larger than 2 GiB, size64 holds the correct value\n    * but a naked (int32_t) cast would truncate -- worse, on files in\n    * (INT32_MAX, UINT32_MAX] the high bit wraps and callers see a\n    * negative size that they may interpret as an error.  Saturate to\n    * INT_MAX so a caller using the legacy API gets a clamped-large\n    * value rather than a corrupted one, and migrate to\n    * retro_vfs_stat_64_impl for files that need the real size.\n    * INT_MAX is used instead of INT32_MAX for C89 / VC6 portability\n    * (stdint.h's INT32_MAX is a C99 addition; INT_MAX is C89).  int\n    * is 32-bit on all MSVC targets including VC6, so INT_MAX ==\n    * INT32_MAX everywhere this code runs. */\n   if (size)\n      *size = (size64 > (int64_t)INT_MAX) ? INT_MAX : (int32_t)size64;\n\n   return ret;\n}\n\n#if defined(VITA)\n#define path_mkdir_err(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))\n#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH)\n#define path_mkdir_err(ret) ((ret) == -1)\n#else\n#define path_mkdir_err(ret) ((ret) < 0 && errno == EEXIST)\n#endif\n\nint retro_vfs_mkdir_impl(const char *dir)\n{\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (path_is_saf(dir))\n   {\n      int ret;\n      struct libretro_vfs_implementation_saf_path_split_result saf_split_result;\n      if (!retro_vfs_path_split_saf(&saf_split_result, dir))\n         return -1;\n      ret = retro_vfs_mkdir_saf(saf_split_result.tree, saf_split_result.path);\n      free(saf_split_result.path);\n      free(saf_split_result.tree);\n      return ret;\n   }\n   else\n#endif\n   {\n#if defined(_WIN32)\n#ifdef LEGACY_WIN32\n      int ret        = _mkdir(dir);\n#else\n      wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);\n      int       ret  = -1;\n\n      if (dir_w)\n      {\n         ret = _wmkdir(dir_w);\n         free(dir_w);\n      }\n#endif\n#elif defined(IOS)\n      int ret = mkdir(dir, 0755);\n#elif defined(VITA)\n      int ret = sceIoMkdir(dir, 0777);\n#elif defined(__QNX__)\n      int ret = mkdir(dir, 0777);\n#elif defined(GEKKO) || defined(WIIU)\n      /* On GEKKO platforms, mkdir() fails if\n       * the path has a trailing slash. We must\n       * therefore remove it. */\n      int ret       = -1;\n      char *dir_buf = strdup(dir);\n\n      if (dir_buf)\n      {\n         size_t _len = strlen(dir_buf);\n\n         if (_len > 0)\n            if (dir_buf[_len - 1] == '/')\n               dir_buf[_len - 1] = '\\0';\n\n         ret = mkdir(dir_buf, 0750);\n\n         free(dir_buf);\n      }\n#else\n      int ret = mkdir(dir, 0750);\n#endif\n\n      if (path_mkdir_err(ret))\n         return -2;\n      return ret < 0 ? -1 : 0;\n   }\n}\n\n#ifdef VFS_FRONTEND\nstruct retro_vfs_dir_handle\n#else\nstruct libretro_vfs_implementation_dir\n#endif\n{\n   char* orig_path;\n#if defined(_WIN32)\n#if defined(LEGACY_WIN32)\n   WIN32_FIND_DATA entry;\n#else\n   WIN32_FIND_DATAW entry;\n#endif\n   HANDLE directory;\n   bool next;\n   char path[PATH_MAX_LENGTH];\n#elif defined(VITA)\n   SceUID directory;\n   SceIoDirent entry;\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n   int error;\n   int directory;\n   sysFSDirent entry;\n#else\n   DIR *directory;\n   const struct dirent *entry;\n#endif\n#if defined(ANDROID) && defined(HAVE_SAF)\n   libretro_vfs_implementation_saf_dir *saf_directory;\n#endif\n#ifdef HAVE_SMBCLIENT\n   smb_dir_handle* smb_handle;\n   char smb_path[PATH_MAX_LENGTH];\n#endif\n};\n\nstatic bool dirent_check_err(libretro_vfs_implementation_dir *rdir)\n{\n#if defined(_WIN32)\n   return (rdir->directory == INVALID_HANDLE_VALUE);\n#elif defined(VITA) || defined(ORBIS)\n   return (rdir->directory < 0);\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n   return (rdir->error != FS_SUCCEEDED);\n#else\n   return !(rdir->directory);\n#endif\n}\n\nlibretro_vfs_implementation_dir *retro_vfs_opendir_impl(\n      const char *name, bool include_hidden)\n{\n#if defined(_WIN32)\n   char path_buf[1024];\n   size_t _len;\n#if defined(LEGACY_WIN32)\n   char *path_local   = NULL;\n#else\n   wchar_t *path_wide = NULL;\n#endif\n#endif\n   libretro_vfs_implementation_dir *rdir;\n\n   /* Reject NULL or empty string paths*/\n   if (!name || (*name == 0))\n      return NULL;\n\n   /*Allocate RDIR struct. Tidied later with retro_closedir*/\n   if (!(rdir = (libretro_vfs_implementation_dir*)\n            calloc(1, sizeof(*rdir))))\n      return NULL;\n\n   rdir->orig_path       = strdup(name);\n   if (rdir->orig_path == NULL)\n   {\n      free(rdir);\n      return NULL;\n   }\n\n#ifdef HAVE_SMBCLIENT\n   if (path_is_smb(name))\n   {\n      smb_dir_handle *dh = retro_vfs_opendir_smb(name, include_hidden);\n      if (!dh || !dh->dir)\n      {\n         free(rdir->orig_path);\n         free(rdir);\n         return NULL;\n      }\n      rdir->smb_handle = dh;\n      rdir->smb_path[0] = '\\0';\n      return rdir;\n   }\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n   rdir->saf_directory = NULL;\n\n   if (path_is_saf(name))\n   {\n      struct libretro_vfs_implementation_saf_path_split_result saf_split_result;\n      if (!retro_vfs_path_split_saf(&saf_split_result, name))\n      {\n         free(rdir->orig_path);\n         free(rdir);\n         return NULL;\n      }\n      rdir->saf_directory = retro_vfs_opendir_saf(saf_split_result.tree, saf_split_result.path, include_hidden);\n      free(saf_split_result.path);\n      free(saf_split_result.tree);\n      if (rdir->saf_directory == NULL)\n      {\n         free(rdir->orig_path);\n         free(rdir);\n         return NULL;\n      }\n      return rdir;\n   }\n#endif\n\n#if defined(_WIN32)\n   _len = strlcpy(path_buf, name, sizeof(path_buf));\n   /* Non-NT platforms don't like extra slashes in the path */\n   if (path_buf[_len - 1] != '\\\\')\n      path_buf [_len++]    = '\\\\';\n\n   path_buf[_len    ]      = '*';\n   path_buf[_len + 1]      = '\\0';\n#if defined(LEGACY_WIN32)\n   path_local              = utf8_to_local_string_alloc(path_buf);\n   rdir->directory         = FindFirstFile(path_local, &rdir->entry);\n   if (path_local)\n      free(path_local);\n#else\n   path_wide               = utf8_to_utf16_string_alloc(path_buf);\n   rdir->directory         = FindFirstFileW(path_wide, &rdir->entry);\n   if (path_wide)\n      free(path_wide);\n#endif\n\n#elif defined(VITA)\n   rdir->directory       = sceIoDopen(name);\n#elif defined(_3DS)\n   rdir->directory       = opendir(name);\n   rdir->entry           = NULL;\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n   rdir->error           = sysFsOpendir(name, &rdir->directory);\n#else\n   rdir->directory       = opendir(name);\n   rdir->entry           = NULL;\n#endif\n\n#ifdef _WIN32\n   if (include_hidden)\n      rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;\n   else\n      rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;\n#else\n   (void)include_hidden;\n#endif\n\n   if (rdir->directory && !dirent_check_err(rdir))\n      return rdir;\n\n   retro_vfs_closedir_impl(rdir);\n   return NULL;\n}\n\nbool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)\n{\n#ifdef HAVE_SMBCLIENT\n   if (rdir->smb_handle && rdir->smb_handle->dir)\n   {\n      struct smbc_dirent *de = retro_vfs_readdir_smb(rdir->smb_handle);\n      if (!de)\n         return false;\n      strlcpy(rdir->smb_path, de->name, sizeof(rdir->smb_path));\n      return true;\n   }\n   /* If we opened an SMB path but failed, do not fall through to native readdir */\n   if (path_is_smb(rdir->orig_path))\n      return false;\n#endif\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (rdir->saf_directory != NULL)\n      return retro_vfs_readdir_saf(rdir->saf_directory);\n#endif\n\n#if defined(_WIN32)\n   if (rdir->next)\n#if defined(LEGACY_WIN32)\n      return (FindNextFile(rdir->directory, &rdir->entry) != 0);\n#else\n      return (FindNextFileW(rdir->directory, &rdir->entry) != 0);\n#endif\n\n   rdir->next = true;\n   return (rdir->directory != INVALID_HANDLE_VALUE);\n#elif defined(VITA)\n   return (sceIoDread(rdir->directory, &rdir->entry) > 0);\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n   uint64_t nread;\n   rdir->error = sysFsReaddir(rdir->directory, &rdir->entry, &nread);\n   return (nread != 0);\n#else\n   return ((rdir->entry = readdir(rdir->directory)) != NULL);\n#endif\n}\n\nconst char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)\n{\n#ifdef HAVE_SMBCLIENT\n   if (rdir->smb_handle && rdir->smb_handle->dir)\n      return rdir->smb_path;\n#endif\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (rdir->saf_directory != NULL)\n      return retro_vfs_dirent_get_name_saf(rdir->saf_directory);\n   else\n#endif\n   {\n#if defined(_WIN32)\n#if defined(LEGACY_WIN32)\n      char *name       = local_to_utf8_string_alloc(rdir->entry.cFileName);\n#else\n      char *name       = utf16_to_utf8_string_alloc(rdir->entry.cFileName);\n#endif\n      if (!name)\n         return NULL;\n      memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));\n      strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));\n      free(name);\n      return (char*)rdir->entry.cFileName;\n#elif defined(VITA) || defined(__PSL1GHT__) || defined(__PS3__)\n      return rdir->entry.d_name;\n#else\n      if (!rdir || !rdir->entry)\n         return NULL;\n      return rdir->entry->d_name;\n#endif\n   }\n}\n\nbool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)\n{\n#ifdef HAVE_SMBCLIENT\n   if (rdir->smb_handle && rdir->smb_handle->dir)\n   {\n      char full[PATH_MAX_LENGTH];\n      const char *name = retro_vfs_dirent_get_name_impl(rdir);\n      int64_t sz = 0;\n      int st = 0;\n\n      if (!name)\n         return false;\n\n      fill_pathname_join_special(full, rdir->orig_path, name, sizeof(full));\n      st = retro_vfs_stat_smb(full, &sz);\n\n      return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0;\n   }\n#endif\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (rdir->saf_directory != NULL)\n      return retro_vfs_dirent_is_dir_saf(rdir->saf_directory);\n   else\n#endif\n   {\n#if defined(_WIN32)\n      const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;\n      return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;\n#elif defined(VITA)\n      const SceIoDirent *entry     = (const SceIoDirent*)&rdir->entry;\n      return SCE_S_ISDIR(entry->d_stat.st_mode);\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n      sysFSDirent *entry          = (sysFSDirent*)&rdir->entry;\n      return (entry->d_type == FS_TYPE_DIR);\n#else\n      struct stat buf;\n      char path[PATH_MAX_LENGTH];\n#if defined(DT_DIR)\n      const struct dirent *entry = (const struct dirent*)rdir->entry;\n      if (entry->d_type == DT_DIR)\n         return true;\n      /* This can happen on certain file systems. */\n      if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))\n         return false;\n#endif\n      /* dirent struct doesn't have d_type, do it the slow way ... */\n      fill_pathname_join_special(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));\n      if (stat(path, &buf) < 0)\n         return false;\n      return S_ISDIR(buf.st_mode);\n#endif\n   }\n}\n\nint retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)\n{\n   int ret = 0;\n\n   if (!rdir)\n      return -1;\n\n#ifdef HAVE_SMBCLIENT\n   if (rdir->smb_handle && rdir->smb_handle->dir)\n   {\n      retro_vfs_closedir_smb(rdir->smb_handle);\n      rdir->smb_handle = NULL;\n   }\n#endif\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n   if (rdir->saf_directory != NULL)\n      ret = retro_vfs_closedir_saf(rdir->saf_directory);\n   else\n#endif\n   {\n#if defined(_WIN32)\n      if (rdir->directory != INVALID_HANDLE_VALUE)\n         FindClose(rdir->directory);\n#elif defined(VITA)\n      sceIoDclose(rdir->directory);\n#elif defined(__PSL1GHT__) || defined(__PS3__)\n      rdir->error = sysFsClosedir(rdir->directory);\n#else\n      if (rdir->directory)\n         closedir(rdir->directory);\n#endif\n   }\n\n   if (rdir->orig_path)\n      free(rdir->orig_path);\n   free(rdir);\n   return ret;\n}\n"
  },
  {
    "path": "vfs/vfs_implementation_cdrom.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation_cdrom.c).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <vfs/vfs_implementation.h>\n#include <file/file_path.h>\n#include <compat/fopen_utf8.h>\n#include <cdrom/cdrom.h>\n\n#if defined(_WIN32) && !defined(_XBOX)\n#include <windows.h>\n#endif\n\n/* TODO/FIXME - static global variable */\nstatic cdrom_toc_t vfs_cdrom_toc = {0};\n\nconst cdrom_toc_t* retro_vfs_file_get_cdrom_toc(void)\n{\n   return &vfs_cdrom_toc;\n}\n\nint64_t retro_vfs_file_seek_cdrom(\n      libretro_vfs_implementation_file *stream,\n      int64_t offset, int whence)\n{\n   const char *ext = path_get_extension(stream->orig_path);\n\n   if (     (ext[0] == 'c' || ext[0] == 'C')\n         && (ext[1] == 'u' || ext[1] == 'U')\n         && (ext[2] == 'e' || ext[2] == 'E')\n         &&  ext[3] == '\\0')\n   {\n      switch (whence)\n      {\n         case SEEK_SET:\n            stream->cdrom.byte_pos = offset;\n            break;\n         case SEEK_CUR:\n            stream->cdrom.byte_pos += offset;\n            break;\n         case SEEK_END:\n            stream->cdrom.byte_pos  = (stream->cdrom.cue_len - 1) + offset;\n            break;\n      }\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] Seek: Path %s Offset %\" PRIu64 \" is now at %\" PRIu64 \"\\n\",\n            stream->orig_path,\n            offset,\n            stream->cdrom.byte_pos);\n      fflush(stdout);\n#endif\n   }\n   else if ( (ext[0] == 'b' || ext[0] == 'B')\n         &&  (ext[1] == 'i' || ext[1] == 'I')\n         &&  (ext[2] == 'n' || ext[2] == 'N')\n         &&   ext[3] == '\\0')\n   {\n      int lba               = (offset / 2352);\n      unsigned char min     = 0;\n      unsigned char sec     = 0;\n      unsigned char frame   = 0;\n#ifdef CDROM_DEBUG\n      const char *seek_type = \"SEEK_SET\";\n#endif\n\n      switch (whence)\n      {\n         case SEEK_CUR:\n            {\n               unsigned new_lba;\n#ifdef CDROM_DEBUG\n               seek_type               = \"SEEK_CUR\";\n#endif\n               stream->cdrom.byte_pos += offset;\n               new_lba                 = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352);\n               cdrom_lba_to_msf(new_lba, &min, &sec, &frame);\n            }\n            break;\n         case SEEK_END:\n            {\n               ssize_t pregap_lba_len = (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].audio\n                      ? 0\n                      : (vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba_start));\n               ssize_t lba_len        = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_size - pregap_lba_len;\n#ifdef CDROM_DEBUG\n               seek_type              = \"SEEK_END\";\n#endif\n               cdrom_lba_to_msf(lba_len + lba, &min, &sec, &frame);\n               stream->cdrom.byte_pos = lba_len * 2352;\n            }\n            break;\n         case SEEK_SET:\n         default:\n            {\n#ifdef CDROM_DEBUG\n               seek_type = \"SEEK_SET\";\n#endif\n               stream->cdrom.byte_pos = offset;\n               cdrom_lba_to_msf(vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba + (stream->cdrom.byte_pos / 2352), &min, &sec, &frame);\n            }\n            break;\n      }\n\n      stream->cdrom.cur_min   = min;\n      stream->cdrom.cur_sec   = sec;\n      stream->cdrom.cur_frame = frame;\n      stream->cdrom.cur_lba   = cdrom_msf_to_lba(min, sec, frame);\n\n#ifdef CDROM_DEBUG\n      printf(\n            \"[CDROM] Seek %s: Path %s Offset %\" PRIu64 \" is now at %\" PRIu64 \" (MSF %02u:%02u:%02u) (LBA %u)...\\n\",\n            seek_type,\n            stream->orig_path,\n            offset,\n            stream->cdrom.byte_pos,\n            (unsigned)stream->cdrom.cur_min,\n            (unsigned)stream->cdrom.cur_sec,\n            (unsigned)stream->cdrom.cur_frame,\n            stream->cdrom.cur_lba);\n      fflush(stdout);\n#endif\n   }\n   else\n      return -1;\n\n   return 0;\n}\n\nvoid retro_vfs_file_open_cdrom(\n      libretro_vfs_implementation_file *stream,\n      const char *path, unsigned mode, unsigned hints)\n{\n#if defined(__linux__) && !defined(ANDROID)\n   char cdrom_path[]       = \"/dev/sg1\";\n   size_t path_len         = strlen(path);\n   const char *ext         = path_get_extension(path);\n\n   stream->cdrom.cur_track = 1;\n\n   if (     !(ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\\0')\n         && !(ext[0] == 'b' && ext[1] == 'i' && ext[2] == 'n' && ext[3] == '\\0'))\n      return;\n\n   if (path_len >= (sizeof(\"drive1-track01.bin\")-1))\n   {\n      if (!memcmp(path, \"drive\", (sizeof(\"drive\")-1)))\n      {\n         if (!memcmp(path + 6, \"-track\", (sizeof(\"-track\")-1)))\n         {\n            if (     path[12] >= '0' && path[12] <= '9'\n                  && path[13] >= '0' && path[13] <= '9')\n            {\n               unsigned parsed = (path[12] - '0') * 10 + (path[13] - '0');\n               /* Reject track 00 -- track numbers are 1-based, and\n                * cur_track == 0 would later index track[-1] in the\n                * TOC array (OOB read).  Leave the init value (1)\n                * in place on reject. */\n               if (parsed >= 1 && parsed <= 99)\n                  stream->cdrom.cur_track = parsed;\n#ifdef CDROM_DEBUG\n               printf(\"[CDROM] Opening track %d\\n\", stream->cdrom.cur_track);\n               fflush(stdout);\n#endif\n            }\n         }\n      }\n   }\n\n   if (path_len >= (sizeof(\"drive1.cue\")-1))\n   {\n      if (!memcmp(path, \"drive\", (sizeof(\"drive\")-1)))\n      {\n         if (path[5] >= '0' && path[5] <= '9')\n         {\n            cdrom_path[7]       = path[5];\n            stream->cdrom.drive = path[5];\n            vfs_cdrom_toc.drive = stream->cdrom.drive;\n         }\n      }\n   }\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] Open: Path %s URI %s\\n\", cdrom_path, path);\n   fflush(stdout);\n#endif\n   stream->fp = (FILE*)fopen_utf8(cdrom_path, \"r+b\");\n\n   if (!stream->fp)\n      return;\n\n   if (ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\\0')\n   {\n      if (stream->cdrom.cue_buf)\n      {\n         free(stream->cdrom.cue_buf);\n         stream->cdrom.cue_buf = NULL;\n      }\n\n      cdrom_write_cue(stream,\n            &stream->cdrom.cue_buf,\n            &stream->cdrom.cue_len,\n            stream->cdrom.drive,\n            &vfs_cdrom_toc.num_tracks,\n            &vfs_cdrom_toc);\n      cdrom_get_timeouts(stream, &vfs_cdrom_toc.timeouts);\n\n#ifdef CDROM_DEBUG\n      if (!stream->cdrom.cue_buf || !*stream->cdrom.cue_buf)\n      {\n         printf(\"[CDROM] Error writing cue sheet.\\n\");\n         fflush(stdout);\n      }\n      else\n      {\n         printf(\"[CDROM] CUE Sheet:\\n%s\\n\", stream->cdrom.cue_buf);\n         fflush(stdout);\n      }\n#endif\n   }\n#endif\n#if defined(_WIN32) && !defined(_XBOX)\n   char cdrom_path[] = \"\\\\\\\\.\\\\D:\";\n   size_t path_len   = strlen(path);\n   const char *ext   = path_get_extension(path);\n\n   if (     !(ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\\0')\n         && !(ext[0] == 'b' && ext[1] == 'i' && ext[2] == 'n' && ext[3] == '\\0'))\n      return;\n\n   if (path_len >= (sizeof(\"d:/drive-track01.bin\")-1))\n   {\n      if (!memcmp(path + 1, \":/drive-track\", (sizeof(\":/drive-track\")-1)))\n      {\n         if (   path[14] >= '0' && path[14] <= '9'\n             && path[15] >= '0' && path[15] <= '9')\n         {\n            unsigned parsed = (path[14] - '0') * 10 + (path[15] - '0');\n            /* Reject track 00 -- track numbers are 1-based, and\n             * cur_track == 0 would later index track[-1] in the\n             * TOC array (OOB read).  Leave the init value (1) in\n             * place on reject. */\n            if (parsed >= 1 && parsed <= 99)\n               stream->cdrom.cur_track = parsed;\n#ifdef CDROM_DEBUG\n            printf(\"[CDROM] Opening track %d\\n\", stream->cdrom.cur_track);\n            fflush(stdout);\n#endif\n         }\n      }\n   }\n\n   if (path_len >= (sizeof(\"d:/drive.cue\")-1))\n   {\n      if (!memcmp(path + 1, \":/drive\", (sizeof(\":/drive\")-1)))\n      {\n         if ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))\n         {\n            cdrom_path[4]       = path[0];\n            stream->cdrom.drive = path[0];\n            vfs_cdrom_toc.drive = stream->cdrom.drive;\n         }\n      }\n   }\n\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] Open: Path %s URI %s\\n\", cdrom_path, path);\n   fflush(stdout);\n#endif\n   stream->fh = CreateFile(cdrom_path,\n         GENERIC_READ | GENERIC_WRITE,\n         FILE_SHARE_READ | FILE_SHARE_WRITE,\n         NULL,\n         OPEN_EXISTING,\n         FILE_ATTRIBUTE_NORMAL,\n         NULL);\n\n   if (stream->fh == INVALID_HANDLE_VALUE)\n      return;\n\n   if (ext[0] == 'c' && ext[1] == 'u' && ext[2] == 'e' && ext[3] == '\\0')\n   {\n      if (stream->cdrom.cue_buf)\n      {\n         free(stream->cdrom.cue_buf);\n         stream->cdrom.cue_buf = NULL;\n      }\n\n      cdrom_write_cue(stream,\n            &stream->cdrom.cue_buf,\n            &stream->cdrom.cue_len,\n            stream->cdrom.drive,\n            &vfs_cdrom_toc.num_tracks,\n            &vfs_cdrom_toc);\n      cdrom_get_timeouts(stream,\n            &vfs_cdrom_toc.timeouts);\n\n#ifdef CDROM_DEBUG\n      if (!stream->cdrom.cue_buf || !*stream->cdrom.cue_buf)\n      {\n         printf(\"[CDROM] Error writing cue sheet.\\n\");\n         fflush(stdout);\n      }\n      else\n      {\n         printf(\"[CDROM] CUE Sheet:\\n%s\\n\", stream->cdrom.cue_buf);\n         fflush(stdout);\n      }\n#endif\n   }\n#endif\n   if (vfs_cdrom_toc.num_tracks > 1 && stream->cdrom.cur_track)\n   {\n      stream->cdrom.cur_min   = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].min;\n      stream->cdrom.cur_sec   = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].sec;\n      stream->cdrom.cur_frame = vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].frame;\n      stream->cdrom.cur_lba   = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);\n   }\n   else\n   {\n      stream->cdrom.cur_min   = vfs_cdrom_toc.track[0].min;\n      stream->cdrom.cur_sec   = vfs_cdrom_toc.track[0].sec;\n      stream->cdrom.cur_frame = vfs_cdrom_toc.track[0].frame;\n      stream->cdrom.cur_lba   = cdrom_msf_to_lba(stream->cdrom.cur_min, stream->cdrom.cur_sec, stream->cdrom.cur_frame);\n   }\n}\n\nint retro_vfs_file_close_cdrom(libretro_vfs_implementation_file *stream)\n{\n#ifdef CDROM_DEBUG\n   printf(\"[CDROM] Close: Path %s\\n\", stream->orig_path);\n   fflush(stdout);\n#endif\n\n#if defined(_WIN32) && !defined(_XBOX)\n   if (!stream->fh || !CloseHandle(stream->fh))\n      return -1;\n#else\n   if (!stream->fp || fclose(stream->fp))\n      return -1;\n#endif\n\n   return 0;\n}\n\nint64_t retro_vfs_file_tell_cdrom(libretro_vfs_implementation_file *stream)\n{\n   const char *ext = NULL;\n   if (!stream)\n      return -1;\n\n   ext = path_get_extension(stream->orig_path);\n\n   if (     (ext[0] == 'c' || ext[0] == 'C')\n         && (ext[1] == 'u' || ext[1] == 'U')\n         && (ext[2] == 'e' || ext[2] == 'E')\n         &&  ext[3] == '\\0')\n   {\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] (cue) Tell: Path %s Position %\" PRIu64 \"\\n\", stream->orig_path, stream->cdrom.byte_pos);\n      fflush(stdout);\n#endif\n      return stream->cdrom.byte_pos;\n   }\n   else if ( (ext[0] == 'b' || ext[0] == 'B')\n         &&  (ext[1] == 'i' || ext[1] == 'I')\n         &&  (ext[2] == 'n' || ext[2] == 'N')\n         &&   ext[3] == '\\0')\n   {\n#ifdef CDROM_DEBUG\n      printf(\"[CDROM] (bin) Tell: Path %s Position %\" PRId64 \"\\n\", stream->orig_path, stream->cdrom.byte_pos);\n      fflush(stdout);\n#endif\n      return stream->cdrom.byte_pos;\n   }\n\n   return -1;\n}\n\nint64_t retro_vfs_file_read_cdrom(libretro_vfs_implementation_file *stream,\n      void *s, uint64_t len)\n{\n   int rv;\n   const char *ext = path_get_extension(stream->orig_path);\n\n   if (     (ext[0] == 'c' || ext[0] == 'C')\n         && (ext[1] == 'u' || ext[1] == 'U')\n         && (ext[2] == 'e' || ext[2] == 'E')\n         &&  ext[3] == '\\0')\n   {\n      /* Guard against byte_pos being outside the cue buffer (can\n       * happen after a seek -- seek does not clamp).  Treat as\n       * end-of-file. */\n      if (     stream->cdrom.byte_pos < 0\n            || (size_t)stream->cdrom.byte_pos >= stream->cdrom.cue_len)\n         return 0;\n      /* Clamp len against the remaining bytes using unsigned\n       * subtraction.  Computing (byte_pos + len) and comparing\n       * against cue_len wraps uint64_t when len is attacker-\n       * controlled.  The -1 preserves legacy behaviour of stopping\n       * one byte before cue_len so consumers that rely on the cue\n       * buffer being NUL-terminated don't re-read the terminator. */\n      {\n         size_t remaining = stream->cdrom.cue_len\n                          - (size_t)stream->cdrom.byte_pos;\n         if (remaining > 0)\n            remaining -= 1;\n         if (len > (uint64_t)remaining)\n            len = (uint64_t)remaining;\n      }\n#ifdef CDROM_DEBUG\n      printf(\n            \"[CDROM] Read: Reading %\" PRIu64 \" bytes from cuesheet starting at %\" PRIu64 \"...\\n\",\n            len,\n            stream->cdrom.byte_pos);\n      fflush(stdout);\n#endif\n      memcpy(s, stream->cdrom.cue_buf + stream->cdrom.byte_pos, (size_t)len);\n      stream->cdrom.byte_pos += len;\n\n      return (int64_t)len;\n   }\n   else if ( (ext[0] == 'b' || ext[0] == 'B')\n         &&  (ext[1] == 'i' || ext[1] == 'I')\n         &&  (ext[2] == 'n' || ext[2] == 'N')\n         &&   ext[3] == '\\0')\n   {\n      unsigned char min    = 0;\n      unsigned char sec    = 0;\n      unsigned char frame  = 0;\n      unsigned char rmin   = 0;\n      unsigned char rsec   = 0;\n      unsigned char rframe = 0;\n      size_t skip          = stream->cdrom.byte_pos % 2352;\n\n      /* Guard against cur_track == 0 (would index track[-1]) and\n       * against an out-of-range byte_pos.  cur_track can become\n       * 0 via a crafted VFS path like \"driveN-track00.bin\" unless\n       * the parser rejects it (see retro_vfs_file_open_cdrom). */\n      if (stream->cdrom.cur_track == 0\n            || stream->cdrom.cur_track > 99)\n         return 0;\n      {\n         size_t track_bytes =\n            vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].track_bytes;\n         if (     stream->cdrom.byte_pos < 0\n               || (size_t)stream->cdrom.byte_pos >= track_bytes)\n            return 0;\n         /* Clamp len against remaining bytes using unsigned\n          * subtraction.  Computing (byte_pos + len) first is a\n          * uint64_t wrap hazard when len is attacker-controlled. */\n         {\n            size_t remaining = track_bytes - (size_t)stream->cdrom.byte_pos;\n            if (len > (uint64_t)remaining)\n               len = (uint64_t)remaining;\n         }\n      }\n\n      cdrom_lba_to_msf(stream->cdrom.cur_lba, &min, &sec, &frame);\n      cdrom_lba_to_msf(stream->cdrom.cur_lba \n            - vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba,\n            &rmin, &rsec, &rframe);\n\n#ifdef CDROM_DEBUG\n      printf(\n            \"[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\",\n            len,\n            stream->orig_path,\n            stream->cdrom.byte_pos,\n            (unsigned)rmin,\n            (unsigned)rsec,\n            (unsigned)rframe,\n            (unsigned)min,\n            (unsigned)sec,\n            (unsigned)frame,\n            stream->cdrom.cur_lba,\n            skip);\n      fflush(stdout);\n#endif\n\n#if 1\n      rv = cdrom_read(stream, &vfs_cdrom_toc.timeouts, min, sec,\n            frame, s, (size_t)len, skip);\n#else\n      rv = cdrom_read_lba(stream, stream->cdrom.cur_lba, s,\n            (size_t)len, skip);\n#endif\n\n      if (rv)\n      {\n#ifdef CDROM_DEBUG\n         printf(\"[CDROM] Failed to read %\" PRIu64 \" bytes from CD.\\n\", len);\n         fflush(stdout);\n#endif\n         return 0;\n      }\n\n      stream->cdrom.byte_pos += len;\n      stream->cdrom.cur_lba   = \n         vfs_cdrom_toc.track[stream->cdrom.cur_track - 1].lba \n         + (stream->cdrom.byte_pos / 2352);\n\n      cdrom_lba_to_msf(stream->cdrom.cur_lba,\n            &stream->cdrom.cur_min,\n            &stream->cdrom.cur_sec,\n            &stream->cdrom.cur_frame);\n\n#ifdef CDROM_DEBUG\n      printf(\n            \"[CDROM] read %\" PRIu64 \" bytes, position is now: %\" PRIu64 \" (MSF %02u:%02u:%02u) (LBA %u)\\n\",\n            len,\n            stream->cdrom.byte_pos,\n            (unsigned)stream->cdrom.cur_min,\n            (unsigned)stream->cdrom.cur_sec,\n            (unsigned)stream->cdrom.cur_frame,\n            cdrom_msf_to_lba(\n               stream->cdrom.cur_min,\n               stream->cdrom.cur_sec,\n               stream->cdrom.cur_frame)\n            );\n      fflush(stdout);\n#endif\n\n      return len;\n   }\n\n   return 0;\n}\n\nint retro_vfs_file_error_cdrom(libretro_vfs_implementation_file *stream)\n{\n   return 0;\n}\n\nconst vfs_cdrom_t* retro_vfs_file_get_cdrom_position(\n      const libretro_vfs_implementation_file *stream)\n{\n   return &stream->cdrom;\n}\n"
  },
  {
    "path": "vfs/vfs_implementation_saf.c",
    "content": "/* Copyright  (C) 2010-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation_saf.c).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#if defined(ANDROID) && defined(HAVE_SAF)\n\n#include <vfs/vfs_implementation_saf.h>\n#include <stdlib.h>\n#include <string.h>\n\nstatic JNIEnv *(*vfs_saf_get_jni_env)(void) = NULL;\nstatic jobject vfs_saf_content_resolver_object;\nstatic jclass vfs_saf_vfs_implementation_saf_class;\nstatic jmethodID vfs_saf_open_saf_file_method;\nstatic jmethodID vfs_saf_remove_saf_file_method;\nstatic jclass vfs_saf_saf_stat_class;\nstatic jmethodID vfs_saf_saf_stat_init_method;\nstatic jmethodID vfs_saf_saf_stat_get_is_open_method;\nstatic jmethodID vfs_saf_saf_stat_get_is_directory_method;\nstatic jmethodID vfs_saf_saf_stat_get_size_method;\nstatic jmethodID vfs_saf_mkdir_saf_method;\nstatic jclass vfs_saf_saf_directory_class;\nstatic jmethodID vfs_saf_saf_directory_init_method;\nstatic jmethodID vfs_saf_saf_directory_close_method;\nstatic jmethodID vfs_saf_saf_directory_readdir_method;\nstatic jmethodID vfs_saf_saf_directory_get_dirent_name_method;\nstatic jmethodID vfs_saf_saf_directory_get_dirent_is_directory_method;\n\nbool retro_vfs_init_saf(JNIEnv *(*get_jni_env)(void), jobject activity_object)\n{\n   JNIEnv *env;\n\n   if (vfs_saf_get_jni_env != NULL && !retro_vfs_deinit_saf())\n      return false;\n\n   env = get_jni_env();\n   if (env == NULL)\n      return false;\n\n   (*env)->PushLocalFrame(env, 14);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return false;\n   }\n\n   vfs_saf_content_resolver_object = NULL;\n   vfs_saf_vfs_implementation_saf_class = NULL;\n   vfs_saf_saf_stat_class = NULL;\n   vfs_saf_saf_directory_class = NULL;\n\n   /*\n    * ClassLoader class_loader_object = activity_object.getClassLoader();\n    * Class<?> vfs_saf_vfs_implementation_saf_class = class_loader_object.loadClass(\"com.libretro.common.vfs.VfsImplementationSaf\");\n    * Class<?> vfs_saf_saf_stat_class = class_loader_object.loadClass(\"com.libretro.common.vfs.VfsImplementationSaf$SafStat\");\n    * Class<?> vfs_saf_saf_directory_class = class_loader_object.loadClass(\"com.libretro.common.vfs.VfsImplementationSaf$SafDirectory\");\n    */\n   {\n      jobject class_loader_object;\n      jmethodID load_class_method;\n      jstring vfs_implementation_saf_string;\n      jclass vfs_implementation_saf_class;\n      jstring saf_stat_string;\n      jclass saf_stat_class;\n      jstring saf_directory_string;\n      jclass saf_directory_class;\n\n      {\n         jclass activity_class;\n         jclass class_loader_class;\n         jmethodID get_class_loader_method;\n         activity_class = (*env)->GetObjectClass(env, activity_object);\n         if ((*env)->ExceptionOccurred(env)) goto error;\n         get_class_loader_method = (*env)->GetMethodID(env, activity_class, \"getClassLoader\", \"()Ljava/lang/ClassLoader;\");\n         if ((*env)->ExceptionOccurred(env)) goto error;\n         class_loader_object = (*env)->CallObjectMethod(env, activity_object, get_class_loader_method);\n         if ((*env)->ExceptionOccurred(env)) goto error;\n         class_loader_class = (*env)->FindClass(env, \"java/lang/ClassLoader\");\n         if ((*env)->ExceptionOccurred(env)) goto error;\n         load_class_method = (*env)->GetMethodID(env, class_loader_class, \"loadClass\", \"(Ljava/lang/String;)Ljava/lang/Class;\");\n         if ((*env)->ExceptionOccurred(env)) goto error;\n      }\n\n      vfs_implementation_saf_string = (*env)->NewStringUTF(env, \"com.libretro.common.vfs.VfsImplementationSaf\");\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      vfs_implementation_saf_class = (jclass)(*env)->CallObjectMethod(env, class_loader_object, load_class_method, vfs_implementation_saf_string);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      vfs_implementation_saf_class = (jclass)(*env)->NewGlobalRef(env, vfs_implementation_saf_class);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      vfs_saf_vfs_implementation_saf_class = vfs_implementation_saf_class;\n\n      saf_stat_string = (*env)->NewStringUTF(env, \"com.libretro.common.vfs.VfsImplementationSaf$SafStat\");\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      saf_stat_class = (jclass)(*env)->CallObjectMethod(env, class_loader_object, load_class_method, saf_stat_string);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      saf_stat_class = (jclass)(*env)->NewGlobalRef(env, saf_stat_class);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      vfs_saf_saf_stat_class = saf_stat_class;\n\n      saf_directory_string = (*env)->NewStringUTF(env, \"com.libretro.common.vfs.VfsImplementationSaf$SafDirectory\");\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      saf_directory_class = (jclass)(*env)->CallObjectMethod(env, class_loader_object, load_class_method, saf_directory_string);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      saf_directory_class = (jclass)(*env)->NewGlobalRef(env, saf_directory_class);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      vfs_saf_saf_directory_class = saf_directory_class;\n   }\n\n   vfs_saf_open_saf_file_method = (*env)->GetStaticMethodID(env, vfs_saf_vfs_implementation_saf_class, \"openSafFile\", \"(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;ZZZ)I\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_remove_saf_file_method = (*env)->GetStaticMethodID(env, vfs_saf_vfs_implementation_saf_class, \"removeSafFile\", \"(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;)Z\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_stat_init_method = (*env)->GetMethodID(env, vfs_saf_saf_stat_class, \"<init>\", \"(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;Z)V\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_stat_get_is_open_method = (*env)->GetMethodID(env, vfs_saf_saf_stat_class, \"getIsOpen\", \"()Z\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_stat_get_is_directory_method = (*env)->GetMethodID(env, vfs_saf_saf_stat_class, \"getIsDirectory\", \"()Z\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_stat_get_size_method = (*env)->GetMethodID(env, vfs_saf_saf_stat_class, \"getSize\", \"()J\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_mkdir_saf_method = (*env)->GetStaticMethodID(env, vfs_saf_vfs_implementation_saf_class, \"mkdirSaf\", \"(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;)I\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_directory_init_method = (*env)->GetMethodID(env, vfs_saf_saf_directory_class, \"<init>\", \"(Landroid/content/ContentResolver;Ljava/lang/String;Ljava/lang/String;)V\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_directory_close_method = (*env)->GetMethodID(env, vfs_saf_saf_directory_class, \"close\", \"()V\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_directory_readdir_method = (*env)->GetMethodID(env, vfs_saf_saf_directory_class, \"readdir\", \"()Z\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_directory_get_dirent_name_method = (*env)->GetMethodID(env, vfs_saf_saf_directory_class, \"getDirentName\", \"()Ljava/lang/String;\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   vfs_saf_saf_directory_get_dirent_is_directory_method = (*env)->GetMethodID(env, vfs_saf_saf_directory_class, \"getDirentIsDirectory\", \"()Z\");\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   /*\n    * ContentResolver vfs_saf_content_resolver_object = activity_object.getContentResolver();\n    */\n   {\n      jclass activity_class;\n      jmethodID content_resolver_method;\n      jobject content_resolver_object;\n      activity_class = (*env)->GetObjectClass(env, activity_object);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      content_resolver_method = (*env)->GetMethodID(env, activity_class, \"getContentResolver\", \"()Landroid/content/ContentResolver;\");\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      content_resolver_object = (*env)->CallObjectMethod(env, activity_object, content_resolver_method);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      content_resolver_object = (*env)->NewGlobalRef(env, content_resolver_object);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      vfs_saf_content_resolver_object = content_resolver_object;\n   }\n\n   vfs_saf_get_jni_env = get_jni_env;\n   (*env)->PopLocalFrame(env, NULL);\n   return true;\n\nerror:\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   if (vfs_saf_content_resolver_object != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, vfs_saf_content_resolver_object);\n      vfs_saf_content_resolver_object = NULL;\n      if ((*env)->ExceptionOccurred(env)) goto error;\n   }\n   if (vfs_saf_vfs_implementation_saf_class != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, vfs_saf_vfs_implementation_saf_class);\n      vfs_saf_vfs_implementation_saf_class = NULL;\n      if ((*env)->ExceptionOccurred(env)) goto error;\n   }\n   if (vfs_saf_saf_stat_class != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, vfs_saf_saf_stat_class);\n      vfs_saf_saf_stat_class = NULL;\n      if ((*env)->ExceptionOccurred(env)) goto error;\n   }\n   if (vfs_saf_saf_directory_class != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, vfs_saf_saf_directory_class);\n      vfs_saf_saf_directory_class = NULL;\n      if ((*env)->ExceptionOccurred(env)) goto error;\n   }\n   (*env)->PopLocalFrame(env, NULL);\n   return false;\n}\n\nbool retro_vfs_deinit_saf(void)\n{\n   JNIEnv *env;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return false;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return false;\n\n   (*env)->DeleteGlobalRef(env, vfs_saf_content_resolver_object);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n   }\n\n   (*env)->DeleteGlobalRef(env, vfs_saf_vfs_implementation_saf_class);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n   }\n\n   (*env)->DeleteGlobalRef(env, vfs_saf_saf_stat_class);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n   }\n\n   (*env)->DeleteGlobalRef(env, vfs_saf_saf_directory_class);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n   }\n\n   vfs_saf_get_jni_env = NULL;\n   return true;\n}\n\nbool retro_vfs_path_split_saf(struct libretro_vfs_implementation_saf_path_split_result *out, const char *serialized_path)\n{\n   char *tree;\n   char *tree_ptr;\n   char *path;\n\n   out->tree = NULL;\n   out->path = NULL;\n\n   if (strncmp(serialized_path, \"saf://\", sizeof \"saf://\" - 1) != 0)\n      return false;\n   serialized_path += sizeof \"saf://\" - 1;\n\n   tree = (char *)malloc(strlen(serialized_path) + 1);\n   if (tree == NULL)\n      return false;\n   tree_ptr = tree;\n\n   while (*serialized_path != '/' && *serialized_path != 0)\n   {\n      if (\n         *serialized_path == '%'\n            && (\n               (serialized_path[1] >= '0' && serialized_path[1] <= '9')\n                  || (serialized_path[1] >= 'A' && serialized_path[1] <= 'F')\n                  || (serialized_path[1] >= 'a' && serialized_path[1] <= 'f')\n            ) && (\n               (serialized_path[2] >= '0' && serialized_path[2] <= '9')\n                  || (serialized_path[2] >= 'A' && serialized_path[2] <= 'F')\n                  || (serialized_path[2] >= 'a' && serialized_path[2] <= 'f')\n            ) && (\n               serialized_path[1] != '0'\n                  || serialized_path[2] != '0'\n            )\n      )\n      {\n         if (serialized_path[1] >= '0' && serialized_path[1] <= '9')\n            *tree_ptr = (serialized_path[1] - '0') << 4;\n         else if (serialized_path[1] >= 'A' && serialized_path[1] <= 'F')\n            *tree_ptr = (serialized_path[1] - ('A' - 10)) << 4;\n         else\n            *tree_ptr = (serialized_path[1] - ('a' - 10)) << 4;\n         if (serialized_path[2] >= '0' && serialized_path[2] <= '9')\n            *tree_ptr |= serialized_path[2] - '0';\n         else if (serialized_path[2] >= 'A' && serialized_path[2] <= 'F')\n            *tree_ptr |= serialized_path[2] - ('A' - 10);\n         else\n            *tree_ptr |= serialized_path[2] - ('a' - 10);\n         ++tree_ptr;\n         serialized_path += 3;\n      }\n      else\n         *tree_ptr++ = *serialized_path++;\n   }\n\n   *tree_ptr = 0;\n\n   if (*serialized_path != 0)\n      ++serialized_path;\n\n   path = strdup(serialized_path);\n   if (path == NULL)\n   {\n      free(tree);\n      return false;\n   }\n\n   out->tree = tree;\n   out->path = path;\n   return true;\n}\n\nchar *retro_vfs_path_join_saf(const char *tree, const char *path)\n{\n   size_t tree_length = strlen(tree);\n   size_t path_length = strlen(path);\n   char *serialized_path;\n   char *serialized_path_ptr;\n\n   if (3 * tree_length < tree_length || 3 * tree_length + path_length < 3 * tree_length || 3 * tree_length + path_length + (sizeof \"saf://\" - 1) + 2 < 3 * tree_length + path_length)\n      return NULL;\n   serialized_path = (char *)malloc(3 * tree_length + path_length + (sizeof \"saf://\" - 1) + 2);\n   if (serialized_path == NULL)\n      return NULL;\n   serialized_path_ptr = serialized_path;\n\n   memcpy(serialized_path_ptr, \"saf://\", sizeof \"saf://\" - 1);\n   serialized_path_ptr += sizeof \"saf://\" - 1;\n\n   for (; *tree != 0; ++tree)\n      switch (*tree)\n      {\n         case '%':\n            memcpy(serialized_path_ptr, \"%25\", 3);\n            serialized_path_ptr += 3;\n            break;\n         case '/':\n            memcpy(serialized_path_ptr, \"%2F\", 3);\n            serialized_path_ptr += 3;\n            break;\n         default:\n            *serialized_path_ptr++ = *tree;\n            break;\n      }\n\n   if (*path != 0)\n   {\n      *serialized_path_ptr++ = '/';\n      *serialized_path_ptr = 0;\n      strcpy(serialized_path_ptr, path);\n   }\n   else\n      *serialized_path_ptr = 0;\n\n   return serialized_path;\n}\n\nbool retro_vfs_path_split_content_saf(struct libretro_vfs_implementation_saf_path_split_result *out, const char *content_uri)\n{\n   const char *ptr;\n   char *tree;\n   char *path;\n\n   if (strncmp(content_uri, \"content://\", sizeof \"content://\" - 1) != 0)\n      return false;\n\n   /* Advance ptr to the first forward slash in the content URI after the content:// */\n   for (ptr = content_uri + (sizeof \"content://\" - 1); *ptr != 0 && *ptr != '/'; ++ptr);\n   if (*ptr == 0)\n      return false;\n\n   /* If the content URI does not contain a tree component, consider the entire content URI to be the tree and the path to be the root */\n   if (strncmp(ptr, \"/tree/\", sizeof \"/tree/\" - 1) != 0)\n   {\n      if ((tree = strdup(content_uri)) == NULL)\n         return false;\n      if ((path = strdup(\"/\")) == NULL)\n      {\n         free(tree);\n         return false;\n      }\n   }\n   else\n   {\n      size_t tree_size;\n\n      /* Advance ptr to the next forward slash after /tree/ */\n      for (tree_size = 0, ptr += sizeof \"/tree/\" - 1; *ptr != 0 && *ptr != '/'; ++tree_size)\n      {\n         if (\n            *ptr == '%'\n               && (\n                  (ptr[1] >= '0' && ptr[1] <= '9')\n                     || (ptr[1] >= 'A' && ptr[1] <= 'F')\n                     || (ptr[1] >= 'a' && ptr[1] <= 'f')\n               ) && (\n                  (ptr[2] >= '0' && ptr[2] <= '9')\n                     || (ptr[2] >= 'A' && ptr[2] <= 'F')\n                     || (ptr[2] >= 'a' && ptr[2] <= 'f')\n               ) && (\n                  ptr[1] != '0'\n                     || ptr[2] != '0'\n               )\n         )\n            ptr += 3;\n         else\n            ++ptr;\n      }\n\n      /* If the content URI does not also contain a document component, consider the entire content URI to be the tree and the path to be the root */\n      if (*ptr == 0 || strncmp(ptr, \"/document/\", sizeof \"/document/\" - 1) != 0)\n      {\n         if ((tree = strdup(content_uri)) == NULL)\n            return false;\n         if ((path = strdup(\"/\")) == NULL)\n         {\n            free(tree);\n            return false;\n         }\n      }\n      /* Otherwise, isolate the document component of the content URI as the path and use the rest of the content URI as the tree */\n      else\n      {\n         char *path_ptr;\n         size_t path_size;\n\n         if ((tree = (char *)malloc(ptr - content_uri + 1)) == NULL)\n            return false;\n         memcpy(tree, content_uri, ptr - content_uri);\n         tree[ptr - content_uri] = 0;\n\n         content_uri = ptr + (sizeof \"/document/\" - 1);\n         for (path_size = 0, ptr = content_uri; *ptr != 0 && *ptr != '/'; ++path_size)\n         {\n            if (\n               *ptr == '%'\n                  && (\n                     (ptr[1] >= '0' && ptr[1] <= '9')\n                        || (ptr[1] >= 'A' && ptr[1] <= 'F')\n                        || (ptr[1] >= 'a' && ptr[1] <= 'f')\n                  ) && (\n                     (ptr[2] >= '0' && ptr[2] <= '9')\n                        || (ptr[2] >= 'A' && ptr[2] <= 'F')\n                        || (ptr[2] >= 'a' && ptr[2] <= 'f')\n                  ) && (\n                     ptr[1] != '0'\n                        || ptr[2] != '0'\n                  )\n            )\n            {\n               ptr += 3;\n               if (path_size < tree_size)\n                  content_uri += 3;\n            }\n            else\n            {\n               ++ptr;\n               if (path_size < tree_size)\n                  ++content_uri;\n            }\n         }\n         if (path_size <= tree_size)\n            path_size = 0;\n         else\n            path_size -= tree_size;\n         if (*content_uri != '%' || content_uri[1] != '2' || (content_uri[2] != 'F' && content_uri[2] != 'f'))\n            ++path_size;\n         if ((path_ptr = path = (char *)malloc(path_size + 1)) == NULL)\n         {\n            free(tree);\n            return false;\n         }\n         if (*content_uri != '%' || content_uri[1] != '2' || (content_uri[2] != 'F' && content_uri[2] != 'f'))\n            *path_ptr++ = '/';\n         for (ptr = content_uri; *ptr != 0 && *ptr != '/';)\n         {\n            if (\n               *ptr == '%'\n                  && (\n                     (ptr[1] >= '0' && ptr[1] <= '9')\n                        || (ptr[1] >= 'A' && ptr[1] <= 'F')\n                        || (ptr[1] >= 'a' && ptr[1] <= 'f')\n                  ) && (\n                     (ptr[2] >= '0' && ptr[2] <= '9')\n                        || (ptr[2] >= 'A' && ptr[2] <= 'F')\n                        || (ptr[2] >= 'a' && ptr[2] <= 'f')\n                  ) && (\n                     ptr[1] != '0'\n                        || ptr[2] != '0'\n                  )\n            )\n            {\n               if (ptr[1] >= '0' && ptr[1] <= '9')\n                  *path_ptr = (ptr[1] - '0') << 4;\n               else if (ptr[1] >= 'A' && ptr[1] <= 'F')\n                  *path_ptr = (ptr[1] - ('A' - 10)) << 4;\n               else\n                  *path_ptr = (ptr[1] - ('a' - 10)) << 4;\n               if (ptr[2] >= '0' && ptr[2] <= '9')\n                  *path_ptr |= ptr[2] - '0';\n               else if (ptr[2] >= 'A' && ptr[2] <= 'F')\n                  *path_ptr |= ptr[2] - ('A' - 10);\n               else\n                  *path_ptr |= ptr[2] - ('a' - 10);\n               ++path_ptr;\n               ptr += 3;\n            }\n            else\n               *path_ptr++ = *ptr++;\n         }\n         *path_ptr = 0;\n      }\n   }\n\n   out->tree = tree;\n   out->path = path;\n   return true;\n}\n\nint retro_vfs_file_open_saf(const char *tree, const char *path, unsigned mode)\n{\n   JNIEnv *env;\n   jstring tree_object;\n   jstring path_object;\n   int fd;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return -1;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return -1;\n\n   (*env)->PushLocalFrame(env, 2);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return -1;\n   }\n\n   tree_object = (*env)->NewStringUTF(env, tree);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   path_object = (*env)->NewStringUTF(env, path);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   fd = (*env)->CallStaticIntMethod(env, vfs_saf_vfs_implementation_saf_class, vfs_saf_open_saf_file_method, vfs_saf_content_resolver_object, tree_object, path_object, !!(mode & RETRO_VFS_FILE_ACCESS_READ), !!(mode & RETRO_VFS_FILE_ACCESS_WRITE), !(mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING));\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   (*env)->PopLocalFrame(env, NULL);\n   return fd;\n\nerror:\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   (*env)->PopLocalFrame(env, NULL);\n   return -1;\n}\n\nint retro_vfs_file_remove_saf(const char *tree, const char *path)\n{\n   JNIEnv *env;\n   jstring tree_object;\n   jstring path_object;\n   bool ret;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return -1;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return -1;\n\n   (*env)->PushLocalFrame(env, 2);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return -1;\n   }\n\n   tree_object = (*env)->NewStringUTF(env, tree);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   path_object = (*env)->NewStringUTF(env, path);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   ret = (*env)->CallStaticBooleanMethod(env, vfs_saf_vfs_implementation_saf_class, vfs_saf_remove_saf_file_method, vfs_saf_content_resolver_object, tree_object, path_object);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   (*env)->PopLocalFrame(env, NULL);\n   return ret ? 0 : -1;\n\nerror:\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   (*env)->PopLocalFrame(env, NULL);\n   return -1;\n}\n\nint retro_vfs_file_rename_saf(const char *old_tree, const char *old_path, const char *new_tree, const char *new_path)\n{\n   return -1;\n}\n\nint retro_vfs_stat_saf(const char *tree, const char *path, int64_t *size)\n{\n   JNIEnv *env;\n   jstring tree_object;\n   jstring path_object;\n   jobject saf_stat;\n   int64_t saf_stat_size;\n   bool saf_stat_is_directory;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return 0;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return 0;\n\n   (*env)->PushLocalFrame(env, 3);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return 0;\n   }\n\n   tree_object = (*env)->NewStringUTF(env, tree);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   path_object = (*env)->NewStringUTF(env, path);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   saf_stat = (*env)->NewObject(env, vfs_saf_saf_stat_class, vfs_saf_saf_stat_init_method, vfs_saf_content_resolver_object, tree_object, path_object, size != NULL);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   if (size != NULL)\n   {\n      saf_stat_size = (*env)->CallLongMethod(env, saf_stat, vfs_saf_saf_stat_get_size_method);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      if (saf_stat_size < 0)\n      {\n         (*env)->PopLocalFrame(env, NULL);\n         return 0;\n      }\n   }\n   else\n   {\n      bool saf_stat_is_open = (*env)->CallBooleanMethod(env, saf_stat, vfs_saf_saf_stat_get_is_open_method);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      if (!saf_stat_is_open)\n      {\n         (*env)->PopLocalFrame(env, NULL);\n         return 0;\n      }\n   }\n\n   saf_stat_is_directory = (*env)->CallBooleanMethod(env, saf_stat, vfs_saf_saf_stat_get_is_directory_method);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   if (size != NULL)\n      *size = saf_stat_size > INT64_MAX ? INT64_MAX : (int64_t)saf_stat_size;\n\n   (*env)->PopLocalFrame(env, NULL);\n   return saf_stat_is_directory ? RETRO_VFS_STAT_IS_VALID | RETRO_VFS_STAT_IS_DIRECTORY : RETRO_VFS_STAT_IS_VALID;\n\nerror:\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   (*env)->PopLocalFrame(env, NULL);\n   return 0;\n}\n\nint retro_vfs_mkdir_saf(const char *tree, const char *dir)\n{\n   JNIEnv *env;\n   jstring tree_object;\n   jstring path_object;\n   int ret;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return -1;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return -1;\n\n   (*env)->PushLocalFrame(env, 2);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return -1;\n   }\n\n   tree_object = (*env)->NewStringUTF(env, tree);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   path_object = (*env)->NewStringUTF(env, dir);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   ret = (*env)->CallStaticIntMethod(env, vfs_saf_vfs_implementation_saf_class, vfs_saf_mkdir_saf_method, vfs_saf_content_resolver_object, tree_object, path_object);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   (*env)->PopLocalFrame(env, NULL);\n   return ret;\n\nerror:\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   (*env)->PopLocalFrame(env, NULL);\n   return -1;\n}\n\nlibretro_vfs_implementation_saf_dir *retro_vfs_opendir_saf(const char *tree, const char *dir, bool include_hidden)\n{\n   JNIEnv *env;\n   libretro_vfs_implementation_saf_dir *dirstream;\n   jstring tree_object;\n   jstring path_object;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return NULL;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return NULL;\n\n   dirstream = (libretro_vfs_implementation_saf_dir *)malloc(sizeof *dirstream);\n   if (dirstream == NULL)\n      return NULL;\n\n   (*env)->PushLocalFrame(env, 2);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      free(dirstream);\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return NULL;\n   }\n\n   tree_object = (*env)->NewStringUTF(env, tree);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   path_object = (*env)->NewStringUTF(env, dir);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   dirstream->directory_object = (*env)->NewObject(env, vfs_saf_saf_directory_class, vfs_saf_saf_directory_init_method, vfs_saf_content_resolver_object, tree_object, path_object);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   dirstream->directory_object = (*env)->NewGlobalRef(env, dirstream->directory_object);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   dirstream->dirent_name_object = NULL;\n   dirstream->dirent_name = NULL;\n   dirstream->dirent_is_dir = false;\n   (*env)->PopLocalFrame(env, NULL);\n   return dirstream;\n\nerror:\n   free(dirstream);\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   (*env)->PopLocalFrame(env, NULL);\n   return NULL;\n}\n\nbool retro_vfs_readdir_saf(libretro_vfs_implementation_saf_dir *dirstream)\n{\n   JNIEnv *env;\n   bool ret;\n   jobject dirent_name_object;\n   const char *dirent_name;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return false;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return false;\n\n   (*env)->PushLocalFrame(env, 1);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n      return false;\n   }\n\n   ret = (*env)->CallBooleanMethod(env, dirstream->directory_object, vfs_saf_saf_directory_readdir_method);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   if (dirstream->dirent_name != NULL)\n   {\n      (*env)->ReleaseStringUTFChars(env, dirstream->dirent_name_object, dirstream->dirent_name);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      dirstream->dirent_name = NULL;\n   }\n   if (dirstream->dirent_name_object != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, dirstream->dirent_name_object);\n      if ((*env)->ExceptionOccurred(env)) goto error;\n      dirstream->dirent_name_object = NULL;\n   }\n\n   if (!ret)\n   {\n      dirstream->dirent_is_dir = false;\n      (*env)->PopLocalFrame(env, NULL);\n      return false;\n   }\n\n   dirstream->dirent_is_dir = (*env)->CallBooleanMethod(env, dirstream->directory_object, vfs_saf_saf_directory_get_dirent_is_directory_method);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   dirent_name_object = (*env)->CallObjectMethod(env, dirstream->directory_object, vfs_saf_saf_directory_get_dirent_name_method);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n\n   dirent_name_object = (*env)->NewGlobalRef(env, dirent_name_object);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n   dirstream->dirent_name_object = dirent_name_object;\n\n   dirent_name = (*env)->GetStringUTFChars(env, (jstring)dirstream->dirent_name_object, NULL);\n   if ((*env)->ExceptionOccurred(env)) goto error;\n   dirstream->dirent_name = dirent_name;\n\n   (*env)->PopLocalFrame(env, NULL);\n   return true;\n\nerror:\n   (*env)->ExceptionDescribe(env);\n   (*env)->ExceptionClear(env);\n   if (dirstream->dirent_name != NULL)\n   {\n      (*env)->ReleaseStringUTFChars(env, dirstream->dirent_name_object, dirstream->dirent_name);\n      dirstream->dirent_name = NULL;\n      if ((*env)->ExceptionOccurred(env)) goto error;\n   }\n   if (dirstream->dirent_name_object != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, dirstream->dirent_name_object);\n      dirstream->dirent_name_object = NULL;\n      if ((*env)->ExceptionOccurred(env)) goto error;\n   }\n   dirstream->dirent_is_dir = false;\n   (*env)->PopLocalFrame(env, NULL);\n   return false;\n}\n\nconst char *retro_vfs_dirent_get_name_saf(libretro_vfs_implementation_saf_dir *dirstream)\n{\n   return dirstream->dirent_name;\n}\n\nbool retro_vfs_dirent_is_dir_saf(libretro_vfs_implementation_saf_dir *dirstream)\n{\n   return dirstream->dirent_is_dir;\n}\n\nint retro_vfs_closedir_saf(libretro_vfs_implementation_saf_dir *dirstream)\n{\n   JNIEnv *env;\n\n   if (dirstream == NULL)\n      return -1;\n\n   if (vfs_saf_get_jni_env == NULL)\n      return -1;\n   env = vfs_saf_get_jni_env();\n   if (env == NULL)\n      return -1;\n\n   if (dirstream->dirent_name != NULL)\n   {\n      (*env)->ReleaseStringUTFChars(env, dirstream->dirent_name_object, dirstream->dirent_name);\n      if ((*env)->ExceptionOccurred(env))\n      {\n         (*env)->ExceptionDescribe(env);\n         (*env)->ExceptionClear(env);\n      }\n   }\n   if (dirstream->dirent_name_object != NULL)\n   {\n      (*env)->DeleteGlobalRef(env, dirstream->dirent_name_object);\n      if ((*env)->ExceptionOccurred(env))\n      {\n         (*env)->ExceptionDescribe(env);\n         (*env)->ExceptionClear(env);\n      }\n   }\n\n   (*env)->CallVoidMethod(env, dirstream->directory_object, vfs_saf_saf_directory_close_method);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n   }\n\n   (*env)->DeleteGlobalRef(env, dirstream->directory_object);\n   if ((*env)->ExceptionOccurred(env))\n   {\n      (*env)->ExceptionDescribe(env);\n      (*env)->ExceptionClear(env);\n   }\n\n   free(dirstream);\n   return 0;\n}\n\n#endif\n"
  },
  {
    "path": "vfs/vfs_implementation_smb.c",
    "content": "/*  RetroArch - A frontend for libretro.\n *  Copyright (C) 2025 - The RetroArch Team\n *\n *  RetroArch is free software: you can redistribute it and/or modify it under the terms\n *  of the GNU General Public License as published by the Free Software Found-\n *  ation, either version 3 of the License, or (at your option) any later version.\n *\n *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;\n *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n *  PURPOSE.  See the GNU General Public License for more details.\n *\n *  You should have received a copy of the GNU General Public License along with RetroArch.\n *  If not, see <http://www.gnu.org/licenses/>.\n */\n\n#include <stdio.h>\n#include <stdint.h>  /* UINT32_MAX, INT64_MAX -- via compat shim on VC6 */\n#include <string.h>\n#include <errno.h>\n#include <time.h>\n#include <fcntl.h>\n#include <smb2/smb2.h>\n#include <smb2/libsmb2.h>\n#include <file/file_path.h>\n#include <retro_miscellaneous.h>\n#include <string/stdstring.h>\n#include <net/net_compat.h>\n#include <vfs/vfs_implementation.h>\n#include \"vfs_implementation_smb.h\"\n\n#define SMB_PREFIX \"smb://\"\n\nstatic struct smb2_context **smb_context_pool = NULL;\nstatic int next_context_index = 0;\nstatic bool smb_initialized = false;\nstatic int max_context_configured = 0;\nstatic const struct smb_settings *smb_cfg = NULL;\n\nstatic struct smb2_context *get_smb_context(void)\n{\n   int idx;\n\n   if (!smb_initialized)\n      return NULL;\n\n   if (!smb_context_pool || max_context_configured == 0)\n      return NULL;\n\n   if (next_context_index < 0 || next_context_index >= max_context_configured)\n      next_context_index = 0;\n\n   idx = next_context_index;\n   next_context_index = (next_context_index + 1) % max_context_configured;\n\n   if (!smb_context_pool[idx])\n      return NULL;\n\n   return smb_context_pool[idx];\n}\n\nvoid reset(unsigned num_contexts)\n{\n   for (unsigned i = 0; i < num_contexts; i++)\n   {\n      if(smb_context_pool[i])\n         smb2_destroy_context(smb_context_pool[i]);\n   }\n\n   free(smb_context_pool);\n   smb_context_pool = NULL;\n\n   smb_initialized = false;\n   next_context_index = 0;\n   max_context_configured = 0;\n}\n\nbool smb_init_cfg(const struct smb_settings *new_cfg)\n{\n   smb_cfg = new_cfg;\n   return true;\n}\n\n/* Initialize SMB context */\nstatic bool smb_init(void)\n{\n   char server[256];\n   char share[256];\n   char *username = NULL;\n   unsigned i;\n   int error_no = 0;\n\n   if (smb_initialized)\n      return true;\n\n   if (!network_init())\n      return false;\n\n   if (!smb_cfg || (!smb_cfg->server_address || !*smb_cfg->server_address))\n      return false;\n\n   unsigned max_smb_contexts = smb_cfg->num_contexts;\n   smb_context_pool = calloc(max_smb_contexts, sizeof(struct smb2_context *));\n\n   if (!smb_context_pool)\n      return false;\n\n   for (i = 0; i < max_smb_contexts; i++)\n   {\n      struct smb2_context *smb_context = smb2_init_context();\n\n      if (!smb_context)\n      {\n         reset(max_context_configured);\n         return false;\n      }\n\n      strlcpy(server, smb_cfg->server_address, sizeof(server));\n\n      /* Set credentials */\n      if (smb_cfg->username && *smb_cfg->username)\n      {\n         username = (char*)smb_cfg->username;\n         smb2_set_user(smb_context, username);\n      }\n\n      if (smb_cfg->password && *smb_cfg->password)\n         smb2_set_password(smb_context, smb_cfg->password);\n\n      if (smb_cfg->workgroup && *smb_cfg->workgroup)\n         smb2_set_domain(smb_context, smb_cfg->workgroup);\n\n      if (smb_cfg->share && *smb_cfg->share)\n         strlcpy(share, smb_cfg->share, sizeof(share));\n      else\n         share[0] = '\\0';\n\n      /* set timeout */\n      smb2_set_timeout(smb_context, smb_cfg->timeout);\n\n      /* SMB2_SEC_ defines missing on system headers but provided with latest libsmb2 */\n      switch(smb_cfg->auth_mode)\n      {\n         case RETRO_SMB2_SEC_NTLMSSP:\n            smb2_set_security_mode(smb_context, RETRO_SMB2_SEC_NTLMSSP);\n            smb2_set_authentication(smb_context, RETRO_SMB2_SEC_NTLMSSP);\n            break;\n         case RETRO_SMB2_SEC_KRB5:\n            smb2_set_security_mode(smb_context, RETRO_SMB2_SEC_KRB5);\n            smb2_set_authentication(smb_context, RETRO_SMB2_SEC_KRB5);\n            break;\n         case RETRO_SMB2_SEC_UNDEFINED:\n         default:\n            /* Only probe auth mode on the first context */\n            if (i == 0)\n            {\n               /* first try SMB2_SEC_KRB5 */\n               smb2_set_security_mode(smb_context, RETRO_SMB2_SEC_KRB5);\n               smb2_set_authentication(smb_context, RETRO_SMB2_SEC_KRB5);\n\n               if (smb2_connect_share(smb_context, server, share, username) == 0)\n               {\n                  /* KRB5 worked — use it for all remaining contexts */\n                  smb_context_pool[i] = smb_context;\n                  max_context_configured = i + 1;\n                  continue;\n               }\n\n               /* reset to we can use it again */\n               smb2_destroy_context(smb_context);\n               smb_context = smb2_init_context();\n\n               if (!smb_context)\n               {\n                  reset(max_context_configured);\n                  return false;\n               }\n\n               smb2_set_user(smb_context, username);\n               if (smb_cfg->password && *smb_cfg->password)\n                  smb2_set_password(smb_context, smb_cfg->password);\n               if (smb_cfg->workgroup && *smb_cfg->workgroup)\n                  smb2_set_domain(smb_context, smb_cfg->workgroup);\n               smb2_set_timeout(smb_context, smb_cfg->timeout);\n            }\n\n            /* if that fails, try SMB2_SEC_KRB5 in fallthrough */\n            smb2_set_security_mode(smb_context, RETRO_SMB2_SEC_NTLMSSP);\n            smb2_set_authentication(smb_context, RETRO_SMB2_SEC_NTLMSSP);\n            break;\n      }\n\n      /* Connect to share */\n      if ((error_no = smb2_connect_share(smb_context, server, share, username)) < 0)\n      {\n         smb2_destroy_context(smb_context);\n         reset(max_context_configured);\n         return false;\n      }\n\n      smb_context_pool[i] = smb_context;\n      max_context_configured = i + 1;\n   }\n\n   smb_initialized = true;\n\n   return true;\n}\n\nvoid smb_close_context(int index)\n{\n   if (index < 0 || index >= max_context_configured)\n      return;\n\n   if (smb_context_pool[index])\n   {\n      smb2_disconnect_share(smb_context_pool[index]);\n      smb2_destroy_context(smb_context_pool[index]);\n      smb_context_pool[index] = NULL;\n   }\n}\n\n/* Shutdown SMB context - called on exit */\nvoid smb_shutdown(void)\n{\n   int i;\n\n   if(!smb_initialized || max_context_configured == 0)\n      return;\n\n   for (i = 0; i < max_context_configured; i++)\n      smb_close_context(i);\n\n   reset(max_context_configured);\n}\n\n/* Build full SMB path from settings */\nstatic bool smb_build_path(char *dest, size_t dest_size, const char *relative_path)\n{\n   char temp_path[PATH_MAX_LENGTH];\n   const char *p;\n\n   /* If already has smb:// prefix, extract just the path component */\n   if (string_starts_with(relative_path, SMB_PREFIX))\n   {\n      p = relative_path + strlen(SMB_PREFIX);\n      /* Skip server */\n      while (*p && *p != '/')\n         p++;\n      if (*p == '/')\n         p++;\n      /* Skip share */\n      while (*p && *p != '/')\n         p++;\n\n      strlcpy(dest, p, dest_size);\n      return true;\n   }\n\n   /* Build path from settings */\n   temp_path[0] = '\\0';\n\n   /* Add base folder if specified */\n   if (smb_cfg->subdir && *smb_cfg->subdir)\n   {\n      strlcpy(temp_path, smb_cfg->subdir, sizeof(temp_path));\n      if (temp_path[0] != '\\0' && temp_path[strlen(temp_path) - 1] != '/')\n         strlcat(temp_path, \"/\", sizeof(temp_path));\n   }\n\n   /* Add relative path if provided */\n   if (relative_path && relative_path[0])\n   {\n      if (relative_path[0] == '/')\n         relative_path++;\n      strlcat(temp_path, relative_path, sizeof(temp_path));\n   }\n\n   strlcpy(dest, temp_path, dest_size);\n\n   return true;\n}\n\nbool retro_vfs_file_open_smb(libretro_vfs_implementation_file *stream,\n   const char *path, unsigned mode, unsigned hints)\n{\n   char full_path[PATH_MAX_LENGTH];\n   struct smb2fh *fh;\n   int flags = 0;\n   struct smb2_context *smb_context;\n\n   if (!stream)\n      return false;\n\n   /* reset file handle */\n   stream->smb_fh = (intptr_t)0;\n   stream->smb_ctx = (intptr_t)0;\n\n   if (!smb_init())\n      return false;\n\n   smb_context = get_smb_context();\n   if (!smb_context)\n      return false;\n\n   if (!smb_build_path(full_path, sizeof(full_path), path))\n      return false;\n\n   /* Strip leading slash ONLY for non-empty subpaths */\n   if (full_path[0] == '/' && full_path[1] != '\\0')\n      memmove(full_path, full_path + 1, strlen(full_path));\n\n   /* Do not treat empty string as a file path */\n   if (full_path[0] == '\\0')\n      return false;\n\n   /* Convert mode to SMB flags safely */\n   if (mode & RETRO_VFS_FILE_ACCESS_READ)\n   {\n      if (mode & RETRO_VFS_FILE_ACCESS_WRITE)\n         flags = O_RDWR;\n      else\n         flags = O_RDONLY;\n   }\n   else if (mode & RETRO_VFS_FILE_ACCESS_WRITE)\n   {\n      flags = O_WRONLY;\n   }\n\n   if ((mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) &&\n       (mode & RETRO_VFS_FILE_ACCESS_WRITE))\n      flags |= O_CREAT;\n\n   fh = smb2_open(smb_context, full_path, flags);\n   if (!fh)\n      return false;\n\n   stream->smb_fh = (intptr_t)(uintptr_t)fh;\n   stream->smb_ctx = (intptr_t)(uintptr_t)smb_context;\n   stream->scheme = VFS_SCHEME_SMB; /* ensure SMB dispatch on IO calls */\n   return true;\n}\n\nint64_t retro_vfs_file_read_smb(libretro_vfs_implementation_file *stream,\n   void *s, uint64_t len)\n{\n   int ret;\n   struct smb2_context *ctx;\n\n   if (!smb_initialized || !stream || stream->smb_fh < 0)\n      return -1;\n\n   ctx = (struct smb2_context *)(void *)(uintptr_t)stream->smb_ctx;\n   if (!ctx)\n       return -1;\n\n   /* smb2_read takes uint32_t count; passing a uint64_t len that\n    * exceeds UINT32_MAX was silently truncated pre-patch.  Cap at\n    * UINT32_MAX so the caller gets back the (partial) byte count\n    * and knows to loop for more.  This matches fread-style\n    * short-read semantics already observed by VFS consumers. */\n   if (len > (uint64_t)UINT32_MAX)\n      len = UINT32_MAX;\n\n   ret = smb2_read(ctx, (struct smb2fh *)(intptr_t)stream->smb_fh, s, (uint32_t)len);\n\n   return ret;\n}\n\nint64_t retro_vfs_file_write_smb(libretro_vfs_implementation_file *stream,\n   const void *s, uint64_t len)\n{\n   int ret;\n   struct smb2_context *ctx;\n\n   if (!smb_initialized || !stream || stream->smb_fh < 0)\n      return -1;\n\n   ctx = (struct smb2_context *)(void *)(uintptr_t)stream->smb_ctx;\n   if (!ctx)\n       return -1;\n\n   /* smb2_write takes uint32_t count; see retro_vfs_file_read_smb\n    * for the rationale.  Cap at UINT32_MAX and let the caller\n    * re-issue for remaining bytes. */\n   if (len > (uint64_t)UINT32_MAX)\n      len = UINT32_MAX;\n\n   ret = smb2_write(ctx, (struct smb2fh *)(intptr_t)stream->smb_fh, (void*)s, (uint32_t)len);\n\n   return ret;\n}\n\nint64_t retro_vfs_file_seek_smb(libretro_vfs_implementation_file *stream,\n   int64_t offset, int whence)\n{\n   uint64_t newpos = 0;\n   struct smb2fh *fh;\n   struct smb2_context *ctx;\n   int64_t ret;\n\n   if (!smb_initialized || !stream || !stream->smb_ctx)\n      return -1;\n\n   /* fd holds the pointer returned by smb2_open(); */\n   if (stream->smb_fh == 0 || stream->smb_fh == (intptr_t)-1)\n      return -1;\n\n   /* Reconstruct the exact pointer safely */\n   fh = (struct smb2fh *)(void *)(uintptr_t)stream->smb_fh;\n   if (!fh)\n      return -1;\n\n   ctx = (struct smb2_context *)(void *)(uintptr_t)stream->smb_ctx;\n   if (!ctx)\n      return -1;\n\n   /* Only allow valid values */\n   if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END)\n      return -1;\n\n   /* libsmb2 returns status via ret, and the new offset via out param */\n   ret = smb2_lseek(ctx, fh, offset, whence, &newpos);\n   if (ret < 0)\n      return -1;\n\n   return (int64_t)newpos;\n}\n\n/* return the current byte offset in an open file */\nint64_t retro_vfs_file_tell_smb(libretro_vfs_implementation_file *stream)\n{\n   uint64_t cur = 0;\n   struct smb2fh *fh;\n   struct smb2_context *ctx;\n   int64_t ret;\n\n   if (!smb_initialized || !stream || !stream->smb_ctx)\n      return -1;\n\n   if (stream->smb_fh == 0 || stream->smb_fh == (intptr_t)-1)\n      return -1;\n\n   fh = (struct smb2fh *)(void *)(uintptr_t)stream->smb_fh;\n   if (!fh)\n      return -1;\n\n   ctx = (struct smb2_context *)(void *)(uintptr_t)stream->smb_ctx;\n   if (!ctx)\n      return -1;\n\n   ret = smb2_lseek(ctx, fh, 0, SEEK_CUR, &cur);\n   if (ret < 0)\n      return -1;\n\n   return (int64_t)cur;\n}\n\nint retro_vfs_file_close_smb(libretro_vfs_implementation_file *stream)\n{\n   int ret;\n   struct smb2_context *ctx;\n\n   /* during shutdown */\n   if (!smb_initialized)\n      return -1;\n\n   if (!stream || stream->smb_fh < 0)\n      return -1;\n\n   ctx = (struct smb2_context *)(void *)(uintptr_t)stream->smb_ctx;\n   if (!ctx)\n      return -1;\n\n   ret = smb2_close(ctx, (struct smb2fh *)(intptr_t)stream->smb_fh);\n\n   stream->smb_fh = (intptr_t)-1;\n   stream->smb_ctx = (intptr_t)0;\n\n   return ret;\n}\n\nsmb_dir_handle* retro_vfs_opendir_smb(const char *path, bool include_hidden)\n{\n   char full_path[PATH_MAX_LENGTH];\n   struct smb2dir *dir;\n   struct smb2_context *smb_context;\n   smb_dir_handle *handle;\n\n   (void)include_hidden;\n\n   if (!smb_init())\n      return NULL;\n\n   if (!smb_build_path(full_path, sizeof(full_path), path))\n      return NULL;\n\n   /* Root-of-share: bare \"/\" should become \"\" for libsmb2 opendir */\n   if (full_path[0] == '/' && full_path[1] == '\\0')\n      full_path[0] = '\\0';\n   /* Strip leading slash for non-root subpaths */\n   else if (full_path[0] == '/' && full_path[1] != '\\0')\n      memmove(full_path, full_path + 1, strlen(full_path));\n\n   smb_context = get_smb_context();\n   if (!smb_context)\n      return NULL;\n\n   dir = smb2_opendir(smb_context, full_path);\n   if (!dir)\n      return NULL;\n\n   handle = (smb_dir_handle*)malloc(sizeof(smb_dir_handle));\n   if (!handle)\n   {\n      smb2_closedir(smb_context, dir);\n      return NULL;\n   }\n\n   handle->ctx = smb_context;\n   handle->dir = dir;\n\n   return handle;\n}\n\nstruct smbc_dirent* retro_vfs_readdir_smb(smb_dir_handle* dh)\n{\n   struct smb2dirent *ent;\n   static struct smbc_dirent result;\n\n   if (!smb_initialized || !dh)\n      return NULL;\n\n   if (!dh->ctx || !dh->dir)\n      return NULL;\n\n   ent = smb2_readdir(dh->ctx, dh->dir);\n   if (!ent)\n      return NULL;\n\n   memset(&result, 0, sizeof(result));\n   strlcpy(result.name, ent->name ? ent->name : \"\", sizeof(result.name));\n\n   result.type = (ent->st.smb2_type == SMB2_TYPE_DIRECTORY) ? 1 : 0;\n   result.size = ent->st.smb2_size;\n\n   return &result;\n}\n\nint retro_vfs_closedir_smb(smb_dir_handle* dh)\n{\n   if (!smb_initialized || !dh)\n      return -1;\n\n   if (!dh->ctx || !dh->dir)\n      return -1;\n\n   smb2_closedir(dh->ctx, dh->dir);\n   free(dh);\n   return 0;\n}\n\nint retro_vfs_stat_smb(const char *path, int64_t *size)\n{\n   char rel_path[PATH_MAX_LENGTH];\n   struct smb2_stat_64 st;\n   struct smb2_context *smb_context;\n\n   if (!smb_init())\n      return 0;\n\n   if (!smb_build_path(rel_path, sizeof(rel_path), path))\n      return 0;\n\n   /* Root-of-share: normalize \"/\" to \"\" for libsmb2 */\n   if (rel_path[0] == '/' && rel_path[1] == '\\0')\n      rel_path[0] = '\\0';\n\n   /* Strip leading slash safely (preserve NULL terminator) */\n   if (rel_path[0] == '/' && rel_path[1] != '\\0')\n      memmove(rel_path, rel_path + 1, strlen(rel_path));\n\n   smb_context = get_smb_context();\n   if (!smb_context)\n      return 0;\n\n   if (smb2_stat(smb_context, rel_path, &st) < 0)\n      return 0;\n\n   /* smb2_size is uint64_t; *size is int64_t.  A naked cast on\n    * files > INT64_MAX (8 EiB) would produce a negative value\n    * that callers may interpret as a stat error.  Saturate to\n    * INT64_MAX -- unreachable in practice today, but the fix is\n    * cheap and keeps sign semantics sane. */\n   if (size)\n      *size = (st.smb2_size > (uint64_t)INT64_MAX)\n         ? INT64_MAX\n         : (int64_t)st.smb2_size;\n\n   return RETRO_VFS_STAT_IS_VALID |\n         (st.smb2_type == SMB2_TYPE_DIRECTORY ? RETRO_VFS_STAT_IS_DIRECTORY : 0);\n}\n\nint retro_vfs_file_error_smb(libretro_vfs_implementation_file *stream)\n{\n   struct smb2_context *ctx;\n   const char *err;\n\n   if (!smb_initialized)\n      return -1;\n\n   if (!stream || stream->smb_fh == 0 || stream->smb_fh == (intptr_t)-1)\n      return -1;\n\n   if (!stream->smb_ctx)\n      return -1;\n\n   ctx = (struct smb2_context *)(void *)(uintptr_t)stream->smb_ctx;\n   if (!ctx)\n      return -1;\n\n   err = smb2_get_error(ctx);\n   if (err && err[0] != '\\0')\n      return -1;\n\n   return 0;\n}\n"
  },
  {
    "path": "vfs/vfs_implementation_smb.h",
    "content": "#ifndef VFS_IMPLEMENTATION_SMB_H\n#define VFS_IMPLEMENTATION_SMB_H\n\n#include <stdint.h>\n#include <vfs/vfs.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* System headers may lack SMB2_SEC_ defines but\n * will clash with deps/libsmb2 if provided here\n */\n#define RETRO_SMB2_SEC_UNDEFINED 0\n#define RETRO_SMB2_SEC_NTLMSSP 1\n#define RETRO_SMB2_SEC_KRB5 2\n\nstruct smb_settings {\n   const char *server_address;\n   const char *share;\n   const char *username;\n   const char *password;\n   const char *workgroup;\n   unsigned    timeout;\n   unsigned    num_contexts;\n   unsigned    auth_mode;\n   const char *subdir;\n};\n\ntypedef struct smb_settings smb_settings_t;\n\nstruct smbc_dirent {\n   char name[256];\n   int  type;     /* file vs directory */\n   int64_t size;  /* file size */\n};\n\ntypedef struct {\n   struct smb2_context *ctx;\n   struct smb2dir *dir;\n} smb_dir_handle;\n\nbool smb_init_cfg(const struct smb_settings *new_cfg);\n\n/* File operations */\nbool    retro_vfs_file_open_smb(libretro_vfs_implementation_file *stream,\n        const char *path, unsigned mode, unsigned hints);\nint64_t retro_vfs_file_read_smb(libretro_vfs_implementation_file *stream,\n        void *s, uint64_t len);\nint64_t retro_vfs_file_write_smb(libretro_vfs_implementation_file *stream,\n        const void *s, uint64_t len);\nint64_t retro_vfs_file_seek_smb(libretro_vfs_implementation_file *stream,\n        int64_t offset, int whence);\nint64_t retro_vfs_file_tell_smb(libretro_vfs_implementation_file *stream);\nint     retro_vfs_file_close_smb(libretro_vfs_implementation_file *stream);\n\n/* Directory operations */\nsmb_dir_handle* retro_vfs_opendir_smb(const char *path, bool include_hidden);\nstruct smbc_dirent* retro_vfs_readdir_smb(smb_dir_handle* dh);\nint                 retro_vfs_closedir_smb(smb_dir_handle* dh);\n\n/* Stat */\nint retro_vfs_stat_smb(const char *path, int64_t *size);\n\n/* Errors */\nint retro_vfs_file_error_smb(libretro_vfs_implementation_file *stream);\n\n/* Context management */\nvoid smb_shutdown(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* VFS_IMPLEMENTATION_SMB_H */\n"
  },
  {
    "path": "vfs/vfs_implementation_uwp.cpp",
    "content": "/* Copyright  (C) 2018-2020 The RetroArch team\n*\n* ---------------------------------------------------------------------------------------\n* The following license statement only applies to this file (vfs_implementation_uwp.cpp).\n* ---------------------------------------------------------------------------------------\n*\n* Permission is hereby granted, free of charge,\n* to any person obtaining a copy of this software and associated documentation files (the \"Software\"),\n* to deal in the Software without restriction, including without limitation the rights to\n* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\n* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n*\n* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\n* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n#include <ppl.h>\n#include <ppltasks.h>\n#include <stdio.h>\n#include <wrl.h>\n#include <wrl/implements.h>\n#include <robuffer.h>\n#include <functional>\n#include <fileapifromapp.h>\n#include <AclAPI.h>\n#include <sddl.h>\n#include <io.h>\n#include <fcntl.h>\n\n#ifdef RARCH_INTERNAL\n#ifndef VFS_FRONTEND\n#define VFS_FRONTEND\n#endif\n#endif\n\n#include <vfs/vfs.h>\n#include <vfs/vfs_implementation.h>\n#include <libretro.h>\n#include <encodings/utf.h>\n#include <compat/strl.h>\n#include <retro_miscellaneous.h>\n#include <file/file_path.h>\n#include <retro_environment.h>\n#include <uwp/std_filesystem_compat.h>\n\n#ifdef HAVE_SMBCLIENT\n#include \"vfs_implementation_smb.h\"\n#endif\n\nnamespace\n{\n   /* UWP deals with paths containing / instead of\n    * \\ way worse than normal Windows */\n   /* and RetroArch may sometimes mix them\n    * (e.g. on archive extraction) */\n   static void windowsize_path(wchar_t* path)\n   {\n      if (path)\n      {\n         while (*path)\n         {\n            if (*path == '/')\n               *path = '\\\\';\n            ++path;\n         }\n      }\n   }\n}\n\n#define RFILE_HINT_UNBUFFERED (1 << 8)\n\nint retro_vfs_file_close_impl(libretro_vfs_implementation_file* stream)\n{\n    if (!stream)\n        return -1;\n\n#ifdef HAVE_SMBCLIENT\n    if (stream->scheme == VFS_SCHEME_SMB)\n        retro_vfs_file_close_smb(stream);\n#endif\n\n    if (stream->fp)\n        fclose(stream->fp);\n\n    if (stream->buf != NULL)\n    {\n        free(stream->buf);\n        stream->buf = NULL;\n    }\n    if (stream->orig_path)\n        free(stream->orig_path);\n\n    free(stream);\n\n    return 0;\n}\n\nint retro_vfs_file_error_impl(libretro_vfs_implementation_file* stream)\n{\n#ifdef HAVE_SMBCLIENT\n    if (stream->scheme == VFS_SCHEME_SMB)\n        return retro_vfs_file_error_smb(stream);\n#endif\n\n    return ferror(stream->fp);\n}\n\nint64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file* stream)\n{\n    if (stream)\n        return stream->size;\n    return 0;\n}\n\nint64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file* stream, int64_t length)\n{\n   if (stream && _chsize(_fileno(stream->fp), length) == 0)\n      return 0;\n   return -1;\n}\n\nint64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file* stream)\n{\n    if (!stream)\n        return -1;\n\n    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n    {\n#ifdef HAVE_SMBCLIENT\n        if (stream->scheme == VFS_SCHEME_SMB)\n           return retro_vfs_file_tell_smb(stream);\n#endif\n        return _ftelli64(stream->fp);\n    }\n    if (lseek(stream->fd, 0, SEEK_CUR) < 0)\n        return -1;\n\n    return 0;\n}\n\nint64_t retro_vfs_file_seek_internal(\n    libretro_vfs_implementation_file* stream,\n    int64_t offset, int whence)\n{\n    if (!stream)\n        return -1;\n\n    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n    {\n#ifdef HAVE_SMBCLIENT\n        if (stream->scheme == VFS_SCHEME_SMB)\n            return retro_vfs_file_seek_smb(stream, offset, whence);\n#endif\n        return _fseeki64(stream->fp, offset, whence);\n    }\n    if (lseek(stream->fd, (off_t)offset, whence) < 0)\n        return -1;\n\n    return 0;\n}\n\nint64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file* stream,\n    int64_t offset, int seek_position)\n{\n    return retro_vfs_file_seek_internal(stream, offset, seek_position);\n}\n\nint64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file* stream,\n    void* s, uint64_t len)\n{\n    if (!stream)\n        return -1;\n\n#ifdef HAVE_SMBCLIENT\n    if (stream->scheme == VFS_SCHEME_SMB)\n        return retro_vfs_file_read_smb(stream, s, len);\n#endif\n\n    if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)\n        return -1;\n\n    if (stream->fh != INVALID_HANDLE_VALUE)\n    {\n        DWORD _bytes_read;\n        ReadFile(stream->fh, (char*)s, len, &_bytes_read, NULL);\n        return (int64_t)_bytes_read;\n    }\n\n    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n        return fread(s, 1, (size_t)len, stream->fp);\n    return read(stream->fd, s, (size_t)len);\n}\n\n\nint64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file* stream, const void* s, uint64_t len)\n{\n    if (!stream)\n        return -1;\n\n#ifdef HAVE_SMBCLIENT\n    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 &&\n        stream->scheme == VFS_SCHEME_SMB)\n    {\n        int64_t pos = 0;\n        ssize_t ret = -1;\n\n        pos = retro_vfs_file_tell_smb(stream);\n        ret = retro_vfs_file_write_smb(stream, s, len);\n        if (ret != -1 && pos + ret > stream->size)\n            stream->size = pos + ret;\n        return ret;\n    }\n#endif\n\n    if ((!stream->fp && stream->fh == INVALID_HANDLE_VALUE) || !s)\n        return -1;\n\n    if (stream->fh != INVALID_HANDLE_VALUE)\n    {\n        DWORD bytes_written;\n        WriteFile(stream->fh, s, len, &bytes_written, NULL);\n        return (int64_t)bytes_written;\n    }\n\n    if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)\n        return fwrite(s, 1, (size_t)len, stream->fp);\n\n    return write(stream->fd, s, (size_t)len);\n}\n\nint retro_vfs_file_flush_impl(libretro_vfs_implementation_file* stream)\n{\n    if (stream && fflush(stream->fp) == 0)\n       return 0;\n    return -1;\n}\n\nint retro_vfs_file_remove_impl(const char *path)\n{\n   BOOL ret;\n   wchar_t *path_wide;\n\n   if (!path || !*path)\n      return -1;\n\n   path_wide = utf8_to_utf16_string_alloc(path);\n   windowsize_path(path_wide);\n\n   /* Try Win32 first, this should work in AppData */\n   ret = DeleteFileFromAppW(path_wide);\n   free(path_wide);\n   if (ret)\n      return 0;\n\n   return -1;\n}\n\nlibretro_vfs_implementation_file* retro_vfs_file_open_impl(\n    const char* path, unsigned mode, unsigned hints)\n{\n    HANDLE file_handle;\n    std::wstring path_wstring;\n    DWORD desireAccess;\n    DWORD creationDisposition;\n    wchar_t                       *path_wide = NULL;\n    int                                flags = 0;\n    const char                     *mode_str = NULL;\n    libretro_vfs_implementation_file* stream =\n        (libretro_vfs_implementation_file*)\n        malloc(sizeof(*stream));\n\n    if (!stream)\n        return NULL;\n\n    stream->fd        = 0;\n    stream->hints     = hints;\n    stream->size      = 0;\n    stream->buf       = NULL;\n    stream->fp        = NULL;\n    stream->fh        = 0;\n    stream->orig_path = NULL;\n    stream->mappos    = 0;\n    stream->mapsize   = 0;\n    stream->mapped    = NULL;\n    stream->scheme    = VFS_SCHEME_NONE;\n#ifdef HAVE_SMBCLIENT\n    stream->smb_fh    = 0;\n#endif\n\n#ifdef VFS_FRONTEND\n   if (     path\n         && path[0] == 'v'\n         && path[1] == 'f'\n         && path[2] == 's'\n         && path[3] == 'o'\n         && path[4] == 'n'\n         && path[5] == 'l'\n         && path[6] == 'y'\n         && path[7] == ':'\n         && path[8] == '/'\n         && path[9] == '/')\n         path             += sizeof(\"vfsonly://\")-1;\n#endif\n\n#ifdef HAVE_SMBCLIENT\n   if (     path\n         && path[0] == 's'\n         && path[1] == 'm'\n         && path[2] == 'b'\n         && path[3] == ':'\n         && path[4] == '/'\n         && path[5] == '/'\n         && path[6] != '\\0')\n   {\n        stream->scheme    = VFS_SCHEME_SMB;\n   }\n#endif\n\n    path_wide    = utf8_to_utf16_string_alloc(path);\n    windowsize_path(path_wide);\n    path_wstring = path_wide;\n    free(path_wide);\n\n    for (;;)\n    {\n       size_t p = path_wstring.find(L\"\\\\\\\\\");\n       if (p == std::wstring::npos)\n          break;\n       path_wstring.replace(p, 2, L\"\\\\\");\n    }\n\n    path_wstring      = L\"\\\\\\\\?\\\\\" + path_wstring;\n    stream->orig_path = strdup(path);\n\n    stream->hints    &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;\n\n    switch (mode)\n    {\n       case RETRO_VFS_FILE_ACCESS_READ:\n          mode_str = \"rb\";\n          flags    = O_RDONLY | O_BINARY;\n          break;\n\n       case RETRO_VFS_FILE_ACCESS_WRITE:\n          mode_str = \"wb\";\n          flags    = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;\n          break;\n\n       case RETRO_VFS_FILE_ACCESS_READ_WRITE:\n          mode_str = \"w+b\";\n          flags    = O_RDWR | O_CREAT | O_TRUNC | O_BINARY;\n          break;\n\n       case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:\n       case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:\n          mode_str = \"r+b\";\n          flags    = O_RDWR | O_BINARY;\n          break;\n\n       default:\n          goto error;\n    }\n\n    switch (mode)\n    {\n       case RETRO_VFS_FILE_ACCESS_READ_WRITE:\n          desireAccess = GENERIC_READ | GENERIC_WRITE;\n          break;\n       case RETRO_VFS_FILE_ACCESS_WRITE:\n          desireAccess = GENERIC_WRITE;\n          break;\n       case RETRO_VFS_FILE_ACCESS_READ:\n          desireAccess = GENERIC_READ;\n          break;\n    }\n    if (mode == RETRO_VFS_FILE_ACCESS_READ)\n        creationDisposition = OPEN_EXISTING;\n    else\n        creationDisposition = (mode & RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING) != 0\n           ? OPEN_ALWAYS\n           : CREATE_ALWAYS;\n\n#ifdef HAVE_SMBCLIENT\n    if (stream->scheme == VFS_SCHEME_SMB)\n    {\n        if (!retro_vfs_file_open_smb(stream, path, mode, hints))\n            goto error;\n\n        return stream;\n    }\n#endif\n\n    if ((file_handle = CreateFile2FromAppW(path_wstring.data(), desireAccess,\n                FILE_SHARE_READ, creationDisposition, NULL)) == INVALID_HANDLE_VALUE)\n       goto error;\n\n    stream->fh      = file_handle;\n    if ((stream->fd = _open_osfhandle((uintptr_t)stream->fh, flags)) == -1)\n        goto error;\n\n    {\n        FILE *fp = _fdopen(stream->fd, mode_str);\n\n        if (!fp)\n            goto error;\n        stream->fp = fp;\n    }\n\n    /* Regarding setvbuf:\n        *\n        * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html\n        *\n        * If the size argument is not zero but buf is NULL,\n        * a buffer of the given size will be allocated immediately, and\n        * released on close. This is an extension to ANSI C.\n        *\n        * Since C89 does not support specifying a NULL buffer\n        * with a non-zero size, we create and track our own buffer for it.\n        */\n        /* TODO: this is only useful for a few platforms,\n        * find which and add ifdef */\n    if (stream->scheme != VFS_SCHEME_CDROM)\n    {\n        stream->buf = (char*)calloc(1, 0x4000);\n        if (stream->fp)\n            setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);\n    }\n\n    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);\n    retro_vfs_file_seek_internal(stream, 0, SEEK_END);\n\n    stream->size = retro_vfs_file_tell_impl(stream);\n\n    retro_vfs_file_seek_internal(stream, 0, SEEK_SET);\n\n    return stream;\n\nerror:\n    retro_vfs_file_close_impl(stream);\n    return NULL;\n}\n\nstatic int uwp_mkdir_impl(std::filesystem::path dir)\n{\n    /*I feel like this should create the directory recursively but the existing implementation does not so this update won't\n     *I put in the work but I just commented out the stuff you would need */\n    WIN32_FILE_ATTRIBUTE_DATA lpFileInfo;\n    bool parent_dir_exists = false;\n\n    if (dir.empty())\n        return -1;\n\n    /* Check if file attributes can be gotten successfully  */\n    if (GetFileAttributesExFromAppW(dir.parent_path().wstring().c_str(), GetFileExInfoStandard, &lpFileInfo))\n    {\n        /* Check that the files attributes are not null or empty */\n        if (lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES && lpFileInfo.dwFileAttributes != 0)\n        {\n            if (lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n                parent_dir_exists = true;\n        }\n    }\n    if (!parent_dir_exists)\n    {\n        /* Try to create parent dir */\n        int success = uwp_mkdir_impl(dir.parent_path());\n        if (success != 0 && success != -2)\n            return success;\n    }\n\n\n    /* Try Win32 first, this should work in AppData */\n    if (CreateDirectoryFromAppW(dir.wstring().c_str(), NULL))\n        return 0;\n\n    if (GetLastError() == ERROR_ALREADY_EXISTS)\n        return -2;\n\n    return -1;\n}\n\nint retro_vfs_mkdir_impl(const char* dir)\n{\n    return uwp_mkdir_impl(std::filesystem::path(dir));\n}\n\n/* The first run parameter is used to avoid error checking\n * when doing recursion.\n * Unlike the initial implementation, this can move folders\n * even empty ones when you want to move a directory structure.\n *\n * This will fail even if a single file cannot be moved.\n */\nstatic int uwp_move_path(\n      std::filesystem::path old_path,\n      std::filesystem::path new_path,\n      bool firstrun)\n{\n    if (old_path.empty() || new_path.empty())\n        return -1;\n\n    if (firstrun)\n    {\n        WIN32_FILE_ATTRIBUTE_DATA lpFileInfo, targetfileinfo;\n        bool parent_dir_exists = false;\n\n        /* Make sure that parent path exists */\n        if (GetFileAttributesExFromAppW(\n                 new_path.parent_path().wstring().c_str(),\n                 GetFileExInfoStandard, &lpFileInfo))\n        {\n            /* Check that the files attributes are not null or empty */\n            if (     lpFileInfo.dwFileAttributes\n                  != INVALID_FILE_ATTRIBUTES\n                  && lpFileInfo.dwFileAttributes != 0)\n            {\n               /* Parent path doesn't exist, so we gotta create it  */\n                if (!(lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n                    uwp_mkdir_impl(new_path.parent_path());\n            }\n        }\n\n        /* Make sure that source path exists */\n        if (GetFileAttributesExFromAppW(old_path.wstring().c_str(), GetFileExInfoStandard, &lpFileInfo))\n        {\n            /* Check that the files attributes are not null or empty */\n            if (     lpFileInfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES\n                  && lpFileInfo.dwFileAttributes != 0)\n            {\n                /* Check if source path is a dir */\n                if (lpFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n                {\n                   int ret;\n                   /* create the target dir */\n                   CreateDirectoryFromAppW(new_path.wstring().c_str(), NULL);\n                   /* Call move function again but with first run disabled in\n                    * order to move the folder */\n                   if ((ret = uwp_move_path(old_path, new_path, false)) != 0)\n                      return ret;\n                }\n                else\n                {\n                    /* The file that we want to move exists so we can copy it now\n                     * check if target file already exists. */\n                   if (GetFileAttributesExFromAppW(\n                            new_path.wstring().c_str(),\n                            GetFileExInfoStandard,\n                            &targetfileinfo))\n                    {\n                        if (\n                                 targetfileinfo.dwFileAttributes != INVALID_FILE_ATTRIBUTES\n                              && targetfileinfo.dwFileAttributes != 0\n                              && (!(targetfileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))\n                        {\n                            if (DeleteFileFromAppW(new_path.wstring().c_str()))\n                                return -1;\n                        }\n                    }\n\n                    if (!MoveFileFromAppW(old_path.wstring().c_str(),\n                             new_path.wstring().c_str()))\n                        return -1;\n                    /* Set ACL */\n                    uwp_set_acl(new_path.wstring().c_str(), L\"S-1-15-2-1\");\n                }\n            }\n        }\n\n    }\n    else\n    {\n       HANDLE searchResults;\n       WIN32_FIND_DATA findDataResult;\n       /* We are bypassing error checking and moving a dir.\n        * First we have to get a list of files in the dir. */\n       wchar_t* filteredPath = wcsdup(old_path.wstring().c_str());\n       wcscat_s(filteredPath, sizeof(L\"\\\\*.*\"), L\"\\\\*.*\");\n       searchResults         = FindFirstFileExFromAppW(\n             filteredPath, FindExInfoBasic, &findDataResult,\n             FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);\n\n       if (searchResults != INVALID_HANDLE_VALUE)\n       {\n          bool fail = false;\n          do\n          {\n             if (     wcscmp(findDataResult.cFileName, L\".\")  != 0\n                   && wcscmp(findDataResult.cFileName, L\"..\") != 0)\n             {\n                std::filesystem::path temp_old = old_path;\n                std::filesystem::path temp_new = new_path;\n                temp_old /= findDataResult.cFileName;\n                temp_new /= findDataResult.cFileName;\n                if (    findDataResult.dwFileAttributes\n                      & FILE_ATTRIBUTE_DIRECTORY)\n                {\n                   CreateDirectoryFromAppW(temp_new.wstring().c_str(), NULL);\n                   if (uwp_move_path(temp_old, temp_new, false) != 0)\n                      fail = true;\n                }\n                else\n                {\n                   WIN32_FILE_ATTRIBUTE_DATA targetfileinfo;\n                   /* The file that we want to move exists so we can copy\n                    * it now.\n                    * Check if target file already exists. */\n                   if (GetFileAttributesExFromAppW(temp_new.wstring().c_str(),\n                            GetFileExInfoStandard, &targetfileinfo))\n                   {\n                      if (\n                               (targetfileinfo.dwFileAttributes !=\n                                INVALID_FILE_ATTRIBUTES)\n                            && (targetfileinfo.dwFileAttributes != 0)\n                            && (!(targetfileinfo.dwFileAttributes\n                                  & FILE_ATTRIBUTE_DIRECTORY)))\n                      {\n                         if (DeleteFileFromAppW(temp_new.wstring().c_str()))\n                            fail = true;\n                      }\n                   }\n\n                   if (!MoveFileFromAppW(temp_old.wstring().c_str(),\n                            temp_new.wstring().c_str()))\n                      fail = true;\n                   /* Set ACL - this step sucks or at least used to\n                    * before I made a whole function\n                    * Don't know if we actually \"need\" to set the ACL\n                    * though */\n                   uwp_set_acl(temp_new.wstring().c_str(), L\"S-1-15-2-1\");\n                }\n             }\n          } while (FindNextFile(searchResults, &findDataResult));\n          FindClose(searchResults);\n          if (fail)\n             return -1;\n       }\n       free(filteredPath);\n    }\n    return 0;\n}\n\n/* C doesn't support default arguments so we wrap it up in a shell to enable\n * us to use default arguments.\n * Default arguments mean that we can do better recursion */\nint retro_vfs_file_rename_impl(const char* old_path, const char* new_path)\n{\n    return uwp_move_path(std::filesystem::path(old_path),\n          std::filesystem::path(old_path), true);\n}\n\nconst char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream)\n{\n   /* Should never happen, do something noisy so caller can be fixed */\n   if (!stream)\n      abort();\n   return stream->orig_path;\n}\n\nint retro_vfs_stat_64_impl(const char *path, int64_t *size)\n{\n   wchar_t *path_wide;\n   _WIN32_FILE_ATTRIBUTE_DATA attribdata;\n\n   if (!path || !*path)\n      return 0;\n\n   path_wide = utf8_to_utf16_string_alloc(path);\n   windowsize_path(path_wide);\n\n   /* Try Win32 first, this should work in AppData */\n   if (GetFileAttributesExFromAppW(path_wide,\n            GetFileExInfoStandard, &attribdata))\n   {\n       if (attribdata.dwFileAttributes != INVALID_FILE_ATTRIBUTES)\n       {\n           if (!(attribdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n           {\n               LARGE_INTEGER sz;\n               if (size)\n               {\n                   sz.HighPart = attribdata.nFileSizeHigh;\n                   sz.LowPart = attribdata.nFileSizeLow;\n                   *size = sz.QuadPart;\n               }\n           }\n           free(path_wide);\n           return (attribdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n              ? RETRO_VFS_STAT_IS_VALID | RETRO_VFS_STAT_IS_DIRECTORY\n              : RETRO_VFS_STAT_IS_VALID;\n       }\n   }\n   free(path_wide);\n   return 0;\n}\n\nint retro_vfs_stat_impl(const char *path, int32_t *size)\n{\n   int64_t size64 = 0;\n   int ret = retro_vfs_stat_64_impl(path, size ? &size64 : NULL);\n\n   /* if a file is larger than 2 GB, size64 will hold the correct value\n    * but the cast to int32_t will truncate it.\n    * new code should migrate to retro_vfs_stat_64_t\n   */\n   if (size)\n      *size = (int32_t)size64;\n\n   return ret;\n}\n\n#ifdef VFS_FRONTEND\nstruct retro_vfs_dir_handle\n#else\nstruct libretro_vfs_implementation_dir\n#endif\n{\n    char* orig_path;\n    WIN32_FIND_DATAW entry;\n    HANDLE directory;\n    bool next;\n    char path[PATH_MAX_LENGTH];\n#ifdef HAVE_SMBCLIENT\n    smb_dir_handle* smb_handle;\n    char smb_path[PATH_MAX_LENGTH];\n#endif\n};\n\nlibretro_vfs_implementation_dir* retro_vfs_opendir_impl(\n    const char* name, bool include_hidden)\n{\n    size_t _len;\n    char path_buf[1024];\n    wchar_t* path_wide = NULL;\n    libretro_vfs_implementation_dir* rdir;\n\n    /* Reject NULL or empty string paths*/\n    if (!name || (*name == 0))\n        return NULL;\n\n    /*Allocate RDIR struct. Tidied later with retro_closedir*/\n    if (!(rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir))))\n        return NULL;\n\n    rdir->orig_path = strdup(name);\n\n    _len = strlcpy(path_buf, name, sizeof(path_buf));\n\n#ifdef HAVE_SMBCLIENT\n    if (name[0]=='s' && name[1]=='m' && name[2]=='b' &&\n        name[3]==':' && name[4]=='/' && name[5]=='/' && name[6] != '\\0')\n    {\n        smb_dir_handle *dh = retro_vfs_opendir_smb(name, include_hidden);\n        if (!dh || dh->dir <= 0)\n        {\n            free(rdir->orig_path);\n            free(rdir);\n            return NULL;\n        }\n        rdir->smb_handle = dh;\n        rdir->smb_path[0] = '\\0';\n        return rdir;\n    }\n#endif\n\n    /* Non-NT platforms don't like extra slashes in the path */\n    if (path_buf[_len - 1] != '\\\\')\n        path_buf[_len++]   = '\\\\';\n\n    path_buf[_len]         = '*';\n    path_buf[_len + 1]     = '\\0';\n\n    path_wide              = utf8_to_utf16_string_alloc(path_buf);\n    rdir->directory        = FindFirstFileExFromAppW(\n          path_wide, FindExInfoStandard, &rdir->entry,\n          FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);\n\n    if (path_wide)\n        free(path_wide);\n\n    if (include_hidden)\n        rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;\n    else\n        rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;\n\n    if (rdir->directory && rdir != INVALID_HANDLE_VALUE)\n        return rdir;\n\n    retro_vfs_closedir_impl(rdir);\n    return NULL;\n}\n\nbool retro_vfs_readdir_impl(libretro_vfs_implementation_dir* rdir)\n{\n#ifdef HAVE_SMBCLIENT\n    if (rdir && rdir->smb_handle && rdir->smb_handle->dir != 0)\n    {\n        struct smbc_dirent *de = retro_vfs_readdir_smb(rdir->smb_handle);\n        if (!de)\n            return false;\n\n        strlcpy(rdir->smb_path, de->name, sizeof(rdir->smb_path));\n       return true;\n    }\n    /* If we opened an SMB path but failed, do not fall through to native readdir */\n    if (rdir->orig_path &&\n        rdir->orig_path[0] == 's' && rdir->orig_path[1] == 'm' && rdir->orig_path[2] == 'b' &&\n        rdir->orig_path[3] == ':' && rdir->orig_path[4] == '/' && rdir->orig_path[5] == '/')\n        return false;\n#endif\n\n    if (rdir->next)\n        return (FindNextFileW(rdir->directory, &rdir->entry) != 0);\n\n    rdir->next = true;\n    return (rdir->directory != INVALID_HANDLE_VALUE);\n}\n\nconst char* retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir* rdir)\n{\n#ifdef HAVE_SMBCLIENT\n    if (rdir && rdir->smb_handle && rdir->smb_handle->dir != 0)\n       return rdir->smb_path;\n#endif\n    char* name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);\n    memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));\n    strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));\n    if (name)\n        free(name);\n    return (char*)rdir->entry.cFileName;\n}\n\nbool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir* rdir)\n{\n#ifdef HAVE_SMBCLIENT\n    if (rdir && rdir->smb_handle && rdir->smb_handle->dir != 0)\n    {\n       char full[PATH_MAX_LENGTH];\n       const char *name = retro_vfs_dirent_get_name_impl(rdir);\n\n       if (!name)\n          return false;\n\n       fill_pathname_join_special(full, rdir->orig_path, name, sizeof(full));\n       int64_t sz = 0;\n       int st = retro_vfs_stat_smb(full, &sz);\n\n       return (st & RETRO_VFS_STAT_IS_DIRECTORY) != 0;\n    }\n#endif\n    const WIN32_FIND_DATA* entry = (const WIN32_FIND_DATA*)&rdir->entry;\n    return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;\n}\n\nint retro_vfs_closedir_impl(libretro_vfs_implementation_dir* rdir)\n{\n    if (!rdir)\n        return -1;\n\n#ifdef HAVE_SMBCLIENT\n    if (rdir->smb_handle && rdir->smb_handle->dir != 0)\n    {\n        retro_vfs_closedir_smb(rdir->smb_handle);\n        rdir->smb_handle = NULL;\n    }\n#endif\n\n    if (rdir->directory && rdir->directory != INVALID_HANDLE_VALUE)\n        FindClose(rdir->directory);\n\n    if (rdir->orig_path)\n        free(rdir->orig_path);\n    free(rdir);\n    return 0;\n}\n\nvoid uwp_set_acl(const wchar_t* path, const wchar_t* AccessString)\n{\n    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;\n    EXPLICIT_ACCESSW ExplicitAccess         = { 0 };\n    ACL* AccessControlCurrent               = NULL;\n    ACL* AccessControlNew                   = NULL;\n    SECURITY_INFORMATION SecurityInfo       = DACL_SECURITY_INFORMATION;\n    PSID SecurityIdentifier                 = NULL;\n    HANDLE original_file                    = CreateFileFromAppW(path,\n          GENERIC_READ    | GENERIC_WRITE | WRITE_DAC,\n          FILE_SHARE_READ | FILE_SHARE_WRITE,\n          NULL, OPEN_EXISTING, 0, NULL);\n\n    if (original_file != INVALID_HANDLE_VALUE)\n    {\n       if (\n             GetSecurityInfo(\n                original_file,\n                SE_FILE_OBJECT,\n                DACL_SECURITY_INFORMATION,\n                NULL,\n                NULL,\n                &AccessControlCurrent,\n                NULL,\n                &SecurityDescriptor\n                ) == ERROR_SUCCESS\n          )\n       {\n          ConvertStringSidToSidW(AccessString, &SecurityIdentifier);\n          if (SecurityIdentifier)\n          {\n             ExplicitAccess.grfAccessPermissions= GENERIC_READ | GENERIC_EXECUTE | GENERIC_WRITE;\n             ExplicitAccess.grfAccessMode       = SET_ACCESS;\n             ExplicitAccess.grfInheritance      = SUB_CONTAINERS_AND_OBJECTS_INHERIT;\n             ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;\n             ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;\n             ExplicitAccess.Trustee.ptstrName   = reinterpret_cast<wchar_t*>(SecurityIdentifier);\n\n             if (\n                   SetEntriesInAclW(\n                      1,\n                      &ExplicitAccess,\n                      AccessControlCurrent,\n                      &AccessControlNew\n                      ) == ERROR_SUCCESS\n                )\n                SetSecurityInfo(\n                      original_file,\n                      SE_FILE_OBJECT,\n                      SecurityInfo,\n                      NULL,\n                      NULL,\n                      AccessControlNew,\n                      NULL\n                      );\n          }\n       }\n       if (SecurityDescriptor)\n          LocalFree(reinterpret_cast<HLOCAL>(SecurityDescriptor));\n       if (AccessControlNew)\n          LocalFree(reinterpret_cast<HLOCAL>(AccessControlNew));\n       CloseHandle(original_file);\n    }\n}\n"
  },
  {
    "path": "vulkan/vulkan_symbol_wrapper.c",
    "content": "\n/* This header is autogenerated by vulkan_loader_generator.py */\n#include <vulkan/vulkan_symbol_wrapper.h>\n\nPFN_vkCreateInstance vulkan_symbol_wrapper_vkCreateInstance;\nPFN_vkEnumerateInstanceVersion vulkan_symbol_wrapper_vkEnumerateInstanceVersion;\nPFN_vkEnumerateInstanceExtensionProperties vulkan_symbol_wrapper_vkEnumerateInstanceExtensionProperties;\nPFN_vkEnumerateInstanceLayerProperties vulkan_symbol_wrapper_vkEnumerateInstanceLayerProperties;\nPFN_vkDestroyInstance vulkan_symbol_wrapper_vkDestroyInstance;\nPFN_vkEnumeratePhysicalDevices vulkan_symbol_wrapper_vkEnumeratePhysicalDevices;\nPFN_vkGetPhysicalDeviceFeatures vulkan_symbol_wrapper_vkGetPhysicalDeviceFeatures;\nPFN_vkGetPhysicalDeviceFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceFormatProperties;\nPFN_vkGetPhysicalDeviceImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceImageFormatProperties;\nPFN_vkGetPhysicalDeviceProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceProperties;\nPFN_vkGetPhysicalDeviceQueueFamilyProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceQueueFamilyProperties;\nPFN_vkGetPhysicalDeviceMemoryProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceMemoryProperties;\nPFN_vkGetDeviceProcAddr vulkan_symbol_wrapper_vkGetDeviceProcAddr;\nPFN_vkCreateDevice vulkan_symbol_wrapper_vkCreateDevice;\nPFN_vkDestroyDevice vulkan_symbol_wrapper_vkDestroyDevice;\nPFN_vkEnumerateDeviceExtensionProperties vulkan_symbol_wrapper_vkEnumerateDeviceExtensionProperties;\nPFN_vkEnumerateDeviceLayerProperties vulkan_symbol_wrapper_vkEnumerateDeviceLayerProperties;\nPFN_vkGetDeviceQueue vulkan_symbol_wrapper_vkGetDeviceQueue;\nPFN_vkQueueSubmit vulkan_symbol_wrapper_vkQueueSubmit;\nPFN_vkQueueWaitIdle vulkan_symbol_wrapper_vkQueueWaitIdle;\nPFN_vkDeviceWaitIdle vulkan_symbol_wrapper_vkDeviceWaitIdle;\nPFN_vkAllocateMemory vulkan_symbol_wrapper_vkAllocateMemory;\nPFN_vkFreeMemory vulkan_symbol_wrapper_vkFreeMemory;\nPFN_vkMapMemory vulkan_symbol_wrapper_vkMapMemory;\nPFN_vkUnmapMemory vulkan_symbol_wrapper_vkUnmapMemory;\nPFN_vkFlushMappedMemoryRanges vulkan_symbol_wrapper_vkFlushMappedMemoryRanges;\nPFN_vkInvalidateMappedMemoryRanges vulkan_symbol_wrapper_vkInvalidateMappedMemoryRanges;\nPFN_vkGetDeviceMemoryCommitment vulkan_symbol_wrapper_vkGetDeviceMemoryCommitment;\nPFN_vkBindBufferMemory vulkan_symbol_wrapper_vkBindBufferMemory;\nPFN_vkBindImageMemory vulkan_symbol_wrapper_vkBindImageMemory;\nPFN_vkGetBufferMemoryRequirements vulkan_symbol_wrapper_vkGetBufferMemoryRequirements;\nPFN_vkGetImageMemoryRequirements vulkan_symbol_wrapper_vkGetImageMemoryRequirements;\nPFN_vkGetImageSparseMemoryRequirements vulkan_symbol_wrapper_vkGetImageSparseMemoryRequirements;\nPFN_vkGetPhysicalDeviceSparseImageFormatProperties vulkan_symbol_wrapper_vkGetPhysicalDeviceSparseImageFormatProperties;\nPFN_vkQueueBindSparse vulkan_symbol_wrapper_vkQueueBindSparse;\nPFN_vkCreateFence vulkan_symbol_wrapper_vkCreateFence;\nPFN_vkDestroyFence vulkan_symbol_wrapper_vkDestroyFence;\nPFN_vkResetFences vulkan_symbol_wrapper_vkResetFences;\nPFN_vkGetFenceStatus vulkan_symbol_wrapper_vkGetFenceStatus;\nPFN_vkWaitForFences vulkan_symbol_wrapper_vkWaitForFences;\nPFN_vkCreateSemaphore vulkan_symbol_wrapper_vkCreateSemaphore;\nPFN_vkDestroySemaphore vulkan_symbol_wrapper_vkDestroySemaphore;\nPFN_vkCreateEvent vulkan_symbol_wrapper_vkCreateEvent;\nPFN_vkDestroyEvent vulkan_symbol_wrapper_vkDestroyEvent;\nPFN_vkGetEventStatus vulkan_symbol_wrapper_vkGetEventStatus;\nPFN_vkSetEvent vulkan_symbol_wrapper_vkSetEvent;\nPFN_vkResetEvent vulkan_symbol_wrapper_vkResetEvent;\nPFN_vkCreateQueryPool vulkan_symbol_wrapper_vkCreateQueryPool;\nPFN_vkDestroyQueryPool vulkan_symbol_wrapper_vkDestroyQueryPool;\nPFN_vkGetQueryPoolResults vulkan_symbol_wrapper_vkGetQueryPoolResults;\nPFN_vkCreateBuffer vulkan_symbol_wrapper_vkCreateBuffer;\nPFN_vkDestroyBuffer vulkan_symbol_wrapper_vkDestroyBuffer;\nPFN_vkCreateBufferView vulkan_symbol_wrapper_vkCreateBufferView;\nPFN_vkDestroyBufferView vulkan_symbol_wrapper_vkDestroyBufferView;\nPFN_vkCreateImage vulkan_symbol_wrapper_vkCreateImage;\nPFN_vkDestroyImage vulkan_symbol_wrapper_vkDestroyImage;\nPFN_vkGetImageSubresourceLayout vulkan_symbol_wrapper_vkGetImageSubresourceLayout;\nPFN_vkCreateImageView vulkan_symbol_wrapper_vkCreateImageView;\nPFN_vkDestroyImageView vulkan_symbol_wrapper_vkDestroyImageView;\nPFN_vkCreateShaderModule vulkan_symbol_wrapper_vkCreateShaderModule;\nPFN_vkDestroyShaderModule vulkan_symbol_wrapper_vkDestroyShaderModule;\nPFN_vkCreatePipelineCache vulkan_symbol_wrapper_vkCreatePipelineCache;\nPFN_vkDestroyPipelineCache vulkan_symbol_wrapper_vkDestroyPipelineCache;\nPFN_vkGetPipelineCacheData vulkan_symbol_wrapper_vkGetPipelineCacheData;\nPFN_vkMergePipelineCaches vulkan_symbol_wrapper_vkMergePipelineCaches;\nPFN_vkCreateGraphicsPipelines vulkan_symbol_wrapper_vkCreateGraphicsPipelines;\nPFN_vkCreateComputePipelines vulkan_symbol_wrapper_vkCreateComputePipelines;\nPFN_vkDestroyPipeline vulkan_symbol_wrapper_vkDestroyPipeline;\nPFN_vkCreatePipelineLayout vulkan_symbol_wrapper_vkCreatePipelineLayout;\nPFN_vkDestroyPipelineLayout vulkan_symbol_wrapper_vkDestroyPipelineLayout;\nPFN_vkCreateSampler vulkan_symbol_wrapper_vkCreateSampler;\nPFN_vkDestroySampler vulkan_symbol_wrapper_vkDestroySampler;\nPFN_vkCreateDescriptorSetLayout vulkan_symbol_wrapper_vkCreateDescriptorSetLayout;\nPFN_vkDestroyDescriptorSetLayout vulkan_symbol_wrapper_vkDestroyDescriptorSetLayout;\nPFN_vkCreateDescriptorPool vulkan_symbol_wrapper_vkCreateDescriptorPool;\nPFN_vkDestroyDescriptorPool vulkan_symbol_wrapper_vkDestroyDescriptorPool;\nPFN_vkResetDescriptorPool vulkan_symbol_wrapper_vkResetDescriptorPool;\nPFN_vkAllocateDescriptorSets vulkan_symbol_wrapper_vkAllocateDescriptorSets;\nPFN_vkFreeDescriptorSets vulkan_symbol_wrapper_vkFreeDescriptorSets;\nPFN_vkUpdateDescriptorSets vulkan_symbol_wrapper_vkUpdateDescriptorSets;\nPFN_vkCreateFramebuffer vulkan_symbol_wrapper_vkCreateFramebuffer;\nPFN_vkDestroyFramebuffer vulkan_symbol_wrapper_vkDestroyFramebuffer;\nPFN_vkCreateRenderPass vulkan_symbol_wrapper_vkCreateRenderPass;\nPFN_vkDestroyRenderPass vulkan_symbol_wrapper_vkDestroyRenderPass;\nPFN_vkGetRenderAreaGranularity vulkan_symbol_wrapper_vkGetRenderAreaGranularity;\nPFN_vkCreateCommandPool vulkan_symbol_wrapper_vkCreateCommandPool;\nPFN_vkDestroyCommandPool vulkan_symbol_wrapper_vkDestroyCommandPool;\nPFN_vkResetCommandPool vulkan_symbol_wrapper_vkResetCommandPool;\nPFN_vkAllocateCommandBuffers vulkan_symbol_wrapper_vkAllocateCommandBuffers;\nPFN_vkFreeCommandBuffers vulkan_symbol_wrapper_vkFreeCommandBuffers;\nPFN_vkBeginCommandBuffer vulkan_symbol_wrapper_vkBeginCommandBuffer;\nPFN_vkEndCommandBuffer vulkan_symbol_wrapper_vkEndCommandBuffer;\nPFN_vkResetCommandBuffer vulkan_symbol_wrapper_vkResetCommandBuffer;\nPFN_vkCmdBindPipeline vulkan_symbol_wrapper_vkCmdBindPipeline;\nPFN_vkCmdSetViewport vulkan_symbol_wrapper_vkCmdSetViewport;\nPFN_vkCmdSetScissor vulkan_symbol_wrapper_vkCmdSetScissor;\nPFN_vkCmdSetLineWidth vulkan_symbol_wrapper_vkCmdSetLineWidth;\nPFN_vkCmdSetDepthBias vulkan_symbol_wrapper_vkCmdSetDepthBias;\nPFN_vkCmdSetBlendConstants vulkan_symbol_wrapper_vkCmdSetBlendConstants;\nPFN_vkCmdSetDepthBounds vulkan_symbol_wrapper_vkCmdSetDepthBounds;\nPFN_vkCmdSetStencilCompareMask vulkan_symbol_wrapper_vkCmdSetStencilCompareMask;\nPFN_vkCmdSetStencilWriteMask vulkan_symbol_wrapper_vkCmdSetStencilWriteMask;\nPFN_vkCmdSetStencilReference vulkan_symbol_wrapper_vkCmdSetStencilReference;\nPFN_vkCmdBindDescriptorSets vulkan_symbol_wrapper_vkCmdBindDescriptorSets;\nPFN_vkCmdBindIndexBuffer vulkan_symbol_wrapper_vkCmdBindIndexBuffer;\nPFN_vkCmdBindVertexBuffers vulkan_symbol_wrapper_vkCmdBindVertexBuffers;\nPFN_vkCmdDraw vulkan_symbol_wrapper_vkCmdDraw;\nPFN_vkCmdDrawIndexed vulkan_symbol_wrapper_vkCmdDrawIndexed;\nPFN_vkCmdDrawIndirect vulkan_symbol_wrapper_vkCmdDrawIndirect;\nPFN_vkCmdDrawIndexedIndirect vulkan_symbol_wrapper_vkCmdDrawIndexedIndirect;\nPFN_vkCmdDispatch vulkan_symbol_wrapper_vkCmdDispatch;\nPFN_vkCmdDispatchIndirect vulkan_symbol_wrapper_vkCmdDispatchIndirect;\nPFN_vkCmdCopyBuffer vulkan_symbol_wrapper_vkCmdCopyBuffer;\nPFN_vkCmdCopyImage vulkan_symbol_wrapper_vkCmdCopyImage;\nPFN_vkCmdBlitImage vulkan_symbol_wrapper_vkCmdBlitImage;\nPFN_vkCmdCopyBufferToImage vulkan_symbol_wrapper_vkCmdCopyBufferToImage;\nPFN_vkCmdCopyImageToBuffer vulkan_symbol_wrapper_vkCmdCopyImageToBuffer;\nPFN_vkCmdUpdateBuffer vulkan_symbol_wrapper_vkCmdUpdateBuffer;\nPFN_vkCmdFillBuffer vulkan_symbol_wrapper_vkCmdFillBuffer;\nPFN_vkCmdClearColorImage vulkan_symbol_wrapper_vkCmdClearColorImage;\nPFN_vkCmdClearDepthStencilImage vulkan_symbol_wrapper_vkCmdClearDepthStencilImage;\nPFN_vkCmdClearAttachments vulkan_symbol_wrapper_vkCmdClearAttachments;\nPFN_vkCmdResolveImage vulkan_symbol_wrapper_vkCmdResolveImage;\nPFN_vkCmdSetEvent vulkan_symbol_wrapper_vkCmdSetEvent;\nPFN_vkCmdResetEvent vulkan_symbol_wrapper_vkCmdResetEvent;\nPFN_vkCmdWaitEvents vulkan_symbol_wrapper_vkCmdWaitEvents;\nPFN_vkCmdPipelineBarrier vulkan_symbol_wrapper_vkCmdPipelineBarrier;\nPFN_vkCmdBeginQuery vulkan_symbol_wrapper_vkCmdBeginQuery;\nPFN_vkCmdEndQuery vulkan_symbol_wrapper_vkCmdEndQuery;\nPFN_vkCmdResetQueryPool vulkan_symbol_wrapper_vkCmdResetQueryPool;\nPFN_vkCmdWriteTimestamp vulkan_symbol_wrapper_vkCmdWriteTimestamp;\nPFN_vkCmdCopyQueryPoolResults vulkan_symbol_wrapper_vkCmdCopyQueryPoolResults;\nPFN_vkCmdPushConstants vulkan_symbol_wrapper_vkCmdPushConstants;\nPFN_vkCmdBeginRenderPass vulkan_symbol_wrapper_vkCmdBeginRenderPass;\nPFN_vkCmdNextSubpass vulkan_symbol_wrapper_vkCmdNextSubpass;\nPFN_vkCmdEndRenderPass vulkan_symbol_wrapper_vkCmdEndRenderPass;\nPFN_vkCmdExecuteCommands vulkan_symbol_wrapper_vkCmdExecuteCommands;\nPFN_vkDestroySurfaceKHR vulkan_symbol_wrapper_vkDestroySurfaceKHR;\nPFN_vkGetPhysicalDeviceSurfaceSupportKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceSupportKHR;\nPFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;\nPFN_vkGetPhysicalDeviceSurfaceFormatsKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfaceFormatsKHR;\nPFN_vkGetPhysicalDeviceSurfacePresentModesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceSurfacePresentModesKHR;\nPFN_vkCreateSwapchainKHR vulkan_symbol_wrapper_vkCreateSwapchainKHR;\nPFN_vkDestroySwapchainKHR vulkan_symbol_wrapper_vkDestroySwapchainKHR;\nPFN_vkGetSwapchainImagesKHR vulkan_symbol_wrapper_vkGetSwapchainImagesKHR;\nPFN_vkAcquireNextImageKHR vulkan_symbol_wrapper_vkAcquireNextImageKHR;\nPFN_vkQueuePresentKHR vulkan_symbol_wrapper_vkQueuePresentKHR;\nPFN_vkGetPhysicalDeviceDisplayPropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPropertiesKHR;\nPFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vulkan_symbol_wrapper_vkGetPhysicalDeviceDisplayPlanePropertiesKHR;\nPFN_vkGetDisplayPlaneSupportedDisplaysKHR vulkan_symbol_wrapper_vkGetDisplayPlaneSupportedDisplaysKHR;\nPFN_vkGetDisplayModePropertiesKHR vulkan_symbol_wrapper_vkGetDisplayModePropertiesKHR;\nPFN_vkCreateDisplayModeKHR vulkan_symbol_wrapper_vkCreateDisplayModeKHR;\nPFN_vkGetDisplayPlaneCapabilitiesKHR vulkan_symbol_wrapper_vkGetDisplayPlaneCapabilitiesKHR;\nPFN_vkCreateDisplayPlaneSurfaceKHR vulkan_symbol_wrapper_vkCreateDisplayPlaneSurfaceKHR;\nPFN_vkCreateSharedSwapchainsKHR vulkan_symbol_wrapper_vkCreateSharedSwapchainsKHR;\n\nPFN_vkCreateDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkCreateDebugUtilsMessengerEXT;\nPFN_vkDestroyDebugUtilsMessengerEXT vulkan_symbol_wrapper_vkDestroyDebugUtilsMessengerEXT;\nPFN_vkSetDebugUtilsObjectNameEXT vulkan_symbol_wrapper_vkSetDebugUtilsObjectNameEXT;\n\nstatic PFN_vkGetInstanceProcAddr GetInstanceProcAddr;\nvoid vulkan_symbol_wrapper_init(PFN_vkGetInstanceProcAddr get_instance_proc_addr)\n{\n    GetInstanceProcAddr = get_instance_proc_addr;\n}\n\nPFN_vkGetInstanceProcAddr vulkan_symbol_wrapper_instance_proc_addr(void)\n{\n    return GetInstanceProcAddr;\n}\n\nVkBool32 vulkan_symbol_wrapper_load_instance_symbol(VkInstance instance, const char *name, PFN_vkVoidFunction *ppSymbol)\n{\n    *ppSymbol = GetInstanceProcAddr(instance, name);\n    return *ppSymbol != NULL;\n}\n\nVkBool32 vulkan_symbol_wrapper_load_device_symbol(VkDevice device, const char *name, PFN_vkVoidFunction *ppSymbol)\n{\n    *ppSymbol = vkGetDeviceProcAddr(device, name);\n    return *ppSymbol != NULL;\n}\n\nVkBool32 vulkan_symbol_wrapper_load_global_symbols(void)\n{\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, \"vkCreateInstance\", vkCreateInstance)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, \"vkEnumerateInstanceExtensionProperties\", vkEnumerateInstanceExtensionProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, \"vkEnumerateInstanceLayerProperties\", vkEnumerateInstanceLayerProperties)) return VK_FALSE;\n    VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(NULL, \"vkEnumerateInstanceVersion\", vkEnumerateInstanceVersion);\n    return VK_TRUE;\n}\n\nVkBool32 vulkan_symbol_wrapper_load_core_symbols(VkInstance instance)\n{\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyInstance\", vkDestroyInstance)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEnumeratePhysicalDevices\", vkEnumeratePhysicalDevices)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceFeatures\", vkGetPhysicalDeviceFeatures)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceFormatProperties\", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceImageFormatProperties\", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceProperties\", vkGetPhysicalDeviceProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceQueueFamilyProperties\", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceMemoryProperties\", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetDeviceProcAddr\", vkGetDeviceProcAddr)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateDevice\", vkCreateDevice)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyDevice\", vkDestroyDevice)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEnumerateDeviceExtensionProperties\", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEnumerateDeviceLayerProperties\", vkEnumerateDeviceLayerProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetDeviceQueue\", vkGetDeviceQueue)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkQueueSubmit\", vkQueueSubmit)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkQueueWaitIdle\", vkQueueWaitIdle)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDeviceWaitIdle\", vkDeviceWaitIdle)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkAllocateMemory\", vkAllocateMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkFreeMemory\", vkFreeMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkMapMemory\", vkMapMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkUnmapMemory\", vkUnmapMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkFlushMappedMemoryRanges\", vkFlushMappedMemoryRanges)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkInvalidateMappedMemoryRanges\", vkInvalidateMappedMemoryRanges)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetDeviceMemoryCommitment\", vkGetDeviceMemoryCommitment)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkBindBufferMemory\", vkBindBufferMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkBindImageMemory\", vkBindImageMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetBufferMemoryRequirements\", vkGetBufferMemoryRequirements)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetImageMemoryRequirements\", vkGetImageMemoryRequirements)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetImageSparseMemoryRequirements\", vkGetImageSparseMemoryRequirements)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceSparseImageFormatProperties\", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkQueueBindSparse\", vkQueueBindSparse)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateFence\", vkCreateFence)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyFence\", vkDestroyFence)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkResetFences\", vkResetFences)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetFenceStatus\", vkGetFenceStatus)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkWaitForFences\", vkWaitForFences)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateSemaphore\", vkCreateSemaphore)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroySemaphore\", vkDestroySemaphore)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateEvent\", vkCreateEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyEvent\", vkDestroyEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetEventStatus\", vkGetEventStatus)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkSetEvent\", vkSetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkResetEvent\", vkResetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateQueryPool\", vkCreateQueryPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyQueryPool\", vkDestroyQueryPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetQueryPoolResults\", vkGetQueryPoolResults)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateBuffer\", vkCreateBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyBuffer\", vkDestroyBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateBufferView\", vkCreateBufferView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyBufferView\", vkDestroyBufferView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateImage\", vkCreateImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyImage\", vkDestroyImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetImageSubresourceLayout\", vkGetImageSubresourceLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateImageView\", vkCreateImageView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyImageView\", vkDestroyImageView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateShaderModule\", vkCreateShaderModule)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyShaderModule\", vkDestroyShaderModule)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreatePipelineCache\", vkCreatePipelineCache)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyPipelineCache\", vkDestroyPipelineCache)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPipelineCacheData\", vkGetPipelineCacheData)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkMergePipelineCaches\", vkMergePipelineCaches)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateGraphicsPipelines\", vkCreateGraphicsPipelines)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateComputePipelines\", vkCreateComputePipelines)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyPipeline\", vkDestroyPipeline)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreatePipelineLayout\", vkCreatePipelineLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyPipelineLayout\", vkDestroyPipelineLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateSampler\", vkCreateSampler)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroySampler\", vkDestroySampler)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateDescriptorSetLayout\", vkCreateDescriptorSetLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyDescriptorSetLayout\", vkDestroyDescriptorSetLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateDescriptorPool\", vkCreateDescriptorPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyDescriptorPool\", vkDestroyDescriptorPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkResetDescriptorPool\", vkResetDescriptorPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkAllocateDescriptorSets\", vkAllocateDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkFreeDescriptorSets\", vkFreeDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkUpdateDescriptorSets\", vkUpdateDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateFramebuffer\", vkCreateFramebuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyFramebuffer\", vkDestroyFramebuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateRenderPass\", vkCreateRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyRenderPass\", vkDestroyRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetRenderAreaGranularity\", vkGetRenderAreaGranularity)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateCommandPool\", vkCreateCommandPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyCommandPool\", vkDestroyCommandPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkResetCommandPool\", vkResetCommandPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkAllocateCommandBuffers\", vkAllocateCommandBuffers)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkFreeCommandBuffers\", vkFreeCommandBuffers)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkBeginCommandBuffer\", vkBeginCommandBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEndCommandBuffer\", vkEndCommandBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkResetCommandBuffer\", vkResetCommandBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBindPipeline\", vkCmdBindPipeline)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetViewport\", vkCmdSetViewport)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetScissor\", vkCmdSetScissor)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetLineWidth\", vkCmdSetLineWidth)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetDepthBias\", vkCmdSetDepthBias)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetBlendConstants\", vkCmdSetBlendConstants)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetDepthBounds\", vkCmdSetDepthBounds)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetStencilCompareMask\", vkCmdSetStencilCompareMask)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetStencilWriteMask\", vkCmdSetStencilWriteMask)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetStencilReference\", vkCmdSetStencilReference)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBindDescriptorSets\", vkCmdBindDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBindIndexBuffer\", vkCmdBindIndexBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBindVertexBuffers\", vkCmdBindVertexBuffers)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdDraw\", vkCmdDraw)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdDrawIndexed\", vkCmdDrawIndexed)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdDrawIndirect\", vkCmdDrawIndirect)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdDrawIndexedIndirect\", vkCmdDrawIndexedIndirect)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdDispatch\", vkCmdDispatch)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdDispatchIndirect\", vkCmdDispatchIndirect)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdCopyBuffer\", vkCmdCopyBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdCopyImage\", vkCmdCopyImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBlitImage\", vkCmdBlitImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdCopyBufferToImage\", vkCmdCopyBufferToImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdCopyImageToBuffer\", vkCmdCopyImageToBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdUpdateBuffer\", vkCmdUpdateBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdFillBuffer\", vkCmdFillBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdClearColorImage\", vkCmdClearColorImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdClearDepthStencilImage\", vkCmdClearDepthStencilImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdClearAttachments\", vkCmdClearAttachments)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdResolveImage\", vkCmdResolveImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdSetEvent\", vkCmdSetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdResetEvent\", vkCmdResetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdWaitEvents\", vkCmdWaitEvents)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdPipelineBarrier\", vkCmdPipelineBarrier)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBeginQuery\", vkCmdBeginQuery)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdEndQuery\", vkCmdEndQuery)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdResetQueryPool\", vkCmdResetQueryPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdWriteTimestamp\", vkCmdWriteTimestamp)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdCopyQueryPoolResults\", vkCmdCopyQueryPoolResults)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdPushConstants\", vkCmdPushConstants)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdBeginRenderPass\", vkCmdBeginRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdNextSubpass\", vkCmdNextSubpass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdEndRenderPass\", vkCmdEndRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCmdExecuteCommands\", vkCmdExecuteCommands)) return VK_FALSE;\n    return VK_TRUE;\n}\n\nVkBool32 vulkan_symbol_wrapper_load_core_instance_symbols(VkInstance instance)\n{\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkDestroyInstance\", vkDestroyInstance)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEnumeratePhysicalDevices\", vkEnumeratePhysicalDevices)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceFeatures\", vkGetPhysicalDeviceFeatures)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceFormatProperties\", vkGetPhysicalDeviceFormatProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceImageFormatProperties\", vkGetPhysicalDeviceImageFormatProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceProperties\", vkGetPhysicalDeviceProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceQueueFamilyProperties\", vkGetPhysicalDeviceQueueFamilyProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceMemoryProperties\", vkGetPhysicalDeviceMemoryProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetDeviceProcAddr\", vkGetDeviceProcAddr)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkCreateDevice\", vkCreateDevice)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEnumerateDeviceExtensionProperties\", vkEnumerateDeviceExtensionProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkEnumerateDeviceLayerProperties\", vkEnumerateDeviceLayerProperties)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_SYMBOL(instance, \"vkGetPhysicalDeviceSparseImageFormatProperties\", vkGetPhysicalDeviceSparseImageFormatProperties)) return VK_FALSE;\n    return VK_TRUE;\n}\n\nVkBool32 vulkan_symbol_wrapper_load_core_device_symbols(VkDevice device)\n{\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyDevice\", vkDestroyDevice)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetDeviceQueue\", vkGetDeviceQueue)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkQueueSubmit\", vkQueueSubmit)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkQueueWaitIdle\", vkQueueWaitIdle)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDeviceWaitIdle\", vkDeviceWaitIdle)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkAllocateMemory\", vkAllocateMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkFreeMemory\", vkFreeMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkMapMemory\", vkMapMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkUnmapMemory\", vkUnmapMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkFlushMappedMemoryRanges\", vkFlushMappedMemoryRanges)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkInvalidateMappedMemoryRanges\", vkInvalidateMappedMemoryRanges)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetDeviceMemoryCommitment\", vkGetDeviceMemoryCommitment)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkBindBufferMemory\", vkBindBufferMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkBindImageMemory\", vkBindImageMemory)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetBufferMemoryRequirements\", vkGetBufferMemoryRequirements)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetImageMemoryRequirements\", vkGetImageMemoryRequirements)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetImageSparseMemoryRequirements\", vkGetImageSparseMemoryRequirements)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkQueueBindSparse\", vkQueueBindSparse)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateFence\", vkCreateFence)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyFence\", vkDestroyFence)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkResetFences\", vkResetFences)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetFenceStatus\", vkGetFenceStatus)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkWaitForFences\", vkWaitForFences)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateSemaphore\", vkCreateSemaphore)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroySemaphore\", vkDestroySemaphore)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateEvent\", vkCreateEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyEvent\", vkDestroyEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetEventStatus\", vkGetEventStatus)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkSetEvent\", vkSetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkResetEvent\", vkResetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateQueryPool\", vkCreateQueryPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyQueryPool\", vkDestroyQueryPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetQueryPoolResults\", vkGetQueryPoolResults)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateBuffer\", vkCreateBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyBuffer\", vkDestroyBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateBufferView\", vkCreateBufferView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyBufferView\", vkDestroyBufferView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateImage\", vkCreateImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyImage\", vkDestroyImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetImageSubresourceLayout\", vkGetImageSubresourceLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateImageView\", vkCreateImageView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyImageView\", vkDestroyImageView)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateShaderModule\", vkCreateShaderModule)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyShaderModule\", vkDestroyShaderModule)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreatePipelineCache\", vkCreatePipelineCache)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyPipelineCache\", vkDestroyPipelineCache)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetPipelineCacheData\", vkGetPipelineCacheData)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkMergePipelineCaches\", vkMergePipelineCaches)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateGraphicsPipelines\", vkCreateGraphicsPipelines)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateComputePipelines\", vkCreateComputePipelines)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyPipeline\", vkDestroyPipeline)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreatePipelineLayout\", vkCreatePipelineLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyPipelineLayout\", vkDestroyPipelineLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateSampler\", vkCreateSampler)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroySampler\", vkDestroySampler)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateDescriptorSetLayout\", vkCreateDescriptorSetLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyDescriptorSetLayout\", vkDestroyDescriptorSetLayout)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateDescriptorPool\", vkCreateDescriptorPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyDescriptorPool\", vkDestroyDescriptorPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkResetDescriptorPool\", vkResetDescriptorPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkAllocateDescriptorSets\", vkAllocateDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkFreeDescriptorSets\", vkFreeDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkUpdateDescriptorSets\", vkUpdateDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateFramebuffer\", vkCreateFramebuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyFramebuffer\", vkDestroyFramebuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateRenderPass\", vkCreateRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyRenderPass\", vkDestroyRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkGetRenderAreaGranularity\", vkGetRenderAreaGranularity)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCreateCommandPool\", vkCreateCommandPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkDestroyCommandPool\", vkDestroyCommandPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkResetCommandPool\", vkResetCommandPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkAllocateCommandBuffers\", vkAllocateCommandBuffers)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkFreeCommandBuffers\", vkFreeCommandBuffers)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkBeginCommandBuffer\", vkBeginCommandBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkEndCommandBuffer\", vkEndCommandBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkResetCommandBuffer\", vkResetCommandBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBindPipeline\", vkCmdBindPipeline)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetViewport\", vkCmdSetViewport)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetScissor\", vkCmdSetScissor)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetLineWidth\", vkCmdSetLineWidth)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetDepthBias\", vkCmdSetDepthBias)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetBlendConstants\", vkCmdSetBlendConstants)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetDepthBounds\", vkCmdSetDepthBounds)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetStencilCompareMask\", vkCmdSetStencilCompareMask)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetStencilWriteMask\", vkCmdSetStencilWriteMask)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetStencilReference\", vkCmdSetStencilReference)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBindDescriptorSets\", vkCmdBindDescriptorSets)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBindIndexBuffer\", vkCmdBindIndexBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBindVertexBuffers\", vkCmdBindVertexBuffers)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdDraw\", vkCmdDraw)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdDrawIndexed\", vkCmdDrawIndexed)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdDrawIndirect\", vkCmdDrawIndirect)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdDrawIndexedIndirect\", vkCmdDrawIndexedIndirect)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdDispatch\", vkCmdDispatch)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdDispatchIndirect\", vkCmdDispatchIndirect)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdCopyBuffer\", vkCmdCopyBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdCopyImage\", vkCmdCopyImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBlitImage\", vkCmdBlitImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdCopyBufferToImage\", vkCmdCopyBufferToImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdCopyImageToBuffer\", vkCmdCopyImageToBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdUpdateBuffer\", vkCmdUpdateBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdFillBuffer\", vkCmdFillBuffer)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdClearColorImage\", vkCmdClearColorImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdClearDepthStencilImage\", vkCmdClearDepthStencilImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdClearAttachments\", vkCmdClearAttachments)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdResolveImage\", vkCmdResolveImage)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdSetEvent\", vkCmdSetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdResetEvent\", vkCmdResetEvent)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdWaitEvents\", vkCmdWaitEvents)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdPipelineBarrier\", vkCmdPipelineBarrier)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBeginQuery\", vkCmdBeginQuery)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdEndQuery\", vkCmdEndQuery)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdResetQueryPool\", vkCmdResetQueryPool)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdWriteTimestamp\", vkCmdWriteTimestamp)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdCopyQueryPoolResults\", vkCmdCopyQueryPoolResults))\n    {\n       /* Don't return false here. Would cause MESA Intel Ivy Bridge drivers to not work at all. */\n    }\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdPushConstants\", vkCmdPushConstants)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdBeginRenderPass\", vkCmdBeginRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdNextSubpass\", vkCmdNextSubpass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdEndRenderPass\", vkCmdEndRenderPass)) return VK_FALSE;\n    if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_SYMBOL(device, \"vkCmdExecuteCommands\", vkCmdExecuteCommands)) return VK_FALSE;\n    return VK_TRUE;\n}\n"
  }
]