update libretro-common

This commit is contained in:
Mats A 2020-11-12 15:30:31 +01:00 committed by Mats
parent 9106ca4fe3
commit 5e56e468ce
285 changed files with 15042 additions and 10065 deletions

View File

@ -1 +1,6 @@
*.o
glsm/
*.[od]
*.dll
*.so
*.dylib
*.exe

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (audio_mix.c).
@ -20,7 +20,12 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <audio/audio_mix.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memalign.h>
#include <retro_environment.h>
#if defined(__SSE2__)
#include <emmintrin.h>
@ -28,10 +33,6 @@
#include <altivec.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memalign.h>
#include <retro_miscellaneous.h>
#include <audio/audio_mix.h>
#include <streams/file_stream.h>
@ -48,7 +49,7 @@ void audio_mix_volume_C(float *out, const float *in, float vol, size_t samples)
#ifdef __SSE2__
void audio_mix_volume_SSE2(float *out, const float *in, float vol, size_t samples)
{
size_t i;
size_t i, remaining_samples;
__m128 volume = _mm_set1_ps(vol);
for (i = 0; i + 16 <= samples; i += 16, out += 16, in += 16)
@ -71,7 +72,10 @@ void audio_mix_volume_SSE2(float *out, const float *in, float vol, size_t sample
_mm_storeu_ps(out + 4 * j, _mm_add_ps(input[j], additive[j]));
}
audio_mix_volume_C(out, in, vol, samples - i);
remaining_samples = samples - i;
for (i = 0; i < remaining_samples; i++)
out[i] += in[i] * vol;
}
#endif
@ -80,12 +84,14 @@ void audio_mix_free_chunk(audio_chunk_t *chunk)
if (!chunk)
return;
#ifdef HAVE_RWAV
if (chunk->rwav && chunk->rwav->samples)
{
/* rwav_free only frees the samples */
rwav_free(chunk->rwav);
free(chunk->rwav);
}
#endif
if (chunk->buf)
free(chunk->buf);
@ -110,24 +116,44 @@ void audio_mix_free_chunk(audio_chunk_t *chunk)
audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
{
#ifdef HAVE_RWAV
int sample_size;
int64_t len = 0;
void *buf = NULL;
audio_chunk_t *chunk = (audio_chunk_t*)calloc(1, sizeof(*chunk));
int64_t len = 0;
void *buf = NULL;
audio_chunk_t *chunk = (audio_chunk_t*)malloc(sizeof(*chunk));
if (!chunk)
return NULL;
chunk->buf = NULL;
chunk->upsample_buf = NULL;
chunk->float_buf = NULL;
chunk->float_resample_buf = NULL;
chunk->resample_buf = NULL;
chunk->len = 0;
chunk->resample_len = 0;
chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t));
chunk->sample_rate = sample_rate;
chunk->resample = false;
chunk->resampler = NULL;
chunk->resampler_data = NULL;
chunk->ratio = 0.00f;
chunk->rwav->bitspersample = 0;
chunk->rwav->numchannels = 0;
chunk->rwav->samplerate = 0;
chunk->rwav->numsamples = 0;
chunk->rwav->subchunk2size = 0;
chunk->rwav->samples = NULL;
if (!filestream_read_file(path, &buf, &len))
{
printf("Could not open WAV file for reading.\n");
goto error;
}
chunk->sample_rate = sample_rate;
chunk->buf = buf;
chunk->len = len;
chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t));
chunk->buf = buf;
chunk->len = len;
if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)
{
@ -137,28 +163,42 @@ audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
/* numsamples does not know or care about
* multiple channels, but we need space for 2 */
chunk->upsample_buf = (int16_t*)memalign_alloc(128,
chunk->upsample_buf = (int16_t*)memalign_alloc(128,
chunk->rwav->numsamples * 2 * sizeof(int16_t));
sample_size = chunk->rwav->bitspersample / 8;
sample_size = chunk->rwav->bitspersample / 8;
if (sample_size == 1)
{
unsigned i;
for (i = 0; i < chunk->rwav->numsamples; i++)
{
uint8_t *sample = (
(uint8_t*)chunk->rwav->samples) +
(i * chunk->rwav->numchannels);
if (chunk->rwav->numchannels == 1)
{
for (i = 0; i < chunk->rwav->numsamples; i++)
{
uint8_t *sample = (
(uint8_t*)chunk->rwav->samples) + i;
chunk->upsample_buf[i * 2] = (int16_t)((sample[0] - 128) << 8);
chunk->upsample_buf[i * 2] =
(int16_t)((sample[0] - 128) << 8);
chunk->upsample_buf[(i * 2) + 1] =
(int16_t)((sample[0] - 128) << 8);
}
}
else if (chunk->rwav->numchannels == 2)
{
for (i = 0; i < chunk->rwav->numsamples; i++)
{
uint8_t *sample = (
(uint8_t*)chunk->rwav->samples) +
(i * 2);
if (chunk->rwav->numchannels == 1)
chunk->upsample_buf[(i * 2) + 1] = (int16_t)((sample[0] - 128) << 8);
else if (chunk->rwav->numchannels == 2)
chunk->upsample_buf[(i * 2) + 1] = (int16_t)((sample[1] - 128) << 8);
}
chunk->upsample_buf[i * 2] =
(int16_t)((sample[0] - 128) << 8);
chunk->upsample_buf[(i * 2) + 1] =
(int16_t)((sample[1] - 128) << 8);
}
}
}
else if (sample_size == 2)
{
@ -168,14 +208,16 @@ audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
for (i = 0; i < chunk->rwav->numsamples; i++)
{
int16_t sample = ((int16_t*)chunk->rwav->samples)[i];
int16_t sample = ((int16_t*)
chunk->rwav->samples)[i];
chunk->upsample_buf[i * 2] = sample;
chunk->upsample_buf[(i * 2) + 1] = sample;
}
}
else if (chunk->rwav->numchannels == 2)
memcpy(chunk->upsample_buf, chunk->rwav->samples, chunk->rwav->subchunk2size);
memcpy(chunk->upsample_buf, chunk->rwav->samples,
chunk->rwav->subchunk2size);
}
else if (sample_size != 2)
{
@ -187,7 +229,7 @@ audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
if (sample_rate != (int)chunk->rwav->samplerate)
{
chunk->resample = true;
chunk->ratio = (double)sample_rate / chunk->rwav->samplerate;
chunk->ratio = (double)sample_rate / chunk->rwav->samplerate;
retro_resampler_realloc(&chunk->resampler_data,
&chunk->resampler,
@ -199,12 +241,18 @@ audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
{
struct resampler_data info;
chunk->float_buf = (float*)memalign_alloc(128, chunk->rwav->numsamples * 2 * chunk->ratio * sizeof(float));
chunk->float_buf = (float*)memalign_alloc(128,
chunk->rwav->numsamples * 2 *
chunk->ratio * sizeof(float));
/* why is *3 needed instead of just *2? does the sinc driver require more space than we know about? */
chunk->float_resample_buf = (float*)memalign_alloc(128, chunk->rwav->numsamples * 3 * chunk->ratio * sizeof(float));
/* why is *3 needed instead of just *2? Does the
* sinc driver require more space than we know about? */
chunk->float_resample_buf = (float*)memalign_alloc(128,
chunk->rwav->numsamples * 3 *
chunk->ratio * sizeof(float));
convert_s16_to_float(chunk->float_buf, chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);
convert_s16_to_float(chunk->float_buf,
chunk->upsample_buf, chunk->rwav->numsamples * 2, 1.0);
info.data_in = (const float*)chunk->float_buf;
info.data_out = chunk->float_resample_buf;
@ -216,10 +264,13 @@ audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
chunk->resampler->process(chunk->resampler_data, &info);
/* number of output_frames does not increase with multiple channels, but assume we need space for 2 */
chunk->resample_buf = (int16_t*)memalign_alloc(128, info.output_frames * 2 * sizeof(int16_t));
/* number of output_frames does not increase with
* multiple channels, but assume we need space for 2 */
chunk->resample_buf = (int16_t*)memalign_alloc(128,
info.output_frames * 2 * sizeof(int16_t));
chunk->resample_len = info.output_frames;
convert_float_to_s16(chunk->resample_buf, chunk->float_resample_buf, info.output_frames * 2);
convert_float_to_s16(chunk->resample_buf,
chunk->float_resample_buf, info.output_frames * 2);
}
}
@ -227,6 +278,7 @@ audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
error:
audio_mix_free_chunk(chunk);
#endif
return NULL;
}
@ -235,12 +287,14 @@ size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
if (!chunk)
return 0;
#ifdef HAVE_RWAV
if (chunk->rwav)
{
if (chunk->resample)
return chunk->resample_len;
return chunk->rwav->numsamples;
}
#endif
/* no other filetypes supported yet */
return 0;
@ -256,11 +310,13 @@ size_t audio_mix_get_chunk_num_samples(audio_chunk_t *chunk)
*
* Returns: A signed 16-bit audio sample.
**/
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_t index)
int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk,
unsigned channel, size_t index)
{
if (!chunk)
return 0;
#ifdef HAVE_RWAV
if (chunk->rwav)
{
int sample_size = chunk->rwav->bitspersample / 8;
@ -271,15 +327,18 @@ int16_t audio_mix_get_chunk_sample(audio_chunk_t *chunk, unsigned channel, size_
if (chunk->resample)
sample = (uint8_t*)chunk->resample_buf +
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
(sample_size * index * chunk->rwav->numchannels)
+ (channel * sample_size);
else
sample = (uint8_t*)chunk->upsample_buf +
(sample_size * index * chunk->rwav->numchannels) + (channel * sample_size);
(sample_size * index * chunk->rwav->numchannels)
+ (channel * sample_size);
sample_out = (int16_t)*sample;
return sample_out;
}
#endif
/* no other filetypes supported yet */
return 0;
@ -290,6 +349,7 @@ int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
if (!chunk)
return 0;
#ifdef HAVE_RWAV
if (chunk->rwav)
{
int16_t *sample;
@ -301,6 +361,7 @@ int16_t* audio_mix_get_chunk_samples(audio_chunk_t *chunk)
return sample;
}
#endif
return NULL;
}
@ -310,8 +371,10 @@ int audio_mix_get_chunk_num_channels(audio_chunk_t *chunk)
if (!chunk)
return 0;
#ifdef HAVE_RWAV
if (chunk->rwav)
return chunk->rwav->numchannels;
#endif
/* don't support other formats yet */
return 0;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (audio_mixer.c).
@ -20,10 +20,16 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
#include <audio/audio_mixer.h>
#include <audio/audio_resampler.h>
#ifdef HAVE_RWAV
#include <formats/rwav.h>
#endif
#include <memalign.h>
#include <stdio.h>
@ -31,10 +37,6 @@
#include <string.h>
#include <math.h>
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif
#ifdef HAVE_STB_VORBIS
#define STB_VORBIS_NO_PUSHDATA_API
#define STB_VORBIS_NO_STDIO
@ -71,16 +73,16 @@ struct audio_mixer_sound
struct
{
/* wav */
unsigned frames;
const float* pcm;
unsigned frames;
} wav;
#ifdef HAVE_STB_VORBIS
struct
{
/* ogg */
unsigned size;
const void* data;
unsigned size;
} ogg;
#endif
@ -88,8 +90,8 @@ struct audio_mixer_sound
struct
{
/* flac */
unsigned size;
const void* data;
unsigned size;
} flac;
#endif
@ -97,8 +99,8 @@ struct audio_mixer_sound
struct
{
/* mp */
unsigned size;
const void* data;
unsigned size;
} mp3;
#endif
@ -106,8 +108,8 @@ struct audio_mixer_sound
struct
{
/* mod/s3m/xm */
unsigned size;
const void* data;
unsigned size;
} mod;
#endif
} types;
@ -115,12 +117,6 @@ struct audio_mixer_sound
struct audio_mixer_voice
{
bool repeat;
unsigned type;
float volume;
audio_mixer_sound_t *sound;
audio_mixer_stop_cb_t stop_cb;
union
{
struct
@ -131,63 +127,71 @@ struct audio_mixer_voice
#ifdef HAVE_STB_VORBIS
struct
{
unsigned position;
unsigned samples;
unsigned buf_samples;
float* buffer;
float ratio;
stb_vorbis *stream;
void *resampler_data;
const retro_resampler_t *resampler;
float *buffer;
unsigned position;
unsigned samples;
unsigned buf_samples;
float ratio;
} ogg;
#endif
#ifdef HAVE_DR_FLAC
struct
{
unsigned position;
unsigned samples;
unsigned buf_samples;
float* buffer;
float ratio;
drflac *stream;
void *resampler_data;
const retro_resampler_t *resampler;
unsigned position;
unsigned samples;
unsigned buf_samples;
float ratio;
} flac;
#endif
#ifdef HAVE_DR_MP3
struct
{
unsigned position;
unsigned samples;
unsigned buf_samples;
float* buffer;
float ratio;
drmp3 stream;
void *resampler_data;
const retro_resampler_t *resampler;
float* buffer;
unsigned position;
unsigned samples;
unsigned buf_samples;
float ratio;
} mp3;
#endif
#ifdef HAVE_IBXM
struct
{
unsigned position;
unsigned samples;
unsigned buf_samples;
int* buffer;
struct replay* stream;
struct module* module;
unsigned position;
unsigned samples;
unsigned buf_samples;
} mod;
#endif
} types;
audio_mixer_sound_t *sound;
audio_mixer_stop_cb_t stop_cb;
unsigned type;
float volume;
bool repeat;
};
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {{0}};
/* TODO/FIXME - static globals */
static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES] = {0};
static unsigned s_rate = 0;
static bool wav2float(const rwav_t* wav, float** pcm, size_t samples_out)
#ifdef HAVE_RWAV
static bool wav_to_float(const rwav_t* wav, float** pcm, size_t samples_out)
{
size_t i;
/* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */
@ -299,6 +303,7 @@ static bool one_shot_resample(const float* in, size_t samples_in,
resampler->free(data);
return true;
}
#endif
void audio_mixer_init(unsigned rate)
{
@ -320,6 +325,7 @@ void audio_mixer_done(void)
audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size)
{
#ifdef HAVE_RWAV
/* WAV data */
rwav_t wav;
/* WAV samples converted to float */
@ -334,7 +340,7 @@ audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size)
samples = wav.numsamples * 2;
if (!wav2float(&wav, &pcm, samples))
if (!wav_to_float(&wav, &pcm, samples))
return NULL;
if (wav.samplerate != s_rate)
@ -364,6 +370,9 @@ audio_mixer_sound_t* audio_mixer_load_wav(void *buffer, int32_t size)
rwav_free(&wav);
return sound;
#else
return NULL;
#endif
}
audio_mixer_sound_t* audio_mixer_load_ogg(void *buffer, int32_t size)
@ -839,8 +848,8 @@ void audio_mixer_stop(audio_mixer_voice_t* voice)
if (voice)
{
stop_cb = voice->stop_cb;
sound = voice->sound;
stop_cb = voice->stop_cb;
sound = voice->sound;
voice->type = AUDIO_MIXER_TYPE_NONE;
@ -899,8 +908,7 @@ static void audio_mixer_mix_ogg(float* buffer, size_t num_frames,
float volume)
{
int i;
struct resampler_data info = { 0 };
float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
float* temp_buffer = NULL;
unsigned buf_free = (unsigned)(num_frames * 2);
unsigned temp_samples = 0;
float* pcm = NULL;
@ -908,6 +916,9 @@ static void audio_mixer_mix_ogg(float* buffer, size_t num_frames,
if (voice->types.ogg.position == voice->types.ogg.samples)
{
again:
if (temp_buffer == NULL)
temp_buffer = (float*)malloc(AUDIO_MIXER_TEMP_BUFFER * sizeof(float));
temp_samples = stb_vorbis_get_samples_float_interleaved(
voice->types.ogg.stream, 2, temp_buffer,
AUDIO_MIXER_TEMP_BUFFER) * 2;
@ -922,28 +933,30 @@ again:
stb_vorbis_seek_start(voice->types.ogg.stream);
goto again;
}
else
{
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
goto cleanup;
}
info.data_in = temp_buffer;
info.data_out = voice->types.ogg.buffer;
info.input_frames = temp_samples / 2;
info.output_frames = 0;
info.ratio = voice->types.ogg.ratio;
if (voice->types.ogg.resampler)
{
voice->types.ogg.resampler->process(voice->types.ogg.resampler_data, &info);
struct resampler_data info;
info.data_in = temp_buffer;
info.data_out = voice->types.ogg.buffer;
info.input_frames = temp_samples / 2;
info.output_frames = 0;
info.ratio = voice->types.ogg.ratio;
voice->types.ogg.resampler->process(
voice->types.ogg.resampler_data, &info);
}
else
memcpy(voice->types.ogg.buffer, temp_buffer, temp_samples * sizeof(float));
memcpy(voice->types.ogg.buffer, temp_buffer,
temp_samples * sizeof(float));
voice->types.ogg.position = 0;
voice->types.ogg.samples = voice->types.ogg.buf_samples;
}
@ -958,15 +971,16 @@ again:
buf_free -= voice->types.ogg.samples;
goto again;
}
else
{
int i;
for (i = buf_free; i != 0; --i )
*buffer++ += *pcm++ * volume;
voice->types.ogg.position += buf_free;
voice->types.ogg.samples -= buf_free;
}
for (i = buf_free; i != 0; --i )
*buffer++ += *pcm++ * volume;
voice->types.ogg.position += buf_free;
voice->types.ogg.samples -= buf_free;
cleanup:
if (temp_buffer != NULL)
free(temp_buffer);
}
#endif
@ -1000,14 +1014,12 @@ again:
replay_seek( voice->types.mod.stream, 0);
goto again;
}
else
{
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
voice->types.mod.position = 0;
@ -1028,20 +1040,17 @@ again:
buf_free -= voice->types.mod.samples;
goto again;
}
else
{
int i;
for (i = buf_free; i != 0; --i )
{
samplei = *pcm++ * volume;
samplef = (float)((int)samplei + 32768) / 65535.0f;
samplef = samplef * 2.0f - 1.0f;
*buffer++ += samplef;
}
voice->types.mod.position += buf_free;
voice->types.mod.samples -= buf_free;
for (i = buf_free; i != 0; --i )
{
samplei = *pcm++ * volume;
samplef = (float)((int)samplei + 32768) / 65535.0f;
samplef = samplef * 2.0f - 1.0f;
*buffer++ += samplef;
}
voice->types.mod.position += buf_free;
voice->types.mod.samples -= buf_free;
}
#endif
@ -1051,11 +1060,11 @@ static void audio_mixer_mix_flac(float* buffer, size_t num_frames,
float volume)
{
int i;
struct resampler_data info = { 0 };
struct resampler_data info;
float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
unsigned buf_free = (unsigned)(num_frames * 2);
unsigned temp_samples = 0;
float* pcm = NULL;
float *pcm = NULL;
if (voice->types.flac.position == voice->types.flac.samples)
{
@ -1071,14 +1080,12 @@ again:
drflac_seek_to_sample(voice->types.flac.stream,0);
goto again;
}
else
{
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
info.data_in = temp_buffer;
@ -1088,11 +1095,10 @@ again:
info.ratio = voice->types.flac.ratio;
if (voice->types.flac.resampler)
{
voice->types.flac.resampler->process(voice->types.flac.resampler_data, &info);
}
voice->types.flac.resampler->process(
voice->types.flac.resampler_data, &info);
else
memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float));
memcpy(voice->types.flac.buffer, temp_buffer, temp_samples * sizeof(float));
voice->types.flac.position = 0;
voice->types.flac.samples = voice->types.flac.buf_samples;
}
@ -1107,15 +1113,12 @@ again:
buf_free -= voice->types.flac.samples;
goto again;
}
else
{
int i;
for (i = buf_free; i != 0; --i )
*buffer++ += *pcm++ * volume;
voice->types.flac.position += buf_free;
voice->types.flac.samples -= buf_free;
}
for (i = buf_free; i != 0; --i )
*buffer++ += *pcm++ * volume;
voice->types.flac.position += buf_free;
voice->types.flac.samples -= buf_free;
}
#endif
@ -1125,7 +1128,7 @@ static void audio_mixer_mix_mp3(float* buffer, size_t num_frames,
float volume)
{
int i;
struct resampler_data info = { 0 };
struct resampler_data info;
float temp_buffer[AUDIO_MIXER_TEMP_BUFFER] = { 0 };
unsigned buf_free = (unsigned)(num_frames * 2);
unsigned temp_samples = 0;
@ -1134,7 +1137,9 @@ static void audio_mixer_mix_mp3(float* buffer, size_t num_frames,
if (voice->types.mp3.position == voice->types.mp3.samples)
{
again:
temp_samples = (unsigned)drmp3_read_f32(&voice->types.mp3.stream, AUDIO_MIXER_TEMP_BUFFER/2, temp_buffer) * 2;
temp_samples = (unsigned)drmp3_read_f32(
&voice->types.mp3.stream,
AUDIO_MIXER_TEMP_BUFFER / 2, temp_buffer) * 2;
if (temp_samples == 0)
{
@ -1146,14 +1151,12 @@ again:
drmp3_seek_to_frame(&voice->types.mp3.stream,0);
goto again;
}
else
{
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
if (voice->stop_cb)
voice->stop_cb(voice->sound, AUDIO_MIXER_SOUND_FINISHED);
voice->type = AUDIO_MIXER_TYPE_NONE;
return;
}
info.data_in = temp_buffer;
@ -1163,9 +1166,11 @@ again:
info.ratio = voice->types.mp3.ratio;
if (voice->types.mp3.resampler)
voice->types.mp3.resampler->process(voice->types.mp3.resampler_data, &info);
voice->types.mp3.resampler->process(
voice->types.mp3.resampler_data, &info);
else
memcpy(voice->types.mp3.buffer, temp_buffer, temp_samples * sizeof(float));
memcpy(voice->types.mp3.buffer, temp_buffer,
temp_samples * sizeof(float));
voice->types.mp3.position = 0;
voice->types.mp3.samples = voice->types.mp3.buf_samples;
}
@ -1180,19 +1185,17 @@ again:
buf_free -= voice->types.mp3.samples;
goto again;
}
else
{
int i;
for (i = buf_free; i != 0; --i )
*buffer++ += *pcm++ * volume;
voice->types.mp3.position += buf_free;
voice->types.mp3.samples -= buf_free;
}
for (i = buf_free; i != 0; --i )
*buffer++ += *pcm++ * volume;
voice->types.mp3.position += buf_free;
voice->types.mp3.samples -= buf_free;
}
#endif
void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bool override)
void audio_mixer_mix(float* buffer, size_t num_frames,
float volume_override, bool override)
{
unsigned i;
size_t j = 0;
@ -1233,7 +1236,7 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo
}
}
for (j = 0, sample = buffer; j < num_frames; j++, sample++)
for (j = 0, sample = buffer; j < num_frames * 2; j++, sample++)
{
if (*sample < -1.0f)
*sample = -1.0f;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (float_to_s16.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (float_to_s16_neon.S).
@ -19,7 +19,7 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(__ARM_NEON__)
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
#ifndef __MACH__
.arm

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (float_to_s16_neon.S).
@ -19,7 +19,7 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(__ARM_NEON__)
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
#if defined(__thumb__)
#define DECL_ARMMODE(x) " .align 2\n" " .global " x "\n" " .thumb\n" " .thumb_func\n" " .type " x ", %function\n" x ":\n"

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (s16_to_float.c).
@ -50,7 +50,7 @@ void convert_s16_float_asm(float *out, const int16_t *in,
void convert_s16_to_float(float *out,
const int16_t *in, size_t samples, float gain)
{
size_t i = 0;
unsigned i = 0;
#if defined(__SSE2__)
float fgain = gain / UINT32_C(0x80000000);
@ -77,7 +77,6 @@ void convert_s16_to_float(float *out,
* optimize for the good path (very likely). */
if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
{
size_t i;
const vector float gain_vec = { gain, gain , gain, gain };
const vector float zero_vec = { 0.0f, 0.0f, 0.0f, 0.0f};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (s16_to_float_neon.S).
@ -19,7 +19,7 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(__ARM_NEON__)
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
#ifndef __MACH__
.arm

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (s16_to_float_neon.S).
@ -19,7 +19,7 @@
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(__ARM_NEON__)
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
#if defined(__thumb__)
#define DECL_ARMMODE(x) " .align 2\n" " .global " x "\n" " .thumb\n" " .thumb_func\n" " .type " x ", %function\n" x ":\n"

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dsp_filter.c).

View File

@ -8,17 +8,15 @@ INSTALLDIR := $(PREFIX)/lib/retroarch/filters/audio
ifeq ($(platform),)
platform = unix
ifeq ($(shell uname -a),)
ifeq ($(shell uname -s),)
platform = win
else ifneq ($(findstring MINGW,$(shell uname -a)),)
platform = win
else ifneq ($(findstring Darwin,$(shell uname -a)),)
else ifneq ($(findstring Darwin,$(shell uname -s)),)
platform = osx
arch = intel
arch = intel
ifeq ($(shell uname -p),powerpc)
arch = ppc
endif
else ifneq ($(findstring win,$(shell uname -a)),)
else ifneq ($(findstring MINGW,$(shell uname -s)),)
platform = win
endif
endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (chorus.c).

0
externals/libretro-common/audio/dsp_filters/configure vendored Normal file → Executable file
View File

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (echo.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (echo.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (eq.c).
@ -233,6 +233,7 @@ static void create_filter(struct eq_data *eq, unsigned size_log2,
time_filter[i] *= window_mod * kaiser_window_function(phase, beta);
}
#ifdef DEBUG
/* Debugging. */
if (filter_path)
{
@ -244,6 +245,7 @@ static void create_filter(struct eq_data *eq, unsigned size_log2,
fclose(file);
}
}
#endif
/* Padded FFT to create our FFT filter.
* Make our even-length filter odd by discarding the first coefficient.

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (fft.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (fft.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (iir.c).
@ -223,7 +223,8 @@ static void iir_filter_init(struct iir_data *iir,
case RIAA_phono: /* http://www.dsprelated.com/showmessage/73300/3.php */
{
double y, b_re, a_re, b_im, a_im, g;
float b[3], a[3];
float b[3] = {0.0f};
float a[3] = {0.0f};
if ((int)sample_rate == 44100)
{

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (panning.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (phaser.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (reverb.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (tremolo.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (vibrato.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (wahwah.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (audio_resampler.c).
@ -28,12 +28,28 @@
#include <audio/audio_resampler.h>
static void resampler_null_process(void *a, struct resampler_data *b) { }
static void resampler_null_free(void *a) { }
static void *resampler_null_init(const struct resampler_config *a, double b,
enum resampler_quality c, resampler_simd_mask_t d) { return (void*)0; }
retro_resampler_t null_resampler = {
resampler_null_init,
resampler_null_process,
resampler_null_free,
RESAMPLER_API_VERSION,
"null",
"null"
};
static const retro_resampler_t *resampler_drivers[] = {
&sinc_resampler,
#ifdef HAVE_CC_RESAMPLER
&CC_resampler,
#endif
#ifdef HAVE_NEAREST_RESAMPLER
&nearest_resampler,
#endif
&null_resampler,
NULL,
};
@ -66,36 +82,6 @@ static int find_resampler_driver_index(const char *ident)
return -1;
}
/**
* audio_resampler_driver_find_handle:
* @idx : index of driver to get handle to.
*
* Returns: handle to audio resampler driver at index. Can be NULL
* if nothing found.
**/
const void *audio_resampler_driver_find_handle(int idx)
{
const void *drv = resampler_drivers[idx];
if (!drv)
return NULL;
return drv;
}
/**
* audio_resampler_driver_find_ident:
* @idx : index of driver to get handle to.
*
* Returns: Human-readable identifier of audio resampler driver at index.
* Can be NULL if nothing found.
**/
const char *audio_resampler_driver_find_ident(int idx)
{
const retro_resampler_t *drv = resampler_drivers[idx];
if (!drv)
return NULL;
return drv->ident;
}
/**
* find_resampler_driver:
* @ident : Identifier of resampler driver to find.
@ -140,6 +126,37 @@ static bool resampler_append_plugs(void **re,
return true;
}
/**
* audio_resampler_driver_find_handle:
* @idx : index of driver to get handle to.
*
* Returns: handle to audio resampler driver at index. Can be NULL
* if nothing found.
**/
const void *audio_resampler_driver_find_handle(int idx)
{
const void *drv = resampler_drivers[idx];
if (!drv)
return NULL;
return drv;
}
/**
* audio_resampler_driver_find_ident:
* @idx : index of driver to get handle to.
*
* Returns: Human-readable identifier of audio resampler driver at index.
* Can be NULL if nothing found.
**/
const char *audio_resampler_driver_find_ident(int idx)
{
const retro_resampler_t *drv = resampler_drivers[idx];
if (!drv)
return NULL;
return drv->ident;
}
/**
* retro_resampler_realloc:
* @re : Resampler handle

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nearest_resampler.c).
@ -40,11 +40,11 @@ static void resampler_nearest_process(
audio_frame_float_t *outp = (audio_frame_float_t*)data->data_out;
float ratio = 1.0 / data->ratio;
while(inp != inp_max)
while (inp != inp_max)
{
while(re->fraction > 1)
while (re->fraction > 1)
{
*outp++ = *inp;
*outp++ = *inp;
re->fraction -= ratio;
}
re->fraction++;
@ -68,15 +68,9 @@ static void *resampler_nearest_init(const struct resampler_config *config,
{
rarch_nearest_resampler_t *re = (rarch_nearest_resampler_t*)
calloc(1, sizeof(rarch_nearest_resampler_t));
(void)config;
(void)mask;
if (!re)
return NULL;
re->fraction = 0;
return re;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (sinc_resampler.c).
@ -27,6 +27,7 @@
#include <math.h>
#include <string.h>
#include <retro_environment.h>
#include <retro_inline.h>
#include <filters.h>
#include <memalign.h>
@ -67,6 +68,13 @@ enum sinc_window
typedef struct rarch_sinc_resampler
{
/* A buffer for phase_table, buffer_l and buffer_r
* are created in a single calloc().
* Ensure that we get as good cache locality as we can hope for. */
float *main_buffer;
float *phase_table;
float *buffer_l;
float *buffer_r;
unsigned enable_avx;
unsigned phase_bits;
unsigned subphase_bits;
@ -77,14 +85,6 @@ typedef struct rarch_sinc_resampler
float subphase_mod;
float kaiser_beta;
enum sinc_window window_type;
/* A buffer for phase_table, buffer_l and buffer_r
* are created in a single calloc().
* Ensure that we get as good cache locality as we can hope for. */
float *main_buffer;
float *phase_table;
float *buffer_l;
float *buffer_r;
} rarch_sinc_resampler_t;
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
@ -129,19 +129,21 @@ static void resampler_sinc_process_neon(void *re_, struct resampler_data *data)
frames--;
}
while (resamp->time < phases)
{
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
unsigned phase = resamp->time >> resamp->subphase_bits;
const float *phase_table = resamp->phase_table + phase * taps;
while (resamp->time < phases)
{
unsigned phase = resamp->time >> resamp->subphase_bits;
const float *phase_table = resamp->phase_table + phase * taps;
process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);
process_sinc_neon_asm(output, buffer_l, buffer_r, phase_table, taps);
output += 2;
out_frames++;
resamp->time += ratio;
output += 2;
out_frames++;
resamp->time += ratio;
}
}
}
@ -161,87 +163,141 @@ static void resampler_sinc_process_avx(void *re_, struct resampler_data *data)
size_t frames = data->input_frames;
size_t out_frames = 0;
while (frames)
if (resamp->window_type == SINC_WINDOW_KAISER)
{
while (frames && resamp->time >= phases)
while (frames)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
while (frames && resamp->time >= phases)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->time -= phases;
frames--;
resamp->time -= phases;
frames--;
}
{
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
while (resamp->time < phases)
{
unsigned i;
unsigned phase = resamp->time >> resamp->subphase_bits;
float *phase_table = resamp->phase_table + phase * taps * 2;
float *delta_table = phase_table + taps;
__m256 delta = _mm256_set1_ps((float)
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
__m256 sum_l = _mm256_setzero_ps();
__m256 sum_r = _mm256_setzero_ps();
for (i = 0; i < taps; i += 8)
{
__m256 buf_l = _mm256_loadu_ps(buffer_l + i);
__m256 buf_r = _mm256_loadu_ps(buffer_r + i);
__m256 deltas = _mm256_load_ps(delta_table + i);
__m256 sinc = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),
_mm256_mul_ps(deltas, delta));
sum_l = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
sum_r = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
}
/* hadd on AVX is weird, and acts on low-lanes
* and high-lanes separately. */
__m256 res_l = _mm256_hadd_ps(sum_l, sum_l);
__m256 res_r = _mm256_hadd_ps(sum_r, sum_r);
res_l = _mm256_hadd_ps(res_l, res_l);
res_r = _mm256_hadd_ps(res_r, res_r);
res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);
/* This is optimized to mov %xmmN, [mem].
* There doesn't seem to be any _mm256_store_ss intrinsic. */
_mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
_mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));
output += 2;
out_frames++;
resamp->time += ratio;
}
}
}
while (resamp->time < phases)
}
else
{
while (frames)
{
unsigned i;
__m256 delta, sum_l, sum_r;
float *delta_table = NULL;
float *phase_table = NULL;
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
unsigned phase = resamp->time >> resamp->subphase_bits;
phase_table = resamp->phase_table + phase * taps;
if (resamp->window_type == SINC_WINDOW_KAISER)
while (frames && resamp->time >= phases)
{
phase_table = resamp->phase_table + phase * taps * 2;
delta_table = phase_table + taps;
delta = _mm256_set1_ps((float)
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->time -= phases;
frames--;
}
sum_l = _mm256_setzero_ps();
sum_r = _mm256_setzero_ps();
for (i = 0; i < taps; i += 8)
{
__m256 sinc;
__m256 buf_l = _mm256_loadu_ps(buffer_l + i);
__m256 buf_r = _mm256_loadu_ps(buffer_r + i);
if (resamp->window_type == SINC_WINDOW_KAISER)
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
while (resamp->time < phases)
{
__m256 deltas = _mm256_load_ps(delta_table + i);
sinc = _mm256_add_ps(_mm256_load_ps((const float*)phase_table + i),
_mm256_mul_ps(deltas, delta));
}
else
{
sinc = _mm256_load_ps((const float*)phase_table + i);
}
unsigned i;
__m256 delta;
unsigned phase = resamp->time >> resamp->subphase_bits;
float *phase_table = resamp->phase_table + phase * taps;
sum_l = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
sum_r = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
__m256 sum_l = _mm256_setzero_ps();
__m256 sum_r = _mm256_setzero_ps();
for (i = 0; i < taps; i += 8)
{
__m256 buf_l = _mm256_loadu_ps(buffer_l + i);
__m256 buf_r = _mm256_loadu_ps(buffer_r + i);
__m256 sinc = _mm256_load_ps((const float*)phase_table + i);
sum_l = _mm256_add_ps(sum_l, _mm256_mul_ps(buf_l, sinc));
sum_r = _mm256_add_ps(sum_r, _mm256_mul_ps(buf_r, sinc));
}
/* hadd on AVX is weird, and acts on low-lanes
* and high-lanes separately. */
__m256 res_l = _mm256_hadd_ps(sum_l, sum_l);
__m256 res_r = _mm256_hadd_ps(sum_r, sum_r);
res_l = _mm256_hadd_ps(res_l, res_l);
res_r = _mm256_hadd_ps(res_r, res_r);
res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);
/* This is optimized to mov %xmmN, [mem].
* There doesn't seem to be any _mm256_store_ss intrinsic. */
_mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
_mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));
output += 2;
out_frames++;
resamp->time += ratio;
}
}
/* hadd on AVX is weird, and acts on low-lanes
* and high-lanes separately. */
__m256 res_l = _mm256_hadd_ps(sum_l, sum_l);
__m256 res_r = _mm256_hadd_ps(sum_r, sum_r);
res_l = _mm256_hadd_ps(res_l, res_l);
res_r = _mm256_hadd_ps(res_r, res_r);
res_l = _mm256_add_ps(_mm256_permute2f128_ps(res_l, res_l, 1), res_l);
res_r = _mm256_add_ps(_mm256_permute2f128_ps(res_r, res_r, 1), res_r);
/* This is optimized to mov %xmmN, [mem].
* There doesn't seem to be any _mm256_store_ss intrinsic. */
_mm_store_ss(output + 0, _mm256_extractf128_ps(res_l, 0));
_mm_store_ss(output + 1, _mm256_extractf128_ps(res_r, 0));
output += 2;
out_frames++;
resamp->time += ratio;
}
}
@ -261,99 +317,161 @@ static void resampler_sinc_process_sse(void *re_, struct resampler_data *data)
size_t frames = data->input_frames;
size_t out_frames = 0;
while (frames)
if (resamp->window_type == SINC_WINDOW_KAISER)
{
while (frames && resamp->time >= phases)
while (frames)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
while (frames && resamp->time >= phases)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->time -= phases;
frames--;
resamp->time -= phases;
frames--;
}
{
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
while (resamp->time < phases)
{
unsigned i;
__m128 sum;
unsigned phase = resamp->time >> resamp->subphase_bits;
float *phase_table = resamp->phase_table + phase * taps * 2;
float *delta_table = phase_table + taps;
__m128 delta = _mm_set1_ps((float)
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
__m128 sum_l = _mm_setzero_ps();
__m128 sum_r = _mm_setzero_ps();
for (i = 0; i < taps; i += 4)
{
__m128 buf_l = _mm_loadu_ps(buffer_l + i);
__m128 buf_r = _mm_loadu_ps(buffer_r + i);
__m128 deltas = _mm_load_ps(delta_table + i);
__m128 _sinc = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),
_mm_mul_ps(deltas, delta));
sum_l = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
sum_r = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
}
/* Them annoying shuffles.
* sum_l = { l3, l2, l1, l0 }
* sum_r = { r3, r2, r1, r0 }
*/
sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
_MM_SHUFFLE(1, 0, 1, 0)),
_mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));
/* sum = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
* sum = { R1, R0, L1, L0 }
*/
sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);
/* sum = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
* sum = { X, R, X, L }
*/
/* Store L */
_mm_store_ss(output + 0, sum);
/* movehl { X, R, X, L } == { X, R, X, R } */
_mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));
output += 2;
out_frames++;
resamp->time += ratio;
}
}
}
while (resamp->time < phases)
}
else
{
while (frames)
{
unsigned i;
__m128 sum, sum_l, sum_r, delta;
float *phase_table = NULL;
float *delta_table = NULL;
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
unsigned phase = resamp->time >> resamp->subphase_bits;
while (frames && resamp->time >= phases)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
if (resamp->window_type == SINC_WINDOW_KAISER)
{
phase_table = resamp->phase_table + phase * taps * 2;
delta_table = phase_table + taps;
delta = _mm_set1_ps((float)
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod);
}
else
{
phase_table = resamp->phase_table + phase * taps;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->time -= phases;
frames--;
}
sum_l = _mm_setzero_ps();
sum_r = _mm_setzero_ps();
for (i = 0; i < taps; i += 4)
{
__m128 deltas, _sinc;
__m128 buf_l = _mm_loadu_ps(buffer_l + i);
__m128 buf_r = _mm_loadu_ps(buffer_r + i);
if (resamp->window_type == SINC_WINDOW_KAISER)
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
while (resamp->time < phases)
{
deltas = _mm_load_ps(delta_table + i);
_sinc = _mm_add_ps(_mm_load_ps((const float*)phase_table + i),
_mm_mul_ps(deltas, delta));
unsigned i;
__m128 sum;
unsigned phase = resamp->time >> resamp->subphase_bits;
float *phase_table = resamp->phase_table + phase * taps;
__m128 sum_l = _mm_setzero_ps();
__m128 sum_r = _mm_setzero_ps();
for (i = 0; i < taps; i += 4)
{
__m128 buf_l = _mm_loadu_ps(buffer_l + i);
__m128 buf_r = _mm_loadu_ps(buffer_r + i);
__m128 _sinc = _mm_load_ps((const float*)phase_table + i);
sum_l = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
sum_r = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
}
/* Them annoying shuffles.
* sum_l = { l3, l2, l1, l0 }
* sum_r = { r3, r2, r1, r0 }
*/
sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
_MM_SHUFFLE(1, 0, 1, 0)),
_mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));
/* sum = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
* sum = { R1, R0, L1, L0 }
*/
sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);
/* sum = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
* sum = { X, R, X, L }
*/
/* Store L */
_mm_store_ss(output + 0, sum);
/* movehl { X, R, X, L } == { X, R, X, R } */
_mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));
output += 2;
out_frames++;
resamp->time += ratio;
}
else
{
_sinc = _mm_load_ps((const float*)phase_table + i);
}
sum_l = _mm_add_ps(sum_l, _mm_mul_ps(buf_l, _sinc));
sum_r = _mm_add_ps(sum_r, _mm_mul_ps(buf_r, _sinc));
}
/* Them annoying shuffles.
* sum_l = { l3, l2, l1, l0 }
* sum_r = { r3, r2, r1, r0 }
*/
sum = _mm_add_ps(_mm_shuffle_ps(sum_l, sum_r,
_MM_SHUFFLE(1, 0, 1, 0)),
_mm_shuffle_ps(sum_l, sum_r, _MM_SHUFFLE(3, 2, 3, 2)));
/* sum = { r1, r0, l1, l0 } + { r3, r2, l3, l2 }
* sum = { R1, R0, L1, L0 }
*/
sum = _mm_add_ps(_mm_shuffle_ps(sum, sum, _MM_SHUFFLE(3, 3, 1, 1)), sum);
/* sum = {R1, R1, L1, L1 } + { R1, R0, L1, L0 }
* sum = { X, R, X, L }
*/
/* Store L */
_mm_store_ss(output + 0, sum);
/* movehl { X, R, X, L } == { X, R, X, R } */
_mm_store_ss(output + 1, _mm_movehl_ps(sum, sum));
output += 2;
out_frames++;
resamp->time += ratio;
}
}
@ -372,69 +490,112 @@ static void resampler_sinc_process_c(void *re_, struct resampler_data *data)
size_t frames = data->input_frames;
size_t out_frames = 0;
while (frames)
if (resamp->window_type == SINC_WINDOW_KAISER)
{
while (frames && resamp->time >= phases)
while (frames)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
while (frames && resamp->time >= phases)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->time -= phases;
frames--;
}
{
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
while (resamp->time < phases)
{
unsigned i;
float sum_l = 0.0f;
float sum_r = 0.0f;
unsigned phase = resamp->time >> resamp->subphase_bits;
float *phase_table = resamp->phase_table + phase * taps * 2;
float *delta_table = phase_table + taps;
float delta = (float)
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod;
for (i = 0; i < taps; i++)
{
float sinc_val = phase_table[i] + delta_table[i] * delta;
sum_l += buffer_l[i] * sinc_val;
sum_r += buffer_r[i] * sinc_val;
}
output[0] = sum_l;
output[1] = sum_r;
output += 2;
out_frames++;
resamp->time += ratio;
}
}
resamp->time -= phases;
frames--;
}
while (resamp->time < phases)
}
else
{
while (frames)
{
unsigned i;
float delta = 0.0f;
float sum_l = 0.0f;
float sum_r = 0.0f;
float *phase_table = NULL;
float *delta_table = NULL;
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
unsigned phase = resamp->time >> resamp->subphase_bits;
while (frames && resamp->time >= phases)
{
/* Push in reverse to make filter more obvious. */
if (!resamp->ptr)
resamp->ptr = resamp->taps;
resamp->ptr--;
if (resamp->window_type == SINC_WINDOW_KAISER)
{
phase_table = resamp->phase_table + phase * taps * 2;
delta_table = phase_table + taps;
delta = (float)
(resamp->time & resamp->subphase_mask) * resamp->subphase_mod;
}
else
{
phase_table = resamp->phase_table + phase * taps;
resamp->buffer_l[resamp->ptr + resamp->taps] =
resamp->buffer_l[resamp->ptr] = *input++;
resamp->buffer_r[resamp->ptr + resamp->taps] =
resamp->buffer_r[resamp->ptr] = *input++;
resamp->time -= phases;
frames--;
}
for (i = 0; i < taps; i++)
{
float sinc_val = phase_table[i];
const float *buffer_l = resamp->buffer_l + resamp->ptr;
const float *buffer_r = resamp->buffer_r + resamp->ptr;
unsigned taps = resamp->taps;
while (resamp->time < phases)
{
unsigned i;
float sum_l = 0.0f;
float sum_r = 0.0f;
unsigned phase = resamp->time >> resamp->subphase_bits;
float *phase_table = resamp->phase_table + phase * taps;
if (resamp->window_type == SINC_WINDOW_KAISER)
sinc_val = sinc_val + delta_table[i] * delta;
for (i = 0; i < taps; i++)
{
float sinc_val = phase_table[i];
sum_l += buffer_l[i] * sinc_val;
sum_r += buffer_r[i] * sinc_val;
sum_l += buffer_l[i] * sinc_val;
sum_r += buffer_r[i] * sinc_val;
}
output[0] = sum_l;
output[1] = sum_r;
output += 2;
out_frames++;
resamp->time += ratio;
}
}
output[0] = sum_l;
output[1] = sum_r;
output += 2;
out_frames++;
resamp->time += ratio;
}
}
data->output_frames = out_frames;
@ -506,7 +667,8 @@ static void sinc_init_table_kaiser(rarch_sinc_resampler_t *resamp,
}
}
static void sinc_init_table_lanczos(rarch_sinc_resampler_t *resamp, double cutoff,
static void sinc_init_table_lanczos(
rarch_sinc_resampler_t *resamp, double cutoff,
float *phase_table, int phases, int taps, bool calculate_delta)
{
int i, j;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (sinc_resampler_neon.S).
@ -20,7 +20,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(__ARM_NEON__)
#if defined(__ARM_NEON__) && !defined(DONT_WANT_ARM_OPTIMIZATIONS)
#ifndef __MACH__
.arm

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (cdrom.c).
@ -29,6 +29,7 @@
#include <stdio.h>
#include <string.h>
#include <compat/strl.h>
#include <compat/strcasestr.h>
#include <retro_math.h>
#include <retro_timers.h>
#include <streams/file_stream.h>
@ -96,6 +97,7 @@ void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame)
*frame = (*frame < 74) ? (*frame + 1) : 0;
}
#ifdef CDROM_DEBUG
static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
{
unsigned i;
@ -252,6 +254,7 @@ static void cdrom_print_sense_data(const unsigned char *sense, size_t len)
fflush(stdout);
}
#endif
#if defined(_WIN32) && !defined(_XBOX)
static int cdrom_send_command_win32(const libretro_vfs_implementation_file *stream, CDROM_CMD_Direction dir, void *buf, size_t len, unsigned char *cmd, size_t cmd_len, unsigned char *sense, size_t sense_len)
@ -519,7 +522,9 @@ retry:
}
else
{
#ifdef CDROM_DEBUG
cdrom_print_sense_data(sense, sizeof(sense));
#endif
/* INQUIRY/TEST/SENSE should never fail, don't retry. */
/* READ ATIP seems to fail outright on some drives with pressed discs, skip retries. */
@ -672,7 +677,9 @@ int cdrom_get_sense(libretro_vfs_implementation_file *stream, unsigned char *sen
if (rv)
return 1;
#ifdef CDROM_DEBUG
cdrom_print_sense_data(buf, sizeof(buf));
#endif
return 0;
}
@ -1336,22 +1343,26 @@ struct string_list* cdrom_get_available_drives(void)
for (i = 0; i < (int)dir_list->size; i++)
{
if (strstr(dir_list->elems[i].data, "/dev/sg"))
if (string_starts_with_size(dir_list->elems[i].data, "/dev/sg",
STRLEN_CONST("/dev/sg")))
{
char drive_model[32] = {0};
char drive_string[33] = {0};
union string_list_elem_attr attr = {0};
int dev_index = 0;
RFILE *file = filestream_open(dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
libretro_vfs_implementation_file *stream;
bool is_cdrom = false;
char drive_model[32] = {0};
char drive_string[33] = {0};
union string_list_elem_attr attr = {0};
int dev_index = 0;
RFILE *file = filestream_open(
dir_list->elems[i].data, RETRO_VFS_FILE_ACCESS_READ, 0);
bool is_cdrom = false;
found = true;
if (!file)
{
#ifdef CDROM_DEBUG
printf("[CDROM] Could not open %s, please check permissions.\n", dir_list->elems[i].data);
fflush(stdout);
#endif
continue;
}
@ -1362,10 +1373,11 @@ struct string_list* cdrom_get_available_drives(void)
if (!is_cdrom)
continue;
sscanf(dir_list->elems[i].data + strlen("/dev/sg"), "%d", &dev_index);
sscanf(dir_list->elems[i].data + STRLEN_CONST("/dev/sg"),
"%d", &dev_index);
dev_index = '0' + dev_index;
attr.i = dev_index;
attr.i = dev_index;
if (!string_is_empty(drive_model))
strlcat(drive_string, drive_model, sizeof(drive_string));
@ -1378,29 +1390,34 @@ struct string_list* cdrom_get_available_drives(void)
if (!found)
{
char *buf = NULL;
char *buf = NULL;
int64_t len = 0;
if (filestream_read_file("/proc/modules", (void**)&buf, &len))
{
struct string_list *mods = string_split(buf, "\n");
bool found = false;
#ifdef CDROM_DEBUG
bool found = false;
#endif
struct string_list mods = {0};
if (mods)
string_list_initialize(&mods);
if (string_split_noalloc(&mods, buf, "\n"))
{
for (i = 0; i < mods->size; i++)
for (i = 0; i < mods.size; i++)
{
if (strcasestr(mods->elems[i].data, "sg "))
if (strcasestr(mods.elems[i].data, "sg "))
{
#ifdef CDROM_DEBUG
found = true;
#endif
break;
}
}
string_list_free(mods);
}
string_list_deinitialize(&mods);
#ifdef CDROM_DEBUG
if (found)
{
printf("[CDROM] No sg devices found but kernel module is loaded.\n");
@ -1411,12 +1428,15 @@ struct string_list* cdrom_get_available_drives(void)
printf("[CDROM] No sg devices found and sg kernel module is not loaded.\n");
fflush(stdout);
}
#endif
}
#ifdef CDROM_DEBUG
else
{
printf("[CDROM] No sg devices found, could not check if sg kernel module is loaded.\n");
fflush(stdout);
}
#endif
}
string_list_free(dir_list);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_fnmatch.c).
@ -20,9 +20,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if __TEST_FNMATCH__
#include <assert.h>
#endif
#include <stddef.h>
#include <compat/fnmatch.h>
@ -123,37 +120,3 @@ int rl_fnmatch(const char *pattern, const char *string, int flags)
return 0;
return FNM_NOMATCH;
}
#if __TEST_FNMATCH__
int main(void)
{
assert(rl_fnmatch("TEST", "TEST", 0) == 0);
assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
}
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_getopt.c).

View File

@ -48,12 +48,13 @@ static int netlink_socket(void)
struct sockaddr_nl l_addr;
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
if (l_socket < 0)
return -1;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
if (bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
{
close(l_socket);
return -1;
@ -91,67 +92,77 @@ static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
struct iovec l_iov = { p_buffer, p_len };
struct sockaddr_nl l_addr;
for(;;)
for (;;)
{
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
int l_result = recvmsg(p_socket, &l_msg, 0);
int l_result;
if(l_result < 0)
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
l_result = recvmsg(p_socket, &l_msg, 0);
if (l_result < 0)
{
if(errno == EINTR)
if (errno == EINTR)
continue;
return -2;
}
if(l_msg.msg_flags & MSG_TRUNC) /* buffer too small */
if (l_msg.msg_flags & MSG_TRUNC) /* buffer too small */
return -1;
return l_result;
}
}
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
static struct nlmsghdr *getNetlinkResponse(int p_socket,
int *p_size, int *p_done)
{
size_t l_size = 4096;
size_t l_size = 4096;
void *l_buffer = NULL;
for(;;)
for (;;)
{
int l_read;
free(l_buffer);
l_buffer = malloc(l_size);
if (l_buffer == NULL)
if (!l_buffer)
return NULL;
int l_read = netlink_recv(p_socket, l_buffer, l_size);
l_read = netlink_recv(p_socket, l_buffer, l_size);
*p_size = l_read;
if(l_read == -2)
if (l_read == -2)
{
free(l_buffer);
return NULL;
}
if(l_read >= 0)
if (l_read >= 0)
{
pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
for (l_hdr = (struct nlmsghdr *)l_buffer;
NLMSG_OK(l_hdr, (unsigned int)l_read);
l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
if ( (pid_t)l_hdr->nlmsg_pid != l_pid ||
(int)l_hdr->nlmsg_seq != p_socket)
continue;
if(l_hdr->nlmsg_type == NLMSG_DONE)
if (l_hdr->nlmsg_type == NLMSG_DONE)
{
*p_done = 1;
break;
}
if(l_hdr->nlmsg_type == NLMSG_ERROR)
if (l_hdr->nlmsg_type == NLMSG_ERROR)
{
free(l_buffer);
return NULL;
@ -166,8 +177,8 @@ static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_don
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
NetlinkList *l_item = malloc(sizeof(NetlinkList));
if (l_item == NULL)
NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));
if (!l_item)
return NULL;
l_item->m_next = NULL;
@ -179,7 +190,8 @@ static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
static void freeResultList(NetlinkList *p_list)
{
NetlinkList *l_cur;
while(p_list)
while (p_list)
{
l_cur = p_list;
p_list = p_list->m_next;
@ -190,29 +202,30 @@ static void freeResultList(NetlinkList *p_list)
static NetlinkList *getResultList(int p_socket, int p_request)
{
if(netlink_send(p_socket, p_request) < 0)
int l_size;
NetlinkList *l_list = NULL;
NetlinkList *l_end = NULL;
int l_done = 0;
if (netlink_send(p_socket, p_request) < 0)
return NULL;
NetlinkList *l_list = NULL;
NetlinkList *l_end = NULL;
int l_size;
int l_done = 0;
while(!l_done)
while (!l_done)
{
NetlinkList *l_item = NULL;
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
if(!l_hdr)
if (!l_hdr)
goto error;
l_item = newListItem(l_hdr, l_size);
if (!l_item)
goto error;
if(!l_list)
l_list = l_item;
if (!l_list)
l_list = l_item;
else
l_end->m_next = l_item;
l_end = l_item;
l_end = l_item;
}
return l_list;
@ -267,12 +280,12 @@ static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
if(!*p_resultList)
if (!*p_resultList)
*p_resultList = p_entry;
else
{
struct ifaddrs *l_cur = *p_resultList;
while(l_cur->ifa_next)
while (l_cur->ifa_next)
l_cur = l_cur->ifa_next;
l_cur->ifa_next = p_entry;
}
@ -288,7 +301,8 @@ static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
size_t l_dataSize = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
@ -308,8 +322,8 @@ static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
}
}
l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
if (l_entry == NULL)
l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
if (!l_entry)
return -1;
memset(l_entry, 0, sizeof(struct ifaddrs));
@ -320,16 +334,20 @@ static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
char *l_addr = l_name + l_nameSize;
char *l_data = l_addr + l_addrSize;
// save the interface index so we can look it up when handling the addresses.
/* save the interface index so we can look
* it up when handling the addresses. */
memcpy(l_index, &l_info->ifi_index, sizeof(int));
l_entry->ifa_flags = l_info->ifi_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
@ -339,8 +357,8 @@ static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
if(l_rta->rta_type == IFLA_ADDRESS)
l_entry->ifa_addr = (struct sockaddr *)l_addr;
if (l_rta->rta_type == IFLA_ADDRESS)
l_entry->ifa_addr = (struct sockaddr *)l_addr;
else
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
l_addr += NLMSG_ALIGN(l_addrLen);
@ -364,17 +382,19 @@ static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
return 0;
}
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
static struct ifaddrs *findInterface(int p_index,
struct ifaddrs **p_links, int p_numLinks)
{
int l_num = 0;
int l_num = 0;
struct ifaddrs *l_cur = *p_links;
while(l_cur && l_num < p_numLinks)
while (l_cur && l_num < p_numLinks)
{
int l_index;
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
memcpy(&l_index, l_indexPtr, sizeof(int));
if(l_index == p_index)
if (l_index == p_index)
return l_cur;
l_cur = l_cur->ifa_next;
@ -383,21 +403,24 @@ static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int
return NULL;
}
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
static int interpretAddr(struct nlmsghdr *p_hdr,
struct ifaddrs **p_resultList, int p_numLinks)
{
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
struct rtattr *l_rta;
size_t l_rtaSize;
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
if(l_info->ifa_family == AF_PACKET)
if (l_info->ifa_family == AF_PACKET)
return 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
struct rtattr *l_rta;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
@ -405,7 +428,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
{
case IFA_ADDRESS:
case IFA_LOCAL:
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
{
/* make room for netmask */
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
@ -422,8 +445,8 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
}
}
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
if (l_entry == NULL)
struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
if (!l_entry)
return -1;
memset(l_entry, 0, sizeof(struct ifaddrs));
@ -433,11 +456,12 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
char *l_addr = l_name + l_nameSize;
l_entry->ifa_flags = l_info->ifa_flags;
if(l_interface)
if (l_interface)
l_entry->ifa_flags |= l_interface->ifa_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize);
l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
@ -449,24 +473,24 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
{
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
if(l_info->ifa_family == AF_INET6)
if (l_info->ifa_family == AF_INET6)
{
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
}
if(l_rta->rta_type == IFA_ADDRESS)
if (l_rta->rta_type == IFA_ADDRESS)
{
/* apparently in a point-to-point network IFA_ADDRESS
* contains the dest address and IFA_LOCAL contains the local address */
if(l_entry->ifa_addr)
if (l_entry->ifa_addr)
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
else
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else if(l_rta->rta_type == IFA_LOCAL)
else if (l_rta->rta_type == IFA_LOCAL)
{
if(l_entry->ifa_addr)
if (l_entry->ifa_addr)
l_entry->ifa_dstaddr = l_entry->ifa_addr;
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
@ -485,7 +509,7 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
}
}
if(l_entry->ifa_addr &&
if (l_entry->ifa_addr &&
( l_entry->ifa_addr->sa_family == AF_INET
|| l_entry->ifa_addr->sa_family == AF_INET6))
{
@ -498,9 +522,9 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
l_mask[0] = '\0';
for(i=0; i<(l_prefix/8); ++i)
for (i=0; i<(l_prefix/8); ++i)
l_mask[i] = 0xff;
if(l_prefix % 8)
if (l_prefix % 8)
l_mask[i] = 0xff << (8 - (l_prefix % 8));
makeSockaddr(l_entry->ifa_addr->sa_family,
@ -516,23 +540,26 @@ static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
struct ifaddrs **p_resultList)
{
int l_numLinks = 0;
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
pid_t l_pid = getpid();
for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
struct nlmsghdr *l_hdr = NULL;
unsigned int l_nlsize = p_netlinkList->m_size;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
if ( (pid_t)l_hdr->nlmsg_pid != l_pid ||
(int)l_hdr->nlmsg_seq != p_socket)
continue;
if(l_hdr->nlmsg_type == NLMSG_DONE)
if (l_hdr->nlmsg_type == NLMSG_DONE)
break;
if(l_hdr->nlmsg_type == RTM_NEWLINK)
if (l_hdr->nlmsg_type == RTM_NEWLINK)
{
if(interpretLink(l_hdr, p_resultList) == -1)
if (interpretLink(l_hdr, p_resultList) == -1)
return -1;
++l_numLinks;
}
@ -545,20 +572,22 @@ static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
struct ifaddrs **p_resultList, int p_numLinks)
{
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
struct nlmsghdr *l_hdr = NULL;
unsigned int l_nlsize = p_netlinkList->m_size;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize);
l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
if ( (pid_t)l_hdr->nlmsg_pid != l_pid
|| (int)l_hdr->nlmsg_seq != p_socket)
continue;
if(l_hdr->nlmsg_type == NLMSG_DONE)
if (l_hdr->nlmsg_type == NLMSG_DONE)
break;
if(l_hdr->nlmsg_type == RTM_NEWADDR)
if (l_hdr->nlmsg_type == RTM_NEWADDR)
{
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
return -1;
@ -570,34 +599,40 @@ static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
int getifaddrs(struct ifaddrs **ifap)
{
int l_socket = 0;
int l_result = 0;
if(!ifap)
NetlinkList *l_linkResults;
NetlinkList *l_addrResults;
int l_numLinks;
int l_socket = 0;
int l_result = 0;
if (!ifap)
return -1;
*ifap = NULL;
*ifap = NULL;
l_socket = netlink_socket();
if(l_socket < 0)
if (l_socket < 0)
return -1;
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
if(!l_linkResults)
l_linkResults = getResultList(l_socket, RTM_GETLINK);
if (!l_linkResults)
{
close(l_socket);
return -1;
}
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
if(!l_addrResults)
l_addrResults = getResultList(l_socket, RTM_GETADDR);
if (!l_addrResults)
{
close(l_socket);
freeResultList(l_linkResults);
return -1;
}
int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
if ( l_numLinks == -1 ||
interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
l_result = -1;
freeResultList(l_linkResults);
@ -610,10 +645,10 @@ void freeifaddrs(struct ifaddrs *ifa)
{
struct ifaddrs *l_cur = NULL;
while(ifa)
while (ifa)
{
l_cur = ifa;
ifa = ifa->ifa_next;
ifa = ifa->ifa_next;
free(l_cur);
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_posix_string.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_snprintf.c).
@ -33,12 +33,12 @@
#if _MSC_VER < 1300
#define _vscprintf c89_vscprintf_retro__
static int c89_vscprintf_retro__(const char *format, va_list pargs)
static int c89_vscprintf_retro__(const char *fmt, va_list pargs)
{
int retval;
va_list argcopy;
va_copy(argcopy, pargs);
retval = vsnprintf(NULL, 0, format, argcopy);
retval = vsnprintf(NULL, 0, fmt, argcopy);
va_end(argcopy);
return retval;
}
@ -46,38 +46,36 @@ static int c89_vscprintf_retro__(const char *format, va_list pargs)
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
int c99_vsnprintf_retro__(char *s, size_t len, const char *fmt, va_list ap)
{
int count = -1;
if (size != 0)
if (len != 0)
{
#if (_MSC_VER <= 1310)
count = _vsnprintf(outBuf, size - 1, format, ap);
count = _vsnprintf(s, len - 1, fmt, ap);
#else
count = _vsnprintf_s(outBuf, size, size - 1, format, ap);
count = _vsnprintf_s(s, len, len - 1, fmt, ap);
#endif
}
if (count == -1)
count = _vscprintf(format, ap);
count = _vscprintf(fmt, ap);
if (count == size)
{
/* there was no room for a NULL, so truncate the last character */
outBuf[size - 1] = '\0';
}
/* there was no room for a NULL, so truncate the last character */
if (count == len && len)
s[len - 1] = '\0';
return count;
}
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
int c99_snprintf_retro__(char *s, size_t len, const char *fmt, ...)
{
int count;
va_list ap;
va_start(ap, format);
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
va_start(ap, fmt);
count = c99_vsnprintf_retro__(s, len, fmt, ap);
va_end(ap);
return count;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_strcasestr.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_strl.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2017 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (compat_snprintf.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (fopen_utf8.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dylib.c).
@ -78,35 +78,36 @@ dylib_t dylib_load(const char *path)
int prevmode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
#endif
#ifdef __WINRT__
dylib_t lib;
/* On UWP, you can only load DLLs inside your install directory, using a special function that takes a relative path */
char relative_path_abbrev[PATH_MAX_LENGTH];
char *relative_path = relative_path_abbrev;
wchar_t *path_wide = NULL;
relative_path_abbrev[0] = '\0';
if (!path_is_absolute(path))
RARCH_WARN("Relative path in dylib_load! This is likely an attempt to load a system library that will fail\n");
char *relative_path_abbrev = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
fill_pathname_abbreviate_special(relative_path_abbrev, path, PATH_MAX_LENGTH * sizeof(char));
fill_pathname_abbreviate_special(relative_path_abbrev, path, sizeof(relative_path_abbrev));
char *relative_path = relative_path_abbrev;
if (relative_path[0] != ':' || !path_char_is_slash(relative_path[1]))
{
/* Path to dylib_load is not inside app install directory.
* Loading will probably fail. */
}
/* Path to dylib_load is not inside app install directory.
* Loading will probably fail. */
if (relative_path[0] != ':' || !PATH_CHAR_IS_SLASH(relative_path[1])) { }
else
relative_path += 2;
wchar_t *pathW = utf8_to_utf16_string_alloc(relative_path);
dylib_t lib = LoadPackagedLibrary(pathW, 0);
free(pathW);
path_wide = utf8_to_utf16_string_alloc(relative_path);
lib = LoadPackagedLibrary(path_wide, 0);
free(path_wide);
free(relative_path_abbrev);
#elif defined(LEGACY_WIN32)
dylib_t lib = LoadLibrary(path);
dylib_t lib = LoadLibrary(path);
#else
wchar_t *pathW = utf8_to_utf16_string_alloc(path);
dylib_t lib = LoadLibraryW(pathW);
free(pathW);
wchar_t *path_wide = utf8_to_utf16_string_alloc(path);
dylib_t lib = LoadLibraryW(path_wide);
free(path_wide);
#endif
#ifndef __WINRT__

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (encoding_crc32.c).
@ -117,7 +117,7 @@ uint32_t file_crc32(uint32_t crc, const char *path)
if (!buf)
goto error;
for(i = 0; i < CRC32_MAX_MB; i++)
for (i = 0; i < CRC32_MAX_MB; i++)
{
int64_t nread = filestream_read(file, buf, CRC32_BUFFER_SIZE);
if (nread < 0)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (encoding_utf.c).
@ -37,6 +37,8 @@
#include <xtl.h>
#endif
#define UTF8_WALKBYTE(string) (*((*(string))++))
static unsigned leading_ones(uint8_t c)
{
unsigned ones = 0;
@ -89,13 +91,14 @@ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
const uint16_t *in, size_t in_size)
{
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
size_t out_pos = 0;
size_t in_pos = 0;
size_t out_pos = 0;
size_t in_pos = 0;
static const
uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
for (;;)
{
unsigned numAdds;
unsigned num_adds;
uint32_t value;
if (in_pos == in_size)
@ -124,21 +127,21 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
}
for (numAdds = 1; numAdds < 5; numAdds++)
if (value < (((uint32_t)1) << (numAdds * 5 + 6)))
for (num_adds = 1; num_adds < 5; num_adds++)
if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
break;
if (out)
out[out_pos] = (char)(kUtf8Limits[numAdds - 1]
+ (value >> (6 * numAdds)));
out[out_pos] = (char)(utf8_limits[num_adds - 1]
+ (value >> (6 * num_adds)));
out_pos++;
do
{
numAdds--;
num_adds--;
if (out)
out[out_pos] = (char)(0x80
+ ((value >> (6 * numAdds)) & 0x3F));
+ ((value >> (6 * num_adds)) & 0x3F));
out_pos++;
}while (numAdds != 0);
}while (num_adds != 0);
}
*out_chars = out_pos;
@ -166,13 +169,15 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
while (*sb && chars-- > 0)
{
sb++;
while ((*sb & 0xC0) == 0x80) sb++;
while ((*sb & 0xC0) == 0x80)
sb++;
}
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
{
sb = sb_org + d_len-1;
while ((*sb & 0xC0) == 0x80) sb--;
while ((*sb & 0xC0) == 0x80)
sb--;
}
memcpy(d, sb_org, sb-sb_org);
@ -184,14 +189,18 @@ size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
const char *utf8skip(const char *str, size_t chars)
{
const uint8_t *strb = (const uint8_t*)str;
if (!chars)
return str;
do
{
strb++;
while ((*strb & 0xC0)==0x80) strb++;
while ((*strb & 0xC0)==0x80)
strb++;
chars--;
} while(chars);
}while (chars);
return (const char*)strb;
}
@ -211,24 +220,22 @@ size_t utf8len(const char *string)
return ret;
}
#define utf8_walkbyte(string) (*((*(string))++))
/* Does not validate the input, returns garbage if it's not UTF-8. */
uint32_t utf8_walk(const char **string)
{
uint8_t first = utf8_walkbyte(string);
uint8_t first = UTF8_WALKBYTE(string);
uint32_t ret = 0;
if (first < 128)
return first;
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
if (first >= 0xE0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
if (first >= 0xF0)
{
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
return ret | (first & 7) << 18;
}
return ret | (first & 15) << 12;
@ -277,9 +284,7 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
static char *mb_to_mb_string_alloc(const char *str,
enum CodePage cp_in, enum CodePage cp_out)
{
char *path_buf = NULL;
wchar_t *path_buf_wide = NULL;
int path_buf_len = 0;
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
/* Windows 95 will return 0 from these functions with
@ -292,54 +297,51 @@ static char *mb_to_mb_string_alloc(const char *str,
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
*/
if (path_buf_wide_len)
{
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
if (path_buf_wide)
{
MultiByteToWideChar(cp_in, 0,
str, -1, path_buf_wide, path_buf_wide_len);
if (*path_buf_wide)
{
path_buf_len = WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, NULL, 0, NULL, NULL);
if (path_buf_len)
{
path_buf = (char*)
calloc(path_buf_len + sizeof(char), sizeof(char));
if (path_buf)
{
WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, path_buf,
path_buf_len, NULL, NULL);
free(path_buf_wide);
if (*path_buf)
return path_buf;
free(path_buf);
return NULL;
}
}
else
{
free(path_buf_wide);
return strdup(str);
}
}
}
}
else
if (!path_buf_wide_len)
return strdup(str);
path_buf_wide = (wchar_t*)
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
if (path_buf_wide)
{
MultiByteToWideChar(cp_in, 0,
str, -1, path_buf_wide, path_buf_wide_len);
if (*path_buf_wide)
{
int path_buf_len = WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, NULL, 0, NULL, NULL);
if (path_buf_len)
{
char *path_buf = (char*)
calloc(path_buf_len + sizeof(char), sizeof(char));
if (path_buf)
{
WideCharToMultiByte(cp_out, 0,
path_buf_wide, -1, path_buf,
path_buf_len, NULL, NULL);
free(path_buf_wide);
if (*path_buf)
return path_buf;
free(path_buf);
return NULL;
}
}
else
{
free(path_buf_wide);
return strdup(str);
}
}
free(path_buf_wide);
}
return NULL;
}
@ -379,13 +381,13 @@ char* local_to_utf8_string_alloc(const char *str)
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
#ifdef _WIN32
int len = 0;
int out_len = 0;
int len = 0;
int out_len = 0;
#else
size_t len = 0;
size_t len = 0;
size_t out_len = 0;
#endif
wchar_t *buf = NULL;
wchar_t *buf = NULL;
if (!str || !*str)
return NULL;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (features_cpu.c).
@ -39,6 +39,10 @@
#include <windows.h>
#endif
#ifdef __PSL1GHT__
#include <lv2/systime.h>
#endif
#if defined(__CELLOS_LV2__)
#ifndef _PPU_INTRINSICS_H
#include <ppu_intrinsics.h>
@ -66,9 +70,7 @@
#endif
#if defined(PS2)
#include <kernel.h>
#include <timer.h>
#include <time.h>
#include <ps2sdkapi.h>
#endif
#if defined(__PSL1GHT__)
@ -167,7 +169,7 @@ retro_perf_tick_t cpu_features_get_perf_counter(void)
tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
tv_usec = (long)(system_time.wMilliseconds * 1000);
time_ticks = (1000000 * tv_sec + tv_usec);
#elif defined(__linux__) || defined(__QNX__) || defined(__MACH__)
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
struct timespec tv = {0};
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
@ -181,26 +183,22 @@ retro_perf_tick_t cpu_features_get_perf_counter(void)
time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
#elif defined(__ARM_ARCH_6__)
__asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
#elif defined(__CELLOS_LV2__) || defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__)
#elif defined(__CELLOS_LV2__) || defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__)
time_ticks = __mftb();
#elif defined(GEKKO)
time_ticks = gettime();
#elif defined(PSP)
sceRtcGetCurrentTick((uint64_t*)&time_ticks);
#elif defined(VITA)
sceRtcGetCurrentTick((SceRtcTick*)&time_ticks);
#elif defined(PSP) || defined(VITA)
time_ticks = sceKernelGetSystemTimeWide();
#elif defined(PS2)
time_ticks = clock()*294912; // 294,912MHZ / 1000 msecs
time_ticks = ps2_clock();
#elif defined(_3DS)
time_ticks = svcGetSystemTick();
#elif defined(WIIU)
time_ticks = OSGetSystemTime();
#elif defined(__mips__)
struct timeval tv;
gettimeofday(&tv,NULL);
time_ticks = (1000000 * tv.tv_sec + tv.tv_usec);
#elif defined(HAVE_LIBNX)
time_ticks = armGetSystemTick();
#elif defined(EMSCRIPTEN)
time_ticks = emscripten_get_now() * 1000;
#endif
return time_ticks;
@ -225,7 +223,9 @@ retro_time_t cpu_features_get_time_usec(void)
if (!QueryPerformanceCounter(&count))
return 0;
return count.QuadPart * 1000000 / freq.QuadPart;
return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
#elif defined(__PSL1GHT__)
return sysGetSystemTime();
#elif defined(__CELLOS_LV2__)
return sys_time_get_system_time();
#elif defined(GEKKO)
@ -234,7 +234,9 @@ retro_time_t cpu_features_get_time_usec(void)
return ticks_to_us(OSGetSystemTime());
#elif defined(SWITCH) || defined(HAVE_LIBNX)
return (svcGetSystemTick() * 10) / 192;
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__)
#elif defined(_3DS)
return osGetTime() * 1000;
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__) || defined(DJGPP)
struct timespec tv = {0};
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
return 0;
@ -242,15 +244,9 @@ retro_time_t cpu_features_get_time_usec(void)
#elif defined(EMSCRIPTEN)
return emscripten_get_now() * 1000;
#elif defined(PS2)
return clock()*1000;
#elif defined(__mips__) || defined(DJGPP)
struct timeval tv;
gettimeofday(&tv,NULL);
return (1000000 * tv.tv_sec + tv.tv_usec);
#elif defined(_3DS)
return osGetTime() * 1000;
#elif defined(VITA)
return sceKernelGetProcessTimeWide();
return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
#elif defined(VITA) || defined(PSP)
return sceKernelGetSystemTimeWide();
#else
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
#endif
@ -289,7 +285,9 @@ void x86_cpuid(int func, int flags[4])
#elif defined(_MSC_VER)
__cpuid(flags, func);
#else
#ifndef NDEBUG
printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
#endif
memset(flags, 0, 4 * sizeof(int));
#endif
}
@ -311,7 +309,9 @@ static uint64_t xgetbv_x86(uint32_t idx)
/* Intrinsic only works on 2010 SP1 and above. */
return _xgetbv(idx);
#else
#ifndef NDEBUG
printf("Unknown compiler. Cannot check xgetbv bits.\n");
#endif
return 0;
#endif
}
@ -348,12 +348,12 @@ static unsigned char check_arm_cpu_feature(const char* feature)
if (!fp)
return 0;
while (filestream_gets(fp, line, sizeof(line)) != NULL)
while (filestream_gets(fp, line, sizeof(line)))
{
if (strncmp(line, "Features\t: ", 11))
continue;
if (strstr(line + 11, feature) != NULL)
if (strstr(line + 11, feature))
status = 1;
break;
@ -424,8 +424,7 @@ static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
q = end;
/* Get first value */
p = parse_decimal(p, q, &start_value);
if (p == NULL)
if (!(p = parse_decimal(p, q, &start_value)))
return;
end_value = start_value;
@ -435,8 +434,7 @@ static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
*/
if (p < q && *p == '-')
{
p = parse_decimal(p+1, q, &end_value);
if (p == NULL)
if (!(p = parse_decimal(p+1, q, &end_value)))
return;
}
@ -444,7 +442,7 @@ static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
for (val = start_value; val <= end_value; val++)
{
if ((unsigned)val < 32)
list->mask |= (uint32_t)(1U << val);
list->mask |= (uint32_t)(UINT32_C(1) << val);
}
/* Jump to next item */
@ -494,7 +492,7 @@ unsigned cpu_features_get_core_amount(void)
return sysinfo.dwNumberOfProcessors;
#elif defined(GEKKO)
return 1;
#elif defined(PSP) || defined(PS2)
#elif defined(PSP) || defined(PS2) || defined(__CELLOS_LV2__)
return 1;
#elif defined(VITA)
return 4;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (archive_file.c).
@ -24,19 +24,6 @@
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_MMAP
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#endif
#include <compat/strl.h>
#include <file/archive_file.h>
#include <file/file_path.h>
@ -45,110 +32,12 @@
#include <lists/string_list.h>
#include <string/stdstring.h>
struct file_archive_file_data
{
#ifdef HAVE_MMAP
int fd;
#endif
void *data;
size_t size;
};
static size_t file_archive_size(file_archive_file_data_t *data)
{
if (!data)
return 0;
return data->size;
}
static const uint8_t *file_archive_data(file_archive_file_data_t *data)
{
if (!data)
return NULL;
return (const uint8_t*)data->data;
}
#ifdef HAVE_MMAP
/* Closes, unmaps and frees. */
static void file_archive_free(file_archive_file_data_t *data)
{
if (!data)
return;
if (data->data)
munmap(data->data, data->size);
if (data->fd >= 0)
close(data->fd);
free(data);
}
static file_archive_file_data_t* file_archive_open(const char *path)
{
file_archive_file_data_t *data = (file_archive_file_data_t*)calloc(1, sizeof(*data));
if (!data)
return NULL;
data->fd = open(path, O_RDONLY);
/* Failed to open archive. */
if (data->fd < 0)
goto error;
data->size = path_get_size(path);
if (!data->size)
return data;
data->data = mmap(NULL, data->size, PROT_READ, MAP_SHARED, data->fd, 0);
if (data->data == MAP_FAILED)
{
data->data = NULL;
/* Failed to mmap() file */
goto error;
}
return data;
error:
file_archive_free(data);
return NULL;
}
#else
/* Closes, unmaps and frees. */
static void file_archive_free(file_archive_file_data_t *data)
{
if (!data)
return;
if(data->data)
free(data->data);
free(data);
}
static file_archive_file_data_t* file_archive_open(const char *path)
{
int64_t ret = -1;
bool read_from_file = false;
file_archive_file_data_t *data = (file_archive_file_data_t*)
calloc(1, sizeof(*data));
if (!data)
return NULL;
read_from_file = filestream_read_file(path, &data->data, &ret);
/* Failed to open archive? */
if (!read_from_file || ret < 0)
goto error;
data->size = ret;
return data;
error:
file_archive_free(data);
return NULL;
}
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#endif
static int file_archive_get_file_list_cb(
@ -169,37 +58,34 @@ static int file_archive_get_file_list_cb(
size_t path_len = strlen(path);
/* Checks if this entry is a directory or a file. */
char last_char = path[path_len - 1];
struct string_list *ext_list = NULL;
struct string_list ext_list = {0};
/* Skip if directory. */
if (last_char == '/' || last_char == '\\' )
{
string_list_free(ext_list);
return 0;
}
ext_list = string_split(valid_exts, "|");
if (ext_list)
string_list_initialize(&ext_list);
if (string_split_noalloc(&ext_list, valid_exts, "|"))
{
const char *file_ext = path_get_extension(path);
if (!file_ext)
{
string_list_free(ext_list);
string_list_deinitialize(&ext_list);
return 0;
}
if (!string_list_find_elem_prefix(ext_list, ".", file_ext))
if (!string_list_find_elem_prefix(&ext_list, ".", file_ext))
{
/* keep iterating */
string_list_free(ext_list);
string_list_deinitialize(&ext_list);
return -1;
}
attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;
string_list_free(ext_list);
}
string_list_deinitialize(&ext_list);
}
return string_list_append(userdata->list, path, attr);
@ -216,11 +102,17 @@ static int file_archive_extract_cb(const char *name, const char *valid_exts,
if (ext && string_list_find_elem(userdata->ext, ext))
{
char new_path[PATH_MAX_LENGTH];
char wanted_file[PATH_MAX_LENGTH];
const char *delim = NULL;
const char *delim;
new_path[0] = wanted_file[0] = '\0';
delim = path_get_archive_delim(userdata->archive_path);
if (delim)
{
if (!string_is_equal_noncase(userdata->current_file_path, delim + 1))
return 1; /* keep searching for the right file */
}
new_path[0] = '\0';
if (userdata->extraction_directory)
fill_pathname_join(new_path, userdata->extraction_directory,
path_basename(name), sizeof(new_path));
@ -228,25 +120,14 @@ static int file_archive_extract_cb(const char *name, const char *valid_exts,
fill_pathname_resolve_relative(new_path, userdata->archive_path,
path_basename(name), sizeof(new_path));
userdata->first_extracted_file_path = strdup(new_path);
delim = path_get_archive_delim(userdata->archive_path);
if (delim)
{
strlcpy(wanted_file, delim + 1, sizeof(wanted_file));
if (!string_is_equal_noncase(userdata->extracted_file_path,
wanted_file))
return 1; /* keep searching for the right file */
}
else
strlcpy(wanted_file, userdata->archive_path, sizeof(wanted_file));
if (file_archive_perform_mode(new_path,
valid_exts, cdata, cmode, csize, size,
0, userdata))
checksum, userdata))
{
userdata->found_file = true;
userdata->first_extracted_file_path = strdup(new_path);
}
return 0;
}
@ -273,14 +154,37 @@ static int file_archive_parse_file_init(file_archive_transfer_t *state,
if (!state->backend)
return -1;
state->handle = file_archive_open(path);
if (!state->handle)
state->archive_file = filestream_open(path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
/* Failed to open archive. */
if (!state->archive_file)
return -1;
state->archive_size = (int32_t)file_archive_size(state->handle);
state->data = file_archive_data(state->handle);
state->footer = 0;
state->directory = 0;
state->archive_size = filestream_get_size(state->archive_file);
#ifdef HAVE_MMAP
if (state->archive_size <= (256*1024*1024))
{
state->archive_mmap_fd = open(path, O_RDONLY);
if (state->archive_mmap_fd)
{
state->archive_mmap_data = (uint8_t*)mmap(NULL, (size_t)state->archive_size,
PROT_READ, MAP_SHARED, state->archive_mmap_fd, 0);
if (state->archive_mmap_data == (uint8_t*)MAP_FAILED)
{
close(state->archive_mmap_fd);
state->archive_mmap_fd = 0;
state->archive_mmap_data = NULL;
}
}
}
#endif
state->step_current = 0;
state->step_total = 0;
return state->backend->archive_parse_file_init(state, path);
}
@ -288,35 +192,25 @@ static int file_archive_parse_file_init(file_archive_transfer_t *state,
/**
* file_archive_decompress_data_to_file:
* @path : filename path of archive.
* @valid_exts : Valid extensions of archive to be parsed.
* If NULL, allow all.
* @cdata : input data.
* @csize : size of input data.
* @size : output file size
* @checksum : CRC32 checksum from input data.
*
* Decompress data to file.
* Write data to file.
*
* Returns: true (1) on success, otherwise false (0).
**/
static int file_archive_decompress_data_to_file(
file_archive_transfer_t *transfer,
file_archive_file_handle_t *handle,
int ret,
const char *path,
const char *valid_exts,
const uint8_t *cdata,
uint32_t csize,
uint32_t size,
uint32_t checksum)
{
if (!handle || ret == -1)
{
ret = 0;
goto end;
}
if (!handle)
return 0;
#if 0
handle->real_checksum = handle->backend->stream_crc_calculate(
handle->real_checksum = transfer->backend->stream_crc_calculate(
0, handle->data, size);
if (handle->real_checksum != checksum)
{
@ -327,40 +221,14 @@ static int file_archive_decompress_data_to_file(
#endif
if (!filestream_write_file(path, handle->data, size))
{
ret = false;
goto end;
}
return 0;
end:
if (handle)
{
if (handle->backend)
{
if (handle->backend->stream_free)
{
#ifdef HAVE_7ZIP
if (handle->backend != &sevenzip_backend)
{
handle->backend->stream_free(handle->stream);
if (handle->data)
free(handle->data);
}
#else
handle->backend->stream_free(handle->stream);
#endif
}
}
}
return ret;
return 1;
}
void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)
{
if (!state || !state->handle)
if (!state || !state->archive_file)
return;
state->type = ARCHIVE_TRANSFER_DEINIT;
@ -387,7 +255,7 @@ int file_archive_parse_file_iterate(
{
if (userdata)
{
userdata->context = state->stream;
userdata->transfer = state;
strlcpy(userdata->archive_path, file,
sizeof(userdata->archive_path));
}
@ -397,14 +265,13 @@ int file_archive_parse_file_iterate(
state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
break;
case ARCHIVE_TRANSFER_ITERATE:
if (file_archive_get_file_backend(file))
if (state->backend)
{
const struct file_archive_file_backend *backend =
file_archive_get_file_backend(file);
int ret =
backend->archive_parse_file_iterate_step(state,
valid_exts, userdata, file_cb);
int ret = state->backend->archive_parse_file_iterate_step(
state->context, valid_exts, userdata, file_cb);
if (ret == 1)
state->step_current++; /* found another file */
if (ret != 1)
state->type = ARCHIVE_TRANSFER_DEINIT;
if (ret == -1)
@ -417,25 +284,31 @@ int file_archive_parse_file_iterate(
case ARCHIVE_TRANSFER_DEINIT_ERROR:
*returnerr = false;
case ARCHIVE_TRANSFER_DEINIT:
if (state->handle)
if (state->context)
{
file_archive_free(state->handle);
state->handle = NULL;
if (state->backend->archive_parse_file_free)
state->backend->archive_parse_file_free(state->context);
state->context = NULL;
}
if (state->stream && state->backend)
if (state->archive_file)
{
if (state->backend->stream_free)
state->backend->stream_free(state->stream);
if (state->stream)
free(state->stream);
state->stream = NULL;
if (userdata)
userdata->context = NULL;
filestream_close(state->archive_file);
state->archive_file = NULL;
}
#ifdef HAVE_MMAP
if (state->archive_mmap_data)
{
munmap(state->archive_mmap_data, (size_t)state->archive_size);
close(state->archive_mmap_fd);
state->archive_mmap_fd = 0;
state->archive_mmap_data = NULL;
}
#endif
if (userdata)
userdata->transfer = NULL;
break;
}
@ -463,16 +336,19 @@ static bool file_archive_walk(const char *file, const char *valid_exts,
file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
{
file_archive_transfer_t state;
bool returnerr = true;
bool returnerr = true;
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_size = 0;
state.handle = NULL;
state.stream = NULL;
state.footer = NULL;
state.directory = NULL;
state.data = NULL;
state.backend = NULL;
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_file = NULL;
#ifdef HAVE_MMAP
state.archive_mmap_fd = 0;
state.archive_mmap_data = NULL;
#endif
state.archive_size = 0;
state.context = NULL;
state.step_total = 0;
state.step_current = 0;
state.backend = NULL;
for (;;)
{
@ -486,17 +362,10 @@ static bool file_archive_walk(const char *file, const char *valid_exts,
int file_archive_parse_file_progress(file_archive_transfer_t *state)
{
ptrdiff_t delta = 0;
if (!state || state->archive_size == 0)
if (!state || state->step_total == 0)
return 0;
delta = state->directory - state->data;
if (!state->start_delta)
state->start_delta = delta;
return (int)(((delta - state->start_delta) * 100) / (state->archive_size - state->start_delta));
return (int)((state->step_current * 100) / (state->step_total));
}
/**
@ -524,24 +393,18 @@ bool file_archive_extract_file(
struct string_list *list = string_split(valid_exts, "|");
userdata.archive_path[0] = '\0';
userdata.current_file_path[0] = '\0';
userdata.first_extracted_file_path = NULL;
userdata.extracted_file_path = NULL;
userdata.extraction_directory = extraction_directory;
userdata.archive_path_size = archive_path_size;
userdata.ext = list;
userdata.list = NULL;
userdata.found_file = false;
userdata.list_only = false;
userdata.context = NULL;
userdata.archive_name[0] = '\0';
userdata.crc = 0;
userdata.transfer = NULL;
userdata.dec = NULL;
userdata.decomp_state.opt_file = NULL;
userdata.decomp_state.needle = NULL;
userdata.decomp_state.size = 0;
userdata.decomp_state.found = false;
if (!list)
{
ret = false;
@ -575,6 +438,37 @@ end:
return ret;
}
/* Warning: 'list' must zero initialised before
* calling this function, otherwise memory leaks/
* undefined behaviour will occur */
bool file_archive_get_file_list_noalloc(struct string_list *list,
const char *path,
const char *valid_exts)
{
struct archive_extract_userdata userdata;
if (!list || !string_list_initialize(list))
return false;
strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
userdata.current_file_path[0] = '\0';
userdata.first_extracted_file_path = NULL;
userdata.extraction_directory = NULL;
userdata.archive_path_size = 0;
userdata.ext = NULL;
userdata.list = list;
userdata.found_file = false;
userdata.list_only = true;
userdata.crc = 0;
userdata.transfer = NULL;
userdata.dec = NULL;
if (!file_archive_walk(path, valid_exts,
file_archive_get_file_list_cb, &userdata))
return false;
return true;
}
/**
* file_archive_get_file_list:
* @path : filename path of archive
@ -587,82 +481,56 @@ struct string_list *file_archive_get_file_list(const char *path,
struct archive_extract_userdata userdata;
strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
userdata.current_file_path[0] = '\0';
userdata.first_extracted_file_path = NULL;
userdata.extracted_file_path = NULL;
userdata.extraction_directory = NULL;
userdata.archive_path_size = 0;
userdata.ext = NULL;
userdata.list = string_list_new();
userdata.found_file = false;
userdata.list_only = true;
userdata.context = NULL;
userdata.archive_name[0] = '\0';
userdata.crc = 0;
userdata.transfer = NULL;
userdata.dec = NULL;
userdata.decomp_state.opt_file = NULL;
userdata.decomp_state.needle = NULL;
userdata.decomp_state.size = 0;
userdata.decomp_state.found = false;
if (!userdata.list)
goto error;
return NULL;
if (!file_archive_walk(path, valid_exts,
file_archive_get_file_list_cb, &userdata))
goto error;
return userdata.list;
error:
if (userdata.list)
{
string_list_free(userdata.list);
return NULL;
return NULL;
}
return userdata.list;
}
bool file_archive_perform_mode(const char *path, const char *valid_exts,
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
uint32_t crc32, struct archive_extract_userdata *userdata)
{
switch (cmode)
file_archive_file_handle_t handle;
int ret;
if (!userdata->transfer || !userdata->transfer->backend)
return false;
handle.data = NULL;
handle.real_checksum = 0;
if (!userdata->transfer->backend->stream_decompress_data_to_file_init(
userdata->transfer->context, &handle, cdata, cmode, csize, size))
return false;
do
{
case ARCHIVE_MODE_UNCOMPRESSED:
if (!filestream_write_file(path, cdata, size))
return false;
break;
ret = userdata->transfer->backend->stream_decompress_data_to_file_iterate(
userdata->transfer->context, &handle);
}while (ret == 0);
case ARCHIVE_MODE_COMPRESSED:
{
int ret = 0;
file_archive_file_handle_t handle;
handle.stream = userdata->context;
handle.data = NULL;
handle.real_checksum = 0;
handle.backend = file_archive_get_file_backend(userdata->archive_path);
if (!handle.backend)
return false;
if (!handle.backend->stream_decompress_data_to_file_init(&handle,
cdata, csize, size))
return false;
do
{
ret = handle.backend->stream_decompress_data_to_file_iterate(
handle.stream);
}while(ret == 0);
if (!file_archive_decompress_data_to_file(&handle,
ret, path, valid_exts,
cdata, csize, size, crc32))
return false;
}
break;
default:
return false;
}
if (ret == -1 || !file_archive_decompress_data_to_file(
userdata->transfer, &handle, path,
size, crc32))
return false;
return true;
}
@ -823,7 +691,7 @@ const struct file_archive_file_backend* file_archive_get_file_backend(const char
uint32_t file_archive_get_file_crc32(const char *path)
{
file_archive_transfer_t state;
struct archive_extract_userdata userdata = {{0}};
struct archive_extract_userdata userdata = {0};
bool returnerr = false;
const char *archive_path = NULL;
bool contains_compressed = path_contains_compressed_file(path);
@ -837,14 +705,17 @@ uint32_t file_archive_get_file_crc32(const char *path)
archive_path += 1;
}
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_size = 0;
state.handle = NULL;
state.stream = NULL;
state.footer = NULL;
state.directory = NULL;
state.data = NULL;
state.backend = NULL;
state.type = ARCHIVE_TRANSFER_INIT;
state.archive_file = NULL;
#ifdef HAVE_MMAP
state.archive_mmap_fd = 0;
state.archive_mmap_data = NULL;
#endif
state.archive_size = 0;
state.context = NULL;
state.step_total = 0;
state.step_current = 0;
state.backend = NULL;
/* Initialize and open archive first.
Sets next state type to ITERATE. */
@ -869,7 +740,7 @@ uint32_t file_archive_get_file_crc32(const char *path)
/* Stop when the right file in the archive is found. */
if (archive_path)
{
if (string_is_equal(userdata.extracted_file_path, archive_path))
if (string_is_equal(userdata.current_file_path, archive_path))
break;
}
else
@ -878,8 +749,5 @@ uint32_t file_archive_get_file_crc32(const char *path)
file_archive_parse_file_iterate_stop(&state);
if (userdata.crc)
return userdata.crc;
return 0;
return userdata.crc;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (archive_file_sevenzip.c).
@ -46,7 +46,9 @@
#endif
#endif
struct sevenzip_context_t {
struct sevenzip_context_t
{
uint8_t *output;
CFileInStream archiveStream;
CLookToRead lookStream;
ISzAlloc allocImp;
@ -54,10 +56,9 @@ struct sevenzip_context_t {
CSzArEx db;
size_t temp_size;
uint32_t block_index;
uint32_t index;
uint32_t parse_index;
uint32_t decompress_index;
uint32_t packIndex;
uint8_t *output;
file_archive_file_handle_t *handle;
};
static void *sevenzip_stream_alloc_impl(void *p, size_t size)
@ -96,14 +97,13 @@ static void* sevenzip_stream_new(void)
sevenzip_context->allocTempImp.Free = sevenzip_stream_free_impl;
sevenzip_context->block_index = 0xFFFFFFFF;
sevenzip_context->output = NULL;
sevenzip_context->handle = NULL;
return sevenzip_context;
}
static void sevenzip_stream_free(void *data)
static void sevenzip_parse_file_free(void *context)
{
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)data;
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;
if (!sevenzip_context)
return;
@ -112,11 +112,12 @@ static void sevenzip_stream_free(void *data)
{
IAlloc_Free(&sevenzip_context->allocImp, sevenzip_context->output);
sevenzip_context->output = NULL;
sevenzip_context->handle->data = NULL;
}
SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp);
File_Close(&sevenzip_context->archiveStream.file);
free(sevenzip_context);
}
/* Extract the relative path (needle) from a 7z archive
@ -124,7 +125,7 @@ static void sevenzip_stream_free(void *data)
* If optional_outfile is set, extract to that instead
* and don't allocate buffer.
*/
static int sevenzip_file_read(
static int64_t sevenzip_file_read(
const char *path,
const char *needle, void **buf,
const char *optional_outfile)
@ -135,7 +136,7 @@ static int sevenzip_file_read(
ISzAlloc allocTempImp;
CSzArEx db;
uint8_t *output = 0;
long outsize = -1;
int64_t outsize = -1;
/*These are the allocation routines.
* Currently using the non-standard 7zip choices. */
@ -254,9 +255,9 @@ static int sevenzip_file_read(
if (res != SZ_OK)
break; /* This goes to the error section. */
outsize = outSizeProcessed;
outsize = (int64_t)outSizeProcessed;
if (optional_outfile != NULL)
if (optional_outfile)
{
const void *ptr = (const void*)(output + offset);
@ -274,7 +275,7 @@ static int sevenzip_file_read(
* We would however need to realloc anyways, because RetroArch
* expects a \0 at the end, therefore we allocate new,
* copy and free the old one. */
*buf = malloc(outsize + 1);
*buf = malloc((size_t)(outsize + 1));
((char*)(*buf))[outsize] = '\0';
memcpy(*buf,output + offset,outsize);
}
@ -300,28 +301,29 @@ static int sevenzip_file_read(
SzArEx_Free(&db, &allocImp);
File_Close(&archiveStream.file);
return (int)outsize;
return outsize;
}
static bool sevenzip_stream_decompress_data_to_file_init(
file_archive_file_handle_t *handle,
const uint8_t *cdata, uint32_t csize, uint32_t size)
void *context, file_archive_file_handle_t *handle,
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
struct sevenzip_context_t *sevenzip_context =
(struct sevenzip_context_t*)handle->stream;
(struct sevenzip_context_t*)context;
if (!sevenzip_context)
return false;
sevenzip_context->handle = handle;
sevenzip_context->decompress_index = (uint32_t)(size_t)cdata;
return true;
}
static int sevenzip_stream_decompress_data_to_file_iterate(void *data)
static int sevenzip_stream_decompress_data_to_file_iterate(
void *context, file_archive_file_handle_t *handle)
{
struct sevenzip_context_t *sevenzip_context =
(struct sevenzip_context_t*)data;
(struct sevenzip_context_t*)context;
SRes res = SZ_ERROR_FAIL;
size_t output_size = 0;
@ -329,7 +331,7 @@ static int sevenzip_stream_decompress_data_to_file_iterate(void *data)
size_t outSizeProcessed = 0;
res = SzArEx_Extract(&sevenzip_context->db,
&sevenzip_context->lookStream.s, sevenzip_context->index,
&sevenzip_context->lookStream.s, sevenzip_context->decompress_index,
&sevenzip_context->block_index, &sevenzip_context->output,
&output_size, &offset, &outSizeProcessed,
&sevenzip_context->allocImp, &sevenzip_context->allocTempImp);
@ -337,8 +339,8 @@ static int sevenzip_stream_decompress_data_to_file_iterate(void *data)
if (res != SZ_OK)
return 0;
if (sevenzip_context->handle)
sevenzip_context->handle->data = sevenzip_context->output + offset;
if (handle)
handle->data = sevenzip_context->output + offset;
return 1;
}
@ -346,16 +348,21 @@ static int sevenzip_stream_decompress_data_to_file_iterate(void *data)
static int sevenzip_parse_file_init(file_archive_transfer_t *state,
const char *file)
{
struct sevenzip_context_t *sevenzip_context =
(struct sevenzip_context_t*)sevenzip_stream_new();
uint8_t magic_buf[SEVENZIP_MAGIC_LEN];
struct sevenzip_context_t *sevenzip_context = NULL;
if (state->archive_size < SEVENZIP_MAGIC_LEN)
goto error;
if (string_is_not_equal_fast(state->data, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN))
filestream_seek(state->archive_file, 0, SEEK_SET);
if (filestream_read(state->archive_file, magic_buf, SEVENZIP_MAGIC_LEN) != SEVENZIP_MAGIC_LEN)
goto error;
state->stream = sevenzip_context;
if (string_is_not_equal_fast(magic_buf, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN))
goto error;
sevenzip_context = (struct sevenzip_context_t*)sevenzip_stream_new();
state->context = sevenzip_context;
#if defined(_WIN32) && defined(USE_WINDOWS_FILE) && !defined(LEGACY_WIN32)
if (!string_is_empty(file))
@ -391,27 +398,28 @@ static int sevenzip_parse_file_init(file_archive_transfer_t *state,
&sevenzip_context->allocImp, &sevenzip_context->allocTempImp) != SZ_OK)
goto error;
state->step_total = sevenzip_context->db.db.NumFiles;
return 0;
error:
if (sevenzip_context)
sevenzip_stream_free(sevenzip_context);
sevenzip_parse_file_free(sevenzip_context);
return -1;
}
static int sevenzip_parse_file_iterate_step_internal(
file_archive_transfer_t *state, char *filename,
struct sevenzip_context_t *sevenzip_context, char *filename,
const uint8_t **cdata, unsigned *cmode,
uint32_t *size, uint32_t *csize, uint32_t *checksum,
unsigned *payback, struct archive_extract_userdata *userdata)
{
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)state->stream;
const CSzFileItem *file = sevenzip_context->db.db.Files + sevenzip_context->index;
const CSzFileItem *file = sevenzip_context->db.db.Files + sevenzip_context->parse_index;
if (sevenzip_context->index < sevenzip_context->db.db.NumFiles)
if (sevenzip_context->parse_index < sevenzip_context->db.db.NumFiles)
{
size_t len = SzArEx_GetFileNameUtf16(&sevenzip_context->db,
sevenzip_context->index, NULL);
sevenzip_context->parse_index, NULL);
uint64_t compressed_size = 0;
if (sevenzip_context->packIndex < sevenzip_context->db.db.NumPackStreams)
@ -431,7 +439,7 @@ static int sevenzip_parse_file_iterate_step_internal(
infile[0] = '\0';
SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->index,
SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->parse_index,
temp);
if (temp)
@ -446,10 +454,12 @@ static int sevenzip_parse_file_iterate_step_internal(
strlcpy(filename, infile, PATH_MAX_LENGTH);
*cmode = ARCHIVE_MODE_COMPRESSED;
*cmode = 0; /* unused for 7zip */
*checksum = file->Crc;
*size = (uint32_t)file->Size;
*csize = (uint32_t)compressed_size;
*cdata = (uint8_t *)(size_t)sevenzip_context->parse_index;
}
}
else
@ -460,39 +470,37 @@ static int sevenzip_parse_file_iterate_step_internal(
return 1;
}
static int sevenzip_parse_file_iterate_step(file_archive_transfer_t *state,
static int sevenzip_parse_file_iterate_step(void *context,
const char *valid_exts,
struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)
{
char filename[PATH_MAX_LENGTH];
const uint8_t *cdata = NULL;
uint32_t checksum = 0;
uint32_t size = 0;
uint32_t csize = 0;
unsigned cmode = 0;
unsigned payload = 0;
struct sevenzip_context_t *sevenzip_context = NULL;
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)context;
int ret;
filename[0] = '\0';
userdata->current_file_path[0] = '\0';
ret = sevenzip_parse_file_iterate_step_internal(state, filename,
ret = sevenzip_parse_file_iterate_step_internal(sevenzip_context,
userdata->current_file_path,
&cdata, &cmode, &size, &csize,
&checksum, &payload, userdata);
if (ret != 1)
return ret;
userdata->extracted_file_path = filename;
userdata->crc = checksum;
if (file_cb && !file_cb(filename, valid_exts, cdata, cmode,
if (file_cb && !file_cb(userdata->current_file_path, valid_exts,
cdata, cmode,
csize, size, checksum, userdata))
return 0;
sevenzip_context = (struct sevenzip_context_t*)state->stream;
sevenzip_context->index += payload;
sevenzip_context->parse_index += payload;
return 1;
}
@ -504,13 +512,12 @@ static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,
}
const struct file_archive_file_backend sevenzip_backend = {
sevenzip_stream_new,
sevenzip_stream_free,
sevenzip_parse_file_init,
sevenzip_parse_file_iterate_step,
sevenzip_parse_file_free,
sevenzip_stream_decompress_data_to_file_init,
sevenzip_stream_decompress_data_to_file_iterate,
sevenzip_stream_crc32_calculate,
sevenzip_file_read,
sevenzip_parse_file_init,
sevenzip_parse_file_iterate_step,
"7z"
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (archive_file_zlib.c).
@ -41,6 +41,23 @@
#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
#endif
enum file_archive_compression_mode
{
ZIP_MODE_STORED = 0,
ZIP_MODE_DEFLATED = 8
};
typedef struct
{
struct file_archive_transfer *state;
uint8_t *directory;
uint8_t *directory_entry;
uint8_t *directory_end;
void *current_stream;
uint8_t *compressed_data;
uint8_t *decompressed_data;
} zip_context_t;
static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
{
unsigned i;
@ -53,69 +70,147 @@ static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
return val;
}
static void *zlib_stream_new(void)
static void zip_context_free_stream(
zip_context_t *zip_context, bool keep_decompressed)
{
return zlib_inflate_backend.stream_new();
}
static void zlib_stream_free(void *stream)
{
zlib_inflate_backend.stream_free(stream);
if (zip_context->current_stream)
{
zlib_inflate_backend.stream_free(zip_context->current_stream);
zip_context->current_stream = NULL;
}
if (zip_context->compressed_data)
{
#ifdef HAVE_MMAP
if (!zip_context->state->archive_mmap_data)
#endif
{
free(zip_context->compressed_data);
zip_context->compressed_data = NULL;
}
}
if (zip_context->decompressed_data && !keep_decompressed)
{
free(zip_context->decompressed_data);
zip_context->decompressed_data = NULL;
}
}
static bool zlib_stream_decompress_data_to_file_init(
file_archive_file_handle_t *handle,
const uint8_t *cdata, uint32_t csize, uint32_t size)
void *context, file_archive_file_handle_t *handle,
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size)
{
if (!handle)
return false;
zip_context_t *zip_context = (zip_context_t *)context;
struct file_archive_transfer *state = zip_context->state;
uint8_t local_header_buf[4];
uint8_t *local_header;
uint32_t offsetNL, offsetEL;
int64_t offsetData;
handle->stream = zlib_inflate_backend.stream_new();
/* free previous data and stream if left unfinished */
zip_context_free_stream(zip_context, false);
if (!handle->stream)
goto error;
/* seek past most of the local directory header */
#ifdef HAVE_MMAP
if (state->archive_mmap_data)
{
local_header = state->archive_mmap_data + (size_t)cdata + 26;
}
else
#endif
{
filestream_seek(state->archive_file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, local_header_buf, 4) != 4)
goto error;
local_header = local_header_buf;
}
if (zlib_inflate_backend.define)
zlib_inflate_backend.define(handle->stream, "window_bits", (uint32_t)-MAX_WBITS);
offsetNL = read_le(local_header, 2); /* file name length */
offsetEL = read_le(local_header + 2, 2); /* extra field length */
offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;
handle->data = (uint8_t*)malloc(size);
#ifdef HAVE_MMAP
if (state->archive_mmap_data)
{
zip_context->compressed_data = state->archive_mmap_data + (size_t)offsetData;
}
else
#endif
{
/* allocate memory for the compressed data */
zip_context->compressed_data = (uint8_t*)malloc(csize);
if (!zip_context->compressed_data)
goto error;
if (!handle->data)
goto error;
/* skip over name and extra data */
filestream_seek(state->archive_file, offsetData, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, zip_context->compressed_data, csize) != csize)
goto error;
}
zlib_inflate_backend.set_in(handle->stream,
(const uint8_t*)cdata, csize);
zlib_inflate_backend.set_out(handle->stream,
handle->data, size);
switch (cmode)
{
case ZIP_MODE_STORED:
handle->data = zip_context->compressed_data;
return true;
return true;
case ZIP_MODE_DEFLATED:
zip_context->current_stream = zlib_inflate_backend.stream_new();
if (!zip_context->current_stream)
goto error;
if (zlib_inflate_backend.define)
zlib_inflate_backend.define(zip_context->current_stream, "window_bits", (uint32_t)-MAX_WBITS);
zip_context->decompressed_data = (uint8_t*)malloc(size);
if (!zip_context->decompressed_data)
goto error;
zlib_inflate_backend.set_in(zip_context->current_stream,
zip_context->compressed_data, csize);
zlib_inflate_backend.set_out(zip_context->current_stream,
zip_context->decompressed_data, size);
return true;
}
error:
if (handle->stream)
zlib_inflate_backend.stream_free(handle->stream);
if (handle->data)
free(handle->data);
zip_context_free_stream(zip_context, false);
return false;
}
static int zlib_stream_decompress_data_to_file_iterate(void *stream)
static int zlib_stream_decompress_data_to_file_iterate(
void *context, file_archive_file_handle_t *handle)
{
zip_context_t *zip_context = (zip_context_t *)context;
bool zstatus;
uint32_t rd, wn;
enum trans_stream_error terror;
if (!stream)
return -1;
if (!zip_context->current_stream)
{
/* file was uncompressed or decompression finished before */
return 1;
}
zstatus = zlib_inflate_backend.trans(stream, false, &rd, &wn, &terror);
if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
return -1;
zstatus = zlib_inflate_backend.trans(zip_context->current_stream, false, &rd, &wn, &terror);
if (zstatus && !terror)
{
/* successfully decompressed entire file */
zip_context_free_stream(zip_context, true);
handle->data = zip_context->decompressed_data;
return 1;
}
if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
{
/* error during stream processing */
zip_context_free_stream(zip_context, false);
return -1;
}
/* still more data to process */
return 0;
}
@ -126,49 +221,51 @@ static uint32_t zlib_stream_crc32_calculate(uint32_t crc,
}
static bool zip_file_decompressed_handle(
file_archive_file_handle_t *handle,
const uint8_t *cdata, uint32_t csize,
file_archive_transfer_t *transfer,
file_archive_file_handle_t* handle,
const uint8_t *cdata, unsigned cmode, uint32_t csize,
uint32_t size, uint32_t crc32)
{
int ret = 0;
handle->backend = &zlib_backend;
transfer->backend = &zlib_backend;
if (!handle->backend->stream_decompress_data_to_file_init(
handle, cdata, csize, size))
if (!transfer->backend->stream_decompress_data_to_file_init(
transfer->context, handle, cdata, cmode, csize, size))
return false;
do
{
ret = handle->backend->stream_decompress_data_to_file_iterate(
handle->stream);
}while(ret == 0);
ret = transfer->backend->stream_decompress_data_to_file_iterate(
transfer->context, handle);
}while (ret == 0);
#if 0
handle->real_checksum = handle->backend->stream_crc_calculate(0,
handle->real_checksum = transfer->backend->stream_crc_calculate(0,
handle->data, size);
if (handle->real_checksum != crc32)
goto error;
#endif
{
if (handle->data)
free(handle->data);
if (handle->stream)
free(handle->stream);
handle->data = NULL;
return false;
}
#endif
return true;
#if 0
error:
if (handle->stream)
free(handle->stream);
if (handle->data)
free(handle->data);
handle->stream = NULL;
handle->data = NULL;
return false;
#endif
}
typedef struct
{
char *opt_file;
char *needle;
void **buf;
size_t size;
bool found;
} decomp_state_t;
/* Extract the relative path (needle) from a
* ZIP archive (path) and allocate a buffer for it to write it in.
*
@ -182,212 +279,251 @@ static int zip_file_decompressed(
uint32_t csize, uint32_t size,
uint32_t crc32, struct archive_extract_userdata *userdata)
{
decomp_state_t* decomp_state = (decomp_state_t*)userdata->cb_data;
char last_char = name[strlen(name) - 1];
/* Ignore directories. */
if (last_char == '/' || last_char == '\\')
return 1;
if (strstr(name, userdata->decomp_state.needle))
if (strstr(name, decomp_state->needle))
{
bool goto_error = false;
file_archive_file_handle_t handle = {0};
userdata->decomp_state.found = true;
if (zip_file_decompressed_handle(&handle,
cdata, csize, size, crc32))
if (zip_file_decompressed_handle(userdata->transfer,
&handle, cdata, cmode, csize, size, crc32))
{
if (userdata->decomp_state.opt_file != 0)
if (decomp_state->opt_file != 0)
{
/* Called in case core has need_fullpath enabled. */
char *buf = (char*)malloc(size);
bool success = filestream_write_file(decomp_state->opt_file, handle.data, size);
if (buf)
{
memcpy(buf, handle.data, size);
free(handle.data);
handle.data = NULL;
if (!filestream_write_file(userdata->decomp_state.opt_file, buf, size))
goto_error = true;
}
decomp_state->size = 0;
free(buf);
userdata->decomp_state.size = 0;
if (!success)
return -1;
}
else
{
/* Called in case core has need_fullpath disabled.
* Will copy decompressed content directly into
* Will move decompressed content directly into
* RetroArch's ROM buffer. */
*userdata->decomp_state.buf = malloc(size);
memcpy(*userdata->decomp_state.buf, handle.data, size);
*decomp_state->buf = handle.data;
handle.data = NULL;
userdata->decomp_state.size = size;
decomp_state->size = size;
}
}
if (handle.data)
free(handle.data);
if (goto_error)
return 0;
decomp_state->found = true;
}
return 1;
}
static int zip_file_read(
static int64_t zip_file_read(
const char *path,
const char *needle, void **buf,
const char *optional_outfile)
{
file_archive_transfer_t zlib;
struct archive_extract_userdata userdata = {{0}};
file_archive_transfer_t state = {ARCHIVE_TRANSFER_INIT};
decomp_state_t decomp = {0};
struct archive_extract_userdata userdata = {0};
bool returnerr = true;
int ret = 0;
zlib.type = ARCHIVE_TRANSFER_INIT;
zlib.archive_size = 0;
zlib.start_delta = 0;
zlib.handle = NULL;
zlib.stream = NULL;
zlib.footer = NULL;
zlib.directory = NULL;
zlib.data = NULL;
zlib.backend = NULL;
userdata.decomp_state.needle = NULL;
userdata.decomp_state.opt_file = NULL;
userdata.decomp_state.found = false;
userdata.decomp_state.buf = buf;
if (needle)
userdata.decomp_state.needle = strdup(needle);
decomp.needle = strdup(needle);
if (optional_outfile)
userdata.decomp_state.opt_file = strdup(optional_outfile);
decomp.opt_file = strdup(optional_outfile);
userdata.transfer = &state;
userdata.cb_data = &decomp;
decomp.buf = buf;
do
{
ret = file_archive_parse_file_iterate(&zlib, &returnerr, path,
ret = file_archive_parse_file_iterate(&state, &returnerr, path,
"", zip_file_decompressed, &userdata);
if (!returnerr)
break;
}while(ret == 0 && !userdata.decomp_state.found);
}while (ret == 0 && !decomp.found);
file_archive_parse_file_iterate_stop(&zlib);
file_archive_parse_file_iterate_stop(&state);
if (userdata.decomp_state.opt_file)
free(userdata.decomp_state.opt_file);
if (userdata.decomp_state.needle)
free(userdata.decomp_state.needle);
if (decomp.opt_file)
free(decomp.opt_file);
if (decomp.needle)
free(decomp.needle);
if (!userdata.decomp_state.found)
if (!decomp.found)
return -1;
return (int)userdata.decomp_state.size;
return (int64_t)decomp.size;
}
static int zip_parse_file_init(file_archive_transfer_t *state,
const char *file)
{
if (state->archive_size < 22)
uint8_t footer_buf[1024];
uint8_t *footer = footer_buf;
int64_t read_pos = state->archive_size;
int64_t read_block = MIN(read_pos, sizeof(footer_buf));
int64_t directory_size, directory_offset;
zip_context_t *zip_context = NULL;
/* Minimal ZIP file size is 22 bytes */
if (read_block < 22)
return -1;
state->footer = state->data + state->archive_size - 22;
for (;; state->footer--)
/* Find the end of central directory record by scanning
* the file from the end towards the beginning.
*/
for (;;)
{
if (state->footer <= state->data + 22)
return -1;
if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
if (--footer < footer_buf)
{
unsigned comment_len = read_le(state->footer + 20, 2);
if (state->footer + 22 + comment_len == state->data + state->archive_size)
break;
if (read_pos <= 0)
return -1; /* reached beginning of file */
/* Read 21 bytes of overlaps except on the first block. */
if (read_pos == state->archive_size)
read_pos = read_pos - read_block;
else
read_pos = MAX(read_pos - read_block + 21, 0);
/* Seek to read_pos and read read_block bytes. */
filestream_seek(state->archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, footer_buf, read_block) != read_block)
return -1;
footer = footer_buf + read_block - 22;
}
if (read_le(footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
{
unsigned comment_len = read_le(footer + 20, 2);
if (read_pos + (footer - footer_buf) + 22 + comment_len == state->archive_size)
break; /* found it! */
}
}
state->directory = state->data + read_le(state->footer + 16, 4);
/* Read directory info and do basic sanity checks. */
directory_size = read_le(footer + 12, 4);
directory_offset = read_le(footer + 16, 4);
if (directory_size > state->archive_size
|| directory_offset > state->archive_size)
return -1;
/* This is a ZIP file, allocate one block of memory for both the
* context and the entire directory, then read the directory.
*/
zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
zip_context->state = state;
zip_context->directory = (uint8_t*)(zip_context + 1);
zip_context->directory_entry = zip_context->directory;
zip_context->directory_end = zip_context->directory + (size_t)directory_size;
zip_context->current_stream = NULL;
zip_context->compressed_data = NULL;
zip_context->decompressed_data = NULL;
filestream_seek(state->archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size)
{
free(zip_context);
return -1;
}
state->context = zip_context;
state->step_total = read_le(footer + 10, 2); /* total entries */;
return 0;
}
static int zip_parse_file_iterate_step_internal(
file_archive_transfer_t *state, char *filename,
zip_context_t * zip_context, char *filename,
const uint8_t **cdata,
unsigned *cmode, uint32_t *size, uint32_t *csize,
uint32_t *checksum, unsigned *payback)
{
uint32_t offset;
uint32_t namelength, extralength, commentlength,
offsetNL, offsetEL;
uint32_t signature = read_le(state->directory + 0, 4);
uint8_t *entry = zip_context->directory_entry;
uint32_t signature, namelength, extralength, commentlength, offset;
if (entry < zip_context->directory || entry >= zip_context->directory_end)
return 0;
signature = read_le(zip_context->directory_entry + 0, 4);
if (signature != CENTRAL_FILE_HEADER_SIGNATURE)
return 0;
*cmode = read_le(state->directory + 10, 2); /* compression mode, 0 = store, 8 = deflate */
*checksum = read_le(state->directory + 16, 4); /* CRC32 */
*csize = read_le(state->directory + 20, 4); /* compressed size */
*size = read_le(state->directory + 24, 4); /* uncompressed size */
*cmode = read_le(zip_context->directory_entry + 10, 2); /* compression mode, 0 = store, 8 = deflate */
*checksum = read_le(zip_context->directory_entry + 16, 4); /* CRC32 */
*csize = read_le(zip_context->directory_entry + 20, 4); /* compressed size */
*size = read_le(zip_context->directory_entry + 24, 4); /* uncompressed size */
namelength = read_le(state->directory + 28, 2); /* file name length */
extralength = read_le(state->directory + 30, 2); /* extra field length */
commentlength = read_le(state->directory + 32, 2); /* file comment length */
namelength = read_le(zip_context->directory_entry + 28, 2); /* file name length */
extralength = read_le(zip_context->directory_entry + 30, 2); /* extra field length */
commentlength = read_le(zip_context->directory_entry + 32, 2); /* file comment length */
if (namelength >= PATH_MAX_LENGTH)
return -1;
memcpy(filename, state->directory + 46, namelength); /* file name */
memcpy(filename, zip_context->directory_entry + 46, namelength); /* file name */
filename[namelength] = '\0';
offset = read_le(state->directory + 42, 4); /* relative offset of local file header */
offsetNL = read_le(state->data + offset + 26, 2); /* file name length */
offsetEL = read_le(state->data + offset + 28, 2); /* extra field length */
offset = read_le(zip_context->directory_entry + 42, 4); /* relative offset of local file header */
*cdata = state->data + offset + 30 + offsetNL + offsetEL;
*cdata = (uint8_t*)(size_t)offset; /* store file offset in data pointer */
*payback = 46 + namelength + extralength + commentlength;
*payback = 46 + namelength + extralength + commentlength;
return 1;
}
static int zip_parse_file_iterate_step(file_archive_transfer_t *state,
static int zip_parse_file_iterate_step(void *context,
const char *valid_exts, struct archive_extract_userdata *userdata,
file_archive_file_cb file_cb)
{
char filename[PATH_MAX_LENGTH] = {0};
zip_context_t *zip_context = (zip_context_t *)context;
const uint8_t *cdata = NULL;
uint32_t checksum = 0;
uint32_t size = 0;
uint32_t csize = 0;
unsigned cmode = 0;
unsigned payload = 0;
int ret = zip_parse_file_iterate_step_internal(
state, filename, &cdata, &cmode, &size, &csize, &checksum, &payload);
int ret = zip_parse_file_iterate_step_internal(zip_context,
userdata->current_file_path, &cdata, &cmode, &size, &csize, &checksum, &payload);
if (ret != 1)
return ret;
userdata->extracted_file_path = filename;
userdata->crc = checksum;
if (file_cb && !file_cb(filename, valid_exts, cdata, cmode,
if (file_cb && !file_cb(userdata->current_file_path, valid_exts, cdata, cmode,
csize, size, checksum, userdata))
return 0;
state->directory += payload;
zip_context->directory_entry += payload;
return 1;
}
static void zip_parse_file_free(void *context)
{
zip_context_t *zip_context = (zip_context_t *)context;
zip_context_free_stream(zip_context, false);
free(zip_context);
}
const struct file_archive_file_backend zlib_backend = {
zlib_stream_new,
zlib_stream_free,
zip_parse_file_init,
zip_parse_file_iterate_step,
zip_parse_file_free,
zlib_stream_decompress_data_to_file_init,
zlib_stream_decompress_data_to_file_iterate,
zlib_stream_crc32_calculate,
zip_file_read,
zip_parse_file_init,
zip_parse_file_iterate_step,
"zlib"
};

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (config_file_userdata.c).
@ -61,6 +61,24 @@ int config_userdata_get_int(void *userdata, const char *key_str,
return got;
}
int config_userdata_get_hex(void *userdata, const char *key_str,
unsigned *value, unsigned default_value)
{
bool got;
char key[2][256];
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
got = config_get_hex(usr->conf, key[0], value);
got = got || config_get_hex(usr->conf, key[1], value);
if (!got)
*value = default_value;
return got;
}
int config_userdata_get_float_array(void *userdata, const char *key_str,
float **values, unsigned *out_num_values,
const float *default_values, unsigned num_default_values)
@ -76,12 +94,14 @@ int config_userdata_get_float_array(void *userdata, const char *key_str,
config_get_string(usr->conf, key[1], &str))
{
unsigned i;
struct string_list *list = string_split(str, " ");
*values = (float*)calloc(list->size, sizeof(float));
for (i = 0; i < list->size; i++)
(*values)[i] = (float)strtod(list->elems[i].data, NULL);
*out_num_values = (unsigned)list->size;
string_list_free(list);
struct string_list list = {0};
string_list_initialize(&list);
string_split_noalloc(&list, str, " ");
*values = (float*)calloc(list.size, sizeof(float));
for (i = 0; i < list.size; i++)
(*values)[i] = (float)strtod(list.elems[i].data, NULL);
*out_num_values = (unsigned)list.size;
string_list_deinitialize(&list);
free(str);
return true;
}
@ -106,12 +126,14 @@ int config_userdata_get_int_array(void *userdata, const char *key_str,
config_get_string(usr->conf, key[1], &str))
{
unsigned i;
struct string_list *list = string_split(str, " ");
*values = (int*)calloc(list->size, sizeof(int));
for (i = 0; i < list->size; i++)
(*values)[i] = (int)strtod(list->elems[i].data, NULL);
*out_num_values = (unsigned)list->size;
string_list_free(list);
struct string_list list = {0};
string_list_initialize(&list);
string_split_noalloc(&list, str, " ");
*values = (int*)calloc(list.size, sizeof(int));
for (i = 0; i < list.size; i++)
(*values)[i] = (int)strtod(list.elems[i].data, NULL);
*out_num_values = (unsigned)list.size;
string_list_deinitialize(&list);
free(str);
return true;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path.c).
@ -32,8 +32,7 @@
#include <file/file_path.h>
#include <retro_assert.h>
#include <string/stdstring.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
#include <time/rtime.h>
/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
#ifdef __APPLE__
@ -46,7 +45,6 @@
#include <compat/strl.h>
#include <compat/posix_string.h>
#endif
#include <compat/strcasestr.h>
#include <retro_miscellaneous.h>
#include <encodings/utf.h>
@ -82,12 +80,7 @@
#include <pspkernel.h>
#endif
#if defined(PS2)
#include <fileXio_rpc.h>
#include <fileXio.h>
#endif
#if defined(__CELLOS_LV2__)
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <cell/cell_fs.h>
#endif
@ -95,7 +88,7 @@
#define FIO_S_ISDIR SCE_S_ISDIR
#endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
#include <unistd.h> /* stat() is defined here */
#endif
@ -114,133 +107,6 @@
#endif
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface*
vfs_iface = vfs_info->iface;
path_stat_cb = retro_vfs_stat_impl;
path_mkdir_cb = retro_vfs_mkdir_impl;
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
return;
path_stat_cb = vfs_iface->stat;
path_mkdir_cb = vfs_iface->mkdir;
}
int path_stat(const char *path)
{
return path_stat_cb(path, NULL);
}
/**
* path_is_directory:
* @path : path
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
*/
bool path_is_directory(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
}
bool path_is_character_special(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
}
bool path_is_valid(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
}
int32_t path_get_size(const char *path)
{
int32_t filesize = 0;
if (path_stat_cb(path, &filesize) != 0)
return filesize;
return -1;
}
/**
* path_mkdir:
* @dir : directory
*
* Create directory on filesystem.
*
* Returns: true (1) if directory could be created, otherwise false (0).
**/
bool path_mkdir(const char *dir)
{
bool sret = false;
bool norecurse = false;
char *basedir = NULL;
if (!(dir && *dir))
return false;
/* Use heap. Real chance of stack
* overflow if we recurse too hard. */
basedir = strdup(dir);
if (!basedir)
return false;
path_parent_dir(basedir);
if (!*basedir || !strcmp(basedir, dir))
{
free(basedir);
return false;
}
#if defined(GEKKO)
{
size_t len = strlen(basedir);
/* path_parent_dir() keeps the trailing slash.
* On Wii, mkdir() fails if the path has a
* trailing slash...
* We must therefore remove it. */
if (len > 0)
if (basedir[len - 1] == '/')
basedir[len - 1] = '\0';
}
#endif
if (path_is_directory(basedir))
norecurse = true;
else
{
sret = path_mkdir(basedir);
if (sret)
norecurse = true;
}
free(basedir);
if (norecurse)
{
int ret = path_mkdir_cb(dir);
/* Don't treat this as an error. */
if (ret == -2 && path_is_directory(dir))
return true;
return (ret == 0);
}
return sret;
}
/**
* path_get_archive_delim:
* @path : path
@ -253,26 +119,48 @@ bool path_mkdir(const char *dir)
*/
const char *path_get_archive_delim(const char *path)
{
const char *last = find_last_slash(path);
const char *delim = NULL;
const char *last_slash = find_last_slash(path);
const char *delim = NULL;
char buf[5];
if (!last)
buf[0] = '\0';
if (!last_slash)
return NULL;
/* Test if it's .zip */
delim = strcasestr(last, ".zip#");
/* Find delimiter position */
delim = strrchr(last_slash, '#');
if (!delim) /* If it's not a .zip, test if it's .apk */
delim = strcasestr(last, ".apk#");
if (!delim)
return NULL;
if (delim)
return delim + 4;
/* Check whether this is a known archive type
* > Note: The code duplication here is
* deliberate, to maximise performance */
if (delim - last_slash > 4)
{
strlcpy(buf, delim - 4, sizeof(buf));
buf[4] = '\0';
/* If it's not a .zip or .apk file, test if it's .7z */
delim = strcasestr(last, ".7z#");
string_to_lower(buf);
if (delim)
return delim + 3;
/* Check if this is a '.zip', '.apk' or '.7z' file */
if (string_is_equal(buf, ".zip") ||
string_is_equal(buf, ".apk") ||
string_is_equal(buf + 1, ".7z"))
return delim;
}
else if (delim - last_slash > 3)
{
strlcpy(buf, delim - 3, sizeof(buf));
buf[3] = '\0';
string_to_lower(buf);
/* Check if this is a '.7z' file */
if (string_is_equal(buf, ".7z"))
return delim;
}
return NULL;
}
@ -331,9 +219,12 @@ bool path_is_compressed_file(const char* path)
{
const char *ext = path_get_extension(path);
if ( strcasestr(ext, "zip")
|| strcasestr(ext, "apk")
|| strcasestr(ext, "7z"))
if (string_is_empty(ext))
return false;
if (string_is_equal_noncase(ext, "zip") ||
string_is_equal_noncase(ext, "apk") ||
string_is_equal_noncase(ext, "7z"))
return true;
return false;
@ -423,7 +314,7 @@ void fill_pathname_slash(char *path, size_t size)
if (!last_slash)
{
strlcat(path, path_default_slash(), size);
strlcat(path, PATH_DEFAULT_SLASH(), size);
return;
}
@ -592,11 +483,13 @@ void fill_pathname_parent_dir(char *out_dir,
size_t fill_dated_filename(char *out_filename,
const char *ext, size_t size)
{
time_t cur_time = time(NULL);
const struct tm* tm_ = localtime(&cur_time);
time_t cur_time = time(NULL);
struct tm tm_;
rtime_localtime(&cur_time, &tm_);
strftime(out_filename, size,
"RetroArch-%m%d-%H%M%S", tm_);
"RetroArch-%m%d-%H%M%S", &tm_);
return strlcat(out_filename, ext, size);
}
@ -617,19 +510,21 @@ void fill_str_dated_filename(char *out_filename,
const char *in_str, const char *ext, size_t size)
{
char format[256];
time_t cur_time = time(NULL);
const struct tm* tm_ = localtime(&cur_time);
struct tm tm_;
time_t cur_time = time(NULL);
format[0] = '\0';
format[0] = '\0';
rtime_localtime(&cur_time, &tm_);
if (string_is_empty(ext))
{
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", tm_);
strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
fill_pathname_noext(out_filename, in_str, format, size);
}
else
{
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", tm_);
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
fill_pathname_join_concat_noext(out_filename,
in_str, format, ext,
@ -656,7 +551,7 @@ void path_basedir(char *path)
if (last)
last[1] = '\0';
else
snprintf(path, 3, ".%s", path_default_slash());
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
}
/**
@ -676,7 +571,7 @@ void path_parent_dir(char *path)
len = strlen(path);
if (len && path_char_is_slash(path[len - 1]))
if (len && PATH_CHAR_IS_SLASH(path[len - 1]))
{
bool path_was_absolute = path_is_absolute(path);
@ -731,19 +626,27 @@ const char *path_basename(const char *path)
**/
bool path_is_absolute(const char *path)
{
if (string_is_empty(path))
return false;
if (path[0] == '/')
return true;
#ifdef _WIN32
/* Many roads lead to Rome ... */
if (( strstr(path, "\\\\") == path)
|| strstr(path, ":/")
|| strstr(path, ":\\")
|| strstr(path, ":\\\\"))
return true;
#elif defined(__wiiu__)
if (strstr(path, ":/"))
#if defined(_WIN32)
/* Many roads lead to Rome...
* Note: Drive letter can only be 1 character long */
if (string_starts_with_size(path, "\\\\", STRLEN_CONST("\\\\")) ||
string_starts_with_size(path + 1, ":/", STRLEN_CONST(":/")) ||
string_starts_with_size(path + 1, ":\\", STRLEN_CONST(":\\")))
return true;
#elif defined(__wiiu__) || defined(VITA)
{
const char *seperator = strchr(path, ':');
if (seperator && (seperator[1] == '/'))
return true;
}
#endif
return false;
}
@ -893,7 +796,7 @@ end:
size_t path_relative_to(char *out,
const char *path, const char *base, size_t size)
{
size_t i;
size_t i, j;
const char *trimmed_path, *trimmed_base;
#ifdef _WIN32
@ -905,16 +808,18 @@ size_t path_relative_to(char *out,
#endif
/* Trim common beginning */
for (i = 0; path[i] && base[i] && path[i] == base[i]; )
i++;
trimmed_path = path+i;
for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
if (path[i] == PATH_DEFAULT_SLASH_C())
j = i + 1;
trimmed_path = path+j;
trimmed_base = base+i;
/* Each segment of base turns into ".." */
out[0] = '\0';
for (i = 0; trimmed_base[i]; i++)
if (trimmed_base[i] == path_default_slash_c())
strlcat(out, ".." path_default_slash(), size);
if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
strlcat(out, ".." PATH_DEFAULT_SLASH(), size);
return strlcat(out, trimmed_path, size);
}
@ -1099,13 +1004,13 @@ void fill_pathname_expand_special(char *out_path,
out_path += src_size;
size -= src_size;
if (!path_char_is_slash(out_path[-1]))
if (!PATH_CHAR_IS_SLASH(out_path[-1]))
{
src_size = strlcpy(out_path, path_default_slash(), size);
src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
retro_assert(src_size < size);
out_path += src_size;
size -= src_size;
size -= src_size;
}
in_path += 2;
@ -1130,9 +1035,9 @@ void fill_pathname_expand_special(char *out_path,
out_path += src_size;
size -= src_size;
if (!path_char_is_slash(out_path[-1]))
if (!PATH_CHAR_IS_SLASH(out_path[-1]))
{
src_size = strlcpy(out_path, path_default_slash(), size);
src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
retro_assert(src_size < size);
out_path += src_size;
@ -1156,10 +1061,11 @@ void fill_pathname_abbreviate_special(char *out_path,
unsigned i;
const char *candidates[3];
const char *notations[3];
char *application_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
char *home_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
char application_dir[PATH_MAX_LENGTH];
char home_dir[PATH_MAX_LENGTH];
application_dir[0] = '\0';
home_dir[0] = '\0';
/* application_dir could be zero-string. Safeguard against this.
*
@ -1176,15 +1082,13 @@ void fill_pathname_abbreviate_special(char *out_path,
notations [1] = "~";
notations [2] = NULL;
fill_pathname_application_dir(application_dir,
PATH_MAX_LENGTH * sizeof(char));
fill_pathname_home_dir(home_dir,
PATH_MAX_LENGTH * sizeof(char));
fill_pathname_application_dir(application_dir, sizeof(application_dir));
fill_pathname_home_dir(home_dir, sizeof(home_dir));
for (i = 0; candidates[i]; i++)
{
if (!string_is_empty(candidates[i]) &&
strstr(in_path, candidates[i]) == in_path)
string_starts_with(in_path, candidates[i]))
{
size_t src_size = strlcpy(out_path, notations[i], size);
@ -1194,10 +1098,9 @@ void fill_pathname_abbreviate_special(char *out_path,
size -= src_size;
in_path += strlen(candidates[i]);
if (!path_char_is_slash(*in_path))
if (!PATH_CHAR_IS_SLASH(*in_path))
{
retro_assert(strlcpy(out_path,
path_default_slash(), size) < size);
strcpy_literal(out_path, PATH_DEFAULT_SLASH());
out_path++;
size--;
}
@ -1206,8 +1109,6 @@ void fill_pathname_abbreviate_special(char *out_path,
}
}
free(application_dir);
free(home_dir);
#endif
retro_assert(strlcpy(out_path, in_path, size) < size);
@ -1238,7 +1139,7 @@ void path_basedir_wrapper(char *path)
if (last)
last[1] = '\0';
else
snprintf(path, 3, ".%s", path_default_slash());
snprintf(path, 3, "." PATH_DEFAULT_SLASH());
}
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
@ -1365,29 +1266,27 @@ void fill_pathname_application_dir(char *s, size_t len)
void fill_pathname_home_dir(char *s, size_t len)
{
#ifdef __WINRT__
strlcpy(s, uwp_dir_data, len);
const char *home = uwp_dir_data;
#else
const char *home = getenv("HOME");
#endif
if (home)
strlcpy(s, home, len);
else
*s = 0;
#endif
}
#endif
bool is_path_accessible_using_standard_io(const char *path)
{
#ifdef __WINRT__
bool result;
size_t path_sizeof = PATH_MAX_LENGTH * sizeof(char);
char *relative_path_abbrev = (char*)malloc(path_sizeof);
fill_pathname_abbreviate_special(relative_path_abbrev, path, path_sizeof);
result = strlen(relative_path_abbrev) >= 2 && (relative_path_abbrev[0] == ':' || relative_path_abbrev[0] == '~') && path_char_is_slash(relative_path_abbrev[1]);
free(relative_path_abbrev);
return result;
char relative_path_abbrev[PATH_MAX_LENGTH];
fill_pathname_abbreviate_special(relative_path_abbrev,
path, sizeof(relative_path_abbrev));
return (strlen(relative_path_abbrev) >= 2 )
&& ( relative_path_abbrev[0] == ':'
|| relative_path_abbrev[0] == '~')
&& PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
#else
return true;
#endif

View File

@ -0,0 +1,224 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (file_path_io.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <boolean.h>
#include <file/file_path.h>
#include <retro_assert.h>
#include <string/stdstring.h>
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef __HAIKU__
#include <kernel/image.h>
#endif
#ifndef __MACH__
#include <compat/strl.h>
#include <compat/posix_string.h>
#endif
#include <compat/strcasestr.h>
#include <retro_miscellaneous.h>
#include <encodings/utf.h>
#if defined(_WIN32)
#ifdef _MSC_VER
#define setmode _setmode
#endif
#include <sys/stat.h>
#ifdef _XBOX
#include <xtl.h>
#define INVALID_FILE_ATTRIBUTES -1
#else
#include <io.h>
#include <fcntl.h>
#include <direct.h>
#include <windows.h>
#if defined(_MSC_VER) && _MSC_VER <= 1200
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
#endif
#elif defined(VITA)
#define SCE_ERROR_ERRNO_EEXIST 0x80010011
#include <psp2/io/fcntl.h>
#include <psp2/io/dirent.h>
#include <psp2/io/stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#if defined(PSP)
#include <pspkernel.h>
#endif
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
#include <cell/cell_fs.h>
#endif
#if defined(VITA)
#define FIO_S_ISDIR SCE_S_ISDIR
#endif
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) || defined(PS2)
#include <unistd.h> /* stat() is defined here */
#endif
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
#ifdef __WINRT__
#include <uwp/uwp_func.h>
#endif
#endif
/* Assume W-functions do not work below Win2K and Xbox platforms */
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
#ifndef LEGACY_WIN32
#define LEGACY_WIN32
#endif
#endif
/* TODO/FIXME - globals */
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface*
vfs_iface = vfs_info->iface;
path_stat_cb = retro_vfs_stat_impl;
path_mkdir_cb = retro_vfs_mkdir_impl;
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
return;
path_stat_cb = vfs_iface->stat;
path_mkdir_cb = vfs_iface->mkdir;
}
int path_stat(const char *path)
{
return path_stat_cb(path, NULL);
}
/**
* path_is_directory:
* @path : path
*
* Checks if path is a directory.
*
* Returns: true (1) if path is a directory, otherwise false (0).
*/
bool path_is_directory(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_DIRECTORY) != 0;
}
bool path_is_character_special(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_CHARACTER_SPECIAL) != 0;
}
bool path_is_valid(const char *path)
{
return (path_stat_cb(path, NULL) & RETRO_VFS_STAT_IS_VALID) != 0;
}
int32_t path_get_size(const char *path)
{
int32_t filesize = 0;
if (path_stat_cb(path, &filesize) != 0)
return filesize;
return -1;
}
/**
* path_mkdir:
* @dir : directory
*
* Create directory on filesystem.
*
* Returns: true (1) if directory could be created, otherwise false (0).
**/
bool path_mkdir(const char *dir)
{
bool sret = false;
bool norecurse = false;
char *basedir = NULL;
if (!(dir && *dir))
return false;
/* Use heap. Real chance of stack
* overflow if we recurse too hard. */
basedir = strdup(dir);
if (!basedir)
return false;
path_parent_dir(basedir);
if (!*basedir || !strcmp(basedir, dir))
{
free(basedir);
return false;
}
if (path_is_directory(basedir))
norecurse = true;
else
{
sret = path_mkdir(basedir);
if (sret)
norecurse = true;
}
free(basedir);
if (norecurse)
{
int ret = path_mkdir_cb(dir);
/* Don't treat this as an error. */
if (ret == -2 && path_is_directory(dir))
return true;
return (ret == 0);
}
return sret;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_intf.c).
@ -37,11 +37,29 @@ extern nbio_intf_t nbio_orbis;
#endif
extern nbio_intf_t nbio_stdio;
#ifndef _XBOX
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1500
#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#elif !defined(_MSC_VER)
#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#endif
#endif
#endif
#if defined(_linux__)
static nbio_intf_t *internal_nbio = &nbio_linux;
#elif defined(HAVE_MMAP) && defined(BSD)
static nbio_intf_t *internal_nbio = &nbio_mmap_unix;
#elif defined(_WIN32) && !defined(_XBOX)
#elif defined(HAVE_MMAP_WIN32)
static nbio_intf_t *internal_nbio = &nbio_mmap_win32;
#elif defined(ORBIS)
static nbio_intf_t *internal_nbio = &nbio_orbis;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_linux.c).
@ -31,6 +31,7 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
@ -39,14 +40,12 @@
struct nbio_linux_t
{
int fd;
bool busy;
void* ptr;
aio_context_t ctx;
struct iocb cb;
void* ptr;
size_t len;
int fd;
bool busy;
};
/* there's also a Unix AIO thingy, but it's not in glibc

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_orbis.c).
@ -31,10 +31,11 @@
struct nbio_orbis_t
{
int fd;
void* data;
size_t progress;
size_t len;
int fd;
unsigned int mode;
/*
* possible values:
* NBIO_READ, NBIO_WRITE - obvious
@ -42,7 +43,6 @@ struct nbio_orbis_t
* -2 - the pointer was reallocated since the last operation
*/
signed char op;
unsigned int mode;
};
static void *nbio_orbis_open(const char * filename, unsigned int mode)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_stdio.c).
@ -35,6 +35,18 @@
#endif
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1400
#define ATLEAST_VC2005
#endif
#endif
#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
#ifndef HAVE_64BIT_OFFSETS
#define HAVE_64BIT_OFFSETS
#endif
#endif
struct nbio_stdio_t
{
FILE* f;
@ -57,11 +69,35 @@ static const char *stdio_modes[] = { "rb", "wb", "r+b", "rb", "wb", "r+b" };
static const wchar_t *stdio_modes[] = { L"rb", L"wb", L"r+b", L"rb", L"wb", L"r+b" };
#endif
static int64_t fseek_wrap(FILE *f, int64_t offset, int origin)
{
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit fseek */
return _fseeki64(f, offset, origin);
#elif defined(HAVE_64BIT_OFFSETS)
return fseeko(f, (off_t)offset, origin);
#else
return fseek(f, (long)offset, origin);
#endif
}
static int64_t ftell_wrap(FILE *f)
{
#ifdef ATLEAST_VC2005
/* VC2005 and up have a special 64-bit ftell */
return _ftelli64(f);
#elif defined(HAVE_64BIT_OFFSETS)
return ftello(f);
#else
return ftell(f);
#endif
}
static void *nbio_stdio_open(const char * filename, unsigned mode)
{
void *buf = NULL;
struct nbio_stdio_t* handle = NULL;
size_t len = 0;
int64_t len = 0;
#if !defined(_WIN32) || defined(LEGACY_WIN32)
FILE* f = fopen(filename, stdio_modes[mode]);
#else
@ -87,15 +123,15 @@ static void *nbio_stdio_open(const char * filename, unsigned mode)
case BIO_WRITE:
break;
default:
fseek(handle->f, 0, SEEK_END);
len = ftell(handle->f);
fseek_wrap(handle->f, 0, SEEK_END);
len = ftell_wrap(handle->f);
break;
}
handle->mode = mode;
if (len)
buf = malloc(len);
buf = malloc((size_t)len);
if (len && !buf)
goto error;
@ -123,7 +159,7 @@ static void nbio_stdio_begin_read(void *data)
if (handle->op >= 0)
abort();
fseek(handle->f, 0, SEEK_SET);
fseek_wrap(handle->f, 0, SEEK_SET);
handle->op = NBIO_READ;
handle->progress = 0;
@ -138,7 +174,7 @@ static void nbio_stdio_begin_write(void *data)
if (handle->op >= 0)
abort();
fseek(handle->f, 0, SEEK_SET);
fseek_wrap(handle->f, 0, SEEK_SET);
handle->op = NBIO_WRITE;
handle->progress = 0;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_unixmmap.c).
@ -55,10 +55,10 @@
struct nbio_mmap_unix_t
{
void* ptr;
size_t len;
int fd;
int map_flags;
size_t len;
void* ptr;
};
static void *nbio_mmap_unix_open(const char * filename, unsigned mode)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (nbio_windowsmmap.c).
@ -22,7 +22,23 @@
#include <file/nbio.h>
#if defined(_WIN32) && !defined(_XBOX)
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1500
#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#elif !defined(_MSC_VER)
#ifndef HAVE_MMAP_WIN32
#define HAVE_MMAP_WIN32
#endif
#endif
#endif
#if defined(HAVE_MMAP_WIN32)
#include <stdio.h>
#include <stdlib.h>
@ -47,9 +63,9 @@
struct nbio_mmap_win32_t
{
HANDLE file;
bool is_write;
size_t len;
void* ptr;
size_t len;
bool is_write;
};
static void *nbio_mmap_win32_open(const char * filename, unsigned mode)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (retro_dirent.c).
@ -31,37 +31,41 @@
#define VFS_FRONTEND
#include <vfs/vfs_implementation.h>
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
/* TODO/FIXME - static globals */
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
{
const struct retro_vfs_interface* vfs_iface;
dirent_opendir_cb = NULL;
dirent_readdir_cb = NULL;
dirent_opendir_cb = NULL;
dirent_readdir_cb = NULL;
dirent_dirent_get_name_cb = NULL;
dirent_dirent_is_dir_cb = NULL;
dirent_closedir_cb = NULL;
dirent_dirent_is_dir_cb = NULL;
dirent_closedir_cb = NULL;
vfs_iface = vfs_info->iface;
vfs_iface = vfs_info->iface;
if (vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || !vfs_iface)
if (
vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION ||
!vfs_iface)
return;
dirent_opendir_cb = vfs_iface->opendir;
dirent_readdir_cb = vfs_iface->readdir;
dirent_opendir_cb = vfs_iface->opendir;
dirent_readdir_cb = vfs_iface->readdir;
dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
dirent_closedir_cb = vfs_iface->closedir;
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
dirent_closedir_cb = vfs_iface->closedir;
}
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden)
struct RDIR *retro_opendir_include_hidden(
const char *name, bool include_hidden)
{
if (dirent_opendir_cb != NULL)
if (dirent_opendir_cb)
return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
}
@ -79,14 +83,14 @@ bool retro_dirent_error(struct RDIR *rdir)
int retro_readdir(struct RDIR *rdir)
{
if (dirent_readdir_cb != NULL)
if (dirent_readdir_cb)
return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
}
const char *retro_dirent_get_name(struct RDIR *rdir)
{
if (dirent_dirent_get_name_cb != NULL)
if (dirent_dirent_get_name_cb)
return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
}
@ -104,14 +108,14 @@ const char *retro_dirent_get_name(struct RDIR *rdir)
*/
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
{
if (dirent_dirent_is_dir_cb != NULL)
if (dirent_dirent_is_dir_cb)
return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
}
void retro_closedir(struct RDIR *rdir)
{
if (dirent_closedir_cb != NULL)
if (dirent_closedir_cb)
dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
else
retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rbmp.c).
@ -41,17 +41,15 @@
typedef struct
{
uint32_t img_x;
uint32_t img_y;
int img_n;
int img_out_n;
int buflen;
unsigned char buffer_start[128];
unsigned char *img_buffer;
unsigned char *img_buffer_end;
unsigned char *img_buffer_original;
int img_n;
int img_out_n;
int buflen;
uint32_t img_x;
uint32_t img_y;
unsigned char buffer_start[128];
} rbmp_context;
struct rbmp
@ -107,40 +105,40 @@ static unsigned char *rbmp_convert_format(
switch (((img_n)*8+(req_comp)))
{
case 10:
for(i = x-1; i >= 0; --i, src += 1, dest += 2)
for (i = x-1; i >= 0; --i, src += 1, dest += 2)
{
dest[0]=src[0];
dest[1]=255;
}
break;
case 11:
for(i = x-1; i >= 0; --i, src += 1, dest += 3)
for (i = x-1; i >= 0; --i, src += 1, dest += 3)
dest[0]=dest[1]=dest[2]=src[0];
break;
case 12:
for(i = x-1; i >= 0; --i, src += 1, dest += 4)
for (i = x-1; i >= 0; --i, src += 1, dest += 4)
{
dest[0]=dest[1]=dest[2]=src[0];
dest[3]=255;
}
break;
case 17:
for(i = x-1; i >= 0; --i, src += 2, dest += 1)
for (i = x-1; i >= 0; --i, src += 2, dest += 1)
dest[0]=src[0];
break;
case 19:
for(i = x-1; i >= 0; --i, src += 2, dest += 3)
for (i = x-1; i >= 0; --i, src += 2, dest += 3)
dest[0]=dest[1]=dest[2]=src[0];
break;
case 20:
for(i = x-1; i >= 0; --i, src += 2, dest += 4)
for (i = x-1; i >= 0; --i, src += 2, dest += 4)
{
dest[0]=dest[1]=dest[2]=src[0];
dest[3]=src[1];
}
break;
case 28:
for(i = x-1; i >= 0; --i, src += 3, dest += 4)
for (i = x-1; i >= 0; --i, src += 3, dest += 4)
{
dest[0]=src[0];
dest[1]=src[1];
@ -149,29 +147,29 @@ static unsigned char *rbmp_convert_format(
}
break;
case 25:
for(i = x-1; i >= 0; --i, src += 3, dest += 1)
for (i = x-1; i >= 0; --i, src += 3, dest += 1)
dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
break;
case 26:
for(i = x-1; i >= 0; --i, src += 3, dest += 2)
for (i = x-1; i >= 0; --i, src += 3, dest += 2)
{
dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
dest[1] = 255;
}
break;
case 33:
for(i = x-1; i >= 0; --i, src += 4, dest += 1)
for (i = x-1; i >= 0; --i, src += 4, dest += 1)
dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
break;
case 34:
for(i = x-1; i >= 0; --i, src += 4, dest += 2)
for (i = x-1; i >= 0; --i, src += 4, dest += 2)
{
dest[0] = RBMP_COMPUTE_Y(src[0],src[1],src[2]);
dest[1] = src[3];
}
break;
case 35:
for(i = x-1; i >= 0; --i, src += 4, dest += 3)
for (i = x-1; i >= 0; --i, src += 4, dest += 3)
{
dest[0]=src[0];
dest[1]=src[1];
@ -735,7 +733,7 @@ static void rbmp_convert_frame(uint32_t *frame, unsigned width, unsigned height)
{
uint32_t *end = frame + (width * height * sizeof(uint32_t))/4;
while(frame < end)
while (frame < end)
{
uint32_t pixel = *frame;
*frame = (pixel & 0xff00ff00) | ((pixel << 16) & 0x00ff0000) | ((pixel >> 16) & 0xff);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rbmp_encode.c).

View File

@ -0,0 +1,630 @@
#include <formats/cdfs.h>
#include <retro_miscellaneous.h>
#include <compat/strl.h>
#include <file/file_path.h>
#include <string/stdstring.h>
#ifdef HAVE_CHD
#include <streams/chd_stream.h>
#endif
static void cdfs_determine_sector_size(cdfs_track_t* track)
{
uint8_t buffer[32];
const int toc_sector = 16;
/* MODE information is normally found in the CUE sheet, but we can try to determine it from the raw data.
*
* MODE1/2048 - CDROM Mode1 Data (cooked) [no header, no footer]
* MODE1/2352 - CDROM Mode1 Data (raw) [16 byte header, 288 byte footer]
* MODE2/2336 - CDROM-XA Mode2 Data [8 byte header, 280 byte footer]
* MODE2/2352 - CDROM-XA Mode2 Data [24 byte header, 280 byte footer]
*
* Note that MODE is actually a property on each sector and can change between 1 and 2 depending on how much error
* correction the author desired. To support that, the data format must be "/2352" to include the full header and
* data without error correction information, at which point the CUE sheet information becomes just a hint.
*/
/* The boot record or primary volume descriptor is always at sector 16 and will contain a "CD001" marker */
intfstream_seek(track->stream, toc_sector * 2352 + track->first_sector_offset, SEEK_SET);
if (intfstream_read(track->stream, buffer, sizeof(buffer)) < sizeof(buffer))
return;
/* if this is a CDROM-XA data source, the "CD001" tag will be 25 bytes into the sector */
if (buffer[25] == 0x43 && buffer[26] == 0x44 &&
buffer[27] == 0x30 && buffer[28] == 0x30 && buffer[29] == 0x31)
{
track->stream_sector_size = 2352;
track->stream_sector_header_size = 24;
}
/* otherwise it should be 17 bytes into the sector */
else if (buffer[17] == 0x43 && buffer[18] == 0x44 &&
buffer[19] == 0x30 && buffer[20] == 0x30 && buffer[21] == 0x31)
{
track->stream_sector_size = 2352;
track->stream_sector_header_size = 16;
}
else
{
/* ISO-9660 says the first twelve bytes of a sector should be the sync pattern 00 FF FF FF FF FF FF FF FF FF FF 00 */
if (buffer[0] == 0 && buffer[1] == 0xFF && buffer[2] == 0xFF && buffer[3] == 0xFF &&
buffer[4] == 0xFF && buffer[5] == 0xFF && buffer[6] == 0xFF && buffer[7] == 0xFF &&
buffer[8] == 0xFF && buffer[9] == 0xFF && buffer[10] == 0xFF && buffer[11] == 0)
{
/* if we didn't find a CD001 tag, this format may predate ISO-9660 */
/* after the 12 byte sync pattern is three bytes identifying the sector and then one byte for the mode (total 16 bytes) */
track->stream_sector_size = 2352;
track->stream_sector_header_size = 16;
}
else
{
/* attempt to determine stream_sector_size from file size */
size_t size = intfstream_get_size(track->stream);
if ((size % 2352) == 0)
{
/* raw tracks use all 2352 bytes and have a 24 byte header */
track->stream_sector_size = 2352;
track->stream_sector_header_size = 24;
}
else if ((size % 2048) == 0)
{
/* cooked tracks eliminate all header/footer data */
track->stream_sector_size = 2048;
track->stream_sector_header_size = 0;
}
else if ((size % 2336) == 0)
{
/* MODE 2 format without 16-byte sync data */
track->stream_sector_size = 2336;
track->stream_sector_header_size = 8;
}
}
}
}
static void cdfs_seek_track_sector(cdfs_track_t* track, unsigned int sector)
{
intfstream_seek(track->stream,
sector * track->stream_sector_size +
track->stream_sector_header_size +
track->first_sector_offset, SEEK_SET);
}
void cdfs_seek_sector(cdfs_file_t* file, unsigned int sector)
{
/* only allowed if open_file was called with a NULL path */
if (file->first_sector == 0)
{
if (sector != file->current_sector)
{
file->current_sector = sector;
file->sector_buffer_valid = 0;
}
file->pos = file->current_sector * 2048;
file->current_sector_offset = 0;
}
}
static int cdfs_find_file(cdfs_file_t* file, const char* path)
{
uint8_t buffer[2048], *tmp;
int sector, path_length;
const char* slash = strrchr(path, '\\');
if (slash)
{
/* navigate the path to the directory record for the file */
const int dir_length = (int)(slash - path);
memcpy(buffer, path, dir_length);
buffer[dir_length] = '\0';
sector = cdfs_find_file(file, (const char*)buffer);
if (sector < 0)
return sector;
path += dir_length + 1;
}
else
{
int offset;
/* find the CD information (always 16 frames in) */
cdfs_seek_track_sector(file->track, 16);
intfstream_read(file->track->stream, buffer, sizeof(buffer));
/* the directory_record starts at 156 bytes into the sector.
* the sector containing the root directory contents is a
* 3 byte value that is 2 bytes into the directory_record. */
offset = 156 + 2;
sector = buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16);
}
/* process the contents of the directory */
cdfs_seek_track_sector(file->track, sector);
intfstream_read(file->track->stream, buffer, sizeof(buffer));
path_length = strlen(path);
tmp = buffer;
while (tmp < buffer + sizeof(buffer))
{
/* The first byte of the record is the length of
* the record - if 0, we reached the end of the data */
if (!*tmp)
break;
/* filename is 33 bytes into the record and
* the format is "FILENAME;version" or "DIRECTORY" */
if ((tmp[33 + path_length] == ';' || tmp[33 + path_length] == '\0') &&
strncasecmp((const char*)(tmp + 33), path, path_length) == 0)
{
/* the file size is in bytes 10-13 of the record */
file->size = tmp[10] | (tmp[11] << 8)
| (tmp[12] << 16) | (tmp[13] << 24);
/* the file contents are in the sector identified
* in bytes 2-4 of the record */
sector = tmp[2] | (tmp[3] << 8) | (tmp[4] << 16);
return sector;
}
/* the first byte of the record is the length of the record */
tmp += tmp[0];
}
return -1;
}
int cdfs_open_file(cdfs_file_t* file, cdfs_track_t* track, const char* path)
{
if (!file || !track)
return 0;
memset(file, 0, sizeof(*file));
file->track = track;
file->current_sector = -1;
if (path)
file->first_sector = cdfs_find_file(file, path);
else if (file->track->stream_sector_size)
{
file->first_sector = 0;
file->size = (intfstream_get_size(
file->track->stream) / file->track->stream_sector_size)
* 2048;
}
else
file->first_sector = -1;
return (file->first_sector >= 0);
}
int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
{
int bytes_read = 0;
if (!file || file->first_sector < 0 || !buffer)
return 0;
if (len > file->size - file->pos)
len = file->size - file->pos;
if (len == 0)
return 0;
if (file->sector_buffer_valid)
{
size_t remaining = 2048 - file->current_sector_offset;
if (remaining > 0)
{
if (remaining >= len)
{
memcpy(buffer,
&file->sector_buffer[file->current_sector_offset],
(size_t)len);
file->current_sector_offset += len;
return len;
}
memcpy(buffer,
&file->sector_buffer[file->current_sector_offset], remaining);
buffer = (char*)buffer + remaining;
bytes_read += remaining;
len -= remaining;
file->current_sector_offset += remaining;
}
++file->current_sector;
file->current_sector_offset = 0;
file->sector_buffer_valid = 0;
}
else if (file->current_sector < file->first_sector)
{
file->current_sector = file->first_sector;
file->current_sector_offset = 0;
}
while (len >= 2048)
{
cdfs_seek_track_sector(file->track, file->current_sector);
intfstream_read(file->track->stream, buffer, 2048);
buffer = (char*)buffer + 2048;
bytes_read += 2048;
++file->current_sector;
len -= 2048;
}
if (len > 0)
{
cdfs_seek_track_sector(file->track, file->current_sector);
intfstream_read(file->track->stream, file->sector_buffer, 2048);
memcpy(buffer, file->sector_buffer, (size_t)len);
file->current_sector_offset = len;
file->sector_buffer_valid = 1;
bytes_read += len;
}
file->pos += bytes_read;
return bytes_read;
}
void cdfs_close_file(cdfs_file_t* file)
{
if (file)
{
/* not really anything to do here, just
* clear out the first_sector so read() won't do anything */
file->first_sector = -1;
}
}
int64_t cdfs_get_size(cdfs_file_t* file)
{
if (!file || file->first_sector < 0)
return 0;
return file->size;
}
int64_t cdfs_tell(cdfs_file_t* file)
{
if (!file || file->first_sector < 0)
return -1;
return file->pos;
}
int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)
{
int64_t new_pos;
int new_sector;
if (!file || file->first_sector < 0)
return -1;
switch (whence)
{
case SEEK_SET:
new_pos = offset;
break;
case SEEK_CUR:
new_pos = file->pos + offset;
break;
case SEEK_END:
new_pos = file->size - offset;
break;
default:
return -1;
}
if (new_pos < 0)
return -1;
else if (new_pos > file->size)
return -1;
file->pos = (unsigned int)new_pos;
file->current_sector_offset = file->pos % 2048;
new_sector = file->pos / 2048;
if (new_sector != file->current_sector)
{
file->current_sector = new_sector;
file->sector_buffer_valid = false;
}
return 0;
}
static void cdfs_skip_spaces(const char** ptr)
{
while (**ptr && (**ptr == ' ' || **ptr == '\t'))
++(*ptr);
}
static cdfs_track_t* cdfs_wrap_stream(
intfstream_t* stream, unsigned first_sector_offset)
{
cdfs_track_t* track = NULL;
if (!stream)
return NULL;
track = (cdfs_track_t*)
calloc(1, sizeof(*track));
track->stream = stream;
track->first_sector_offset = first_sector_offset;
cdfs_determine_sector_size(track);
return track;
}
static cdfs_track_t* cdfs_open_cue_track(
const char* path, unsigned int track_index)
{
char* cue = NULL;
const char* line = NULL;
int found_track = 0;
char current_track_path[PATH_MAX_LENGTH] = {0};
char track_path[PATH_MAX_LENGTH] = {0};
unsigned int sector_size = 0;
unsigned int previous_sector_size = 0;
unsigned int previous_index_sector_offset= 0;
unsigned int track_offset = 0;
intfstream_t *cue_stream = intfstream_open_file(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
int64_t stream_size = intfstream_get_size(cue_stream);
char *cue_contents = (char*)malloc((size_t)(stream_size + 1));
cdfs_track_t* track = NULL;
if (!cue_contents)
{
intfstream_close(cue_stream);
return NULL;
}
intfstream_read(cue_stream, cue_contents, stream_size);
intfstream_close(cue_stream);
cue_contents[stream_size] = '\0';
cue = cue_contents;
while (*cue)
{
cdfs_skip_spaces((const char**)&cue);
line = cue;
while (*cue && *cue != '\n')
++cue;
if (*cue)
*cue++ = '\0';
if (!strncasecmp(line, "FILE", 4))
{
const char *file = line + 4;
cdfs_skip_spaces(&file);
if (file[0])
{
const char *file_end = cue - 1;
while (file_end > file && *file_end != ' ' && *file_end != '\t')
--file_end;
if (file[0] == '"' && file_end[-1] == '"')
{
++file;
--file_end;
}
memcpy(current_track_path, file, file_end - file);
current_track_path[file_end - file] = '\0';
}
previous_sector_size = 0;
previous_index_sector_offset = 0;
track_offset = 0;
}
else if (!strncasecmp(line, "TRACK", 5))
{
unsigned track_number = 0;
const char *track = line + 5;
cdfs_skip_spaces(&track);
sscanf(track, "%d", (int*)&track_number);
while (*track && *track != ' ' && *track != '\n')
++track;
previous_sector_size = sector_size;
cdfs_skip_spaces(&track);
if (!strncasecmp(track, "MODE", 4))
{
/* track_index = 0 means find the first data track */
if (!track_index || track_index == track_number)
found_track = track_number;
sector_size = atoi(track + 6);
}
else
{
/* assume AUDIO */
sector_size = 2352;
}
}
else if (!strncasecmp(line, "INDEX", 5))
{
unsigned min = 0, sec = 0, frame = 0;
unsigned index_number = 0;
unsigned sector_offset;
const char *index = line + 5;
cdfs_skip_spaces(&index);
sscanf(index, "%u", &index_number);
while (*index && *index != ' ' && *index != '\n')
++index;
cdfs_skip_spaces(&index);
sscanf(index, "%u:%u:%u", &min, &sec, &frame);
sector_offset = ((min * 60) + sec) * 75 + frame;
sector_offset -= previous_index_sector_offset;
track_offset += sector_offset * previous_sector_size;
previous_sector_size = sector_size;
previous_index_sector_offset += sector_offset;
if (found_track && index_number == 1)
{
if ( strstr(current_track_path, "/") ||
strstr(current_track_path, "\\"))
strncpy(track_path, current_track_path, sizeof(track_path));
else
{
fill_pathname_basedir(track_path, path, sizeof(track_path));
strlcat(track_path, current_track_path, sizeof(track_path));
}
break;
}
}
}
free(cue_contents);
if (string_is_empty(track_path))
return NULL;
track = cdfs_wrap_stream(intfstream_open_file(
track_path, RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE), track_offset);
if (track && track->stream_sector_size == 0)
{
track->stream_sector_size = sector_size;
if (sector_size == 2352)
track->stream_sector_header_size = 16;
else if (sector_size == 2336)
track->stream_sector_header_size = 8;
}
return track;
}
#ifdef HAVE_CHD
static cdfs_track_t* cdfs_open_chd_track(const char* path, int32_t track_index)
{
intfstream_t* intf_stream;
cdfs_track_t* track;
intf_stream = intfstream_open_chd_track(path,
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE,
track_index);
if (!intf_stream)
return NULL;
track = cdfs_wrap_stream(intf_stream,
intfstream_get_offset_to_start(intf_stream));
if (track && track->stream_sector_header_size == 0)
{
track->stream_sector_size = intfstream_get_frame_size(intf_stream);
if (track->stream_sector_size == 2352)
track->stream_sector_header_size = 16;
else if (track->stream_sector_size == 2336)
track->stream_sector_header_size = 8;
}
return track;
}
#endif
struct cdfs_track_t* cdfs_open_track(const char* path,
unsigned int track_index)
{
const char* ext = path_get_extension(path);
if (string_is_equal_noncase(ext, "cue"))
return cdfs_open_cue_track(path, track_index);
#ifdef HAVE_CHD
if (string_is_equal_noncase(ext, "chd"))
return cdfs_open_chd_track(path, track_index);
#endif
/* if opening track 1, try opening as a raw track */
if (track_index == 1)
return cdfs_open_raw_track(path);
/* unsupported file type */
return NULL;
}
struct cdfs_track_t* cdfs_open_data_track(const char* path)
{
const char* ext = path_get_extension(path);
if (string_is_equal_noncase(ext, "cue"))
return cdfs_open_cue_track(path, 0);
#ifdef HAVE_CHD
if (string_is_equal_noncase(ext, "chd"))
return cdfs_open_chd_track(path, CHDSTREAM_TRACK_PRIMARY);
#endif
/* unsupported file type - try opening as a raw track */
return cdfs_open_raw_track(path);
}
cdfs_track_t* cdfs_open_raw_track(const char* path)
{
const char* ext = path_get_extension(path);
cdfs_track_t* track = NULL;
if ( string_is_equal_noncase(ext, "bin") ||
string_is_equal_noncase(ext, "iso"))
{
intfstream_t* file = intfstream_open_file(path,
RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
track = cdfs_wrap_stream(file, 0);
if (track != NULL && track->stream_sector_size == 0)
{
cdfs_close_track(track);
track = NULL;
}
}
else
{
/* unsupported file type */
}
return track;
}
void cdfs_close_track(cdfs_track_t* track)
{
if (track)
{
if (track->stream)
{
intfstream_close(track->stream);
free(track->stream);
}
free(track);
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (image_texture.c).
@ -28,26 +28,51 @@
#include <boolean.h>
#include <formats/image.h>
#include <file/nbio.h>
#include <string/stdstring.h>
enum image_type_enum image_texture_get_type(const char *path)
{
#ifdef HAVE_RTGA
if (strstr(path, ".tga"))
return IMAGE_TYPE_TGA;
#endif
/* We are comparing against a fixed list of file
* extensions, the longest (jpeg) being 4 characters
* in length. We therefore only need to extract the first
* 5 characters from the extension of the input path
* to correctly validate a match */
const char *ext = NULL;
char ext_lower[6];
ext_lower[0] = '\0';
if (string_is_empty(path))
return IMAGE_TYPE_NONE;
/* Get file extension */
ext = strrchr(path, '.');
if (!ext || (*(++ext) == '\0'))
return IMAGE_TYPE_NONE;
/* Copy and convert to lower case */
strlcpy(ext_lower, ext, sizeof(ext_lower));
string_to_lower(ext_lower);
#ifdef HAVE_RPNG
if (strstr(path, ".png"))
if (string_is_equal(ext_lower, "png"))
return IMAGE_TYPE_PNG;
#endif
#ifdef HAVE_RJPEG
if (strstr(path, ".jpg") || strstr(path, ".jpeg"))
if (string_is_equal(ext_lower, "jpg") ||
string_is_equal(ext_lower, "jpeg"))
return IMAGE_TYPE_JPEG;
#endif
#ifdef HAVE_RBMP
if (strstr(path, ".bmp"))
if (string_is_equal(ext_lower, "bmp"))
return IMAGE_TYPE_BMP;
#endif
#ifdef HAVE_RTGA
if (string_is_equal(ext_lower, "tga"))
return IMAGE_TYPE_TGA;
#endif
return IMAGE_TYPE_NONE;
}
@ -90,8 +115,13 @@ bool image_texture_color_convert(unsigned r_shift,
uint8_t r = (uint8_t)(col >> 16);
uint8_t g = (uint8_t)(col >> 8);
uint8_t b = (uint8_t)(col >> 0);
pixels[i] = (a << a_shift) |
(r << r_shift) | (g << g_shift) | (b << b_shift);
/* Explicitly cast these to uint32_t to prevent
* ASAN runtime error: left shift of 255 by 24 places
* cannot be represented in type 'int' */
pixels[i] = ((uint32_t)a << a_shift) |
((uint32_t)r << r_shift) |
((uint32_t)g << g_shift) |
((uint32_t)b << b_shift);
}
return true;
@ -190,7 +220,7 @@ static bool image_texture_load_internal(
ret = image_transfer_process(img, type,
(uint32_t**)&out_img->pixels, len, &out_img->width,
&out_img->height);
}while(ret == IMAGE_PROCESS_NEXT);
} while (ret == IMAGE_PROCESS_NEXT);
if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
goto end;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (image_transfer.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rjpeg.c).
@ -141,17 +141,15 @@ struct rjpeg
typedef struct
{
uint32_t img_x;
uint32_t img_y;
int img_n;
int img_out_n;
int buflen;
uint8_t buffer_start[128];
uint8_t *img_buffer;
uint8_t *img_buffer_end;
uint8_t *img_buffer_original;
int img_n;
int img_out_n;
int buflen;
uint32_t img_x;
uint32_t img_y;
uint8_t buffer_start[128];
} rjpeg_context;
static INLINE uint8_t rjpeg_get8(rjpeg_context *s)
@ -171,31 +169,32 @@ static INLINE uint8_t rjpeg_get8(rjpeg_context *s)
typedef struct
{
uint8_t fast[1 << FAST_BITS];
/* weirdly, repacking this into AoS is a 10% speed loss, instead of a win */
uint16_t code[256];
uint8_t values[256];
uint8_t size[257];
unsigned int maxcode[18];
int delta[17]; /* old 'firstsymbol' - old 'firstcode' */
/* weirdly, repacking this into AoS is a 10% speed loss, instead of a win */
uint16_t code[256];
uint8_t fast[1 << FAST_BITS];
uint8_t values[256];
uint8_t size[257];
} rjpeg_huffman;
typedef struct
{
rjpeg_context *s;
rjpeg_huffman huff_dc[4];
rjpeg_huffman huff_ac[4];
uint8_t dequant[4][64];
int16_t fast_ac[4][1 << FAST_BITS];
/* sizes for components, interleaved MCUs */
int img_h_max, img_v_max;
int img_mcu_x, img_mcu_y;
int img_mcu_w, img_mcu_h;
/* kernels */
void (*idct_block_kernel)(uint8_t *out, int out_stride, short data[64]);
void (*YCbCr_to_RGB_kernel)(uint8_t *out, const uint8_t *y, const uint8_t *pcb,
const uint8_t *pcr, int count, int step);
uint8_t *(*resample_row_hv_2_kernel)(uint8_t *out, uint8_t *in_near,
uint8_t *in_far, int w, int hs);
/* definition of jpeg image component */
struct
{
uint8_t *data;
void *raw_data, *raw_coeff;
uint8_t *linebuf;
short *coeff; /* progressive only */
int id;
int h,v;
int tq;
@ -203,35 +202,31 @@ typedef struct
int dc_pred;
int x,y,w2,h2;
uint8_t *data;
void *raw_data, *raw_coeff;
uint8_t *linebuf;
short *coeff; /* progressive only */
int coeff_w; /* number of 8x8 coefficient blocks */
int coeff_h; /* number of 8x8 coefficient blocks */
} img_comp[4];
uint32_t code_buffer; /* jpeg entropy-coded buffer */
int code_bits; /* number of valid bits */
unsigned char marker; /* marker seen while filling entropy buffer */
int nomore; /* flag if we saw a marker so must stop */
/* sizes for components, interleaved MCUs */
int img_h_max, img_v_max;
int img_mcu_x, img_mcu_y;
int img_mcu_w, img_mcu_h;
int code_bits; /* number of valid bits */
int nomore; /* flag if we saw a marker so must stop */
int progressive;
int spec_start;
int spec_end;
int succ_high;
int succ_low;
int eob_run;
int scan_n, order[4];
int restart_interval, todo;
/* kernels */
void (*idct_block_kernel)(uint8_t *out, int out_stride, short data[64]);
void (*YCbCr_to_RGB_kernel)(uint8_t *out, const uint8_t *y, const uint8_t *pcb,
const uint8_t *pcr, int count, int step);
uint8_t *(*resample_row_hv_2_kernel)(uint8_t *out, uint8_t *in_near,
uint8_t *in_far, int w, int hs);
uint32_t code_buffer; /* jpeg entropy-coded buffer */
rjpeg_huffman huff_dc[4]; /* unsigned int alignment */
rjpeg_huffman huff_ac[4]; /* unsigned int alignment */
int16_t fast_ac[4][1 << FAST_BITS];
unsigned char marker; /* marker seen while filling entropy buffer */
uint8_t dequant[4][64];
} rjpeg_jpeg;
#define RJPEG_F2F(x) ((int) (((x) * 4096 + 0.5)))

View File

@ -1,316 +0,0 @@
/* Copyright (C) 2010-2018 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (jsonsax.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <setjmp.h>
#include <string.h>
#include <ctype.h>
#include <retro_inline.h>
#include <formats/jsonsax.h>
#ifdef JSONSAX_ERRORS
const char* jsonsax_errors[] =
{
"Ok",
"Interrupted",
"Missing key",
"Unterminated key",
"Missing value",
"Unterminated object",
"Unterminated array",
"Unterminated string",
"Invalid value"
};
#endif
typedef struct
{
const jsonsax_handlers_t* handlers;
const char* json;
void* ud;
jmp_buf env;
}
state_t;
static INLINE void skip_spaces( state_t* state )
{
while ( isspace( (unsigned char)*state->json ) )
state->json++;
}
static INLINE void skip_digits( state_t* state )
{
while ( isdigit( (unsigned char)*state->json ) )
state->json++;
}
#define HANDLE_0( event ) \
do { \
if ( state->handlers->event && state->handlers->event( state->ud ) ) \
longjmp( state->env, JSONSAX_INTERRUPTED ); \
} while ( 0 )
#define HANDLE_1( event, arg1 ) \
do { \
if ( state->handlers->event && state->handlers->event( state->ud, arg1 ) ) \
longjmp( state->env, JSONSAX_INTERRUPTED ); \
} while ( 0 )
#define HANDLE_2( event, arg1, arg2 ) \
do { \
if ( state->handlers->event && state->handlers->event( state->ud, arg1, arg2 ) ) \
longjmp( state->env, JSONSAX_INTERRUPTED ); \
} while ( 0 )
static void jsonx_parse_value(state_t* state);
static void jsonx_parse_object( state_t* state )
{
state->json++; /* we're sure the current character is a '{' */
skip_spaces( state );
HANDLE_0( start_object );
while ( *state->json != '}' )
{
const char *name = NULL;
if ( *state->json != '"' )
longjmp( state->env, JSONSAX_MISSING_KEY );
name = ++state->json;
for ( ;; )
{
const char* quote = strchr( state->json, '"' );
if ( !quote )
longjmp( state->env, JSONSAX_UNTERMINATED_KEY );
state->json = quote + 1;
if ( quote[ -1 ] != '\\' )
break;
}
HANDLE_2( key, name, state->json - name - 1 );
skip_spaces( state );
if ( *state->json != ':' )
longjmp( state->env, JSONSAX_MISSING_VALUE );
state->json++;
skip_spaces( state );
jsonx_parse_value( state );
skip_spaces( state );
if ( *state->json != ',' )
break;
state->json++;
skip_spaces( state );
}
if ( *state->json != '}' )
longjmp( state->env, JSONSAX_UNTERMINATED_OBJECT );
state->json++;
HANDLE_0( end_object );
}
static void jsonx_parse_array(state_t* state)
{
unsigned int ndx = 0;
state->json++; /* we're sure the current character is a '[' */
skip_spaces( state );
HANDLE_0( start_array );
while ( *state->json != ']' )
{
HANDLE_1( array_index, ndx++ );
jsonx_parse_value( state );
skip_spaces( state );
if ( *state->json != ',' )
break;
state->json++;
skip_spaces( state );
}
if ( *state->json != ']' )
longjmp( state->env, JSONSAX_UNTERMINATED_ARRAY );
state->json++;
HANDLE_0( end_array );
}
static void jsonx_parse_string(state_t* state)
{
const char* string = ++state->json;
for ( ;; )
{
const char* quote = strchr( state->json, '"' );
if ( !quote )
longjmp( state->env, JSONSAX_UNTERMINATED_STRING );
state->json = quote + 1;
if ( quote[ -1 ] != '\\' )
break;
}
HANDLE_2( string, string, state->json - string - 1 );
}
static void jsonx_parse_boolean(state_t* state)
{
if ( !strncmp( state->json, "true", 4 ) )
{
state->json += 4;
HANDLE_1( boolean, 1 );
}
else if ( !strncmp( state->json, "false", 5 ) )
{
state->json += 5;
HANDLE_1( boolean, 0 );
}
else
longjmp( state->env, JSONSAX_INVALID_VALUE );
}
static void jsonx_parse_null(state_t* state)
{
if ( !strncmp( state->json + 1, "ull", 3 ) ) /* we're sure the current character is a 'n' */
{
state->json += 4;
HANDLE_0( null );
}
else
longjmp( state->env, JSONSAX_INVALID_VALUE );
}
static void jsonx_parse_number(state_t* state)
{
const char* number = state->json;
if ( *state->json == '-' )
state->json++;
if ( !isdigit( (unsigned char)*state->json ) )
longjmp( state->env, JSONSAX_INVALID_VALUE );
skip_digits( state );
if ( *state->json == '.' )
{
state->json++;
if ( !isdigit( (unsigned char)*state->json ) )
longjmp( state->env, JSONSAX_INVALID_VALUE );
skip_digits( state );
}
if ( *state->json == 'e' || *state->json == 'E' )
{
state->json++;
if ( *state->json == '-' || *state->json == '+' )
state->json++;
if ( !isdigit( (unsigned char)*state->json ) )
longjmp( state->env, JSONSAX_INVALID_VALUE );
skip_digits( state );
}
HANDLE_2( number, number, state->json - number );
}
static void jsonx_parse_value(state_t* state)
{
skip_spaces( state );
switch ( *state->json )
{
case '{':
jsonx_parse_object(state);
break;
case '[':
jsonx_parse_array( state );
break;
case '"':
jsonx_parse_string( state );
break;
case 't':
case 'f':
jsonx_parse_boolean( state );
break;
case 'n':
jsonx_parse_null( state );
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
jsonx_parse_number( state );
break;
default:
longjmp( state->env, JSONSAX_INVALID_VALUE );
}
}
int jsonsax_parse( const char* json, const jsonsax_handlers_t* handlers, void* userdata )
{
state_t state;
int res;
state.json = json;
state.handlers = handlers;
state.ud = userdata;
if ( ( res = setjmp( state.env ) ) == 0 )
{
if ( handlers->start_document )
handlers->start_document( userdata );
jsonx_parse_value(&state);
if ( handlers->end_document )
handlers->end_document( userdata );
res = JSONSAX_OK;
}
return res;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -65,8 +65,6 @@
#define TRUE 1
#define FALSE 0
#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
/***************************************************************************
DEBUGGING
***************************************************************************/
@ -95,18 +93,22 @@
#define NO_MATCH (~0)
#define MAP_ENTRY_TYPE_INVALID 0x0000 /* invalid type */
#define MAP_ENTRY_TYPE_COMPRESSED 0x0001 /* standard compression */
#define MAP_ENTRY_TYPE_UNCOMPRESSED 0x0002 /* uncompressed data */
#define MAP_ENTRY_TYPE_MINI 0x0003 /* mini: use offset as raw data */
#define MAP_ENTRY_TYPE_SELF_HUNK 0x0004 /* same as another hunk in this file */
#define MAP_ENTRY_TYPE_PARENT_HUNK 0x0005 /* same as a hunk in the parent file */
#define MAP_ENTRY_TYPE_2ND_COMPRESSED 0x0006 /* compressed with secondary algorithm (usually FLAC CDDA) */
#ifdef WANT_RAW_DATA_SECTOR
const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
#endif
/* V3-V4 entry types */
enum
{
V34_MAP_ENTRY_TYPE_INVALID = 0, /* invalid type */
V34_MAP_ENTRY_TYPE_COMPRESSED = 1, /* standard compression */
V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, /* uncompressed data */
V34_MAP_ENTRY_TYPE_MINI = 3, /* mini: use offset as raw data */
V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, /* same as another hunk in this file */
V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, /* same as a hunk in the parent file */
V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 /* compressed with secondary algorithm (usually FLAC CDDA) */
};
/* V5 compression types */
enum
{
@ -147,8 +149,6 @@ enum
MACROS
***************************************************************************/
#define SET_ERROR_AND_CLEANUP(err) do { last_error = (err); goto cleanup; } while (0)
#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0)
/***************************************************************************
@ -262,13 +262,6 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai
CODEC INTERFACES
***************************************************************************/
#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
/* general codecs with CD frontend */
#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l')
#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z')
#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l')
static const codec_interface codec_interfaces[] =
{
/* "none" or no compression */
@ -305,6 +298,17 @@ static const codec_interface codec_interfaces[] =
NULL
},
/* V5 zlib compression */
{
CHD_CODEC_ZLIB,
"zlib (Deflate)",
FALSE,
zlib_codec_init,
zlib_codec_free,
zlib_codec_decompress,
NULL
},
/* V5 CD zlib compression */
{
CHD_CODEC_CD_ZLIB,
@ -417,12 +421,12 @@ static INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
the data stream in bigendian order
-------------------------------------------------*/
static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
{
value &= 0xffffff;
base[0] = value >> 16;
base[1] = value >> 8;
base[2] = value;
base[0] = value >> 24;
base[1] = value >> 16;
base[2] = value >> 8;
base[3] = value;
}
/*-------------------------------------------------
@ -430,7 +434,7 @@ static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
the data stream in bigendian order
-------------------------------------------------*/
static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
{
value &= 0xffffff;
base[0] = value >> 16;
@ -745,7 +749,7 @@ static INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 h
entry->offset = get_bigendian_uint64(&base[0]);
entry->crc = 0;
entry->length = entry->offset >> 44;
entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? MAP_ENTRY_TYPE_UNCOMPRESSED : MAP_ENTRY_TYPE_COMPRESSED);
entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
#ifdef __MWERKS__
entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
#else
@ -826,14 +830,13 @@ chd_error chd_open_file(RFILE *file, int mode, chd_file *parent, chd_file **chd)
if (newchd->header.version < 5)
{
err = map_read(newchd);
if (err != CHDERR_NONE)
EARLY_EXIT(err);
}
else
{
err = decompress_v5_map(newchd, &(newchd->header));
(void)err;
}
if (err != CHDERR_NONE)
EARLY_EXIT(err);
#ifdef NEED_CACHE_HUNK
/* allocate and init the hunk cache */
@ -894,6 +897,12 @@ chd_error chd_open_file(RFILE *file, int mode, chd_file *parent, chd_file **chd)
void* codec = NULL;
switch (newchd->header.compression[decompnum])
{
case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
codec = &newchd->zlib_codec_data;
#endif
break;
case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
codec = &newchd->cdzl_codec_data;
@ -940,6 +949,38 @@ cleanup:
return err;
}
/*-------------------------------------------------
chd_precache - precache underlying file in
memory
-------------------------------------------------*/
chd_error chd_precache(chd_file *chd)
{
int64_t size, count;
if (!chd->file_cache)
{
filestream_seek(chd->file, 0, SEEK_END);
size = filestream_tell(chd->file);
if (size <= 0)
return CHDERR_INVALID_DATA;
chd->file_cache = (UINT8*)malloc(size);
if (chd->file_cache == NULL)
return CHDERR_OUT_OF_MEMORY;
filestream_seek(chd->file, 0, SEEK_SET);
count = filestream_read(chd->file, chd->file_cache, size);
if (count != size)
{
free(chd->file_cache);
chd->file_cache = NULL;
return CHDERR_READ_ERROR;
}
}
return CHDERR_NONE;
}
/*-------------------------------------------------
chd_open - open a CHD file by
filename
@ -986,32 +1027,6 @@ cleanup:
return err;
}
chd_error chd_precache(chd_file *chd)
{
int64_t size, count;
if (!chd->file_cache)
{
filestream_seek(chd->file, 0, SEEK_END);
size = filestream_tell(chd->file);
if (size <= 0)
return CHDERR_INVALID_DATA;
chd->file_cache = (UINT8*)malloc(size);
if (chd->file_cache == NULL)
return CHDERR_OUT_OF_MEMORY;
filestream_seek(chd->file, 0, SEEK_SET);
count = filestream_read(chd->file, chd->file_cache, size);
if (count != size)
{
free(chd->file_cache);
chd->file_cache = NULL;
return CHDERR_READ_ERROR;
}
}
return CHDERR_NONE;
}
/*-------------------------------------------------
chd_close - close a CHD file for access
-------------------------------------------------*/
@ -1048,6 +1063,12 @@ void chd_close(chd_file *chd)
#endif
break;
case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
codec = &chd->zlib_codec_data;
#endif
break;
case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
codec = &chd->cdzl_codec_data;
@ -1357,6 +1378,7 @@ static UINT32 header_guess_unitbytes(chd_file *chd)
if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
return CD_FRAME_SIZE;
@ -1531,7 +1553,12 @@ static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
}
#endif
static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size)
/*-------------------------------------------------
hunk_read_compressed - read a compressed
hunk
-------------------------------------------------*/
static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
{
int64_t bytes;
if (chd->file_cache)
@ -1543,7 +1570,12 @@ static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size)
return chd->compressed;
}
static chd_error read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
/*-------------------------------------------------
hunk_read_uncompressed - read an uncompressed
hunk
-------------------------------------------------*/
static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
{
int64_t bytes;
if (chd->file_cache)
@ -1582,17 +1614,20 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
{
map_entry *entry = &chd->map[hunknum];
UINT32 bytes;
UINT8* compressed_bytes;
/* switch off the entry type */
switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
{
/* compressed data */
case MAP_ENTRY_TYPE_COMPRESSED:
case V34_MAP_ENTRY_TYPE_COMPRESSED:
{
/* read it into the decompression buffer */
void *codec;
UINT8 *bytes = read_compressed(chd, entry->offset,
compressed_bytes = hunk_read_compressed(chd, entry->offset,
entry->length);
if (bytes == NULL)
if (compressed_bytes == NULL)
return CHDERR_READ_ERROR;
#ifdef HAVE_ZLIB
@ -1600,7 +1635,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
err = CHDERR_NONE;
codec = &chd->zlib_codec_data;
if (chd->codecintf[0]->decompress != NULL)
err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes);
err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
if (err != CHDERR_NONE)
return err;
#endif
@ -1608,21 +1643,21 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
break;
/* uncompressed data */
case MAP_ENTRY_TYPE_UNCOMPRESSED:
err = read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
if (err != CHDERR_NONE)
return err;
break;
/* mini-compressed data */
case MAP_ENTRY_TYPE_MINI:
case V34_MAP_ENTRY_TYPE_MINI:
put_bigendian_uint64(&dest[0], entry->offset);
for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
dest[bytes] = dest[bytes - 8];
break;
/* self-referenced data */
case MAP_ENTRY_TYPE_SELF_HUNK:
case V34_MAP_ENTRY_TYPE_SELF_HUNK:
#ifdef NEED_CACHE_HUNK
if (chd->cachehunk == entry->offset && dest == chd->cache)
break;
@ -1630,7 +1665,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
return hunk_read_into_memory(chd, (UINT32)entry->offset, dest);
/* parent-referenced data */
case MAP_ENTRY_TYPE_PARENT_HUNK:
case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
err = hunk_read_into_memory(chd->parent, (UINT32)entry->offset, dest);
if (err != CHDERR_NONE)
return err;
@ -1648,7 +1683,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
uint16_t blockcrc;
#endif
uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
UINT8 *bytes;
UINT8 *compressed_bytes;
#if 0
/* uncompressed case - TODO */
@ -1679,9 +1714,11 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
case COMPRESSION_TYPE_1:
case COMPRESSION_TYPE_2:
case COMPRESSION_TYPE_3:
bytes = read_compressed(chd, blockoffs, blocklen);
if (bytes == NULL)
compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
if (compressed_bytes == NULL)
return CHDERR_READ_ERROR;
if (!chd->codecintf[rawmap[0]])
return CHDERR_UNSUPPORTED_FORMAT;
switch (chd->codecintf[rawmap[0]]->compression)
{
case CHD_CODEC_CD_LZMA:
@ -1690,6 +1727,12 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
#endif
break;
case CHD_CODEC_ZLIB:
#ifdef HAVE_ZLIB
codec = &chd->zlib_codec_data;
#endif
break;
case CHD_CODEC_CD_ZLIB:
#ifdef HAVE_ZLIB
codec = &chd->cdzl_codec_data;
@ -1704,7 +1747,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
}
if (codec==NULL)
return CHDERR_CODEC_ERROR;
err = (*chd->codecintf[rawmap[0]]->decompress)(codec, chd->compressed, blocklen, dest, chd->header.hunkbytes);
err = (*chd->codecintf[rawmap[0]]->decompress)(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
if (err != CHDERR_NONE)
return err;
#ifdef VERIFY_BLOCK_CRC
@ -1714,7 +1757,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
return CHDERR_NONE;
case COMPRESSION_NONE:
err = read_uncompressed(chd, blockoffs, blocklen, dest);
err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
if (err != CHDERR_NONE)
return err;
#ifdef VERIFY_BLOCK_CRC
@ -1807,8 +1850,8 @@ static chd_error map_read(chd_file *chd)
/* track the maximum offset */
for (j = 0; j < entries; j++)
if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_COMPRESSED ||
(chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_UNCOMPRESSED)
if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
(chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
}

View File

@ -335,7 +335,8 @@ enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decod
/* binary search to achieve the optimum encoding */
upperweight = sdatacount * 2;
while (1)
for (;;)
{
/* build a tree using the current weight */
uint32_t curweight = (upperweight + lowerweight) / 2;
@ -548,16 +549,13 @@ void huffman_build_lookup_table(struct huffman_decoder* decoder)
struct node_t* node = &decoder->huffnode[curcode];
if (node->numbits > 0)
{
int shift;
lookup_value *dest;
lookup_value *destend;
/* set up the entry */
lookup_value value = MAKE_LOOKUP(curcode, node->numbits);
/* fill all matching entries */
shift = decoder->maxbits - node->numbits;
dest = &decoder->lookup[node->bits << shift];
destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
int shift = decoder->maxbits - node->numbits;
lookup_value *dest = &decoder->lookup[node->bits << shift];
lookup_value *destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
while (dest <= destend)
*dest++ = value;
}

View File

@ -66,11 +66,16 @@
*-------------------------------------------------
*/
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define LZMA_MIN_ALIGNMENT_BITS 512
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
static void *lzma_fast_alloc(void *p, size_t size)
{
int scan;
uint32_t *addr = NULL;
uint32_t *addr = NULL;
lzma_allocator *codec = (lzma_allocator *)(p);
uintptr_t vaddr = 0;
/* compute the size, rounding to the nearest 1k */
size = (size + 0x3ff) & ~0x3ff;
@ -83,27 +88,36 @@ static void *lzma_fast_alloc(void *p, size_t size)
{
/* set the low bit of the size so we don't match next time */
*ptr |= 1;
return ptr + 1;
/* return aligned address of the block */
return codec->allocptr2[scan];
}
}
/* alloc a new one and put it into the list */
addr = (uint32_t *)malloc(sizeof(uint32_t) * (size + sizeof(uint32_t)));
if (!addr)
addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
if (addr==NULL)
return NULL;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
if (codec->allocptr[scan] == NULL)
{
/* store block address */
codec->allocptr[scan] = addr;
/* compute aligned address, store it */
vaddr = (uintptr_t)addr;
vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
codec->allocptr2[scan] = (uint32_t*)vaddr;
break;
}
}
/* set the low bit of the size so we don't match next time */
*addr = (uint32_t)(size | 1);
return addr + 1;
*addr = size | 1;
/* return aligned address */
return (void*)vaddr;
}
/*-------------------------------------------------
@ -114,21 +128,22 @@ static void *lzma_fast_alloc(void *p, size_t size)
static void lzma_fast_free(void *p, void *address)
{
int scan;
uint32_t *ptr;
lzma_allocator *codec;
uint32_t *ptr = NULL;
lzma_allocator *codec = NULL;
if (address == NULL)
return;
codec = (lzma_allocator *)(p);
/* find the hunk */
ptr = (uint32_t *)(address) - 1;
ptr = (uint32_t *)address;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
if (ptr == codec->allocptr[scan])
if (ptr == codec->allocptr2[scan])
{
/* clear the low bit of the size to allow matches */
*ptr &= ~1;
*codec->allocptr[scan] &= ~1;
return;
}
}
@ -238,8 +253,8 @@ void lzma_codec_free(void* codec)
lzma_allocator* alloc = &lzma_codec->allocator;
/* free memory */
lzma_allocator_free(alloc);
LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
lzma_allocator_free(alloc);
}
/*-------------------------------------------------

View File

@ -174,6 +174,10 @@ chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
else
err = CHDERR_NONE;
/* handle an error */
if (err != CHDERR_NONE)
free(data);
return err;
}
@ -225,7 +229,7 @@ chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
/* do it */
zerr = inflate(&data->inflater, Z_FINISH);
(void)zerr;
(void)zerr;
if (data->inflater.total_out != destlen)
return CHDERR_DECOMPRESSION_ERROR;
@ -237,9 +241,14 @@ chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t comple
allocates and frees memory frequently
-------------------------------------------------*/
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define ZLIB_MIN_ALIGNMENT_BITS 512
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
zlib_allocator *alloc = (zlib_allocator *)opaque;
uintptr_t paddr = 0;
UINT32 *ptr;
int i;
@ -254,12 +263,14 @@ voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
/* set the low bit of the size so we don't match next time */
*ptr |= 1;
return ptr + 1;
/* return aligned block address */
return (voidpf)(alloc->allocptr2[i]);
}
}
/* alloc a new one */
ptr = (UINT32 *)malloc(size + sizeof(UINT32));
ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
if (!ptr)
return NULL;
@ -268,12 +279,16 @@ voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
if (!alloc->allocptr[i])
{
alloc->allocptr[i] = ptr;
paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
alloc->allocptr2[i] = (uint32_t*)paddr;
break;
}
/* set the low bit of the size so we don't match next time */
*ptr = size | 1;
return ptr + 1;
/* return aligned block address */
return (voidpf)paddr;
}
/*-------------------------------------------------
@ -284,15 +299,15 @@ voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
void zlib_fast_free(voidpf opaque, voidpf address)
{
zlib_allocator *alloc = (zlib_allocator *)opaque;
UINT32 *ptr = (UINT32 *)address - 1;
UINT32 *ptr = (UINT32 *)address;
int i;
/* find the hunk */
for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
if (ptr == alloc->allocptr[i])
if (ptr == alloc->allocptr2[i])
{
/* clear the low bit of the size to allow matches */
*ptr &= ~1;
*(alloc->allocptr[i]) &= ~1;
return;
}
}

View File

@ -0,0 +1,455 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (logiqx_dat.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <file/file_path.h>
#include <string/stdstring.h>
#include <formats/rxml.h>
#include <formats/logiqx_dat.h>
/* Holds all internal DAT file data */
struct logiqx_dat
{
rxml_document_t *data;
rxml_node_t *current_node;
};
/* List of HTML formatting codes that must
* be replaced when parsing XML data */
const char *logiqx_dat_html_code_list[][2] = {
{"&amp;", "&"},
{"&apos;", "'"},
{"&gt;", ">"},
{"&lt;", "<"},
{"&quot;", "\""}
};
#define LOGIQX_DAT_HTML_CODE_LIST_SIZE 5
/* Validation */
/* Performs rudimentary validation of the specified
* Logiqx XML DAT file path (not rigorous - just
* enough to prevent obvious errors).
* Also provides access to file size (DAT files can
* be very large, so it is useful to have this information
* on hand - i.e. so we can check that the system has
* enough free memory to load the file). */
bool logiqx_dat_path_is_valid(const char *path, uint64_t *file_size)
{
const char *file_ext = NULL;
int32_t file_size_int;
if (string_is_empty(path))
return false;
/* Check file extension */
file_ext = path_get_extension(path);
if (string_is_empty(file_ext))
return false;
if (!string_is_equal_noncase(file_ext, "dat") &&
!string_is_equal_noncase(file_ext, "xml"))
return false;
/* Ensure file exists */
if (!path_is_valid(path))
return false;
/* Get file size */
file_size_int = path_get_size(path);
if (file_size_int <= 0)
return false;
if (file_size)
*file_size = (uint64_t)file_size_int;
return true;
}
/* File initialisation/de-initialisation */
/* Loads specified Logiqx XML DAT file from disk.
* Returned logiqx_dat_t object must be free'd using
* logiqx_dat_free().
* Returns NULL if file is invalid or a read error
* occurs. */
logiqx_dat_t *logiqx_dat_init(const char *path)
{
logiqx_dat_t *dat_file = NULL;
rxml_node_t *root_node = NULL;
/* Check file path */
if (!logiqx_dat_path_is_valid(path, NULL))
goto error;
/* Create logiqx_dat_t object */
dat_file = (logiqx_dat_t*)calloc(1, sizeof(*dat_file));
if (!dat_file)
goto error;
/* Read file from disk */
dat_file->data = rxml_load_document(path);
if (!dat_file->data)
goto error;
/* Ensure root node has the correct name */
root_node = rxml_root_node(dat_file->data);
if (!root_node)
goto error;
if (string_is_empty(root_node->name))
goto error;
/* > Logiqx XML uses: 'datafile'
* > MAME List XML uses: 'mame'
* > MAME 'Software List' uses: 'softwarelist' */
if (!string_is_equal(root_node->name, "datafile") &&
!string_is_equal(root_node->name, "mame") &&
!string_is_equal(root_node->name, "softwarelist"))
goto error;
/* Get pointer to initial child node */
dat_file->current_node = root_node->children;
if (!dat_file->current_node)
goto error;
/* All is well - return logiqx_dat_t object */
return dat_file;
error:
logiqx_dat_free(dat_file);
return NULL;
}
/* Frees specified DAT file */
void logiqx_dat_free(logiqx_dat_t *dat_file)
{
if (!dat_file)
return;
dat_file->current_node = NULL;
if (dat_file->data)
{
rxml_free_document(dat_file->data);
dat_file->data = NULL;
}
free(dat_file);
dat_file = NULL;
}
/* Game information access */
/* Returns true if specified node is a 'game' entry */
static bool logiqx_dat_is_game_node(rxml_node_t *node)
{
const char *node_name = NULL;
if (!node)
return false;
/* Check node name */
node_name = node->name;
if (string_is_empty(node_name))
return false;
/* > Logiqx XML uses: 'game'
* > MAME List XML uses: 'machine'
* > MAME 'Software List' uses: 'software' */
return string_is_equal(node_name, "game") ||
string_is_equal(node_name, "machine") ||
string_is_equal(node_name, "software");
}
/* Returns true if specified node is a game
* node containing information for a game with
* the specified name */
static bool logiqx_dat_game_node_matches_name(
rxml_node_t *node, const char *game_name)
{
const char *node_game_name = NULL;
if (!logiqx_dat_is_game_node(node) ||
string_is_empty(game_name))
return false;
/* Get 'name' attribute of XML node */
node_game_name = rxml_node_attrib(node, "name");
if (string_is_empty(node_game_name))
return false;
return string_is_equal(node_game_name, game_name);
}
/* The XML element data strings returned from
* DAT files are very 'messy'. This function
* removes all cruft, replaces formatting strings
* and copies the result (if valid) to 'str' */
static void logiqx_dat_sanitise_element_data(
const char *data, char *str, size_t len)
{
char sanitised_data[PATH_MAX_LENGTH];
size_t i;
sanitised_data[0] = '\0';
if (string_is_empty(data))
return;
strlcpy(sanitised_data, data, sizeof(sanitised_data));
/* Element data includes leading/trailing
* newline characters - trim them away */
string_trim_whitespace(sanitised_data);
if (string_is_empty(sanitised_data))
return;
/* XML has a number of special characters that
* are handled using a HTML formatting codes.
* All of these have to be replaced...
* &amp; -> &
* &apos; -> '
* &gt; -> >
* &lt; -> <
* &quot; -> "
*/
for (i = 0; i < LOGIQX_DAT_HTML_CODE_LIST_SIZE; i++)
{
const char *find_string = logiqx_dat_html_code_list[i][0];
const char *replace_string = logiqx_dat_html_code_list[i][1];
/* string_replace_substring() is expensive
* > only invoke if element string contains
* HTML code */
if (strstr(sanitised_data, find_string))
{
char *tmp = string_replace_substring(
sanitised_data, find_string, replace_string);
if (!string_is_empty(tmp))
strlcpy(sanitised_data, tmp, sizeof(sanitised_data));
if (tmp)
free(tmp);
}
}
if (string_is_empty(sanitised_data))
return;
/* All is well - can copy result */
strlcpy(str, sanitised_data, len);
}
/* Extracts game information from specified node.
* Returns false if node is invalid */
static bool logiqx_dat_parse_game_node(
rxml_node_t *node, logiqx_dat_game_info_t *game_info)
{
const char *game_name = NULL;
const char *is_bios = NULL;
const char *is_runnable = NULL;
rxml_node_t *info_node = NULL;
bool description_found = false;
bool year_found = false;
bool manufacturer_found = false;
if (!logiqx_dat_is_game_node(node))
return false;
if (!game_info)
return false;
/* Initialise logiqx_dat_game_info_t object */
game_info->name[0] = '\0';
game_info->description[0] = '\0';
game_info->year[0] = '\0';
game_info->manufacturer[0] = '\0';
game_info->is_bios = false;
game_info->is_runnable = true;
/* Get game name */
game_name = rxml_node_attrib(node, "name");
if (!string_is_empty(game_name))
strlcpy(game_info->name, game_name, sizeof(game_info->name));
/* Get 'is bios' status */
is_bios = rxml_node_attrib(node, "isbios");
if (!string_is_empty(is_bios))
game_info->is_bios = string_is_equal(is_bios, "yes");
/* Get 'is runnable' status
* > Note: This attribute only exists in MAME List
* XML files, but there is no harm in checking for
* it generally. For normal Logiqx XML files,
* 'is runnable' is just the inverse of 'is bios' */
is_runnable = rxml_node_attrib(node, "runnable");
if (!string_is_empty(is_runnable))
game_info->is_runnable = string_is_equal(is_runnable, "yes");
else
game_info->is_runnable = !game_info->is_bios;
/* Loop over all game info nodes */
for (info_node = node->children; info_node; info_node = info_node->next)
{
const char *info_node_name = info_node->name;
const char *info_node_data = info_node->data;
if (string_is_empty(info_node_name))
continue;
/* Check description */
if (string_is_equal(info_node_name, "description"))
{
logiqx_dat_sanitise_element_data(
info_node_data, game_info->description,
sizeof(game_info->description));
description_found = true;
}
/* Check year */
else if (string_is_equal(info_node_name, "year"))
{
logiqx_dat_sanitise_element_data(
info_node_data, game_info->year,
sizeof(game_info->year));
year_found = true;
}
/* Check manufacturer */
else if (string_is_equal(info_node_name, "manufacturer"))
{
logiqx_dat_sanitise_element_data(
info_node_data, game_info->manufacturer,
sizeof(game_info->manufacturer));
manufacturer_found = true;
}
/* If all required entries have been found,
* can end loop */
if (description_found && year_found && manufacturer_found)
break;
}
return true;
}
/* Sets/resets internal node pointer to the first
* entry in the DAT file */
void logiqx_dat_set_first(logiqx_dat_t *dat_file)
{
rxml_node_t *root_node = NULL;
if (!dat_file)
return;
if (!dat_file->data)
return;
/* Get root node */
root_node = rxml_root_node(dat_file->data);
if (!root_node)
{
dat_file->current_node = NULL;
return;
}
/* Get pointer to initial child node */
dat_file->current_node = root_node->children;
}
/* Fetches game information for the current entry
* in the DAT file and increments the internal node
* pointer.
* Returns false if the end of the DAT file has been
* reached (in which case 'game_info' will be invalid) */
bool logiqx_dat_get_next(
logiqx_dat_t *dat_file, logiqx_dat_game_info_t *game_info)
{
if (!dat_file || !game_info)
return false;
if (!dat_file->data)
return false;
while (dat_file->current_node)
{
rxml_node_t *current_node = dat_file->current_node;
/* Whatever happens, internal node pointer must
* be 'incremented' */
dat_file->current_node = dat_file->current_node->next;
/* If this is a game node, extract info
* and return */
if (logiqx_dat_is_game_node(current_node))
return logiqx_dat_parse_game_node(current_node, game_info);
}
return false;
}
/* Fetches information for the specified game.
* Returns false if game does not exist, or arguments
* are invalid. */
bool logiqx_dat_search(
logiqx_dat_t *dat_file, const char *game_name,
logiqx_dat_game_info_t *game_info)
{
rxml_node_t *root_node = NULL;
rxml_node_t *game_node = NULL;
if (!dat_file || !game_info || string_is_empty(game_name))
return false;
if (!dat_file->data)
return false;
/* Get root node */
root_node = rxml_root_node(dat_file->data);
if (!root_node)
return false;
/* Loop over all child nodes of the DAT file */
for (game_node = root_node->children; game_node; game_node = game_node->next)
{
/* If this is the requested game, fetch info and return */
if (logiqx_dat_game_node_matches_name(game_node, game_name))
return logiqx_dat_parse_game_node(game_node, game_info);
}
return false;
}

View File

@ -0,0 +1,633 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (m3u_file.c).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <retro_miscellaneous.h>
#include <string/stdstring.h>
#include <lists/string_list.h>
#include <file/file_path.h>
#include <streams/file_stream.h>
#include <array/rbuf.h>
#include <formats/m3u_file.h>
/* We parse the following types of entry label:
* - '#LABEL:<label>' non-standard, but used by
* some cores
* - '#EXTINF:<runtime>,<label>' standard extended
* M3U directive
* - '<content path>|<label>' non-standard, but
* used by some cores
* All other comments/directives are ignored */
#define M3U_FILE_COMMENT '#'
#define M3U_FILE_NONSTD_LABEL "#LABEL:"
#define M3U_FILE_EXTSTD_LABEL "#EXTINF:"
#define M3U_FILE_EXTSTD_LABEL_TOKEN ','
#define M3U_FILE_RETRO_LABEL_TOKEN '|'
/* Holds all internal M3U file data
* > Note the awkward name: 'content_m3u_file'
* If we used just 'm3u_file' here, it would
* lead to conflicts elsewhere... */
struct content_m3u_file
{
char *path;
m3u_file_entry_t *entries;
};
/* File Initialisation / De-Initialisation */
/* Reads M3U file contents from disk
* - Does nothing if file does not exist
* - Returns false in the event of an error */
static bool m3u_file_load(m3u_file_t *m3u_file)
{
const char *file_ext = NULL;
int64_t file_len = 0;
uint8_t *file_buf = NULL;
struct string_list *lines = NULL;
bool success = false;
size_t i;
char entry_path[PATH_MAX_LENGTH];
char entry_label[PATH_MAX_LENGTH];
entry_path[0] = '\0';
entry_label[0] = '\0';
if (!m3u_file)
goto end;
/* Check whether file exists
* > If path is empty, then an error
* has occurred... */
if (string_is_empty(m3u_file->path))
goto end;
/* > File must have the correct extension */
file_ext = path_get_extension(m3u_file->path);
if (string_is_empty(file_ext) ||
!string_is_equal_noncase(file_ext, M3U_FILE_EXT))
goto end;
/* > If file does not exist, no action
* is required */
if (!path_is_valid(m3u_file->path))
{
success = true;
goto end;
}
/* Read file from disk */
if (filestream_read_file(m3u_file->path, (void**)&file_buf, &file_len) >= 0)
{
/* Split file into lines */
if (file_len > 0)
lines = string_split((const char*)file_buf, "\n");
/* File buffer no longer required */
if (file_buf)
{
free(file_buf);
file_buf = NULL;
}
}
/* File IO error... */
else
goto end;
/* If file was empty, no action is required */
if (!lines)
{
success = true;
goto end;
}
/* Parse lines of file */
for (i = 0; i < lines->size; i++)
{
const char *line = lines->elems[i].data;
if (string_is_empty(line))
continue;
/* Determine line 'type' */
/* > '#LABEL:' */
if (string_starts_with_size(line, M3U_FILE_NONSTD_LABEL,
STRLEN_CONST(M3U_FILE_NONSTD_LABEL)))
{
/* Label is the string to the right
* of '#LABEL:' */
const char *label = line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL);
if (!string_is_empty(label))
{
strlcpy(
entry_label, line + STRLEN_CONST(M3U_FILE_NONSTD_LABEL),
sizeof(entry_label));
string_trim_whitespace(entry_label);
}
}
/* > '#EXTINF:' */
else if (string_starts_with_size(line, M3U_FILE_EXTSTD_LABEL,
STRLEN_CONST(M3U_FILE_EXTSTD_LABEL)))
{
/* Label is the string to the right
* of the first comma */
const char* label_ptr = strchr(
line + STRLEN_CONST(M3U_FILE_EXTSTD_LABEL),
M3U_FILE_EXTSTD_LABEL_TOKEN);
if (!string_is_empty(label_ptr))
{
label_ptr++;
if (!string_is_empty(label_ptr))
{
strlcpy(entry_label, label_ptr, sizeof(entry_label));
string_trim_whitespace(entry_label);
}
}
}
/* > Ignore other comments/directives */
else if (line[0] == M3U_FILE_COMMENT)
continue;
/* > An actual 'content' line */
else
{
/* This is normally a file name/path, but may
* have the format <content path>|<label> */
const char *token_ptr = strchr(line, M3U_FILE_RETRO_LABEL_TOKEN);
if (token_ptr)
{
size_t len = (size_t)(1 + token_ptr - line);
/* Get entry_path segment */
if (len > 0)
{
memset(entry_path, 0, sizeof(entry_path));
strlcpy(
entry_path, line,
((len < PATH_MAX_LENGTH ?
len : PATH_MAX_LENGTH) * sizeof(char)));
string_trim_whitespace(entry_path);
}
/* Get entry_label segment */
token_ptr++;
if (*token_ptr != '\0')
{
strlcpy(entry_label, token_ptr, sizeof(entry_label));
string_trim_whitespace(entry_label);
}
}
else
{
/* Just a normal file name/path */
strlcpy(entry_path, line, sizeof(entry_path));
string_trim_whitespace(entry_path);
}
/* Add entry to file
* > Note: The only way that m3u_file_add_entry()
* can fail here is if we run out of memory.
* This is a critical error, and m3u_file must
* be considered invalid in this case */
if (!string_is_empty(entry_path) &&
!m3u_file_add_entry(m3u_file, entry_path, entry_label))
goto end;
/* Reset entry_path/entry_label */
entry_path[0] = '\0';
entry_label[0] = '\0';
}
}
success = true;
end:
/* Clean up */
if (lines)
{
string_list_free(lines);
lines = NULL;
}
if (file_buf)
{
free(file_buf);
file_buf = NULL;
}
return success;
}
/* Creates and initialises an M3U file
* - If 'path' refers to an existing file,
* contents is parsed
* - If path does not exist, an empty M3U file
* is created
* - Returned m3u_file_t object must be free'd using
* m3u_file_free()
* - Returns NULL in the event of an error */
m3u_file_t *m3u_file_init(const char *path)
{
m3u_file_t *m3u_file = NULL;
char m3u_path[PATH_MAX_LENGTH];
m3u_path[0] = '\0';
/* Sanity check */
if (string_is_empty(path))
return NULL;
/* Get 'real' file path */
strlcpy(m3u_path, path, sizeof(m3u_path));
path_resolve_realpath(m3u_path, sizeof(m3u_path), false);
if (string_is_empty(m3u_path))
return NULL;
/* Create m3u_file_t object */
m3u_file = (m3u_file_t*)malloc(sizeof(*m3u_file));
if (!m3u_file)
return NULL;
/* Initialise members */
m3u_file->path = NULL;
m3u_file->entries = NULL;
/* Copy file path */
m3u_file->path = strdup(m3u_path);
/* Read existing file contents from
* disk, if required */
if (!m3u_file_load(m3u_file))
{
m3u_file_free(m3u_file);
return NULL;
}
return m3u_file;
}
/* Frees specified M3U file entry */
static void m3u_file_free_entry(m3u_file_entry_t *entry)
{
if (!entry)
return;
if (entry->path)
free(entry->path);
if (entry->full_path)
free(entry->full_path);
if (entry->label)
free(entry->label);
entry->path = NULL;
entry->full_path = NULL;
entry->label = NULL;
}
/* Frees specified M3U file */
void m3u_file_free(m3u_file_t *m3u_file)
{
size_t i;
if (!m3u_file)
return;
if (m3u_file->path)
free(m3u_file->path);
m3u_file->path = NULL;
/* Free entries */
if (m3u_file->entries)
{
for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
{
m3u_file_entry_t *entry = &m3u_file->entries[i];
m3u_file_free_entry(entry);
}
RBUF_FREE(m3u_file->entries);
}
free(m3u_file);
}
/* Getters */
/* Returns M3U file path */
char *m3u_file_get_path(m3u_file_t *m3u_file)
{
if (!m3u_file)
return NULL;
return m3u_file->path;
}
/* Returns number of entries in M3U file */
size_t m3u_file_get_size(m3u_file_t *m3u_file)
{
if (!m3u_file)
return 0;
return RBUF_LEN(m3u_file->entries);
}
/* Fetches specified M3U file entry
* - Returns false if 'idx' is invalid, or internal
* entry is NULL */
bool m3u_file_get_entry(
m3u_file_t *m3u_file, size_t idx, m3u_file_entry_t **entry)
{
if (!m3u_file ||
!entry ||
(idx >= RBUF_LEN(m3u_file->entries)))
return false;
*entry = &m3u_file->entries[idx];
if (!*entry)
return false;
return true;
}
/* Setters */
/* Adds specified entry to the M3U file
* - Returns false if path is invalid, or
* memory could not be allocated for the
* entry */
bool m3u_file_add_entry(
m3u_file_t *m3u_file, const char *path, const char *label)
{
m3u_file_entry_t *entry = NULL;
size_t num_entries;
char full_path[PATH_MAX_LENGTH];
full_path[0] = '\0';
if (!m3u_file || string_is_empty(path))
return false;
/* Get current number of file entries */
num_entries = RBUF_LEN(m3u_file->entries);
/* Attempt to allocate memory for new entry */
if (!RBUF_TRYFIT(m3u_file->entries, num_entries + 1))
return false;
/* Allocation successful - increment array size */
RBUF_RESIZE(m3u_file->entries, num_entries + 1);
/* Fetch entry at end of list, and zero-initialise
* members */
entry = &m3u_file->entries[num_entries];
memset(entry, 0, sizeof(*entry));
/* Copy path and label */
entry->path = strdup(path);
if (!string_is_empty(label))
entry->label = strdup(label);
/* Populate 'full_path' field */
if (path_is_absolute(path))
{
strlcpy(full_path, path, sizeof(full_path));
path_resolve_realpath(full_path, sizeof(full_path), false);
}
else
fill_pathname_resolve_relative(
full_path, m3u_file->path, path,
sizeof(full_path));
/* Handle unforeseen errors... */
if (string_is_empty(full_path))
{
m3u_file_free_entry(entry);
return false;
}
entry->full_path = strdup(full_path);
return true;
}
/* Removes all entries in M3U file */
void m3u_file_clear(m3u_file_t *m3u_file)
{
size_t i;
if (!m3u_file)
return;
if (m3u_file->entries)
{
for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
{
m3u_file_entry_t *entry = &m3u_file->entries[i];
m3u_file_free_entry(entry);
}
RBUF_FREE(m3u_file->entries);
}
}
/* Saving */
/* Saves M3U file to disk
* - Setting 'label_type' to M3U_FILE_LABEL_NONE
* just outputs entry paths - this the most
* common format supported by most cores
* - Returns false in the event of an error */
bool m3u_file_save(
m3u_file_t *m3u_file, enum m3u_file_label_type label_type)
{
RFILE *file = NULL;
size_t i;
char base_dir[PATH_MAX_LENGTH];
base_dir[0] = '\0';
if (!m3u_file || !m3u_file->entries)
return false;
/* This should never happen */
if (string_is_empty(m3u_file->path))
return false;
/* Get M3U file base directory */
if (find_last_slash(m3u_file->path))
{
strlcpy(base_dir, m3u_file->path, sizeof(base_dir));
path_basedir(base_dir);
}
/* Open file for writing */
file = filestream_open(
m3u_file->path,
RETRO_VFS_FILE_ACCESS_WRITE,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!file)
return false;
/* Loop over entries */
for (i = 0; i < RBUF_LEN(m3u_file->entries); i++)
{
m3u_file_entry_t *entry = &m3u_file->entries[i];
char entry_path[PATH_MAX_LENGTH];
entry_path[0] = '\0';
if (!entry || string_is_empty(entry->full_path))
continue;
/* When writing M3U files, entry paths are
* always relative */
if (string_is_empty(base_dir))
strlcpy(
entry_path, entry->full_path,
sizeof(entry_path));
else
path_relative_to(
entry_path, entry->full_path, base_dir,
sizeof(entry_path));
if (string_is_empty(entry_path))
continue;
/* Check if we need to write a label */
if (!string_is_empty(entry->label))
{
switch (label_type)
{
case M3U_FILE_LABEL_NONSTD:
filestream_printf(
file, "%s%s\n%s\n",
M3U_FILE_NONSTD_LABEL, entry->label,
entry_path);
break;
case M3U_FILE_LABEL_EXTSTD:
filestream_printf(
file, "%s%c%s\n%s\n",
M3U_FILE_EXTSTD_LABEL, M3U_FILE_EXTSTD_LABEL_TOKEN, entry->label,
entry_path);
break;
case M3U_FILE_LABEL_RETRO:
filestream_printf(
file, "%s%c%s\n",
entry_path, M3U_FILE_RETRO_LABEL_TOKEN, entry->label);
break;
case M3U_FILE_LABEL_NONE:
default:
filestream_printf(
file, "%s\n", entry_path);
break;
}
}
/* No label - just write entry path */
else
filestream_printf(
file, "%s\n", entry_path);
}
/* Close file */
filestream_close(file);
return true;
}
/* Utilities */
/* Internal qsort function */
static int m3u_file_qsort_func(
const m3u_file_entry_t *a, const m3u_file_entry_t *b)
{
if (!a || !b)
return 0;
if (string_is_empty(a->full_path) || string_is_empty(b->full_path))
return 0;
return strcasecmp(a->full_path, b->full_path);
}
/* Sorts M3U file entries in alphabetical order */
void m3u_file_qsort(m3u_file_t *m3u_file)
{
size_t num_entries;
if (!m3u_file)
return;
num_entries = RBUF_LEN(m3u_file->entries);
if (num_entries < 2)
return;
qsort(
m3u_file->entries, num_entries,
sizeof(m3u_file_entry_t),
(int (*)(const void *, const void *))m3u_file_qsort_func);
}
/* Returns true if specified path corresponds
* to an M3U file (simple convenience function) */
bool m3u_file_is_m3u(const char *path)
{
const char *file_ext = NULL;
int32_t file_size;
if (string_is_empty(path))
return false;
/* Check file extension */
file_ext = path_get_extension(path);
if (string_is_empty(file_ext))
return false;
if (!string_is_equal_noncase(file_ext, M3U_FILE_EXT))
return false;
/* Ensure file exists */
if (!path_is_valid(path))
return false;
/* Ensure we have non-zero file size */
file_size = path_get_size(path);
if (file_size <= 0)
return false;
return true;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rpng.c).
@ -20,7 +20,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef DEBUG
#include <stdio.h>
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -80,22 +82,15 @@ struct idat_buffer
size_t size;
};
struct png_chunk
{
uint32_t size;
char type[4];
uint8_t *data;
};
struct rpng_process
{
bool inflate_initialized;
bool adam7_pass_initialized;
bool pass_initialized;
uint32_t *data;
uint32_t *palette;
void *stream;
const struct trans_stream_backend *stream_backend;
uint8_t *prev_scanline;
uint8_t *decoded_scanline;
uint8_t *inflate_buf;
struct png_ihdr ihdr;
size_t restore_buf_size;
size_t adam7_restore_buf_size;
size_t data_restore_buf_size;
@ -104,31 +99,41 @@ struct rpng_process
size_t avail_out;
size_t total_out;
size_t pass_size;
struct png_ihdr ihdr; /* uint32_t alignment */
unsigned bpp;
unsigned pitch;
unsigned h;
unsigned pass_width;
unsigned pass_height;
unsigned pass_pos;
uint32_t *data;
uint32_t *palette;
void *stream;
const struct trans_stream_backend *stream_backend;
bool inflate_initialized;
bool adam7_pass_initialized;
bool pass_initialized;
};
struct rpng
{
struct rpng_process *process;
uint8_t *buff_data;
uint8_t *buff_end;
struct idat_buffer idat_buf; /* ptr alignment */
struct png_ihdr ihdr; /* uint32 alignment */
uint32_t palette[256];
bool has_ihdr;
bool has_idat;
bool has_iend;
bool has_plte;
bool has_trns;
struct idat_buffer idat_buf;
struct png_ihdr ihdr;
uint8_t *buff_data;
uint8_t *buff_end;
uint32_t palette[256];
};
static const struct adam7_pass passes[] = {
{ 0, 0, 8, 8 },
{ 4, 0, 8, 8 },
{ 0, 4, 4, 8 },
{ 2, 0, 4, 4 },
{ 0, 2, 2, 4 },
{ 1, 0, 2, 2 },
{ 0, 1, 1, 2 },
};
static INLINE uint32_t dword_be(const uint8_t *buf)
@ -136,98 +141,85 @@ static INLINE uint32_t dword_be(const uint8_t *buf)
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
}
static enum png_chunk_type png_chunk_type(const struct png_chunk *chunk)
{
unsigned i;
struct
{
const char *id;
enum png_chunk_type type;
} static const chunk_map[] = {
{ "IHDR", PNG_CHUNK_IHDR },
{ "IDAT", PNG_CHUNK_IDAT },
{ "IEND", PNG_CHUNK_IEND },
{ "PLTE", PNG_CHUNK_PLTE },
{ "tRNS", PNG_CHUNK_tRNS },
};
for (i = 0; i < ARRAY_SIZE(chunk_map); i++)
{
if (string_is_equal(chunk->type, chunk_map[i].id))
return chunk_map[i].type;
}
return PNG_CHUNK_NOOP;
}
#if defined(DEBUG) || defined(RPNG_TEST)
static bool png_process_ihdr(struct png_ihdr *ihdr)
{
unsigned i;
bool ret = true;
uint8_t ihdr_depth = ihdr->depth;
switch (ihdr->color_type)
{
case PNG_IHDR_COLOR_RGB:
case PNG_IHDR_COLOR_GRAY_ALPHA:
case PNG_IHDR_COLOR_RGBA:
if (ihdr->depth != 8 && ihdr->depth != 16)
GOTO_END_ERROR();
if (ihdr_depth != 8 && ihdr_depth != 16)
{
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
return false;
}
break;
case PNG_IHDR_COLOR_GRAY:
/* Valid bitdepths are: 1, 2, 4, 8, 16 */
if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
{
static const unsigned valid_bpp[] = { 1, 2, 4, 8, 16 };
bool correct_bpp = false;
for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
{
if (valid_bpp[i] == ihdr->depth)
{
correct_bpp = true;
break;
}
}
if (!correct_bpp)
GOTO_END_ERROR();
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
return false;
}
break;
case PNG_IHDR_COLOR_PLT:
/* Valid bitdepths are: 1, 2, 4, 8 */
if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth) & 0x80000000)
{
static const unsigned valid_bpp[] = { 1, 2, 4, 8 };
bool correct_bpp = false;
for (i = 0; i < ARRAY_SIZE(valid_bpp); i++)
{
if (valid_bpp[i] == ihdr->depth)
{
correct_bpp = true;
break;
}
}
if (!correct_bpp)
GOTO_END_ERROR();
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
return false;
}
break;
default:
GOTO_END_ERROR();
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
return false;
}
#ifdef RPNG_TEST
fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
ihdr->width, ihdr->height,
ihdr->depth, (ihdr->color_type == PNG_IHDR_COLOR_PLT) ? "yes" : "no",
(ihdr->color_type & PNG_IHDR_COLOR_RGB) ? "yes" : "no",
(ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA) ? "yes" : "no",
ihdr_depth, (ihdr->color_type == PNG_IHDR_COLOR_PLT) ? "yes" : "no",
(ihdr->color_type & PNG_IHDR_COLOR_RGB) ? "yes" : "no",
(ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA) ? "yes" : "no",
ihdr->interlace == 1 ? "yes" : "no");
#endif
if (ihdr->compression != 0)
GOTO_END_ERROR();
end:
return ret;
return true;
}
#else
static bool png_process_ihdr(struct png_ihdr *ihdr)
{
uint8_t ihdr_depth = ihdr->depth;
switch (ihdr->color_type)
{
case PNG_IHDR_COLOR_RGB:
case PNG_IHDR_COLOR_GRAY_ALPHA:
case PNG_IHDR_COLOR_RGBA:
if (ihdr_depth != 8 && ihdr_depth != 16)
return false;
break;
case PNG_IHDR_COLOR_GRAY:
/* Valid bitdepths are: 1, 2, 4, 8, 16 */
if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
return false;
break;
case PNG_IHDR_COLOR_PLT:
/* Valid bitdepths are: 1, 2, 4, 8 */
if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth) & 0x80000000)
return false;
break;
default:
return false;
}
return true;
}
#endif
static void png_reverse_filter_copy_line_rgb(uint32_t *data,
const uint8_t *decoded, unsigned width, unsigned bpp)
@ -407,9 +399,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
}
if (width & 1)
{
*data = palette[*decoded >> 4];
}
}
break;
@ -418,9 +408,7 @@ static void png_reverse_filter_copy_line_plt(uint32_t *data,
unsigned i;
for (i = 0; i < width; i++, decoded++, data++)
{
*data = palette[*decoded];
}
}
break;
}
@ -430,8 +418,8 @@ static void png_pass_geom(const struct png_ihdr *ihdr,
unsigned width, unsigned height,
unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)
{
unsigned bpp;
unsigned pitch;
unsigned bpp = 0;
unsigned pitch = 0;
switch (ihdr->color_type)
{
@ -456,15 +444,13 @@ static void png_pass_geom(const struct png_ihdr *ihdr,
pitch = (ihdr->width * ihdr->depth * 4 + 7) / 8;
break;
default:
bpp = 0;
pitch = 0;
break;
}
if (pass_size)
*pass_size = (pitch + 1) * ihdr->height;
if (bpp_out)
*bpp_out = bpp;
*bpp_out = bpp;
if (pitch_out)
*pitch_out = pitch;
}
@ -503,16 +489,6 @@ static void png_reverse_filter_deinit(struct rpng_process *pngp)
pngp->h = 0;
}
static const struct adam7_pass passes[] = {
{ 0, 0, 8, 8 },
{ 4, 0, 8, 8 },
{ 0, 4, 4, 8 },
{ 2, 0, 4, 4 },
{ 0, 2, 2, 4 },
{ 1, 0, 2, 2 },
{ 0, 1, 1, 2 },
};
static int png_reverse_filter_init(const struct png_ihdr *ihdr,
struct rpng_process *pngp)
{
@ -705,10 +681,11 @@ static int png_reverse_filter_adam7_iterate(uint32_t **data_,
if (png_reverse_filter_init(&pngp->ihdr, pngp) == -1)
return IMAGE_PROCESS_ERROR;
do{
do
{
ret = png_reverse_filter_regular_iterate(&pngp->data,
&pngp->ihdr, pngp);
}while(ret == IMAGE_PROCESS_NEXT);
} while (ret == IMAGE_PROCESS_NEXT);
if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
return IMAGE_PROCESS_ERROR;
@ -856,9 +833,9 @@ static bool png_read_trns(uint8_t *buf, uint32_t *palette, unsigned entries)
return true;
}
bool png_realloc_idat(const struct png_chunk *chunk, struct idat_buffer *buf)
bool png_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
{
uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk->size);
uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk_size);
if (!new_buffer)
return false;
@ -869,13 +846,45 @@ bool png_realloc_idat(const struct png_chunk *chunk, struct idat_buffer *buf)
static struct rpng_process *rpng_process_init(rpng_t *rpng)
{
uint8_t *inflate_buf = NULL;
struct rpng_process *process = (struct rpng_process*)calloc(1, sizeof(*process));
uint8_t *inflate_buf = NULL;
struct rpng_process *process = (struct rpng_process*)malloc(sizeof(*process));
if (!process)
return NULL;
process->stream_backend = trans_stream_get_zlib_inflate_backend();
process->inflate_initialized = false;
process->adam7_pass_initialized = false;
process->pass_initialized = false;
process->prev_scanline = NULL;
process->decoded_scanline = NULL;
process->inflate_buf = NULL;
process->ihdr.width = 0;
process->ihdr.height = 0;
process->ihdr.depth = 0;
process->ihdr.color_type = 0;
process->ihdr.compression = 0;
process->ihdr.filter = 0;
process->ihdr.interlace = 0;
process->restore_buf_size = 0;
process->adam7_restore_buf_size = 0;
process->data_restore_buf_size = 0;
process->inflate_buf_size = 0;
process->avail_in = 0;
process->avail_out = 0;
process->total_out = 0;
process->pass_size = 0;
process->bpp = 0;
process->pitch = 0;
process->h = 0;
process->pass_width = 0;
process->pass_height = 0;
process->pass_pos = 0;
process->data = 0;
process->palette = 0;
process->stream = NULL;
process->stream_backend = trans_stream_get_zlib_inflate_backend();
png_pass_geom(&rpng->ihdr, rpng->ihdr.width,
rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size);
@ -895,9 +904,9 @@ static struct rpng_process *rpng_process_init(rpng_t *rpng)
goto error;
process->inflate_buf = inflate_buf;
process->avail_in = rpng->idat_buf.size;
process->avail_out = process->inflate_buf_size;
process->total_out = 0;
process->avail_in = rpng->idat_buf.size;
process->avail_out = process->inflate_buf_size;
process->stream_backend->set_in(
process->stream,
rpng->idat_buf.data,
@ -919,26 +928,11 @@ error:
return NULL;
}
static bool read_chunk_header(uint8_t *buf, uint8_t *buf_end, struct png_chunk *chunk)
static enum png_chunk_type read_chunk_header(
uint8_t *buf, uint32_t chunk_size)
{
unsigned i;
uint8_t dword[4];
dword[0] = '\0';
/* Check whether reading the header will overflow
* the data buffer */
if (buf_end - buf < 8)
return false;
for (i = 0; i < 4; i++)
dword[i] = buf[i];
chunk->size = dword_be(dword);
/* Check whether chunk will overflow the data buffer */
if (buf + 8 + chunk->size > buf_end)
return false;
char type[4];
for (i = 0; i < 4; i++)
{
@ -947,99 +941,139 @@ static bool read_chunk_header(uint8_t *buf, uint8_t *buf_end, struct png_chunk *
/* All four bytes of the chunk type must be
* ASCII letters (codes 65-90 and 97-122) */
if ((byte < 65) || ((byte > 90) && (byte < 97)) || (byte > 122))
return false;
chunk->type[i] = byte;
return PNG_CHUNK_ERROR;
type[i] = byte;
}
return true;
}
if (
type[0] == 'I'
&& type[1] == 'H'
&& type[2] == 'D'
&& type[3] == 'R'
)
return PNG_CHUNK_IHDR;
else if
(
type[0] == 'I'
&& type[1] == 'D'
&& type[2] == 'A'
&& type[3] == 'T'
)
return PNG_CHUNK_IDAT;
else if
(
type[0] == 'I'
&& type[1] == 'E'
&& type[2] == 'N'
&& type[3] == 'D'
)
return PNG_CHUNK_IEND;
else if
(
type[0] == 'P'
&& type[1] == 'L'
&& type[2] == 'T'
&& type[3] == 'E'
)
return PNG_CHUNK_PLTE;
else if
(
type[0] == 't'
&& type[1] == 'R'
&& type[2] == 'N'
&& type[3] == 'S'
)
return PNG_CHUNK_tRNS;
static bool png_parse_ihdr(uint8_t *buf,
struct png_ihdr *ihdr)
{
buf += 4 + 4;
ihdr->width = dword_be(buf + 0);
ihdr->height = dword_be(buf + 4);
ihdr->depth = buf[8];
ihdr->color_type = buf[9];
ihdr->compression = buf[10];
ihdr->filter = buf[11];
ihdr->interlace = buf[12];
if (ihdr->width == 0 || ihdr->height == 0)
return false;
return true;
return PNG_CHUNK_NOOP;
}
bool rpng_iterate_image(rpng_t *rpng)
{
unsigned i;
struct png_chunk chunk;
uint8_t *buf = (uint8_t*)rpng->buff_data;
chunk.size = 0;
chunk.type[0] = 0;
chunk.data = NULL;
uint8_t *buf = (uint8_t*)rpng->buff_data;
uint32_t chunk_size = 0;
/* Check whether data buffer pointer is valid */
if (buf > rpng->buff_end)
goto error;
return false;
if (!read_chunk_header(buf, rpng->buff_end, &chunk))
goto error;
/* Check whether reading the header will overflow
* the data buffer */
if (rpng->buff_end - buf < 8)
return false;
#if 0
for (i = 0; i < 4; i++)
{
fprintf(stderr, "chunktype: %c\n", chunk.type[i]);
}
#endif
chunk_size = dword_be(buf);
switch (png_chunk_type(&chunk))
/* Check whether chunk will overflow the data buffer */
if (buf + 8 + chunk_size > rpng->buff_end)
return false;
switch (read_chunk_header(buf, chunk_size))
{
case PNG_CHUNK_NOOP:
default:
break;
case PNG_CHUNK_ERROR:
goto error;
return false;
case PNG_CHUNK_IHDR:
if (rpng->has_ihdr || rpng->has_idat || rpng->has_iend)
goto error;
return false;
if (chunk.size != 13)
goto error;
if (chunk_size != 13)
return false;
if (!png_parse_ihdr(buf, &rpng->ihdr))
goto error;
buf += 4 + 4;
rpng->ihdr.width = dword_be(buf + 0);
rpng->ihdr.height = dword_be(buf + 4);
rpng->ihdr.depth = buf[8];
rpng->ihdr.color_type = buf[9];
rpng->ihdr.compression = buf[10];
rpng->ihdr.filter = buf[11];
rpng->ihdr.interlace = buf[12];
if ( rpng->ihdr.width == 0
|| rpng->ihdr.height == 0)
return false;
if (!png_process_ihdr(&rpng->ihdr))
goto error;
return false;
if (rpng->ihdr.compression != 0)
{
#if defined(DEBUG) || defined(RPNG_TEST)
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
#endif
return false;
}
rpng->has_ihdr = true;
break;
case PNG_CHUNK_PLTE:
{
unsigned entries = chunk.size / 3;
unsigned entries = chunk_size / 3;
if (!rpng->has_ihdr || rpng->has_plte || rpng->has_iend || rpng->has_idat || rpng->has_trns)
goto error;
if ( !rpng->has_ihdr
|| rpng->has_plte
|| rpng->has_iend
|| rpng->has_idat
|| rpng->has_trns)
return false;
if (chunk.size % 3)
goto error;
if (chunk_size % 3)
return false;
if (entries > 256)
goto error;
return false;
buf += 8;
if (!png_read_plte(buf, rpng->palette, entries))
goto error;
return false;
rpng->has_plte = true;
}
@ -1047,18 +1081,18 @@ bool rpng_iterate_image(rpng_t *rpng)
case PNG_CHUNK_tRNS:
if (rpng->has_idat)
goto error;
return false;
if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)
{
/* we should compare with the number of palette entries */
if (chunk.size > 256)
goto error;
if (chunk_size > 256)
return false;
buf += 8;
if (!png_read_trns(buf, rpng->palette, chunk.size))
goto error;
if (!png_read_trns(buf, rpng->palette, chunk_size))
return false;
}
/* TODO: support colorkey in grayscale and truecolor images */
@ -1067,39 +1101,35 @@ bool rpng_iterate_image(rpng_t *rpng)
case PNG_CHUNK_IDAT:
if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !(rpng->has_plte)))
goto error;
return false;
if (!png_realloc_idat(&chunk, &rpng->idat_buf))
goto error;
if (!png_realloc_idat(&rpng->idat_buf, chunk_size))
return false;
buf += 8;
for (i = 0; i < chunk.size; i++)
for (i = 0; i < chunk_size; i++)
rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i];
rpng->idat_buf.size += chunk.size;
rpng->idat_buf.size += chunk_size;
rpng->has_idat = true;
break;
case PNG_CHUNK_IEND:
if (!(rpng->has_ihdr) || !(rpng->has_idat))
goto error;
return false;
rpng->has_iend = true;
goto error;
return false;
}
rpng->buff_data += chunk.size + 12;
rpng->buff_data += chunk_size + 12;
/* Check whether data buffer pointer is valid */
if (rpng->buff_data > rpng->buff_end)
goto error;
return false;
return true;
error:
return false;
}
int rpng_process_image(rpng_t *rpng,
@ -1170,9 +1200,6 @@ void rpng_free(rpng_t *rpng)
bool rpng_start(rpng_t *rpng)
{
unsigned i;
char header[8];
if (!rpng)
return false;
@ -1181,12 +1208,8 @@ bool rpng_start(rpng_t *rpng)
if (rpng->buff_end - rpng->buff_data < 8)
return false;
header[0] = '\0';
for (i = 0; i < 8; i++)
header[i] = rpng->buff_data[i];
if (string_is_not_equal_fast(header, png_magic, sizeof(png_magic)))
if (string_is_not_equal_fast(
rpng->buff_data, png_magic, sizeof(png_magic)))
return false;
rpng->buff_data += 8;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rpng_encode.c).
@ -36,7 +36,7 @@
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__); \
ret = false; \
goto end; \
} while(0)
} while (0)
double DEFLATE_PADDING = 1.1;
int PNG_ROUGH_HEADER = 100;
@ -413,7 +413,7 @@ uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
buf = (uint8_t*)malloc(buf_length*sizeof(uint8_t));
if (!buf)
GOTO_END_ERROR();
intf_s = intfstream_open_writable_memory(buf,
RETRO_VFS_FILE_ACCESS_WRITE,
RETRO_VFS_FILE_ACCESS_HINT_NONE,
@ -424,7 +424,7 @@ uint8_t* rpng_save_image_bgr24_string(const uint8_t *data,
*bytes = intfstream_get_ptr(intf_s);
intfstream_rewind(intf_s);
output = (uint8_t*)malloc((*bytes)*sizeof(uint8_t));
output = (uint8_t*)malloc((size_t)((*bytes)*sizeof(uint8_t)));
if (!output)
GOTO_END_ERROR();
intfstream_read(intf_s, output, *bytes);
@ -433,7 +433,10 @@ end:
if (buf)
free(buf);
if (intf_s)
{
intfstream_close(intf_s);
free(intf_s);
}
if (ret == false)
{
if (output)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rpng_internal.h).
@ -27,13 +27,6 @@
#include <filters.h>
#include <formats/rpng.h>
#undef GOTO_END_ERROR
#define GOTO_END_ERROR() do { \
fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__); \
ret = false; \
goto end; \
} while(0)
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rtga.c).
@ -45,15 +45,13 @@ struct rtga
typedef struct
{
uint32_t img_x, img_y;
int img_n, img_out_n;
int buflen;
uint8_t buffer_start[128];
uint8_t *img_buffer;
uint8_t *img_buffer_end;
uint8_t *img_buffer_original;
int buflen;
int img_n, img_out_n;
uint32_t img_x, img_y;
uint8_t buffer_start[128];
} rtga_context;
static INLINE uint8_t rtga_get8(rtga_context *s)
@ -102,40 +100,40 @@ static unsigned char *rtga_convert_format(
switch (((img_n)*8+(req_comp)))
{
case ((1)*8+(2)):
for(i=x-1; i >= 0; --i, src += 1, dest += 2)
for (i=x-1; i >= 0; --i, src += 1, dest += 2)
{
dest[0]=src[0];
dest[1]=255;
}
break;
case ((1)*8+(3)):
for(i=x-1; i >= 0; --i, src += 1, dest += 3)
for (i=x-1; i >= 0; --i, src += 1, dest += 3)
dest[0]=dest[1]=dest[2]=src[0];
break;
case ((1)*8+(4)):
for(i=x-1; i >= 0; --i, src += 1, dest += 4)
for (i=x-1; i >= 0; --i, src += 1, dest += 4)
{
dest[0]=dest[1]=dest[2]=src[0];
dest[3]=255;
}
break;
case ((2)*8+(1)):
for(i=x-1; i >= 0; --i, src += 2, dest += 1)
for (i=x-1; i >= 0; --i, src += 2, dest += 1)
dest[0]=src[0];
break;
case ((2)*8+(3)):
for(i=x-1; i >= 0; --i, src += 2, dest += 3)
for (i=x-1; i >= 0; --i, src += 2, dest += 3)
dest[0]=dest[1]=dest[2]=src[0];
break;
case ((2)*8+(4)):
for(i=x-1; i >= 0; --i, src += 2, dest += 4)
for (i=x-1; i >= 0; --i, src += 2, dest += 4)
{
dest[0]=dest[1]=dest[2]=src[0];
dest[3]=src[1];
}
break;
case ((3)*8+(4)):
for(i=x-1; i >= 0; --i, src += 3, dest += 4)
for (i=x-1; i >= 0; --i, src += 3, dest += 4)
{
dest[0]=src[0];
dest[1]=src[1];
@ -144,29 +142,29 @@ static unsigned char *rtga_convert_format(
}
break;
case ((3)*8+(1)):
for(i=x-1; i >= 0; --i, src += 3, dest += 1)
for (i=x-1; i >= 0; --i, src += 3, dest += 1)
dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
break;
case ((3)*8+(2)):
for(i=x-1; i >= 0; --i, src += 3, dest += 2)
for (i=x-1; i >= 0; --i, src += 3, dest += 2)
{
dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
dest[1] = 255;
}
break;
case ((4)*8+(1)):
for(i=x-1; i >= 0; --i, src += 4, dest += 1)
for (i=x-1; i >= 0; --i, src += 4, dest += 1)
dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
break;
case ((4)*8+(2)):
for(i=x-1; i >= 0; --i, src += 4, dest += 2)
for (i=x-1; i >= 0; --i, src += 4, dest += 2)
{
dest[0] = RTGA_COMPUTE_Y(src[0],src[1],src[2]);
dest[1] = src[3];
}
break;
case ((4)*8+(3)):
for(i=x-1; i >= 0; --i, src += 4, dest += 3)
for (i=x-1; i >= 0; --i, src += 4, dest += 3)
{
dest[0]=src[0];
dest[1]=src[1];
@ -357,18 +355,21 @@ static uint8_t *rtga_tga_load(rtga_context *s,
/* do I need to invert the image? */
if (tga_inverted)
{
for (j = 0; j*2 < tga_height; ++j)
if (tga_data)
{
int index1 = j * tga_width * tga_comp;
int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
for (i = tga_width * tga_comp; i > 0; --i)
for (j = 0; j*2 < tga_height; ++j)
{
unsigned char temp = tga_data[index1];
tga_data[index1] = tga_data[index2];
tga_data[index2] = temp;
++index1;
++index2;
int index1 = j * tga_width * tga_comp;
int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
for (i = tga_width * tga_comp; i > 0; --i)
{
unsigned char temp = tga_data[index1];
tga_data[index1] = tga_data[index2];
tga_data[index2] = temp;
++index1;
++index2;
}
}
}
}
@ -431,7 +432,7 @@ int rtga_process_image(rtga_t *rtga, void **buf_data,
size_tex = (*width) * (*height);
/* Convert RGBA to ARGB */
while(size_tex--)
while (size_tex--)
{
unsigned int texel = rtga->output_image[size_tex];
unsigned int A = texel & 0xFF000000;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rwav.c).
@ -95,12 +95,13 @@ enum rwav_state rwav_iterate(rwav_iterator_t *iter)
rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24;
if (rwav->subchunk2size > iter->size - 44)
if ((rwav->subchunk2size < 1) ||
(rwav->subchunk2size > iter->size - 44))
return RWAV_ITERATE_ERROR; /* too few bytes in buffer */
samples = malloc(rwav->subchunk2size);
if (samples == NULL)
if (!samples)
return RWAV_ITERATE_ERROR;
rwav->numchannels = data[22] | data[23] << 8;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rxml.c).
@ -20,14 +20,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <boolean.h>
#include <streams/file_stream.h>
#include <compat/posix_string.h>
@ -35,6 +27,17 @@
#include <formats/rxml.h>
#include "../../deps/yxml/yxml.h"
#define BUFSIZE 4096
struct rxml_parse_buffer
{
rxml_node_t *stack[32];
char xml[BUFSIZE];
char val[BUFSIZE];
};
struct rxml_document
{
struct rxml_node *root_node;
@ -64,19 +67,15 @@ static void rxml_free_node(struct rxml_node *node)
for (attrib_node_head = node->attrib; attrib_node_head; )
{
struct rxml_attrib_node *next_attrib = NULL;
struct rxml_attrib_node *next_attrib =
(struct rxml_attrib_node*)attrib_node_head->next;
next_attrib = (struct rxml_attrib_node*)attrib_node_head->next;
if (next_attrib)
{
if (attrib_node_head->attrib)
free(attrib_node_head->attrib);
if (attrib_node_head->value)
free(attrib_node_head->value);
if (attrib_node_head)
free(attrib_node_head);
}
if (attrib_node_head->attrib)
free(attrib_node_head->attrib);
if (attrib_node_head->value)
free(attrib_node_head->value);
if (attrib_node_head)
free(attrib_node_head);
attrib_node_head = next_attrib;
}
@ -89,362 +88,30 @@ static void rxml_free_node(struct rxml_node *node)
free(node);
}
static bool validate_header(const char **ptr)
{
if (memcmp(*ptr, "<?xml", 5) == 0)
{
const char *eol = strstr(*ptr, "?>\n");
if (!eol)
return false;
/* Always use UTF-8. Don't really care to check. */
*ptr = eol + 3;
return true;
}
return true;
}
static bool range_is_space(const char *begin, const char *end)
{
for (; begin < end; begin++)
if (!isspace(*begin))
return false;
return true;
}
static void rxml_skip_spaces(const char **ptr_)
{
const char *ptr = *ptr_;
while (isspace(*ptr))
ptr++;
*ptr_ = ptr;
}
static char *strdup_range(const char *begin, const char *end)
{
ptrdiff_t len = end - begin;
char *ret = (char*)malloc(len + 1);
if (!ret)
return NULL;
memcpy(ret, begin, len);
ret[len] = '\0';
return ret;
}
static char *strdup_range_escape(const char *begin, const char *end)
{
/* Escaping is ignored. Assume we don't deal with that. */
return strdup_range(begin, end);
}
static struct rxml_attrib_node *rxml_parse_attrs(const char *str)
{
const char *elem;
struct rxml_attrib_node *list = NULL;
struct rxml_attrib_node *tail = NULL;
char *attrib = NULL;
char *value = NULL;
char *last_char = NULL;
char *save = NULL;
char *copy = strdup(str);
if (!copy)
return NULL;
last_char = copy + strlen(copy) - 1;
if (*last_char == '/')
*last_char = '\0';
elem = strtok_r(copy, " \n\t\f\v\r", &save);
while (elem)
{
const char *end;
struct rxml_attrib_node *new_node;
const char *eq = strstr(elem, "=\"");
if (!eq)
goto end;
end = strrchr(eq + 2, '\"');
if (!end || end != (elem + strlen(elem) - 1))
goto end;
attrib = strdup_range_escape(elem, eq);
value = strdup_range_escape(eq + 2, end);
if (!attrib || !value)
goto end;
new_node =
(struct rxml_attrib_node*)calloc(1, sizeof(*new_node));
if (!new_node)
goto end;
new_node->attrib = attrib;
new_node->value = value;
attrib = NULL;
value = NULL;
if (tail)
{
tail->next = new_node;
tail = new_node;
}
else
list = tail = new_node;
elem = strtok_r(NULL, " \n\t\f\v\r", &save);
}
end:
if (copy)
free(copy);
if (attrib)
free(attrib);
if (value)
free(value);
return list;
}
static char *find_first_space(const char *str)
{
while (*str && !isspace(*str))
str++;
return isspace(*str) ? (char*)str : NULL;
}
static bool rxml_parse_tag(struct rxml_node *node, const char *str)
{
const char *name_end;
const char *str_ptr = str;
rxml_skip_spaces(&str_ptr);
name_end = find_first_space(str_ptr);
if (name_end)
{
node->name = strdup_range(str_ptr, name_end);
if (!node->name || !*node->name)
return false;
node->attrib = rxml_parse_attrs(name_end);
return true;
}
else
{
node->name = strdup(str_ptr);
return node->name && *node->name;
}
}
static struct rxml_node *rxml_parse_node(const char **ptr_)
{
const char *ptr = NULL;
const char *closing = NULL;
char *str = NULL;
bool is_closing = false;
struct rxml_node *node = (struct rxml_node*)calloc(1, sizeof(*node));
if (!node)
return NULL;
rxml_skip_spaces(ptr_);
ptr = *ptr_;
if (*ptr != '<')
goto error;
closing = strchr(ptr, '>');
if (!closing)
goto error;
str = strdup_range(ptr + 1, closing);
if (!str)
goto error;
if (!rxml_parse_tag(node, str))
goto error;
/* Are spaces between / and > allowed? */
is_closing = strstr(ptr, "/>") + 1 == closing;
/* Look for more data. Either child nodes or data. */
if (!is_closing)
{
size_t copied = 0;
size_t closing_tag_size = strlen(node->name) + 4;
char *closing_tag = (char*)malloc(closing_tag_size);
const char *cdata_start = NULL;
const char *child_start = NULL;
const char *closing_start = NULL;
if (!closing_tag)
goto error;
closing_tag[copied] = '<';
closing_tag[copied+1] = '/';
closing_tag[copied+2] = '\0';
copied = strlcat(closing_tag, node->name, closing_tag_size);
closing_tag[copied] = '>';
closing_tag[copied+1] = '\0';
cdata_start = strstr(closing + 1, "<![CDATA[");
child_start = strchr(closing + 1, '<');
closing_start = strstr(closing + 1, closing_tag);
if (!closing_start)
{
free(closing_tag);
goto error;
}
if (cdata_start && range_is_space(closing + 1, cdata_start))
{
/* CDATA section */
const char *cdata_end = strstr(cdata_start, "]]>");
if (!cdata_end)
{
free(closing_tag);
goto error;
}
node->data = strdup_range(cdata_start +
STRLEN_CONST("<![CDATA["), cdata_end);
}
else if (closing_start && closing_start == child_start) /* Simple Data */
node->data = strdup_range(closing + 1, closing_start);
else
{
/* Parse all child nodes. */
struct rxml_node *list = NULL;
struct rxml_node *tail = NULL;
const char *first_start = NULL;
const char *first_closing = NULL;
ptr = child_start;
first_start = strchr(ptr, '<');
first_closing = strstr(ptr, "</");
while (
first_start &&
first_closing &&
(first_start < first_closing)
)
{
struct rxml_node *new_node = rxml_parse_node(&ptr);
if (!new_node)
{
free(closing_tag);
goto error;
}
if (tail)
{
tail->next = new_node;
tail = new_node;
}
else
list = tail = new_node;
first_start = strchr(ptr, '<');
first_closing = strstr(ptr, "</");
}
node->children = list;
closing_start = strstr(ptr, closing_tag);
if (!closing_start)
{
free(closing_tag);
goto error;
}
}
*ptr_ = closing_start + strlen(closing_tag);
free(closing_tag);
}
else
*ptr_ = closing + 1;
if (str)
free(str);
return node;
error:
if (str)
free(str);
rxml_free_node(node);
return NULL;
}
static char *purge_xml_comments(const char *str)
{
char *copy_dest;
const char *copy_src;
size_t len = strlen(str);
char *new_str = (char*)malloc(len + 1);
if (!new_str)
return NULL;
new_str[len] = '\0';
copy_dest = new_str;
copy_src = str;
for (;;)
{
ptrdiff_t copy_len;
const char *comment_start = strstr(copy_src, "<!--");
const char *comment_end = strstr(copy_src, "-->");
if (!comment_start || !comment_end)
break;
copy_len = comment_start - copy_src;
memcpy(copy_dest, copy_src, copy_len);
copy_dest += copy_len;
copy_src = comment_end + STRLEN_CONST("-->");
}
/* Avoid strcpy() as OpenBSD is anal and hates you
* for using it even when it's perfectly safe. */
len = strlen(copy_src);
memcpy(copy_dest, copy_src, len);
copy_dest[len] = '\0';
return new_str;
}
rxml_document_t *rxml_load_document(const char *path)
{
rxml_document_t *doc;
rxml_document_t *doc = NULL;
char *memory_buffer = NULL;
long len = 0;
int64_t len = 0;
RFILE *file = filestream_open(path,
RETRO_VFS_FILE_ACCESS_READ,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!file)
return NULL;
len = filestream_get_size(file);
memory_buffer = (char*)malloc(len + 1);
len = filestream_get_size(file);
memory_buffer = (char*)malloc((size_t)(len + 1));
if (!memory_buffer)
goto error;
memory_buffer[len] = '\0';
memory_buffer[len] = '\0';
if (filestream_read(file, memory_buffer, len) != (size_t)len)
goto error;
filestream_close(file);
file = NULL;
file = NULL;
doc = rxml_load_document_string(memory_buffer);
doc = rxml_load_document_string(memory_buffer);
free(memory_buffer);
return doc;
@ -458,35 +125,200 @@ error:
rxml_document_t *rxml_load_document_string(const char *str)
{
rxml_document_t *doc;
char *memory_buffer = NULL;
const char *mem_ptr = NULL;
yxml_t x;
rxml_document_t *doc = NULL;
size_t stack_i = 0;
size_t level = 0;
int c = 0;
char *valptr = NULL;
rxml_node_t *node = NULL;
struct rxml_attrib_node *attr = NULL;
struct rxml_parse_buffer *buf = (struct rxml_parse_buffer*)
malloc(sizeof(*buf));
if (!buf)
return NULL;
doc = (rxml_document_t*)calloc(1, sizeof(*doc));
valptr = buf->val;
doc = (rxml_document_t*)malloc(sizeof(*doc));
if (!doc)
goto error;
mem_ptr = str;
doc->root_node = (struct rxml_node *)malloc(
sizeof(*doc->root_node));
doc->root_node->name = NULL;
doc->root_node->data = NULL;
doc->root_node->attrib = NULL;
if (!validate_header(&mem_ptr))
goto error;
doc->root_node->children = NULL;
doc->root_node->next = NULL;
memory_buffer = purge_xml_comments(mem_ptr);
if (!memory_buffer)
goto error;
yxml_init(&x, buf->xml, BUFSIZE);
mem_ptr = memory_buffer;
for (; *str; ++str)
{
yxml_ret_t r = yxml_parse(&x, *str);
doc->root_node = rxml_parse_node(&mem_ptr);
if (!doc->root_node)
goto error;
if (r < 0)
goto error;
free(memory_buffer);
switch (r)
{
case YXML_ELEMSTART:
if (node)
{
if (level > stack_i)
{
buf->stack[stack_i] = node;
++stack_i;
node->children = (rxml_node_t*)
malloc(sizeof(*node));
node->children->name = NULL;
node->children->data = NULL;
node->children->attrib = NULL;
node->children->children = NULL;
node->children->next = NULL;
node = node->children;
}
else
{
node->next = (rxml_node_t*)
malloc(sizeof(*node));
node->next->name = NULL;
node->next->data = NULL;
node->next->attrib = NULL;
node->next->children = NULL;
node->next->next = NULL;
node = node->next;
}
}
else
node = doc->root_node = (rxml_node_t*)
calloc(1, sizeof(*node));
if (node->name)
free(node->name);
node->name = strdup(x.elem);
attr = NULL;
++level;
break;
case YXML_ELEMEND:
--level;
if (valptr > buf->val)
{
*valptr = '\0';
/* Original code was broken here:
* > If an element ended on two successive
* iterations, on the second iteration
* the 'data' for the *previous* node would
* get overwritten
* > This effectively erased the data for the
* previous node, *and* caused a memory leak
* (due to the double strdup())
* It seems the correct thing to do here is
* only copy the data if the current 'level'
* and 'stack index' are the same... */
if (level == stack_i)
{
if (node->data)
free(node->data);
node->data = strdup(buf->val);
}
valptr = buf->val;
}
if (level < stack_i)
{
--stack_i;
node = buf->stack[stack_i];
}
break;
case YXML_CONTENT:
for (c = 0; c < sizeof(x.data) && x.data[c]; ++c)
{
*valptr = x.data[c];
++valptr;
}
break;
case YXML_ATTRSTART:
if (attr)
{
struct rxml_attrib_node
*new_node = (struct rxml_attrib_node*)
calloc(1, sizeof(*attr));
attr = new_node;
attr->next = new_node ;
}
else
{
struct rxml_attrib_node
*new_node = (struct rxml_attrib_node*)
calloc(1, sizeof(*attr));
attr = new_node;
if (node)
node->attrib = new_node;
}
if (attr)
{
if (attr->attrib)
free(attr->attrib);
attr->attrib = strdup(x.attr);
}
valptr = buf->val;
break;
case YXML_ATTRVAL:
for (c = 0; c < sizeof(x.data) && x.data[c]; ++c)
{
*valptr = x.data[c];
++valptr;
}
break;
case YXML_ATTREND:
if (valptr > buf->val)
{
*valptr = '\0';
if (attr)
{
if (attr->value)
free(attr->value);
attr->value = strdup(buf->val);
}
valptr = buf->val;
}
break;
default:
break;
}
}
free(buf);
return doc;
error:
free(memory_buffer);
rxml_free_document(doc);
free(buf);
return NULL;
}

View File

@ -2,10 +2,12 @@ TARGET := rxml
LIBRETRO_XML_DIR := ..
LIBRETRO_COMM_DIR := ../../..
LIBRETRO_DEPS_DIR := ../../../../deps
SOURCES := \
rxml_test.c \
$(LIBRETRO_XML_DIR)/rxml.c \
$(LIBRETRO_DEPS_DIR)/yxml/yxml.c \
$(LIBRETRO_COMM_DIR)/streams/file_stream.c
OBJS := $(SOURCES:.c=.o)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (gl_capabilities.c).
@ -300,7 +300,7 @@ bool gl_check_capability(enum gl_capability_enum enum_idx)
case GL_CAPS_BGRA8888:
#ifdef HAVE_OPENGLES
/* There are both APPLE and EXT variants. */
if (gl_query_extension("BGRA8888") && !strstr(renderer, "VideoCore"))
if (gl_query_extension("BGRA8888"))
return true;
#else
return true;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (pixconv.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (scaler.c).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (scaler_filter.c).
@ -85,7 +85,9 @@ static bool validate_filter(struct scaler_ctx *ctx)
{
if (ctx->horiz.filter_pos[i] > max_w_pos || ctx->horiz.filter_pos[i] < 0)
{
#ifndef NDEBUG
fprintf(stderr, "Out X = %d => In X = %d\n", i, ctx->horiz.filter_pos[i]);
#endif
return false;
}
}
@ -96,7 +98,9 @@ static bool validate_filter(struct scaler_ctx *ctx)
{
if (ctx->vert.filter_pos[i] > max_h_pos || ctx->vert.filter_pos[i] < 0)
{
#ifndef NDEBUG
fprintf(stderr, "Out Y = %d => In Y = %d\n", i, ctx->vert.filter_pos[i]);
#endif
return false;
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (scaler_int.c).

2
externals/libretro-common/glsym/glgen.py vendored Normal file → Executable file
View File

@ -2,9 +2,7 @@
"""
License statement applies to this file (glgen.py) only.
"""
"""
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this libretro SDK code part (glsym).

2
externals/libretro-common/glsym/rglgen.py vendored Normal file → Executable file
View File

@ -2,9 +2,7 @@
"""
License statement applies to this file (glgen.py) only.
"""
"""
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to

View File

@ -2,9 +2,7 @@
"""
License statement applies to this file (xglgen.py) only.
"""
"""
Permission is hereby granted, free of charge,
to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rhash.c).
@ -307,7 +307,22 @@ uint32_t crc32_calculate(const uint8_t *data, size_t length)
/* Define the circular shift macro */
#define SHA1CircularShift(bits,word) ((((word) << (bits)) & 0xFFFFFFFF) | ((word) >> (32-(bits))))
static void SHA1Reset(SHA1Context *context)
struct sha1_context
{
unsigned Message_Digest[5]; /* Message Digest (output) */
unsigned Length_Low; /* Message length in bits */
unsigned Length_High; /* Message length in bits */
unsigned char Message_Block[64]; /* 512-bit message blocks */
int Message_Block_Index; /* Index into message block array */
int Computed; /* Is the digest computed? */
int Corrupted; /* Is the message digest corruped? */
};
static void SHA1Reset(struct sha1_context *context)
{
if (!context)
return;
@ -326,7 +341,7 @@ static void SHA1Reset(SHA1Context *context)
context->Corrupted = 0;
}
static void SHA1ProcessMessageBlock(SHA1Context *context)
static void SHA1ProcessMessageBlock(struct sha1_context *context)
{
const unsigned K[] = /* Constants defined in SHA-1 */
{
@ -341,7 +356,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
unsigned A, B, C, D, E; /* Word buffers */
/* Initialize the first 16 words in the array W */
for(t = 0; t < 16; t++)
for (t = 0; t < 16; t++)
{
W[t] = ((unsigned) context->Message_Block[t * 4]) << 24;
W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16;
@ -349,7 +364,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]);
}
for(t = 16; t < 80; t++)
for (t = 16; t < 80; t++)
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
A = context->Message_Digest[0];
@ -358,7 +373,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
D = context->Message_Digest[3];
E = context->Message_Digest[4];
for(t = 0; t < 20; t++)
for (t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
@ -370,7 +385,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
A = temp;
}
for(t = 20; t < 40; t++)
for (t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
temp &= 0xFFFFFFFF;
@ -381,7 +396,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
A = temp;
}
for(t = 40; t < 60; t++)
for (t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
@ -393,7 +408,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
A = temp;
}
for(t = 60; t < 80; t++)
for (t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
temp &= 0xFFFFFFFF;
@ -418,7 +433,7 @@ static void SHA1ProcessMessageBlock(SHA1Context *context)
context->Message_Block_Index = 0;
}
static void SHA1PadMessage(SHA1Context *context)
static void SHA1PadMessage(struct sha1_context *context)
{
if (!context)
return;
@ -433,13 +448,13 @@ static void SHA1PadMessage(SHA1Context *context)
if (context->Message_Block_Index > 55)
{
while(context->Message_Block_Index < 64)
while (context->Message_Block_Index < 64)
context->Message_Block[context->Message_Block_Index++] = 0;
SHA1ProcessMessageBlock(context);
}
while(context->Message_Block_Index < 56)
while (context->Message_Block_Index < 56)
context->Message_Block[context->Message_Block_Index++] = 0;
/* Store the message length as the last 8 octets */
@ -455,7 +470,7 @@ static void SHA1PadMessage(SHA1Context *context)
SHA1ProcessMessageBlock(context);
}
static int SHA1Result(SHA1Context *context)
static int SHA1Result(struct sha1_context *context)
{
if (context->Corrupted)
return 0;
@ -469,7 +484,7 @@ static int SHA1Result(SHA1Context *context)
return 1;
}
static void SHA1Input(SHA1Context *context,
static void SHA1Input(struct sha1_context *context,
const unsigned char *message_array,
unsigned length)
{
@ -482,7 +497,7 @@ static void SHA1Input(SHA1Context *context,
return;
}
while(length-- && !context->Corrupted)
while (length-- && !context->Corrupted)
{
context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF);
@ -508,7 +523,7 @@ static void SHA1Input(SHA1Context *context,
int sha1_calculate(const char *path, char *result)
{
SHA1Context sha;
struct sha1_context sha;
unsigned char buff[4096];
int rv = 1;
RFILE *fd = filestream_open(path,
@ -529,7 +544,7 @@ int sha1_calculate(const char *path, char *result)
goto error;
SHA1Input(&sha, buff, rv);
}while(rv);
} while (rv);
if (!SHA1Result(&sha))
goto error;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (rbuf.h).
* ---------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __LIBRETRO_SDK_ARRAY_RBUF_H__
#define __LIBRETRO_SDK_ARRAY_RBUF_H__
/*
* This file implements stretchy buffers as invented (?) by Sean Barrett.
* Based on the implementation from the public domain Bitwise project
* by Per Vognsen - https://github.com/pervognsen/bitwise
*
* It's a super simple type safe dynamic array for C with no need
* to predeclare any type or anything.
* The first time an element is added, memory for 16 elements are allocated.
* Then every time length is about to exceed capacity, capacity is doubled.
*
* Be careful not to supply modifying statements to the macro arguments.
* Something like RBUF_REMOVE(buf, i--); would have unintended results.
*
* Sample usage:
*
* mytype_t* buf = NULL;
* RBUF_PUSH(buf, some_element);
* RBUF_PUSH(buf, other_element);
* -- now RBUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element
*
* -- Free allocated memory:
* RBUF_FREE(buf);
* -- now buf == NULL, RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 0
*
* -- Explicitly increase allocated memory and set capacity:
* RBUF_FIT(buf, 100);
* -- now RBUF_LEN(buf) == 0, RBUF_CAP(buf) == 100
*
* -- Resize buffer (does not initialize or zero memory!)
* RBUF_RESIZE(buf, 200);
* -- now RBUF_LEN(buf) == 200, RBUF_CAP(buf) == 200
*
* -- To handle running out of memory:
* bool ran_out_of_memory = !RBUF_TRYFIT(buf, 1000);
* -- before RESIZE or PUSH. When out of memory, buf will stay unmodified.
*/
#include <retro_math.h> /* for MAX */
#include <stdlib.h> /* for malloc, realloc */
#define RBUF__HDR(b) (((struct rbuf__hdr *)(b))-1)
#define RBUF_LEN(b) ((b) ? RBUF__HDR(b)->len : 0)
#define RBUF_CAP(b) ((b) ? RBUF__HDR(b)->cap : 0)
#define RBUF_END(b) ((b) + RBUF_LEN(b))
#define RBUF_SIZEOF(b) ((b) ? RBUF_LEN(b)*sizeof(*b) : 0)
#define RBUF_FREE(b) ((b) ? (free(RBUF__HDR(b)), (b) = NULL) : 0)
#define RBUF_FIT(b, n) ((size_t)(n) <= RBUF_CAP(b) ? 0 : (*(void**)(&(b)) = rbuf__grow((b), (n), sizeof(*(b)))))
#define RBUF_PUSH(b, val) (RBUF_FIT((b), 1 + RBUF_LEN(b)), (b)[RBUF__HDR(b)->len++] = (val))
#define RBUF_POP(b) (b)[--RBUF__HDR(b)->len]
#define RBUF_RESIZE(b, sz) (RBUF_FIT((b), (sz)), ((b) ? RBUF__HDR(b)->len = (sz) : 0))
#define RBUF_CLEAR(b) ((b) ? RBUF__HDR(b)->len = 0 : 0)
#define RBUF_TRYFIT(b, n) (RBUF_FIT((b), (n)), (((b) && RBUF_CAP(b) >= (size_t)(n)) || !(n)))
#define RBUF_REMOVE(b, idx) memmove((b) + (idx), (b) + (idx) + 1, (--RBUF__HDR(b)->len - (idx)) * sizeof(*(b)))
struct rbuf__hdr
{
size_t len;
size_t cap;
};
static void *rbuf__grow(void *buf,
size_t new_len, size_t elem_size)
{
struct rbuf__hdr *new_hdr;
size_t new_cap = MAX(2 * RBUF_CAP(buf), MAX(new_len, 16));
size_t new_size = sizeof(struct rbuf__hdr) + new_cap*elem_size;
if (buf)
{
new_hdr = (struct rbuf__hdr *)realloc(RBUF__HDR(buf), new_size);
if (!new_hdr)
return buf; /* out of memory, return unchanged */
}
else
{
new_hdr = (struct rbuf__hdr *)malloc(new_size);
if (!new_hdr)
return NULL; /* out of memory */
new_hdr->len = 0;
}
new_hdr->cap = new_cap;
return new_hdr + 1;
}
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (audio_mix.h).
@ -40,19 +40,19 @@ RETRO_BEGIN_DECLS
typedef struct
{
double ratio;
void *buf;
int16_t *upsample_buf;
float *float_buf;
float *float_resample_buf;
int16_t *resample_buf;
ssize_t len;
size_t resample_len;
rwav_t *rwav;
int sample_rate;
bool resample;
const retro_resampler_t *resampler;
void *resampler_data;
double ratio;
rwav_t *rwav;
ssize_t len;
size_t resample_len;
int sample_rate;
bool resample;
} audio_chunk_t;
#if defined(__SSE2__)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (audio_mixer.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (audio_resampler.h).
@ -155,7 +155,6 @@ extern retro_resampler_t sinc_resampler;
extern retro_resampler_t CC_resampler;
#endif
extern retro_resampler_t nearest_resampler;
extern retro_resampler_t null_resampler;
/**
* audio_resampler_driver_find_handle:

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (float_to_s16.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (s16_to_float.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (dsp_filter.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2018 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (boolean.h).

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010-2019 The RetroArch team
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------
* The following license statement only applies to this file (cdrom.h).
@ -62,10 +62,10 @@ typedef struct
typedef struct
{
char drive;
cdrom_track_t track[99]; /* unsigned alignment */
cdrom_group_timeouts_t timeouts; /* unsigned short alignment */
unsigned char num_tracks;
cdrom_group_timeouts_t timeouts;
cdrom_track_t track[99];
char drive;
} cdrom_toc_t;
void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);

Some files were not shown because too many files have changed in this diff Show More