Replaced AudioToolbox converter process with homebrew solution, using the RetroArch sinc resampler
parent
c8301a9868
commit
c4c9a741ef
|
@ -466,6 +466,8 @@ void* kAppControllerContext = &kAppControllerContext;
|
||||||
|
|
||||||
[userDefaultsValuesDict setObject:@"cubic" forKey:@"resampling"];
|
[userDefaultsValuesDict setObject:@"cubic" forKey:@"resampling"];
|
||||||
|
|
||||||
|
[userDefaultsValuesDict setObject:@"normal" forKey:@"outputResampling"];
|
||||||
|
|
||||||
[userDefaultsValuesDict setObject:[NSNumber numberWithInteger:CogStatusStopped] forKey:@"lastPlaybackStatus"];
|
[userDefaultsValuesDict setObject:[NSNumber numberWithInteger:CogStatusStopped] forKey:@"lastPlaybackStatus"];
|
||||||
[userDefaultsValuesDict setObject:[NSNumber numberWithInteger:-1] forKey:@"lastTrackPlaying"];
|
[userDefaultsValuesDict setObject:[NSNumber numberWithInteger:-1] forKey:@"lastTrackPlaying"];
|
||||||
[userDefaultsValuesDict setObject:[NSNumber numberWithDouble:0] forKey:@"lastTrackPosition"];
|
[userDefaultsValuesDict setObject:[NSNumber numberWithDouble:0] forKey:@"lastTrackPosition"];
|
||||||
|
|
|
@ -60,9 +60,6 @@
|
||||||
|
|
||||||
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused andSeekTo:(double)time
|
- (void)play:(NSURL *)url withUserInfo:(id)userInfo withRGInfo:(NSDictionary *)rgi startPaused:(BOOL)paused andSeekTo:(double)time
|
||||||
{
|
{
|
||||||
if (output) {
|
|
||||||
[output close];
|
|
||||||
}
|
|
||||||
@synchronized(chainQueue) {
|
@synchronized(chainQueue) {
|
||||||
for (id anObject in chainQueue)
|
for (id anObject in chainQueue)
|
||||||
{
|
{
|
||||||
|
@ -240,7 +237,6 @@
|
||||||
{
|
{
|
||||||
//Need to reset everything's buffers, and then seek?
|
//Need to reset everything's buffers, and then seek?
|
||||||
/*HACK TO TEST HOW WELL THIS WOULD WORK*/
|
/*HACK TO TEST HOW WELL THIS WOULD WORK*/
|
||||||
[self play:[[bufferChain inputNode] stealDecoder] startPaused:paused];
|
|
||||||
[output seek:time];
|
[output seek:time];
|
||||||
[bufferChain seek:time];
|
[bufferChain seek:time];
|
||||||
/*END HACK*/
|
/*END HACK*/
|
||||||
|
|
|
@ -12,32 +12,41 @@
|
||||||
#import <AudioToolbox/AudioToolbox.h>
|
#import <AudioToolbox/AudioToolbox.h>
|
||||||
#import <AudioUnit/AudioUnit.h>
|
#import <AudioUnit/AudioUnit.h>
|
||||||
|
|
||||||
|
#import <audio/audio_resampler.h>
|
||||||
|
|
||||||
#import "Node.h"
|
#import "Node.h"
|
||||||
|
|
||||||
@interface ConverterNode : Node {
|
@interface ConverterNode : Node {
|
||||||
NSDictionary * rgInfo;
|
NSDictionary * rgInfo;
|
||||||
|
|
||||||
AudioConverterRef converter;
|
void *resampler_data;
|
||||||
AudioConverterRef converterFloat;
|
const retro_resampler_t *resampler;
|
||||||
void *callbackBuffer;
|
|
||||||
size_t callbackBufferSize;
|
void *inputBuffer;
|
||||||
|
size_t inputBufferSize;
|
||||||
|
size_t inpSize, inpOffset;
|
||||||
|
|
||||||
BOOL stopping;
|
BOOL stopping;
|
||||||
BOOL convertEntered;
|
BOOL convertEntered;
|
||||||
BOOL ACInputEntered;
|
BOOL emittingSilence;
|
||||||
BOOL ACFloatEntered;
|
|
||||||
|
|
||||||
float sampleRatio;
|
BOOL skipResampler;
|
||||||
|
|
||||||
|
ssize_t latencyStarted;
|
||||||
|
size_t latencyEaten;
|
||||||
|
BOOL latencyPostfill;
|
||||||
|
|
||||||
|
double sampleRatio;
|
||||||
|
|
||||||
float volumeScale;
|
float volumeScale;
|
||||||
|
|
||||||
void *floatBuffer;
|
void *floatBuffer;
|
||||||
size_t floatBufferSize;
|
size_t floatBufferSize;
|
||||||
int floatSize, floatOffset;
|
size_t floatSize, floatOffset;
|
||||||
|
|
||||||
AudioStreamBasicDescription inputFormat;
|
AudioStreamBasicDescription inputFormat;
|
||||||
AudioStreamBasicDescription floatFormat;
|
AudioStreamBasicDescription floatFormat;
|
||||||
AudioStreamBasicDescription dmFloatFormat; // downmixed float format
|
AudioStreamBasicDescription dmFloatFormat; // downmixed/upmixed float format
|
||||||
AudioStreamBasicDescription outputFormat;
|
AudioStreamBasicDescription outputFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
|
|
||||||
#import "Logging.h"
|
#import "Logging.h"
|
||||||
|
|
||||||
|
#import <audio/conversion/s16_to_float.h>
|
||||||
|
#import <audio/conversion/s32_to_float.h>
|
||||||
|
|
||||||
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||||
{
|
{
|
||||||
if (!inDesc) {
|
if (!inDesc) {
|
||||||
|
@ -37,19 +40,25 @@ void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
|
||||||
{
|
{
|
||||||
rgInfo = nil;
|
rgInfo = nil;
|
||||||
|
|
||||||
converterFloat = NULL;
|
resampler = NULL;
|
||||||
converter = NULL;
|
resampler_data = NULL;
|
||||||
|
inputBuffer = NULL;
|
||||||
|
inputBufferSize = 0;
|
||||||
floatBuffer = NULL;
|
floatBuffer = NULL;
|
||||||
floatBufferSize = 0;
|
floatBufferSize = 0;
|
||||||
callbackBuffer = NULL;
|
|
||||||
callbackBufferSize = 0;
|
|
||||||
|
|
||||||
stopping = NO;
|
stopping = NO;
|
||||||
convertEntered = NO;
|
convertEntered = NO;
|
||||||
ACInputEntered = NO;
|
emittingSilence = NO;
|
||||||
ACFloatEntered = NO;
|
|
||||||
|
skipResampler = NO;
|
||||||
|
|
||||||
|
latencyStarted = -1;
|
||||||
|
latencyEaten = 0;
|
||||||
|
latencyPostfill = NO;
|
||||||
|
|
||||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:nil];
|
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.volumeScaling" options:0 context:nil];
|
||||||
|
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.outputResampling" options:0 context:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -86,10 +95,10 @@ static const float STEREO_DOWNMIX[8-2][8][2]={
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void downmix_to_stereo(float * buffer, int channels, int count)
|
static void downmix_to_stereo(float * buffer, int channels, size_t count)
|
||||||
{
|
{
|
||||||
if (channels >= 3 && channels <= 8)
|
if (channels >= 3 && channels <= 8)
|
||||||
for (int i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
float left = 0, right = 0;
|
float left = 0, right = 0;
|
||||||
for (int j = 0; j < channels; ++j)
|
for (int j = 0; j < channels; ++j)
|
||||||
|
@ -102,7 +111,7 @@ static void downmix_to_stereo(float * buffer, int channels, int count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void downmix_to_mono(float * buffer, int channels, int count)
|
static void downmix_to_mono(float * buffer, int channels, size_t count)
|
||||||
{
|
{
|
||||||
if (channels >= 3 && channels <= 8)
|
if (channels >= 3 && channels <= 8)
|
||||||
{
|
{
|
||||||
|
@ -110,7 +119,7 @@ static void downmix_to_mono(float * buffer, int channels, int count)
|
||||||
channels = 2;
|
channels = 2;
|
||||||
}
|
}
|
||||||
float invchannels = 1.0 / (float)channels;
|
float invchannels = 1.0 / (float)channels;
|
||||||
for (int i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
float sample = 0;
|
float sample = 0;
|
||||||
for (int j = 0; j < channels; ++j)
|
for (int j = 0; j < channels; ++j)
|
||||||
|
@ -121,9 +130,9 @@ static void downmix_to_mono(float * buffer, int channels, int count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void upmix(float * buffer, int inchannels, int outchannels, int count)
|
static void upmix(float * buffer, int inchannels, int outchannels, size_t count)
|
||||||
{
|
{
|
||||||
for (int i = count - 1; i >= 0; --i)
|
for (ssize_t i = count - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
if (inchannels == 1 && outchannels == 2)
|
if (inchannels == 1 && outchannels == 2)
|
||||||
{
|
{
|
||||||
|
@ -231,105 +240,105 @@ static void upmix(float * buffer, int inchannels, int outchannels, int count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scale_by_volume(float * buffer, int count, float volume)
|
static void scale_by_volume(float * buffer, size_t count, float volume)
|
||||||
{
|
{
|
||||||
if ( volume != 1.0 )
|
if ( volume != 1.0 )
|
||||||
for (int i = 0; i < count; ++i )
|
for (size_t i = 0; i < count; ++i )
|
||||||
buffer[i] *= volume;
|
buffer[i] *= volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
//called from the complexfill when the audio is converted...good clean fun
|
static void convert_u8_to_s16(int16_t *output, uint8_t *input, size_t count)
|
||||||
static OSStatus ACInputProc(AudioConverterRef inAudioConverter,
|
|
||||||
UInt32* ioNumberDataPackets,
|
|
||||||
AudioBufferList* ioData,
|
|
||||||
AudioStreamPacketDescription** outDataPacketDescription,
|
|
||||||
void* inUserData)
|
|
||||||
{
|
{
|
||||||
ConverterNode *converter = (__bridge ConverterNode *)inUserData;
|
for (size_t i = 0; i < count; ++i )
|
||||||
OSStatus err = noErr;
|
|
||||||
int amountToWrite;
|
|
||||||
int amountRead;
|
|
||||||
|
|
||||||
if (converter->stopping || [converter shouldContinue] == NO || [converter endOfStream] == YES)
|
|
||||||
{
|
{
|
||||||
ioData->mBuffers[0].mDataByteSize = 0;
|
uint16_t sample = (input[i] << 8) | input[i];
|
||||||
*ioNumberDataPackets = 0;
|
sample ^= 0x8080;
|
||||||
|
output[i] = (int16_t)(sample);
|
||||||
return noErr;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converter->ACInputEntered = YES;
|
static void convert_s8_to_s16(int16_t *output, uint8_t *input, size_t count)
|
||||||
|
|
||||||
amountToWrite = (*ioNumberDataPackets)*(converter->inputFormat.mBytesPerPacket);
|
|
||||||
|
|
||||||
if (!converter->callbackBuffer || converter->callbackBufferSize < amountToWrite)
|
|
||||||
converter->callbackBuffer = realloc(converter->callbackBuffer, converter->callbackBufferSize = amountToWrite + 1024);
|
|
||||||
|
|
||||||
amountRead = [converter readData:converter->callbackBuffer amount:amountToWrite];
|
|
||||||
if (amountRead == 0 && [converter endOfStream] == NO)
|
|
||||||
{
|
{
|
||||||
ioData->mBuffers[0].mDataByteSize = 0;
|
for (size_t i = 0; i < count; ++i )
|
||||||
*ioNumberDataPackets = 0;
|
{
|
||||||
|
uint16_t sample = (input[i] << 8) | input[i];
|
||||||
converter->ACInputEntered = NO;
|
output[i] = (int16_t)(sample);
|
||||||
|
}
|
||||||
return 100; //Keep asking for data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ioData->mBuffers[0].mData = converter->callbackBuffer;
|
static void convert_u16_to_s16(int16_t *buffer, size_t count)
|
||||||
ioData->mBuffers[0].mDataByteSize = amountRead;
|
{
|
||||||
ioData->mBuffers[0].mNumberChannels = (converter->inputFormat.mChannelsPerFrame);
|
for (size_t i = 0; i < count; ++i )
|
||||||
ioData->mNumberBuffers = 1;
|
{
|
||||||
|
buffer[i] ^= 0x8000;
|
||||||
converter->ACInputEntered = NO;
|
}
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus ACFloatProc(AudioConverterRef inAudioConverter,
|
static void convert_s24_to_s32(int32_t *output, uint8_t *input, size_t count)
|
||||||
UInt32* ioNumberDataPackets,
|
|
||||||
AudioBufferList* ioData,
|
|
||||||
AudioStreamPacketDescription** outDataPacketDescription,
|
|
||||||
void* inUserData)
|
|
||||||
{
|
{
|
||||||
ConverterNode *converter = (__bridge ConverterNode *)inUserData;
|
for (size_t i = 0; i < count; ++i )
|
||||||
OSStatus err = noErr;
|
|
||||||
int amountToWrite;
|
|
||||||
|
|
||||||
if (converter->stopping || [converter shouldContinue] == NO)
|
|
||||||
{
|
{
|
||||||
ioData->mBuffers[0].mDataByteSize = 0;
|
int32_t sample = (input[i * 3] << 8) | (input[i * 3 + 1] << 16) | (input[i * 3 + 2] << 24);
|
||||||
*ioNumberDataPackets = 0;
|
output[i] = sample;
|
||||||
|
}
|
||||||
return noErr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
converter->ACFloatEntered = YES;
|
static void convert_u24_to_s32(int32_t *output, uint8_t *input, size_t count)
|
||||||
|
|
||||||
amountToWrite = (*ioNumberDataPackets) * (converter->dmFloatFormat.mBytesPerPacket);
|
|
||||||
|
|
||||||
if ( amountToWrite + converter->floatOffset > converter->floatSize )
|
|
||||||
{
|
{
|
||||||
amountToWrite = converter->floatSize - converter->floatOffset;
|
for (size_t i = 0; i < count; ++i )
|
||||||
*ioNumberDataPackets = amountToWrite / (converter->dmFloatFormat.mBytesPerPacket);
|
{
|
||||||
|
int32_t sample = (input[i * 3] << 8) | (input[i * 3 + 1] << 16) | (input[i * 3 + 2] << 24);
|
||||||
|
output[i] = sample ^ 0x80000000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ioData->mBuffers[0].mData = converter->floatBuffer + converter->floatOffset;
|
static void convert_u32_to_s32(int32_t *buffer, size_t count)
|
||||||
ioData->mBuffers[0].mDataByteSize = amountToWrite;
|
|
||||||
ioData->mBuffers[0].mNumberChannels = (converter->dmFloatFormat.mChannelsPerFrame);
|
|
||||||
ioData->mNumberBuffers = 1;
|
|
||||||
|
|
||||||
if (amountToWrite == 0)
|
|
||||||
{
|
{
|
||||||
converter->ACFloatEntered = NO;
|
for (size_t i = 0; i < count; ++i )
|
||||||
return 100;
|
{
|
||||||
|
buffer[i] ^= 0x80000000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converter->floatOffset += amountToWrite;
|
static void convert_be_to_le(uint8_t *buffer, size_t bitsPerSample, size_t bytes)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
uint8_t temp;
|
||||||
|
bitsPerSample = (bitsPerSample + 7) / 8;
|
||||||
|
switch (bitsPerSample) {
|
||||||
|
case 2:
|
||||||
|
for (i = 0; i < bytes; i += 2)
|
||||||
|
{
|
||||||
|
temp = buffer[1];
|
||||||
|
buffer[1] = buffer[0];
|
||||||
|
buffer[0] = temp;
|
||||||
|
buffer += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
converter->ACFloatEntered = NO;
|
case 3:
|
||||||
|
for (i = 0; i < bytes; i += 3)
|
||||||
|
{
|
||||||
|
temp = buffer[2];
|
||||||
|
buffer[2] = buffer[0];
|
||||||
|
buffer[0] = temp;
|
||||||
|
buffer += 3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
return err;
|
case 4:
|
||||||
|
for (i = 0; i < bytes; i += 4)
|
||||||
|
{
|
||||||
|
temp = buffer[3];
|
||||||
|
buffer[3] = buffer[0];
|
||||||
|
buffer[0] = temp;
|
||||||
|
temp = buffer[2];
|
||||||
|
buffer[2] = buffer[1];
|
||||||
|
buffer[1] = temp;
|
||||||
|
buffer += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)process
|
-(void)process
|
||||||
|
@ -345,18 +354,22 @@ static OSStatus ACFloatProc(AudioConverterRef inAudioConverter,
|
||||||
|
|
||||||
- (int)convert:(void *)dest amount:(int)amount
|
- (int)convert:(void *)dest amount:(int)amount
|
||||||
{
|
{
|
||||||
AudioBufferList ioData;
|
|
||||||
UInt32 ioNumberPackets;
|
UInt32 ioNumberPackets;
|
||||||
OSStatus err;
|
|
||||||
int amountReadFromFC;
|
int amountReadFromFC;
|
||||||
int amountRead = 0;
|
int amountRead = 0;
|
||||||
|
|
||||||
|
if (emittingSilence)
|
||||||
|
{
|
||||||
|
memset(dest, 0, amount);
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
if (stopping)
|
if (stopping)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
convertEntered = YES;
|
convertEntered = YES;
|
||||||
|
|
||||||
tryagain2:
|
tryagain:
|
||||||
if (stopping || [self shouldContinue] == NO)
|
if (stopping || [self shouldContinue] == NO)
|
||||||
{
|
{
|
||||||
convertEntered = NO;
|
convertEntered = NO;
|
||||||
|
@ -365,51 +378,195 @@ tryagain2:
|
||||||
|
|
||||||
amountReadFromFC = 0;
|
amountReadFromFC = 0;
|
||||||
|
|
||||||
if (floatOffset == floatSize) {
|
while (inpOffset == inpSize) {
|
||||||
UInt32 ioWantedNumberPackets;
|
size_t samplesRead = 0;
|
||||||
|
|
||||||
ioNumberPackets = amount / outputFormat.mBytesPerPacket;
|
// Approximately the most we want on input
|
||||||
|
ioNumberPackets = (amount - amountRead) / outputFormat.mBytesPerPacket;
|
||||||
|
|
||||||
|
size_t newSize = ioNumberPackets * floatFormat.mBytesPerPacket;
|
||||||
|
if (!inputBuffer || inputBufferSize < newSize)
|
||||||
|
inputBuffer = realloc( inputBuffer, inputBufferSize = newSize * 3 );
|
||||||
|
|
||||||
|
if (stopping || [self shouldContinue] == NO || [self endOfStream] == YES)
|
||||||
|
{
|
||||||
|
if (!skipResampler && !latencyPostfill)
|
||||||
|
{
|
||||||
|
ioNumberPackets = (int)resampler->latency(resampler_data);
|
||||||
|
newSize = ioNumberPackets * floatFormat.mBytesPerPacket;
|
||||||
|
if (!inputBuffer || inputBufferSize < newSize)
|
||||||
|
inputBuffer = realloc( inputBuffer, inputBufferSize = newSize * 64);
|
||||||
|
|
||||||
|
inpSize = newSize;
|
||||||
|
inpOffset = 0;
|
||||||
|
latencyPostfill = YES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
convertEntered = NO;
|
||||||
|
return amountRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t amountToWrite = ioNumberPackets * inputFormat.mBytesPerPacket;
|
||||||
|
size_t amountToSkip = 0;
|
||||||
|
|
||||||
|
if (!skipResampler)
|
||||||
|
{
|
||||||
|
if (latencyStarted < 0)
|
||||||
|
{
|
||||||
|
latencyStarted = resampler->latency(resampler_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latencyStarted)
|
||||||
|
{
|
||||||
|
size_t latencyToWrite = latencyStarted * inputFormat.mBytesPerPacket;
|
||||||
|
if (latencyToWrite > amountToWrite)
|
||||||
|
latencyToWrite = amountToWrite;
|
||||||
|
|
||||||
|
if (inputFormat.mBitsPerChannel <= 8)
|
||||||
|
memset(inputBuffer, 0x80, latencyToWrite);
|
||||||
|
else
|
||||||
|
memset(inputBuffer, 0, latencyToWrite);
|
||||||
|
|
||||||
|
amountToSkip = latencyToWrite;
|
||||||
|
amountToWrite -= amountToSkip;
|
||||||
|
|
||||||
|
latencyEaten = latencyStarted * sampleRatio;
|
||||||
|
|
||||||
|
latencyStarted -= latencyToWrite / inputFormat.mBytesPerPacket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytesReadFromInput = [self readData:inputBuffer + amountToSkip amount:(int)amountToWrite] + amountToSkip;
|
||||||
|
|
||||||
|
if (bytesReadFromInput &&
|
||||||
|
(inputFormat.mFormatFlags & kAudioFormatFlagIsBigEndian))
|
||||||
|
{
|
||||||
|
// Time for endian swap!
|
||||||
|
convert_be_to_le(inputBuffer, inputFormat.mBitsPerChannel, bytesReadFromInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesReadFromInput &&
|
||||||
|
!(inputFormat.mFormatFlags & kAudioFormatFlagIsFloat))
|
||||||
|
{
|
||||||
|
size_t bitsPerSample = inputFormat.mBitsPerChannel;
|
||||||
|
BOOL isUnsigned = !(inputFormat.mFormatFlags & kAudioFormatFlagIsSignedInteger);
|
||||||
|
BOOL isFloat = NO;
|
||||||
|
if (bitsPerSample <= 8) {
|
||||||
|
samplesRead = bytesReadFromInput;
|
||||||
|
if (isUnsigned)
|
||||||
|
convert_s8_to_s16(inputBuffer + bytesReadFromInput, inputBuffer, samplesRead);
|
||||||
|
else
|
||||||
|
convert_u8_to_s16(inputBuffer + bytesReadFromInput, inputBuffer, samplesRead);
|
||||||
|
memmove(inputBuffer, inputBuffer + bytesReadFromInput, samplesRead * 2);
|
||||||
|
bitsPerSample = 16;
|
||||||
|
bytesReadFromInput = samplesRead * 2;
|
||||||
|
isUnsigned = NO;
|
||||||
|
}
|
||||||
|
if (bitsPerSample <= 16) {
|
||||||
|
samplesRead = bytesReadFromInput / 2;
|
||||||
|
if (isUnsigned)
|
||||||
|
convert_u16_to_s16(inputBuffer, samplesRead);
|
||||||
|
convert_s16_to_float(inputBuffer + bytesReadFromInput, inputBuffer, samplesRead, 1.0);
|
||||||
|
memmove(inputBuffer, inputBuffer + bytesReadFromInput, samplesRead * sizeof(float));
|
||||||
|
bitsPerSample = 32;
|
||||||
|
bytesReadFromInput = samplesRead * sizeof(float);
|
||||||
|
isUnsigned = NO;
|
||||||
|
isFloat = YES;
|
||||||
|
}
|
||||||
|
else if (bitsPerSample <= 24) {
|
||||||
|
samplesRead = bytesReadFromInput / 3;
|
||||||
|
if (isUnsigned)
|
||||||
|
convert_u24_to_s32(inputBuffer + bytesReadFromInput, inputBuffer, samplesRead);
|
||||||
|
else
|
||||||
|
convert_s24_to_s32(inputBuffer + bytesReadFromInput, inputBuffer, samplesRead);
|
||||||
|
memmove(inputBuffer, inputBuffer + bytesReadFromInput, samplesRead * 4);
|
||||||
|
bitsPerSample = 32;
|
||||||
|
bytesReadFromInput = samplesRead * 4;
|
||||||
|
isUnsigned = NO;
|
||||||
|
}
|
||||||
|
if (!isFloat && bitsPerSample <= 32) {
|
||||||
|
samplesRead = bytesReadFromInput / 4;
|
||||||
|
if (isUnsigned)
|
||||||
|
convert_u32_to_s32(inputBuffer, samplesRead);
|
||||||
|
convert_s32_to_float(inputBuffer + bytesReadFromInput, inputBuffer, samplesRead, 1.0);
|
||||||
|
memmove(inputBuffer, inputBuffer + bytesReadFromInput, samplesRead * sizeof(float));
|
||||||
|
bitsPerSample = 32;
|
||||||
|
bytesReadFromInput = samplesRead * sizeof(float);
|
||||||
|
isUnsigned = NO;
|
||||||
|
isFloat = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input now contains bytesReadFromInput worth of floats, in the input sample rate
|
||||||
|
inpSize = bytesReadFromInput;
|
||||||
|
inpOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (floatOffset == floatSize)
|
||||||
|
{
|
||||||
|
struct resampler_data src_data;
|
||||||
|
|
||||||
|
size_t inputSamples = (inpSize - inpOffset) / floatFormat.mBytesPerPacket;
|
||||||
|
|
||||||
|
ioNumberPackets = (UInt32)inputSamples;
|
||||||
|
|
||||||
ioNumberPackets = (UInt32)((float)ioNumberPackets * sampleRatio);
|
ioNumberPackets = (UInt32)((float)ioNumberPackets * sampleRatio);
|
||||||
ioNumberPackets = (ioNumberPackets + 255) & ~255;
|
ioNumberPackets = (ioNumberPackets + 255) & ~255;
|
||||||
|
|
||||||
ioWantedNumberPackets = ioNumberPackets;
|
|
||||||
|
|
||||||
size_t newSize = ioNumberPackets * floatFormat.mBytesPerPacket;
|
size_t newSize = ioNumberPackets * floatFormat.mBytesPerPacket;
|
||||||
if (newSize < (ioNumberPackets * dmFloatFormat.mBytesPerPacket))
|
if (newSize < (ioNumberPackets * dmFloatFormat.mBytesPerPacket))
|
||||||
newSize = ioNumberPackets * dmFloatFormat.mBytesPerPacket;
|
newSize = ioNumberPackets * dmFloatFormat.mBytesPerPacket;
|
||||||
if (!floatBuffer || floatBufferSize < newSize)
|
if (!floatBuffer || floatBufferSize < newSize)
|
||||||
floatBuffer = realloc( floatBuffer, floatBufferSize = newSize + 1024 );
|
floatBuffer = realloc( floatBuffer, floatBufferSize = newSize * 3 );
|
||||||
ioData.mBuffers[0].mData = floatBuffer;
|
|
||||||
ioData.mBuffers[0].mDataByteSize = ioNumberPackets * floatFormat.mBytesPerPacket;
|
|
||||||
ioData.mBuffers[0].mNumberChannels = floatFormat.mChannelsPerFrame;
|
|
||||||
ioData.mNumberBuffers = 1;
|
|
||||||
|
|
||||||
tryagain:
|
|
||||||
if (stopping)
|
if (stopping)
|
||||||
{
|
{
|
||||||
convertEntered = NO;
|
convertEntered = NO;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = AudioConverterFillComplexBuffer(converterFloat, ACInputProc, (__bridge void * _Nullable)(self), &ioNumberPackets, &ioData, NULL);
|
src_data.data_out = floatBuffer;
|
||||||
amountReadFromFC += ioNumberPackets * floatFormat.mBytesPerPacket;
|
src_data.output_frames = 0;
|
||||||
if (err == 100)
|
|
||||||
|
src_data.data_in = (float*)(((uint8_t*)inputBuffer) + inpOffset);
|
||||||
|
src_data.input_frames = inputSamples;
|
||||||
|
|
||||||
|
src_data.ratio = sampleRatio;
|
||||||
|
|
||||||
|
if (!skipResampler)
|
||||||
{
|
{
|
||||||
ioData.mBuffers[0].mData = (void *)(((uint8_t*)floatBuffer) + amountReadFromFC);
|
resampler->process(resampler_data, &src_data);
|
||||||
ioNumberPackets = ioWantedNumberPackets - ioNumberPackets;
|
|
||||||
ioWantedNumberPackets = ioNumberPackets;
|
|
||||||
ioData.mBuffers[0].mDataByteSize = ioNumberPackets * floatFormat.mBytesPerPacket;
|
|
||||||
usleep(10000);
|
|
||||||
goto tryagain;
|
|
||||||
}
|
}
|
||||||
else if (err != noErr && err != kAudioConverterErr_InvalidInputSize)
|
else
|
||||||
{
|
{
|
||||||
DLog(@"Error: %i", err);
|
memcpy(src_data.data_out, src_data.data_in, inputSamples * floatFormat.mBytesPerPacket);
|
||||||
convertEntered = NO;
|
src_data.output_frames = inputSamples;
|
||||||
return amountRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inpOffset += inputSamples * floatFormat.mBytesPerPacket;
|
||||||
|
|
||||||
|
if (!skipResampler && latencyEaten)
|
||||||
|
{
|
||||||
|
if (src_data.output_frames > latencyEaten)
|
||||||
|
{
|
||||||
|
src_data.output_frames -= latencyEaten;
|
||||||
|
memmove(src_data.data_out, src_data.data_out + latencyEaten * inputFormat.mChannelsPerFrame, src_data.output_frames * floatFormat.mBytesPerPacket);
|
||||||
|
latencyEaten = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
latencyEaten -= src_data.output_frames;
|
||||||
|
src_data.output_frames = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
amountReadFromFC = (int)(src_data.output_frames * floatFormat.mBytesPerPacket);
|
||||||
|
|
||||||
|
scale_by_volume( (float*) floatBuffer, amountReadFromFC / sizeof(float), volumeScale);
|
||||||
|
|
||||||
if ( inputFormat.mChannelsPerFrame > 2 && outputFormat.mChannelsPerFrame == 2 )
|
if ( inputFormat.mChannelsPerFrame > 2 && outputFormat.mChannelsPerFrame == 2 )
|
||||||
{
|
{
|
||||||
int samples = amountReadFromFC / floatFormat.mBytesPerFrame;
|
int samples = amountReadFromFC / floatFormat.mBytesPerFrame;
|
||||||
|
@ -429,40 +586,21 @@ tryagain2:
|
||||||
amountReadFromFC = samples * sizeof(float) * outputFormat.mChannelsPerFrame;
|
amountReadFromFC = samples * sizeof(float) * outputFormat.mChannelsPerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
scale_by_volume( (float*) floatBuffer, amountReadFromFC / sizeof(float), volumeScale);
|
|
||||||
|
|
||||||
floatSize = amountReadFromFC;
|
floatSize = amountReadFromFC;
|
||||||
floatOffset = 0;
|
floatOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ioNumberPackets = amount / outputFormat.mBytesPerPacket;
|
if (floatOffset == floatSize)
|
||||||
ioData.mBuffers[0].mData = dest + amountRead;
|
goto tryagain;
|
||||||
ioData.mBuffers[0].mDataByteSize = amount - amountRead;
|
|
||||||
ioData.mBuffers[0].mNumberChannels = outputFormat.mChannelsPerFrame;
|
|
||||||
ioData.mNumberBuffers = 1;
|
|
||||||
|
|
||||||
if (stopping)
|
ioNumberPackets = (amount - amountRead);
|
||||||
{
|
if (ioNumberPackets > (floatSize - floatOffset))
|
||||||
convertEntered = NO;
|
ioNumberPackets = (UInt32)(floatSize - floatOffset);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = AudioConverterFillComplexBuffer(converter, ACFloatProc, (__bridge void *)(self), &ioNumberPackets, &ioData, NULL);
|
memcpy(dest + amountRead, floatBuffer + floatOffset, ioNumberPackets);
|
||||||
amountRead += ioNumberPackets * outputFormat.mBytesPerPacket;
|
|
||||||
if (err == 100)
|
|
||||||
{
|
|
||||||
if ([self endOfStream] == YES)
|
|
||||||
{
|
|
||||||
convertEntered = NO;
|
|
||||||
return amountRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
goto tryagain2;
|
floatOffset += ioNumberPackets;
|
||||||
}
|
amountRead += ioNumberPackets;
|
||||||
else if (err != noErr && err != kAudioConverterErr_InvalidInputSize)
|
|
||||||
{
|
|
||||||
DLog(@"Error: %i", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
convertEntered = NO;
|
convertEntered = NO;
|
||||||
return amountRead;
|
return amountRead;
|
||||||
|
@ -478,6 +616,11 @@ tryagain2:
|
||||||
//User reset the volume scaling option
|
//User reset the volume scaling option
|
||||||
[self refreshVolumeScaling];
|
[self refreshVolumeScaling];
|
||||||
}
|
}
|
||||||
|
else if ([keyPath isEqual:@"values.outputResampling"]) {
|
||||||
|
// Reset resampler
|
||||||
|
if (resampler && resampler_data)
|
||||||
|
[self inputFormatDidChange:inputFormat];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float db_to_scale(float db)
|
static float db_to_scale(float db)
|
||||||
|
@ -532,89 +675,73 @@ static float db_to_scale(float db)
|
||||||
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inf outputFormat:(AudioStreamBasicDescription)outf
|
- (BOOL)setupWithInputFormat:(AudioStreamBasicDescription)inf outputFormat:(AudioStreamBasicDescription)outf
|
||||||
{
|
{
|
||||||
//Make the converter
|
//Make the converter
|
||||||
OSStatus stat = noErr;
|
|
||||||
|
|
||||||
stopping = NO;
|
|
||||||
convertEntered = NO;
|
|
||||||
ACInputEntered = NO;
|
|
||||||
ACFloatEntered = NO;
|
|
||||||
|
|
||||||
inputFormat = inf;
|
inputFormat = inf;
|
||||||
outputFormat = outf;
|
outputFormat = outf;
|
||||||
|
|
||||||
|
// These are really placeholders, as we're doing everything internally now
|
||||||
|
|
||||||
floatFormat = inputFormat;
|
floatFormat = inputFormat;
|
||||||
floatFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
|
floatFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
|
||||||
floatFormat.mBitsPerChannel = 32;
|
floatFormat.mBitsPerChannel = 32;
|
||||||
floatFormat.mBytesPerFrame = (32/8)*floatFormat.mChannelsPerFrame;
|
floatFormat.mBytesPerFrame = (32/8)*floatFormat.mChannelsPerFrame;
|
||||||
floatFormat.mBytesPerPacket = floatFormat.mBytesPerFrame * floatFormat.mFramesPerPacket;
|
floatFormat.mBytesPerPacket = floatFormat.mBytesPerFrame * floatFormat.mFramesPerPacket;
|
||||||
|
|
||||||
|
inpOffset = 0;
|
||||||
|
inpSize = 0;
|
||||||
|
|
||||||
floatOffset = 0;
|
floatOffset = 0;
|
||||||
floatSize = 0;
|
floatSize = 0;
|
||||||
|
|
||||||
stat = AudioConverterNew( &inputFormat, &floatFormat, &converterFloat );
|
// This is a post resampler, post-down/upmix format
|
||||||
if (stat != noErr)
|
|
||||||
{
|
|
||||||
ALog(@"Error creating converter %i", stat);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmFloatFormat = floatFormat;
|
dmFloatFormat = floatFormat;
|
||||||
|
dmFloatFormat.mSampleRate = outputFormat.mSampleRate;
|
||||||
dmFloatFormat.mChannelsPerFrame = outputFormat.mChannelsPerFrame;
|
dmFloatFormat.mChannelsPerFrame = outputFormat.mChannelsPerFrame;
|
||||||
dmFloatFormat.mBytesPerFrame = (32/8)*dmFloatFormat.mChannelsPerFrame;
|
dmFloatFormat.mBytesPerFrame = (32/8)*dmFloatFormat.mChannelsPerFrame;
|
||||||
dmFloatFormat.mBytesPerPacket = dmFloatFormat.mBytesPerFrame * floatFormat.mFramesPerPacket;
|
dmFloatFormat.mBytesPerPacket = dmFloatFormat.mBytesPerFrame * floatFormat.mFramesPerPacket;
|
||||||
|
|
||||||
stat = AudioConverterNew ( &dmFloatFormat, &outputFormat, &converter );
|
convert_s16_to_float_init_simd();
|
||||||
if (stat != noErr)
|
convert_s32_to_float_init_simd();
|
||||||
|
|
||||||
|
skipResampler = outputFormat.mSampleRate == inputFormat.mSampleRate;
|
||||||
|
|
||||||
|
sampleRatio = (double)outputFormat.mSampleRate / (double)inputFormat.mSampleRate;
|
||||||
|
|
||||||
|
if (!skipResampler)
|
||||||
|
{
|
||||||
|
enum resampler_quality quality = RESAMPLER_QUALITY_DONTCARE;
|
||||||
|
|
||||||
|
NSString * resampling = [[NSUserDefaults standardUserDefaults] stringForKey:@"outputResampling"];
|
||||||
|
if ([resampling isEqualToString:@"lowest"])
|
||||||
|
quality = RESAMPLER_QUALITY_LOWEST;
|
||||||
|
else if ([resampling isEqualToString:@"lower"])
|
||||||
|
quality = RESAMPLER_QUALITY_LOWER;
|
||||||
|
else if ([resampling isEqualToString:@"normal"])
|
||||||
|
quality = RESAMPLER_QUALITY_NORMAL;
|
||||||
|
else if ([resampling isEqualToString:@"higher"])
|
||||||
|
quality = RESAMPLER_QUALITY_HIGHER;
|
||||||
|
else if ([resampling isEqualToString:@"highest"])
|
||||||
|
quality = RESAMPLER_QUALITY_HIGHEST;
|
||||||
|
|
||||||
|
if (!retro_resampler_realloc(&resampler_data, &resampler, "sinc", quality, inputFormat.mChannelsPerFrame, sampleRatio))
|
||||||
{
|
{
|
||||||
ALog(@"Error creating converter %i", stat);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
latencyStarted = -1;
|
||||||
// These mappings don't do what I want, so avoid them.
|
latencyEaten = 0;
|
||||||
if (inputFormat.mChannelsPerFrame > 2 && outputFormat.mChannelsPerFrame == 2)
|
latencyPostfill = NO;
|
||||||
{
|
|
||||||
SInt32 channelMap[2] = { 0, 1 };
|
|
||||||
|
|
||||||
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,sizeof(channelMap),channelMap);
|
|
||||||
if (stat != noErr)
|
|
||||||
{
|
|
||||||
ALog(@"Error mapping channels %i", stat);
|
|
||||||
return NO;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (inputFormat.mChannelsPerFrame > 1 && outputFormat.mChannelsPerFrame == 1)
|
|
||||||
{
|
|
||||||
SInt32 channelMap[1] = { 0 };
|
|
||||||
|
|
||||||
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,(int)sizeof(channelMap),channelMap);
|
|
||||||
if (stat != noErr)
|
|
||||||
{
|
|
||||||
ALog(@"Error mapping channels %i", stat);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (inputFormat.mChannelsPerFrame == 1 && outputFormat.mChannelsPerFrame > 1)
|
|
||||||
{
|
|
||||||
SInt32 channelMap[outputFormat.mChannelsPerFrame];
|
|
||||||
|
|
||||||
memset(channelMap, 0, sizeof(channelMap));
|
|
||||||
|
|
||||||
stat = AudioConverterSetProperty(converter,kAudioConverterChannelMap,(int)sizeof(channelMap),channelMap);
|
|
||||||
if (stat != noErr)
|
|
||||||
{
|
|
||||||
ALog(@"Error mapping channels %i", stat);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PrintStreamDesc(&inf);
|
PrintStreamDesc(&inf);
|
||||||
PrintStreamDesc(&outf);
|
PrintStreamDesc(&outf);
|
||||||
|
|
||||||
[self refreshVolumeScaling];
|
[self refreshVolumeScaling];
|
||||||
|
|
||||||
sampleRatio = (float)inputFormat.mSampleRate / (float)outputFormat.mSampleRate;
|
// Move this here so process call isn't running the resampler until it's allocated
|
||||||
|
stopping = NO;
|
||||||
|
convertEntered = NO;
|
||||||
|
emittingSilence = NO;
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
@ -624,6 +751,7 @@ static float db_to_scale(float db)
|
||||||
DLog(@"Decoder dealloc");
|
DLog(@"Decoder dealloc");
|
||||||
|
|
||||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeScaling"];
|
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.volumeScaling"];
|
||||||
|
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputResampling"];
|
||||||
|
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
}
|
}
|
||||||
|
@ -638,6 +766,7 @@ static float db_to_scale(float db)
|
||||||
- (void)inputFormatDidChange:(AudioStreamBasicDescription)format
|
- (void)inputFormatDidChange:(AudioStreamBasicDescription)format
|
||||||
{
|
{
|
||||||
DLog(@"FORMAT CHANGED");
|
DLog(@"FORMAT CHANGED");
|
||||||
|
emittingSilence = YES;
|
||||||
[self cleanUp];
|
[self cleanUp];
|
||||||
[self setupWithInputFormat:format outputFormat:outputFormat];
|
[self setupWithInputFormat:format outputFormat:outputFormat];
|
||||||
}
|
}
|
||||||
|
@ -652,19 +781,15 @@ static float db_to_scale(float db)
|
||||||
- (void)cleanUp
|
- (void)cleanUp
|
||||||
{
|
{
|
||||||
stopping = YES;
|
stopping = YES;
|
||||||
while (convertEntered || ACInputEntered || ACFloatEntered)
|
while (convertEntered)
|
||||||
{
|
{
|
||||||
usleep(500);
|
usleep(500);
|
||||||
}
|
}
|
||||||
if (converterFloat)
|
if (resampler && resampler_data)
|
||||||
{
|
{
|
||||||
AudioConverterDispose(converterFloat);
|
resampler->free(resampler_data);
|
||||||
converterFloat = NULL;
|
resampler = NULL;
|
||||||
}
|
resampler_data = NULL;
|
||||||
if (converter)
|
|
||||||
{
|
|
||||||
AudioConverterDispose(converter);
|
|
||||||
converter = NULL;
|
|
||||||
}
|
}
|
||||||
if (floatBuffer)
|
if (floatBuffer)
|
||||||
{
|
{
|
||||||
|
@ -672,10 +797,10 @@ static float db_to_scale(float db)
|
||||||
floatBuffer = NULL;
|
floatBuffer = NULL;
|
||||||
floatBufferSize = 0;
|
floatBufferSize = 0;
|
||||||
}
|
}
|
||||||
if (callbackBuffer) {
|
if (inputBuffer) {
|
||||||
free(callbackBuffer);
|
free(inputBuffer);
|
||||||
callbackBuffer = NULL;
|
inputBuffer = NULL;
|
||||||
callbackBufferSize = 0;
|
inputBufferSize = 0;
|
||||||
}
|
}
|
||||||
floatOffset = 0;
|
floatOffset = 0;
|
||||||
floatSize = 0;
|
floatSize = 0;
|
||||||
|
|
|
@ -36,8 +36,6 @@
|
||||||
- (BOOL)openWithSource:(id<CogSource>)source;
|
- (BOOL)openWithSource:(id<CogSource>)source;
|
||||||
- (BOOL)openWithDecoder:(id<CogDecoder>) d;
|
- (BOOL)openWithDecoder:(id<CogDecoder>) d;
|
||||||
|
|
||||||
- (id<CogDecoder>)stealDecoder;
|
|
||||||
|
|
||||||
- (void)process;
|
- (void)process;
|
||||||
- (NSDictionary *) properties;
|
- (NSDictionary *) properties;
|
||||||
- (void)seek:(long)frame;
|
- (void)seek:(long)frame;
|
||||||
|
|
|
@ -235,13 +235,4 @@
|
||||||
return decoder;
|
return decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id<CogDecoder>) stealDecoder
|
|
||||||
{
|
|
||||||
[self removeObservers];
|
|
||||||
id<CogDecoder> decoder = self->decoder;
|
|
||||||
self->decoder = [[NSClassFromString(@"SilenceDecoder") alloc] init];
|
|
||||||
[self registerObservers];
|
|
||||||
return decoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -43,6 +43,54 @@
|
||||||
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DD30B8D0F7000A34E87 /* PluginController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DD30B8D0F7000A34E87 /* PluginController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F94DD40B8D0F7000A34E87 /* PluginController.m */; };
|
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F94DD40B8D0F7000A34E87 /* PluginController.m */; };
|
||||||
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DDC0B8D101100A34E87 /* Plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 17F94DDC0B8D101100A34E87 /* Plugin.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
832BEE90278D40F7005E1BC4 /* features_cpu.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE8F278D40F7005E1BC4 /* features_cpu.c */; };
|
||||||
|
832BEE92278D4109005E1BC4 /* s16_to_float.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE91278D4109005E1BC4 /* s16_to_float.c */; };
|
||||||
|
832BEE94278D412D005E1BC4 /* audio_resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE93278D412D005E1BC4 /* audio_resampler.c */; };
|
||||||
|
832BEE96278D414A005E1BC4 /* sinc_resampler.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE95278D414A005E1BC4 /* sinc_resampler.c */; };
|
||||||
|
832BEE98278D4462005E1BC4 /* config_file_userdata.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE97278D4462005E1BC4 /* config_file_userdata.c */; };
|
||||||
|
832BEE9A278D4473005E1BC4 /* memalign.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE99278D4473005E1BC4 /* memalign.c */; };
|
||||||
|
832BEE9C278D451D005E1BC4 /* config_file.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE9B278D451D005E1BC4 /* config_file.c */; };
|
||||||
|
832BEE9E278D452C005E1BC4 /* string_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE9D278D452C005E1BC4 /* string_list.c */; };
|
||||||
|
832BEEA0278D460F005E1BC4 /* file_stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEE9F278D460F005E1BC4 /* file_stream.c */; };
|
||||||
|
832BEEA2278D464B005E1BC4 /* config.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEA1278D464B005E1BC4 /* config.h */; };
|
||||||
|
832BEEA4278D469D005E1BC4 /* file_path.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEA3278D469D005E1BC4 /* file_path.c */; };
|
||||||
|
832BEEA6278D4755005E1BC4 /* vfs_implementation.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEA5278D4755005E1BC4 /* vfs_implementation.c */; };
|
||||||
|
832BEEA8278D47F0005E1BC4 /* stdstring.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEA7278D47F0005E1BC4 /* stdstring.c */; };
|
||||||
|
832BEEAA278D47FB005E1BC4 /* file_path_io.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEA9278D47FB005E1BC4 /* file_path_io.c */; };
|
||||||
|
832BEEAC278D4848005E1BC4 /* encoding_utf.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEAB278D4848005E1BC4 /* encoding_utf.c */; };
|
||||||
|
832BEEAE278D4853005E1BC4 /* rtime.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEAD278D4853005E1BC4 /* rtime.c */; };
|
||||||
|
832BEEB0278D48C1005E1BC4 /* s32_to_float.c in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEAF278D48C1005E1BC4 /* s32_to_float.c */; };
|
||||||
|
832BEEDD278D4A32005E1BC4 /* utf.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEB3278D4A32005E1BC4 /* utf.h */; };
|
||||||
|
832BEEDE278D4A32005E1BC4 /* memalign.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEB4278D4A32005E1BC4 /* memalign.h */; };
|
||||||
|
832BEEDF278D4A32005E1BC4 /* vfs.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEB6278D4A32005E1BC4 /* vfs.h */; };
|
||||||
|
832BEEE0278D4A32005E1BC4 /* vfs_implementation.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEB7278D4A32005E1BC4 /* vfs_implementation.h */; };
|
||||||
|
832BEEE1278D4A32005E1BC4 /* strl.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEB9278D4A32005E1BC4 /* strl.h */; };
|
||||||
|
832BEEE2278D4A32005E1BC4 /* strcasestr.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEBA278D4A32005E1BC4 /* strcasestr.h */; };
|
||||||
|
832BEEE3278D4A32005E1BC4 /* fopen_utf8.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEBB278D4A32005E1BC4 /* fopen_utf8.h */; };
|
||||||
|
832BEEE4278D4A32005E1BC4 /* posix_string.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEBC278D4A32005E1BC4 /* posix_string.h */; };
|
||||||
|
832BEEE5278D4A32005E1BC4 /* msvc.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEBD278D4A32005E1BC4 /* msvc.h */; };
|
||||||
|
832BEEE6278D4A32005E1BC4 /* retro_common_api.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEBE278D4A32005E1BC4 /* retro_common_api.h */; };
|
||||||
|
832BEEE7278D4A32005E1BC4 /* retro_timers.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEBF278D4A32005E1BC4 /* retro_timers.h */; };
|
||||||
|
832BEEE8278D4A32005E1BC4 /* string_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC1278D4A32005E1BC4 /* string_list.h */; };
|
||||||
|
832BEEE9278D4A32005E1BC4 /* config_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC3278D4A32005E1BC4 /* config_file.h */; };
|
||||||
|
832BEEEA278D4A32005E1BC4 /* config_file_userdata.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC4278D4A32005E1BC4 /* config_file_userdata.h */; };
|
||||||
|
832BEEEB278D4A32005E1BC4 /* file_path.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC5278D4A32005E1BC4 /* file_path.h */; };
|
||||||
|
832BEEEC278D4A32005E1BC4 /* retro_environment.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC6278D4A32005E1BC4 /* retro_environment.h */; };
|
||||||
|
832BEEED278D4A32005E1BC4 /* rhmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC8278D4A32005E1BC4 /* rhmap.h */; };
|
||||||
|
832BEEEE278D4A32005E1BC4 /* retro_inline.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEC9278D4A32005E1BC4 /* retro_inline.h */; };
|
||||||
|
832BEEEF278D4A32005E1BC4 /* retro_math.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEECA278D4A32005E1BC4 /* retro_math.h */; };
|
||||||
|
832BEEF0278D4A32005E1BC4 /* file_stream.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEECC278D4A32005E1BC4 /* file_stream.h */; };
|
||||||
|
832BEEF1278D4A32005E1BC4 /* features_cpu.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEECE278D4A32005E1BC4 /* features_cpu.h */; };
|
||||||
|
832BEEF2278D4A32005E1BC4 /* retro_miscellaneous.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEECF278D4A32005E1BC4 /* retro_miscellaneous.h */; };
|
||||||
|
832BEEF3278D4A32005E1BC4 /* rtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED1278D4A32005E1BC4 /* rtime.h */; };
|
||||||
|
832BEEF4278D4A32005E1BC4 /* boolean.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED2278D4A32005E1BC4 /* boolean.h */; };
|
||||||
|
832BEEF5278D4A32005E1BC4 /* audio_resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED4278D4A32005E1BC4 /* audio_resampler.h */; };
|
||||||
|
832BEEF6278D4A32005E1BC4 /* s16_to_float.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED6278D4A32005E1BC4 /* s16_to_float.h */; };
|
||||||
|
832BEEF7278D4A32005E1BC4 /* s32_to_float.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED7278D4A32005E1BC4 /* s32_to_float.h */; };
|
||||||
|
832BEEF8278D4A32005E1BC4 /* libretro.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED8278D4A32005E1BC4 /* libretro.h */; };
|
||||||
|
832BEEF9278D4A32005E1BC4 /* retro_assert.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEED9278D4A32005E1BC4 /* retro_assert.h */; };
|
||||||
|
832BEEFA278D4A32005E1BC4 /* stdstring.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEDB278D4A32005E1BC4 /* stdstring.h */; };
|
||||||
|
832BEEFB278D4A32005E1BC4 /* filters.h in Headers */ = {isa = PBXBuildFile; fileRef = 832BEEDC278D4A32005E1BC4 /* filters.h */; };
|
||||||
8384912718080FF100E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384912618080FF100E7332D /* Logging.h */; };
|
8384912718080FF100E7332D /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 8384912618080FF100E7332D /* Logging.h */; };
|
||||||
839366671815923C006DD712 /* CogPluginMulti.h in Headers */ = {isa = PBXBuildFile; fileRef = 839366651815923C006DD712 /* CogPluginMulti.h */; };
|
839366671815923C006DD712 /* CogPluginMulti.h in Headers */ = {isa = PBXBuildFile; fileRef = 839366651815923C006DD712 /* CogPluginMulti.h */; };
|
||||||
839366681815923C006DD712 /* CogPluginMulti.m in Sources */ = {isa = PBXBuildFile; fileRef = 839366661815923C006DD712 /* CogPluginMulti.m */; };
|
839366681815923C006DD712 /* CogPluginMulti.m in Sources */ = {isa = PBXBuildFile; fileRef = 839366661815923C006DD712 /* CogPluginMulti.m */; };
|
||||||
|
@ -108,6 +156,54 @@
|
||||||
17F94DD40B8D0F7000A34E87 /* PluginController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PluginController.m; sourceTree = "<group>"; };
|
17F94DD40B8D0F7000A34E87 /* PluginController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PluginController.m; sourceTree = "<group>"; };
|
||||||
17F94DDC0B8D101100A34E87 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Plugin.h; sourceTree = "<group>"; };
|
17F94DDC0B8D101100A34E87 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Plugin.h; sourceTree = "<group>"; };
|
||||||
32DBCF5E0370ADEE00C91783 /* CogAudio_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogAudio_Prefix.pch; sourceTree = "<group>"; };
|
32DBCF5E0370ADEE00C91783 /* CogAudio_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogAudio_Prefix.pch; sourceTree = "<group>"; };
|
||||||
|
832BEE8F278D40F7005E1BC4 /* features_cpu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = features_cpu.c; path = "../ThirdParty/RetroArch/libretro-common/features/features_cpu.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE91278D4109005E1BC4 /* s16_to_float.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = s16_to_float.c; path = "../ThirdParty/RetroArch/libretro-common/audio/conversion/s16_to_float.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE93278D412D005E1BC4 /* audio_resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = audio_resampler.c; path = "../ThirdParty/RetroArch/libretro-common/audio/resampler/audio_resampler.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE95278D414A005E1BC4 /* sinc_resampler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sinc_resampler.c; path = "../ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE97278D4462005E1BC4 /* config_file_userdata.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config_file_userdata.c; path = "../ThirdParty/RetroArch/libretro-common/file/config_file_userdata.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE99278D4473005E1BC4 /* memalign.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = memalign.c; path = "../ThirdParty/RetroArch/libretro-common/memmap/memalign.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE9B278D451D005E1BC4 /* config_file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config_file.c; path = "../ThirdParty/RetroArch/libretro-common/file/config_file.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE9D278D452C005E1BC4 /* string_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = string_list.c; path = "../ThirdParty/RetroArch/libretro-common/lists/string_list.c"; sourceTree = "<group>"; };
|
||||||
|
832BEE9F278D460F005E1BC4 /* file_stream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file_stream.c; path = "../ThirdParty/RetroArch/libretro-common/streams/file_stream.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEA1278D464B005E1BC4 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config.h; path = ../ThirdParty/RetroArch/config.h; sourceTree = "<group>"; };
|
||||||
|
832BEEA3278D469D005E1BC4 /* file_path.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file_path.c; path = "../ThirdParty/RetroArch/libretro-common/file/file_path.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEA5278D4755005E1BC4 /* vfs_implementation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vfs_implementation.c; path = "../ThirdParty/RetroArch/libretro-common/vfs/vfs_implementation.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEA7278D47F0005E1BC4 /* stdstring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stdstring.c; path = "../ThirdParty/RetroArch/libretro-common/string/stdstring.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEA9278D47FB005E1BC4 /* file_path_io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file_path_io.c; path = "../ThirdParty/RetroArch/libretro-common/file/file_path_io.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEAB278D4848005E1BC4 /* encoding_utf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = encoding_utf.c; path = "../ThirdParty/RetroArch/libretro-common/encodings/encoding_utf.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEAD278D4853005E1BC4 /* rtime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rtime.c; path = "../ThirdParty/RetroArch/libretro-common/time/rtime.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEAF278D48C1005E1BC4 /* s32_to_float.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = s32_to_float.c; path = "../ThirdParty/RetroArch/libretro-common/audio/conversion/s32_to_float.c"; sourceTree = "<group>"; };
|
||||||
|
832BEEB3278D4A32005E1BC4 /* utf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf.h; sourceTree = "<group>"; };
|
||||||
|
832BEEB4278D4A32005E1BC4 /* memalign.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memalign.h; sourceTree = "<group>"; };
|
||||||
|
832BEEB6278D4A32005E1BC4 /* vfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vfs.h; sourceTree = "<group>"; };
|
||||||
|
832BEEB7278D4A32005E1BC4 /* vfs_implementation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vfs_implementation.h; sourceTree = "<group>"; };
|
||||||
|
832BEEB9278D4A32005E1BC4 /* strl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strl.h; sourceTree = "<group>"; };
|
||||||
|
832BEEBA278D4A32005E1BC4 /* strcasestr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strcasestr.h; sourceTree = "<group>"; };
|
||||||
|
832BEEBB278D4A32005E1BC4 /* fopen_utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fopen_utf8.h; sourceTree = "<group>"; };
|
||||||
|
832BEEBC278D4A32005E1BC4 /* posix_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = posix_string.h; sourceTree = "<group>"; };
|
||||||
|
832BEEBD278D4A32005E1BC4 /* msvc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = msvc.h; sourceTree = "<group>"; };
|
||||||
|
832BEEBE278D4A32005E1BC4 /* retro_common_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_common_api.h; sourceTree = "<group>"; };
|
||||||
|
832BEEBF278D4A32005E1BC4 /* retro_timers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_timers.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC1278D4A32005E1BC4 /* string_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_list.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC3278D4A32005E1BC4 /* config_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_file.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC4278D4A32005E1BC4 /* config_file_userdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_file_userdata.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC5278D4A32005E1BC4 /* file_path.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_path.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC6278D4A32005E1BC4 /* retro_environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_environment.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC8278D4A32005E1BC4 /* rhmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rhmap.h; sourceTree = "<group>"; };
|
||||||
|
832BEEC9278D4A32005E1BC4 /* retro_inline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_inline.h; sourceTree = "<group>"; };
|
||||||
|
832BEECA278D4A32005E1BC4 /* retro_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_math.h; sourceTree = "<group>"; };
|
||||||
|
832BEECC278D4A32005E1BC4 /* file_stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_stream.h; sourceTree = "<group>"; };
|
||||||
|
832BEECE278D4A32005E1BC4 /* features_cpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = features_cpu.h; sourceTree = "<group>"; };
|
||||||
|
832BEECF278D4A32005E1BC4 /* retro_miscellaneous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_miscellaneous.h; sourceTree = "<group>"; };
|
||||||
|
832BEED1278D4A32005E1BC4 /* rtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtime.h; sourceTree = "<group>"; };
|
||||||
|
832BEED2278D4A32005E1BC4 /* boolean.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = boolean.h; sourceTree = "<group>"; };
|
||||||
|
832BEED4278D4A32005E1BC4 /* audio_resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_resampler.h; sourceTree = "<group>"; };
|
||||||
|
832BEED6278D4A32005E1BC4 /* s16_to_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = s16_to_float.h; sourceTree = "<group>"; };
|
||||||
|
832BEED7278D4A32005E1BC4 /* s32_to_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = s32_to_float.h; sourceTree = "<group>"; };
|
||||||
|
832BEED8278D4A32005E1BC4 /* libretro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libretro.h; sourceTree = "<group>"; };
|
||||||
|
832BEED9278D4A32005E1BC4 /* retro_assert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = retro_assert.h; sourceTree = "<group>"; };
|
||||||
|
832BEEDB278D4A32005E1BC4 /* stdstring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdstring.h; sourceTree = "<group>"; };
|
||||||
|
832BEEDC278D4A32005E1BC4 /* filters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filters.h; sourceTree = "<group>"; };
|
||||||
8384912618080FF100E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
8384912618080FF100E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||||
839366651815923C006DD712 /* CogPluginMulti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogPluginMulti.h; sourceTree = "<group>"; };
|
839366651815923C006DD712 /* CogPluginMulti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CogPluginMulti.h; sourceTree = "<group>"; };
|
||||||
839366661815923C006DD712 /* CogPluginMulti.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CogPluginMulti.m; sourceTree = "<group>"; };
|
839366661815923C006DD712 /* CogPluginMulti.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CogPluginMulti.m; sourceTree = "<group>"; };
|
||||||
|
@ -149,6 +245,7 @@
|
||||||
0867D691FE84028FC02AAC07 /* CogAudio */ = {
|
0867D691FE84028FC02AAC07 /* CogAudio */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
832BEE8E278D40CD005E1BC4 /* ThirdParty */,
|
||||||
08FB77AEFE84172EC02AAC07 /* Classes */,
|
08FB77AEFE84172EC02AAC07 /* Classes */,
|
||||||
32C88DFF0371C24200C91783 /* Other Sources */,
|
32C88DFF0371C24200C91783 /* Other Sources */,
|
||||||
089C1665FE841158C02AAC07 /* Resources */,
|
089C1665FE841158C02AAC07 /* Resources */,
|
||||||
|
@ -301,6 +398,166 @@
|
||||||
name = "Other Sources";
|
name = "Other Sources";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
832BEE8E278D40CD005E1BC4 /* ThirdParty */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEB1278D4A32005E1BC4 /* include */,
|
||||||
|
832BEE93278D412D005E1BC4 /* audio_resampler.c */,
|
||||||
|
832BEE97278D4462005E1BC4 /* config_file_userdata.c */,
|
||||||
|
832BEE9B278D451D005E1BC4 /* config_file.c */,
|
||||||
|
832BEEAB278D4848005E1BC4 /* encoding_utf.c */,
|
||||||
|
832BEE8F278D40F7005E1BC4 /* features_cpu.c */,
|
||||||
|
832BEEA9278D47FB005E1BC4 /* file_path_io.c */,
|
||||||
|
832BEEA3278D469D005E1BC4 /* file_path.c */,
|
||||||
|
832BEE9F278D460F005E1BC4 /* file_stream.c */,
|
||||||
|
832BEE99278D4473005E1BC4 /* memalign.c */,
|
||||||
|
832BEEAD278D4853005E1BC4 /* rtime.c */,
|
||||||
|
832BEE91278D4109005E1BC4 /* s16_to_float.c */,
|
||||||
|
832BEEAF278D48C1005E1BC4 /* s32_to_float.c */,
|
||||||
|
832BEE95278D414A005E1BC4 /* sinc_resampler.c */,
|
||||||
|
832BEEA7278D47F0005E1BC4 /* stdstring.c */,
|
||||||
|
832BEE9D278D452C005E1BC4 /* string_list.c */,
|
||||||
|
832BEEA5278D4755005E1BC4 /* vfs_implementation.c */,
|
||||||
|
832BEEA1278D464B005E1BC4 /* config.h */,
|
||||||
|
);
|
||||||
|
name = ThirdParty;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEB1278D4A32005E1BC4 /* include */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEC7278D4A32005E1BC4 /* array */,
|
||||||
|
832BEED3278D4A32005E1BC4 /* audio */,
|
||||||
|
832BEED2278D4A32005E1BC4 /* boolean.h */,
|
||||||
|
832BEEB8278D4A32005E1BC4 /* compat */,
|
||||||
|
832BEEB2278D4A32005E1BC4 /* encodings */,
|
||||||
|
832BEECD278D4A32005E1BC4 /* features */,
|
||||||
|
832BEEC2278D4A32005E1BC4 /* file */,
|
||||||
|
832BEEDC278D4A32005E1BC4 /* filters.h */,
|
||||||
|
832BEED8278D4A32005E1BC4 /* libretro.h */,
|
||||||
|
832BEEC0278D4A32005E1BC4 /* lists */,
|
||||||
|
832BEEB4278D4A32005E1BC4 /* memalign.h */,
|
||||||
|
832BEED9278D4A32005E1BC4 /* retro_assert.h */,
|
||||||
|
832BEEBE278D4A32005E1BC4 /* retro_common_api.h */,
|
||||||
|
832BEEC6278D4A32005E1BC4 /* retro_environment.h */,
|
||||||
|
832BEEC9278D4A32005E1BC4 /* retro_inline.h */,
|
||||||
|
832BEECA278D4A32005E1BC4 /* retro_math.h */,
|
||||||
|
832BEECF278D4A32005E1BC4 /* retro_miscellaneous.h */,
|
||||||
|
832BEEBF278D4A32005E1BC4 /* retro_timers.h */,
|
||||||
|
832BEECB278D4A32005E1BC4 /* streams */,
|
||||||
|
832BEEDA278D4A32005E1BC4 /* string */,
|
||||||
|
832BEED0278D4A32005E1BC4 /* time */,
|
||||||
|
832BEEB5278D4A32005E1BC4 /* vfs */,
|
||||||
|
);
|
||||||
|
name = include;
|
||||||
|
path = "../ThirdParty/RetroArch/libretro-common/include";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEB2278D4A32005E1BC4 /* encodings */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEB3278D4A32005E1BC4 /* utf.h */,
|
||||||
|
);
|
||||||
|
path = encodings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEB5278D4A32005E1BC4 /* vfs */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEB6278D4A32005E1BC4 /* vfs.h */,
|
||||||
|
832BEEB7278D4A32005E1BC4 /* vfs_implementation.h */,
|
||||||
|
);
|
||||||
|
path = vfs;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEB8278D4A32005E1BC4 /* compat */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEB9278D4A32005E1BC4 /* strl.h */,
|
||||||
|
832BEEBA278D4A32005E1BC4 /* strcasestr.h */,
|
||||||
|
832BEEBB278D4A32005E1BC4 /* fopen_utf8.h */,
|
||||||
|
832BEEBC278D4A32005E1BC4 /* posix_string.h */,
|
||||||
|
832BEEBD278D4A32005E1BC4 /* msvc.h */,
|
||||||
|
);
|
||||||
|
path = compat;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEC0278D4A32005E1BC4 /* lists */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEC1278D4A32005E1BC4 /* string_list.h */,
|
||||||
|
);
|
||||||
|
path = lists;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEC2278D4A32005E1BC4 /* file */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEC3278D4A32005E1BC4 /* config_file.h */,
|
||||||
|
832BEEC4278D4A32005E1BC4 /* config_file_userdata.h */,
|
||||||
|
832BEEC5278D4A32005E1BC4 /* file_path.h */,
|
||||||
|
);
|
||||||
|
path = file;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEC7278D4A32005E1BC4 /* array */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEC8278D4A32005E1BC4 /* rhmap.h */,
|
||||||
|
);
|
||||||
|
path = array;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEECB278D4A32005E1BC4 /* streams */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEECC278D4A32005E1BC4 /* file_stream.h */,
|
||||||
|
);
|
||||||
|
path = streams;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEECD278D4A32005E1BC4 /* features */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEECE278D4A32005E1BC4 /* features_cpu.h */,
|
||||||
|
);
|
||||||
|
path = features;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEED0278D4A32005E1BC4 /* time */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEED1278D4A32005E1BC4 /* rtime.h */,
|
||||||
|
);
|
||||||
|
path = time;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEED3278D4A32005E1BC4 /* audio */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEED4278D4A32005E1BC4 /* audio_resampler.h */,
|
||||||
|
832BEED5278D4A32005E1BC4 /* conversion */,
|
||||||
|
);
|
||||||
|
path = audio;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEED5278D4A32005E1BC4 /* conversion */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEED6278D4A32005E1BC4 /* s16_to_float.h */,
|
||||||
|
832BEED7278D4A32005E1BC4 /* s32_to_float.h */,
|
||||||
|
);
|
||||||
|
path = conversion;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
832BEEDA278D4A32005E1BC4 /* string */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
832BEEDB278D4A32005E1BC4 /* stdstring.h */,
|
||||||
|
);
|
||||||
|
path = string;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
@ -309,25 +566,57 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
17D21CA10B8BE4BA00D1EBDE /* BufferChain.h in Headers */,
|
17D21CA10B8BE4BA00D1EBDE /* BufferChain.h in Headers */,
|
||||||
|
832BEEE0278D4A32005E1BC4 /* vfs_implementation.h in Headers */,
|
||||||
17D21CA50B8BE4BA00D1EBDE /* InputNode.h in Headers */,
|
17D21CA50B8BE4BA00D1EBDE /* InputNode.h in Headers */,
|
||||||
|
832BEEF5278D4A32005E1BC4 /* audio_resampler.h in Headers */,
|
||||||
|
832BEEDF278D4A32005E1BC4 /* vfs.h in Headers */,
|
||||||
|
832BEEF7278D4A32005E1BC4 /* s32_to_float.h in Headers */,
|
||||||
17D21CA70B8BE4BA00D1EBDE /* Node.h in Headers */,
|
17D21CA70B8BE4BA00D1EBDE /* Node.h in Headers */,
|
||||||
|
832BEEE7278D4A32005E1BC4 /* retro_timers.h in Headers */,
|
||||||
17D21CA90B8BE4BA00D1EBDE /* OutputNode.h in Headers */,
|
17D21CA90B8BE4BA00D1EBDE /* OutputNode.h in Headers */,
|
||||||
|
832BEEFA278D4A32005E1BC4 /* stdstring.h in Headers */,
|
||||||
|
832BEEE3278D4A32005E1BC4 /* fopen_utf8.h in Headers */,
|
||||||
|
832BEEE2278D4A32005E1BC4 /* strcasestr.h in Headers */,
|
||||||
|
832BEEEB278D4A32005E1BC4 /* file_path.h in Headers */,
|
||||||
|
832BEEA2278D464B005E1BC4 /* config.h in Headers */,
|
||||||
17D21CC50B8BE4BA00D1EBDE /* OutputCoreAudio.h in Headers */,
|
17D21CC50B8BE4BA00D1EBDE /* OutputCoreAudio.h in Headers */,
|
||||||
17D21CC70B8BE4BA00D1EBDE /* Status.h in Headers */,
|
17D21CC70B8BE4BA00D1EBDE /* Status.h in Headers */,
|
||||||
|
832BEEF2278D4A32005E1BC4 /* retro_miscellaneous.h in Headers */,
|
||||||
|
832BEEE4278D4A32005E1BC4 /* posix_string.h in Headers */,
|
||||||
|
832BEEF1278D4A32005E1BC4 /* features_cpu.h in Headers */,
|
||||||
17D21CDF0B8BE5B400D1EBDE /* VirtualRingBuffer.h in Headers */,
|
17D21CDF0B8BE5B400D1EBDE /* VirtualRingBuffer.h in Headers */,
|
||||||
|
832BEEE6278D4A32005E1BC4 /* retro_common_api.h in Headers */,
|
||||||
|
832BEEF3278D4A32005E1BC4 /* rtime.h in Headers */,
|
||||||
17D21CF30B8BE5EF00D1EBDE /* Semaphore.h in Headers */,
|
17D21CF30B8BE5EF00D1EBDE /* Semaphore.h in Headers */,
|
||||||
|
832BEEE9278D4A32005E1BC4 /* config_file.h in Headers */,
|
||||||
17D21DC70B8BE79700D1EBDE /* CoreAudioUtils.h in Headers */,
|
17D21DC70B8BE79700D1EBDE /* CoreAudioUtils.h in Headers */,
|
||||||
|
832BEEE8278D4A32005E1BC4 /* string_list.h in Headers */,
|
||||||
|
832BEEDE278D4A32005E1BC4 /* memalign.h in Headers */,
|
||||||
17D21EBD0B8BF44000D1EBDE /* AudioPlayer.h in Headers */,
|
17D21EBD0B8BF44000D1EBDE /* AudioPlayer.h in Headers */,
|
||||||
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */,
|
17F94DD50B8D0F7000A34E87 /* PluginController.h in Headers */,
|
||||||
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */,
|
17F94DDD0B8D101100A34E87 /* Plugin.h in Headers */,
|
||||||
17A2D3C50B8D1D37000778C4 /* AudioDecoder.h in Headers */,
|
17A2D3C50B8D1D37000778C4 /* AudioDecoder.h in Headers */,
|
||||||
|
832BEEE1278D4A32005E1BC4 /* strl.h in Headers */,
|
||||||
|
832BEEE5278D4A32005E1BC4 /* msvc.h in Headers */,
|
||||||
|
832BEEF4278D4A32005E1BC4 /* boolean.h in Headers */,
|
||||||
|
832BEEF9278D4A32005E1BC4 /* retro_assert.h in Headers */,
|
||||||
|
832BEEEE278D4A32005E1BC4 /* retro_inline.h in Headers */,
|
||||||
17C940230B900909008627D6 /* AudioMetadataReader.h in Headers */,
|
17C940230B900909008627D6 /* AudioMetadataReader.h in Headers */,
|
||||||
|
832BEEF8278D4A32005E1BC4 /* libretro.h in Headers */,
|
||||||
17B619300B909BC300BC003F /* AudioPropertiesReader.h in Headers */,
|
17B619300B909BC300BC003F /* AudioPropertiesReader.h in Headers */,
|
||||||
|
832BEEEA278D4A32005E1BC4 /* config_file_userdata.h in Headers */,
|
||||||
839366671815923C006DD712 /* CogPluginMulti.h in Headers */,
|
839366671815923C006DD712 /* CogPluginMulti.h in Headers */,
|
||||||
17ADB13C0B97926D00257CA2 /* AudioSource.h in Headers */,
|
17ADB13C0B97926D00257CA2 /* AudioSource.h in Headers */,
|
||||||
|
832BEEF6278D4A32005E1BC4 /* s16_to_float.h in Headers */,
|
||||||
|
832BEEDD278D4A32005E1BC4 /* utf.h in Headers */,
|
||||||
|
832BEEEC278D4A32005E1BC4 /* retro_environment.h in Headers */,
|
||||||
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */,
|
8EC1225F0B993BD500C5B3AD /* ConverterNode.h in Headers */,
|
||||||
|
832BEEF0278D4A32005E1BC4 /* file_stream.h in Headers */,
|
||||||
8384912718080FF100E7332D /* Logging.h in Headers */,
|
8384912718080FF100E7332D /* Logging.h in Headers */,
|
||||||
|
832BEEFB278D4A32005E1BC4 /* filters.h in Headers */,
|
||||||
8E8D3D2F0CBAEE6E00135C1B /* AudioContainer.h in Headers */,
|
8E8D3D2F0CBAEE6E00135C1B /* AudioContainer.h in Headers */,
|
||||||
|
832BEEED278D4A32005E1BC4 /* rhmap.h in Headers */,
|
||||||
|
832BEEEF278D4A32005E1BC4 /* retro_math.h in Headers */,
|
||||||
B0575F2D0D687A0800411D77 /* Helper.h in Headers */,
|
B0575F2D0D687A0800411D77 /* Helper.h in Headers */,
|
||||||
07DB5F3E0ED353A900C2E3EF /* AudioMetadataWriter.h in Headers */,
|
07DB5F3E0ED353A900C2E3EF /* AudioMetadataWriter.h in Headers */,
|
||||||
);
|
);
|
||||||
|
@ -405,23 +694,39 @@
|
||||||
files = (
|
files = (
|
||||||
17D21CA20B8BE4BA00D1EBDE /* BufferChain.m in Sources */,
|
17D21CA20B8BE4BA00D1EBDE /* BufferChain.m in Sources */,
|
||||||
17D21CA60B8BE4BA00D1EBDE /* InputNode.m in Sources */,
|
17D21CA60B8BE4BA00D1EBDE /* InputNode.m in Sources */,
|
||||||
|
832BEEAA278D47FB005E1BC4 /* file_path_io.c in Sources */,
|
||||||
17D21CA80B8BE4BA00D1EBDE /* Node.m in Sources */,
|
17D21CA80B8BE4BA00D1EBDE /* Node.m in Sources */,
|
||||||
17D21CAA0B8BE4BA00D1EBDE /* OutputNode.m in Sources */,
|
17D21CAA0B8BE4BA00D1EBDE /* OutputNode.m in Sources */,
|
||||||
|
832BEEB0278D48C1005E1BC4 /* s32_to_float.c in Sources */,
|
||||||
17D21CC60B8BE4BA00D1EBDE /* OutputCoreAudio.m in Sources */,
|
17D21CC60B8BE4BA00D1EBDE /* OutputCoreAudio.m in Sources */,
|
||||||
|
832BEEA8278D47F0005E1BC4 /* stdstring.c in Sources */,
|
||||||
|
832BEEA0278D460F005E1BC4 /* file_stream.c in Sources */,
|
||||||
17D21CE00B8BE5B400D1EBDE /* VirtualRingBuffer.m in Sources */,
|
17D21CE00B8BE5B400D1EBDE /* VirtualRingBuffer.m in Sources */,
|
||||||
17D21CF40B8BE5EF00D1EBDE /* Semaphore.m in Sources */,
|
17D21CF40B8BE5EF00D1EBDE /* Semaphore.m in Sources */,
|
||||||
|
832BEE9C278D451D005E1BC4 /* config_file.c in Sources */,
|
||||||
|
832BEEA6278D4755005E1BC4 /* vfs_implementation.c in Sources */,
|
||||||
17D21DC80B8BE79700D1EBDE /* CoreAudioUtils.m in Sources */,
|
17D21DC80B8BE79700D1EBDE /* CoreAudioUtils.m in Sources */,
|
||||||
839366681815923C006DD712 /* CogPluginMulti.m in Sources */,
|
839366681815923C006DD712 /* CogPluginMulti.m in Sources */,
|
||||||
|
832BEE90278D40F7005E1BC4 /* features_cpu.c in Sources */,
|
||||||
|
832BEE9E278D452C005E1BC4 /* string_list.c in Sources */,
|
||||||
|
832BEEAC278D4848005E1BC4 /* encoding_utf.c in Sources */,
|
||||||
|
832BEE9A278D4473005E1BC4 /* memalign.c in Sources */,
|
||||||
17D21EBE0B8BF44000D1EBDE /* AudioPlayer.m in Sources */,
|
17D21EBE0B8BF44000D1EBDE /* AudioPlayer.m in Sources */,
|
||||||
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */,
|
17F94DD60B8D0F7000A34E87 /* PluginController.m in Sources */,
|
||||||
|
832BEEA4278D469D005E1BC4 /* file_path.c in Sources */,
|
||||||
17A2D3C60B8D1D37000778C4 /* AudioDecoder.m in Sources */,
|
17A2D3C60B8D1D37000778C4 /* AudioDecoder.m in Sources */,
|
||||||
17C940240B900909008627D6 /* AudioMetadataReader.m in Sources */,
|
17C940240B900909008627D6 /* AudioMetadataReader.m in Sources */,
|
||||||
17B619310B909BC300BC003F /* AudioPropertiesReader.m in Sources */,
|
17B619310B909BC300BC003F /* AudioPropertiesReader.m in Sources */,
|
||||||
17ADB13D0B97926D00257CA2 /* AudioSource.m in Sources */,
|
17ADB13D0B97926D00257CA2 /* AudioSource.m in Sources */,
|
||||||
8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */,
|
8EC122600B993BD500C5B3AD /* ConverterNode.m in Sources */,
|
||||||
8E8D3D300CBAEE6E00135C1B /* AudioContainer.m in Sources */,
|
8E8D3D300CBAEE6E00135C1B /* AudioContainer.m in Sources */,
|
||||||
|
832BEEAE278D4853005E1BC4 /* rtime.c in Sources */,
|
||||||
|
832BEE96278D414A005E1BC4 /* sinc_resampler.c in Sources */,
|
||||||
B0575F300D687A4000411D77 /* Helper.m in Sources */,
|
B0575F300D687A4000411D77 /* Helper.m in Sources */,
|
||||||
|
832BEE98278D4462005E1BC4 /* config_file_userdata.c in Sources */,
|
||||||
07DB5F3F0ED353A900C2E3EF /* AudioMetadataWriter.m in Sources */,
|
07DB5F3F0ED353A900C2E3EF /* AudioMetadataWriter.m in Sources */,
|
||||||
|
832BEE94278D412D005E1BC4 /* audio_resampler.c in Sources */,
|
||||||
|
832BEE92278D4109005E1BC4 /* s16_to_float.c in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -516,13 +821,21 @@
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"RARCH_INTERNAL=1",
|
||||||
|
"HAVE_CONFIG_H=1",
|
||||||
|
);
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"../ThirdParty/RetroArch/libretro-common/include",
|
||||||
|
../ThirdParty/RetroArch,
|
||||||
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
|
@ -557,12 +870,20 @@
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"RARCH_INTERNAL=1",
|
||||||
|
"HAVE_CONFIG_H=1",
|
||||||
|
);
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"../ThirdParty/RetroArch/libretro-common/include",
|
||||||
|
../ThirdParty/RetroArch,
|
||||||
|
);
|
||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
SYMROOT = ../build;
|
SYMROOT = ../build;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19455" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="macosx"/>
|
<deployment identifier="macosx"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19455"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
|
@ -245,11 +245,11 @@
|
||||||
</connections>
|
</connections>
|
||||||
</customObject>
|
</customObject>
|
||||||
<customView id="58" userLabel="OutputView">
|
<customView id="58" userLabel="OutputView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="530" height="103"/>
|
<rect key="frame" x="0.0" y="0.0" width="530" height="139"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="65">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="65">
|
||||||
<rect key="frame" x="17" y="66" width="103" height="17"/>
|
<rect key="frame" x="17" y="100" width="123" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="right" title="Output Device: " id="211">
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="right" title="Output Device: " id="211">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
|
@ -257,8 +257,17 @@
|
||||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8GG-SU-ZrX">
|
||||||
|
<rect key="frame" x="5" y="26" width="135" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="right" title="Resampling Quality: " id="tgE-40-uus">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="60">
|
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="60">
|
||||||
<rect key="frame" x="122" y="60" width="252" height="26"/>
|
<rect key="frame" x="143" y="94" width="252" height="26"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<popUpButtonCell key="cell" type="push" title="Item1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="62" id="210">
|
<popUpButtonCell key="cell" type="push" title="Item1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="62" id="210">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
@ -279,7 +288,7 @@
|
||||||
</connections>
|
</connections>
|
||||||
</popUpButton>
|
</popUpButton>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zkP-2E-1Kc">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zkP-2E-1Kc">
|
||||||
<rect key="frame" x="17" y="29" width="103" height="17"/>
|
<rect key="frame" x="17" y="63" width="123" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Volume Level:" id="wK4-EF-8Wa">
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Volume Level:" id="wK4-EF-8Wa">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
|
@ -288,7 +297,7 @@
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2v7-Ef-ekr">
|
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2v7-Ef-ekr">
|
||||||
<rect key="frame" x="123" y="24" width="251" height="26"/>
|
<rect key="frame" x="144" y="58" width="251" height="26"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="vmS-eb-zen">
|
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="vmS-eb-zen">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
@ -308,8 +317,29 @@
|
||||||
<binding destination="52" name="selectedObject" keyPath="values.volumeScaling" previousBinding="6uG-yb-1C2" id="mQV-hu-vZC"/>
|
<binding destination="52" name="selectedObject" keyPath="values.volumeScaling" previousBinding="6uG-yb-1C2" id="mQV-hu-vZC"/>
|
||||||
</connections>
|
</connections>
|
||||||
</popUpButton>
|
</popUpButton>
|
||||||
|
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tW9-9e-FZx">
|
||||||
|
<rect key="frame" x="144" y="20" width="251" height="26"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Ara-An-Gkf" id="zFu-hG-VFE">
|
||||||
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="menu"/>
|
||||||
|
<menu key="menu" title="OtherViews" id="Fqi-au-3Rx">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Item 1" state="on" id="Ara-An-Gkf"/>
|
||||||
|
<menuItem title="Item 2" id="Yet-s2-7o3"/>
|
||||||
|
<menuItem title="Item 3" id="MOu-Oy-HWV"/>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</popUpButtonCell>
|
||||||
|
<connections>
|
||||||
|
<binding destination="Yrc-8b-9dF" name="content" keyPath="arrangedObjects" id="AUP-bM-LUj"/>
|
||||||
|
<binding destination="Yrc-8b-9dF" name="contentObjects" keyPath="arrangedObjects.preference" previousBinding="AUP-bM-LUj" id="JGE-12-MXt"/>
|
||||||
|
<binding destination="Yrc-8b-9dF" name="contentValues" keyPath="arrangedObjects.name" previousBinding="JGE-12-MXt" id="lIz-gH-9kJ"/>
|
||||||
|
<binding destination="52" name="selectedObject" keyPath="values.outputResampling" previousBinding="lIz-gH-9kJ" id="wcT-TT-yKh"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButton>
|
||||||
</subviews>
|
</subviews>
|
||||||
<point key="canvasLocation" x="-151" y="322"/>
|
<point key="canvasLocation" x="-151" y="337.5"/>
|
||||||
</customView>
|
</customView>
|
||||||
<customObject id="i5B-ga-Atm" userLabel="MIDIPane" customClass="MIDIPane">
|
<customObject id="i5B-ga-Atm" userLabel="MIDIPane" customClass="MIDIPane">
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -601,5 +631,13 @@
|
||||||
</declaredKeys>
|
</declaredKeys>
|
||||||
<classReference key="objectClass" className="NSDictionary"/>
|
<classReference key="objectClass" className="NSDictionary"/>
|
||||||
</arrayController>
|
</arrayController>
|
||||||
|
<arrayController objectClassName="NSDictionary" editable="NO" id="Yrc-8b-9dF" customClass="OutputResamplerBehaviorArrayController">
|
||||||
|
<declaredKeys>
|
||||||
|
<string>name</string>
|
||||||
|
<string>slug</string>
|
||||||
|
<string>preference</string>
|
||||||
|
</declaredKeys>
|
||||||
|
<classReference key="objectClass" className="NSDictionary"/>
|
||||||
|
</arrayController>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// OutputResamplerBehaviorArrayController.h
|
||||||
|
// General
|
||||||
|
//
|
||||||
|
// Created by Christopher Snowhill on 01/11/22.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface OutputResamplerBehaviorArrayController : NSArrayController
|
||||||
|
|
||||||
|
@end
|
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// OutputResamplerBehaviorArrayController.m
|
||||||
|
// General
|
||||||
|
//
|
||||||
|
// Created by Christopher Snowhill on 01/11/22.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "OutputResamplerBehaviorArrayController.h"
|
||||||
|
|
||||||
|
@implementation OutputResamplerBehaviorArrayController
|
||||||
|
- (void)awakeFromNib
|
||||||
|
{
|
||||||
|
[self removeObjects:[self arrangedObjects]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
NSLocalizedStringFromTableInBundle(@"Lowest", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
|
||||||
|
@"lowest", @"preference",nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
NSLocalizedStringFromTableInBundle(@"Lower", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
|
||||||
|
@"lower", @"preference",nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
NSLocalizedStringFromTableInBundle(@"Normal", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
|
||||||
|
@"normal", @"preference",nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
NSLocalizedStringFromTableInBundle(@"Higher", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
|
||||||
|
@"higher", @"preference",nil]];
|
||||||
|
|
||||||
|
[self addObject:
|
||||||
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
NSLocalizedStringFromTableInBundle(@"Highest", nil, [NSBundle bundleForClass:[self class]], @"") , @"name",
|
||||||
|
@"highest", @"preference",nil]];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
|
@ -18,6 +18,7 @@
|
||||||
17E41DB80C130AA500AC744D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 17E41DB70C130AA500AC744D /* Localizable.strings */; };
|
17E41DB80C130AA500AC744D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 17E41DB70C130AA500AC744D /* Localizable.strings */; };
|
||||||
17E78A7E0D68BE3C005C5A59 /* file_tree.png in Resources */ = {isa = PBXBuildFile; fileRef = 17E78A7D0D68BE3C005C5A59 /* file_tree.png */; };
|
17E78A7E0D68BE3C005C5A59 /* file_tree.png in Resources */ = {isa = PBXBuildFile; fileRef = 17E78A7D0D68BE3C005C5A59 /* file_tree.png */; };
|
||||||
17E78B6A0D68C1E3005C5A59 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17E78B680D68C1E3005C5A59 /* Preferences.xib */; };
|
17E78B6A0D68C1E3005C5A59 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17E78B680D68C1E3005C5A59 /* Preferences.xib */; };
|
||||||
|
832BEF00278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 832BEEFC278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.m */; };
|
||||||
83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */; };
|
83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */; };
|
||||||
8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */; };
|
8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */; };
|
||||||
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; };
|
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; };
|
||||||
|
@ -93,6 +94,8 @@
|
||||||
32DBCF630370AF2F00C91783 /* Preferences_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Preferences_Prefix.pch; sourceTree = "<group>"; };
|
32DBCF630370AF2F00C91783 /* Preferences_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Preferences_Prefix.pch; sourceTree = "<group>"; };
|
||||||
3DFAC48E235B6B8100A29416 /* DEVELOPMENT_TEAM.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.xcconfig; sourceTree = "<group>"; };
|
3DFAC48E235B6B8100A29416 /* DEVELOPMENT_TEAM.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DEVELOPMENT_TEAM.xcconfig; sourceTree = "<group>"; };
|
||||||
3DFAC48F235B6B8100A29416 /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
3DFAC48F235B6B8100A29416 /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||||
|
832BEEFC278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OutputResamplerBehaviorArrayController.m; sourceTree = "<group>"; };
|
||||||
|
832BEEFF278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputResamplerBehaviorArrayController.h; sourceTree = "<group>"; };
|
||||||
833F681B1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
833F681B1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
833F681C1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
833F681C1CDBCAA700AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||||
8347435D20E6D58800063D45 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Preferences.strings; sourceTree = "<group>"; };
|
8347435D20E6D58800063D45 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Preferences.strings; sourceTree = "<group>"; };
|
||||||
|
@ -245,6 +248,8 @@
|
||||||
83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */,
|
83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */,
|
||||||
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */,
|
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */,
|
||||||
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */,
|
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */,
|
||||||
|
832BEEFF278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.h */,
|
||||||
|
832BEEFC278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.m */,
|
||||||
17C643370B8A77CC00C53518 /* OutputsArrayController.h */,
|
17C643370B8A77CC00C53518 /* OutputsArrayController.h */,
|
||||||
17C643360B8A77CC00C53518 /* OutputsArrayController.m */,
|
17C643360B8A77CC00C53518 /* OutputsArrayController.m */,
|
||||||
99F1813D0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.h */,
|
99F1813D0DE01D7A00FD5FFB /* PlaylistBehaviorArrayController.h */,
|
||||||
|
@ -457,6 +462,7 @@
|
||||||
8E07AA8A0AAC8EA200A4B32F /* GeneralPreferencesPlugin.m in Sources */,
|
8E07AA8A0AAC8EA200A4B32F /* GeneralPreferencesPlugin.m in Sources */,
|
||||||
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */,
|
83EF495F17FBC96A00642E3C /* VolumeBehaviorArrayController.m in Sources */,
|
||||||
17C643380B8A77CC00C53518 /* OutputsArrayController.m in Sources */,
|
17C643380B8A77CC00C53518 /* OutputsArrayController.m in Sources */,
|
||||||
|
832BEF00278D989E005E1BC4 /* OutputResamplerBehaviorArrayController.m in Sources */,
|
||||||
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */,
|
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */,
|
||||||
17C6433F0B8A783F00C53518 /* OutputPane.m in Sources */,
|
17C6433F0B8A783F00C53518 /* OutputPane.m in Sources */,
|
||||||
170744AD0BFF3938002475C9 /* AppcastArrayController.m in Sources */,
|
170744AD0BFF3938002475C9 /* AppcastArrayController.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef _RARCH_CONFIG_H
|
||||||
|
#define _RARCH_CONFIG_H
|
||||||
|
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
|
||||||
|
#define HAVE_SSIZE_T 1
|
||||||
|
#define HAVE_STRL 1
|
||||||
|
|
||||||
|
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define __SSE__ 1
|
||||||
|
#define __SSE2__ 1
|
||||||
|
#define __AVX__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if TARGET_CPU_ARM || TARGET_CPU_ARM64
|
||||||
|
#define HAVE_NEON 1
|
||||||
|
#define __ARM_NEON__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/* Copyright (C) 2010-2021 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (s16_to_float.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SSE2__)
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <features/features_cpu.h>
|
||||||
|
#include <audio/conversion/s16_to_float.h>
|
||||||
|
|
||||||
|
#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
|
||||||
|
static bool s16_to_float_neon_enabled = false;
|
||||||
|
|
||||||
|
#include <arm_neon.h>
|
||||||
|
|
||||||
|
void convert_s16_to_float(float *out,
|
||||||
|
const int16_t *in, size_t samples, float gain)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
if (s16_to_float_neon_enabled)
|
||||||
|
{
|
||||||
|
float gf = gain / (1 << 15);
|
||||||
|
float32x4_t vgf = {gf, gf, gf, gf};
|
||||||
|
while (samples >= 8)
|
||||||
|
{
|
||||||
|
float32x4x2_t oreg;
|
||||||
|
int16x4x2_t inreg = vld2_s16(in);
|
||||||
|
int32x4_t p1 = vmovl_s16(inreg.val[0]);
|
||||||
|
int32x4_t p2 = vmovl_s16(inreg.val[1]);
|
||||||
|
oreg.val[0] = vmulq_f32(vcvtq_f32_s32(p1), vgf);
|
||||||
|
oreg.val[1] = vmulq_f32(vcvtq_f32_s32(p2), vgf);
|
||||||
|
vst2q_f32(out, oreg);
|
||||||
|
in += 8;
|
||||||
|
out += 8;
|
||||||
|
samples -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gain /= 0x8000;
|
||||||
|
|
||||||
|
for (; i < samples; i++)
|
||||||
|
out[i] = (float)in[i] * gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_s16_to_float_init_simd(void)
|
||||||
|
{
|
||||||
|
uint64_t cpu = cpu_features_get();
|
||||||
|
|
||||||
|
if (cpu & RETRO_SIMD_NEON)
|
||||||
|
s16_to_float_neon_enabled = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void convert_s16_to_float(float *out,
|
||||||
|
const int16_t *in, size_t samples, float gain)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
#if defined(__SSE2__)
|
||||||
|
float fgain = gain / UINT32_C(0x80000000);
|
||||||
|
__m128 factor = _mm_set1_ps(fgain);
|
||||||
|
|
||||||
|
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||||
|
{
|
||||||
|
__m128i input = _mm_loadu_si128((const __m128i *)in);
|
||||||
|
__m128i regs_l = _mm_unpacklo_epi16(_mm_setzero_si128(), input);
|
||||||
|
__m128i regs_r = _mm_unpackhi_epi16(_mm_setzero_si128(), input);
|
||||||
|
__m128 output_l = _mm_mul_ps(_mm_cvtepi32_ps(regs_l), factor);
|
||||||
|
__m128 output_r = _mm_mul_ps(_mm_cvtepi32_ps(regs_r), factor);
|
||||||
|
|
||||||
|
_mm_storeu_ps(out + 0, output_l);
|
||||||
|
_mm_storeu_ps(out + 4, output_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = samples - i;
|
||||||
|
i = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gain /= 0x8000;
|
||||||
|
|
||||||
|
for (; i < samples; i++)
|
||||||
|
out[i] = (float)in[i] * gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_s16_to_float_init_simd(void) { }
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/* Copyright (C) 2010-2021 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (s32_to_float.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SSE2__)
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <features/features_cpu.h>
|
||||||
|
#include <audio/conversion/s32_to_float.h>
|
||||||
|
|
||||||
|
#if (defined(__ARM_NEON__) || defined(HAVE_NEON))
|
||||||
|
static bool s32_to_float_neon_enabled = false;
|
||||||
|
|
||||||
|
#include <arm_neon.h>
|
||||||
|
|
||||||
|
void convert_s32_to_float(float *out,
|
||||||
|
const int32_t *in, size_t samples, float gain)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
if (s32_to_float_neon_enabled)
|
||||||
|
{
|
||||||
|
float gf = gain / (1 << 31);
|
||||||
|
float32x4_t vgf = {gf, gf, gf, gf};
|
||||||
|
while (samples >= 8)
|
||||||
|
{
|
||||||
|
float32x4x2_t oreg;
|
||||||
|
int32x4x2_t inreg = vld1q_s32_x2(in);
|
||||||
|
oreg.val[0] = vmulq_f32(vcvtq_f32_s32(inreg.val[0]), vgf);
|
||||||
|
oreg.val[1] = vmulq_f32(vcvtq_f32_s32(inreg.val[1]), vgf);
|
||||||
|
vst2q_f32(out, oreg);
|
||||||
|
in += 8;
|
||||||
|
out += 8;
|
||||||
|
samples -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gain /= 0x80000000L;
|
||||||
|
|
||||||
|
for (; i < samples; i++)
|
||||||
|
out[i] = (float)in[i] * gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_s32_to_float_init_simd(void)
|
||||||
|
{
|
||||||
|
uint64_t cpu = cpu_features_get();
|
||||||
|
|
||||||
|
if (cpu & RETRO_SIMD_NEON)
|
||||||
|
s32_to_float_neon_enabled = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void convert_s32_to_float(float *out,
|
||||||
|
const int32_t *in, size_t samples, float gain)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
#if defined(__SSE2__)
|
||||||
|
float fgain = gain / UINT32_C(0x80000000);
|
||||||
|
__m128 factor = _mm_set1_ps(fgain);
|
||||||
|
|
||||||
|
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||||
|
{
|
||||||
|
__m128i input = _mm_loadu_si128((const __m128i *)in);
|
||||||
|
__m128i input2 = _mm_loadu_si128((const __m128i *)(in + 4));
|
||||||
|
__m128 output_l = _mm_mul_ps(_mm_cvtepi32_ps(input), factor);
|
||||||
|
__m128 output_r = _mm_mul_ps(_mm_cvtepi32_ps(input2), factor);
|
||||||
|
|
||||||
|
_mm_storeu_ps(out + 0, output_l);
|
||||||
|
_mm_storeu_ps(out + 4, output_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = samples - i;
|
||||||
|
i = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gain /= 0x80000000L;
|
||||||
|
|
||||||
|
for (; i < samples; i++)
|
||||||
|
out[i] = (float)in[i] * gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convert_s32_to_float_init_simd(void) { }
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,197 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (audio_resampler.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <features/features_cpu.h>
|
||||||
|
#include <file/config_file_userdata.h>
|
||||||
|
|
||||||
|
#include <audio/audio_resampler.h>
|
||||||
|
|
||||||
|
static void resampler_null_process(void *a, struct resampler_data *b) { }
|
||||||
|
static size_t resampler_null_latency(void *a) { return 0; }
|
||||||
|
static void resampler_null_free(void *a) { }
|
||||||
|
static void *resampler_null_init(const struct resampler_config *a, double b,
|
||||||
|
enum resampler_quality c, size_t d, resampler_simd_mask_t e) { return (void*)0; }
|
||||||
|
|
||||||
|
retro_resampler_t null_resampler = {
|
||||||
|
resampler_null_init,
|
||||||
|
resampler_null_process,
|
||||||
|
resampler_null_free,
|
||||||
|
resampler_null_latency,
|
||||||
|
RESAMPLER_API_VERSION,
|
||||||
|
"null",
|
||||||
|
"null"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const retro_resampler_t *resampler_drivers[] = {
|
||||||
|
&sinc_resampler,
|
||||||
|
#ifdef HAVE_CC_RESAMPLER
|
||||||
|
&CC_resampler,
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_NEAREST_RESAMPLER
|
||||||
|
&nearest_resampler,
|
||||||
|
#endif
|
||||||
|
&null_resampler,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct resampler_config resampler_config = {
|
||||||
|
config_userdata_get_float,
|
||||||
|
config_userdata_get_int,
|
||||||
|
config_userdata_get_float_array,
|
||||||
|
config_userdata_get_int_array,
|
||||||
|
config_userdata_get_string,
|
||||||
|
config_userdata_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_resampler_driver_index:
|
||||||
|
* @ident : Identifier of resampler driver to find.
|
||||||
|
*
|
||||||
|
* Finds resampler driver index by @ident name.
|
||||||
|
*
|
||||||
|
* Returns: resampler driver index if resampler driver was found, otherwise
|
||||||
|
* -1.
|
||||||
|
**/
|
||||||
|
static int find_resampler_driver_index(const char *ident)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; resampler_drivers[i]; i++)
|
||||||
|
if (string_is_equal_noncase(ident, resampler_drivers[i]->ident))
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_resampler_driver:
|
||||||
|
* @ident : Identifier of resampler driver to find.
|
||||||
|
*
|
||||||
|
* Finds resampler by @ident name.
|
||||||
|
*
|
||||||
|
* Returns: resampler driver if resampler driver was found, otherwise
|
||||||
|
* NULL.
|
||||||
|
**/
|
||||||
|
static const retro_resampler_t *find_resampler_driver(const char *ident)
|
||||||
|
{
|
||||||
|
int i = find_resampler_driver_index(ident);
|
||||||
|
|
||||||
|
if (i >= 0)
|
||||||
|
return resampler_drivers[i];
|
||||||
|
|
||||||
|
return resampler_drivers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resampler_append_plugs:
|
||||||
|
* @re : Resampler handle
|
||||||
|
* @backend : Resampler backend that is about to be set.
|
||||||
|
* @bw_ratio : Bandwidth ratio.
|
||||||
|
*
|
||||||
|
* Initializes resampler driver based on queried CPU features.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successfully initialized, otherwise false (0).
|
||||||
|
**/
|
||||||
|
static bool resampler_append_plugs(void **re,
|
||||||
|
const retro_resampler_t **backend,
|
||||||
|
enum resampler_quality quality,
|
||||||
|
size_t channels,
|
||||||
|
double bw_ratio)
|
||||||
|
{
|
||||||
|
resampler_simd_mask_t mask = (resampler_simd_mask_t)cpu_features_get();
|
||||||
|
|
||||||
|
if (*backend)
|
||||||
|
*re = (*backend)->init(&resampler_config, bw_ratio, quality, channels, mask);
|
||||||
|
|
||||||
|
if (!*re)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_resampler_driver_find_handle:
|
||||||
|
* @idx : index of driver to get handle to.
|
||||||
|
*
|
||||||
|
* Returns: handle to audio resampler driver at index. Can be NULL
|
||||||
|
* if nothing found.
|
||||||
|
**/
|
||||||
|
const void *audio_resampler_driver_find_handle(int idx)
|
||||||
|
{
|
||||||
|
const void *drv = resampler_drivers[idx];
|
||||||
|
if (!drv)
|
||||||
|
return NULL;
|
||||||
|
return drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_resampler_driver_find_ident:
|
||||||
|
* @idx : index of driver to get handle to.
|
||||||
|
*
|
||||||
|
* Returns: Human-readable identifier of audio resampler driver at index.
|
||||||
|
* Can be NULL if nothing found.
|
||||||
|
**/
|
||||||
|
const char *audio_resampler_driver_find_ident(int idx)
|
||||||
|
{
|
||||||
|
const retro_resampler_t *drv = resampler_drivers[idx];
|
||||||
|
if (!drv)
|
||||||
|
return NULL;
|
||||||
|
return drv->ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retro_resampler_realloc:
|
||||||
|
* @re : Resampler handle
|
||||||
|
* @backend : Resampler backend that is about to be set.
|
||||||
|
* @ident : Identifier name for resampler we want.
|
||||||
|
* @bw_ratio : Bandwidth ratio.
|
||||||
|
*
|
||||||
|
* Reallocates resampler. Will free previous handle before
|
||||||
|
* allocating a new one. If ident is NULL, first resampler will be used.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
|
||||||
|
const char *ident, enum resampler_quality quality, size_t channels,
|
||||||
|
double bw_ratio)
|
||||||
|
{
|
||||||
|
if (*re && *backend)
|
||||||
|
(*backend)->free(*re);
|
||||||
|
|
||||||
|
*re = NULL;
|
||||||
|
*backend = find_resampler_driver(ident);
|
||||||
|
|
||||||
|
if (!resampler_append_plugs(re, backend, quality, channels, bw_ratio))
|
||||||
|
{
|
||||||
|
if (!*re)
|
||||||
|
*backend = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
1079
ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c
vendored
Normal file
1079
ThirdParty/RetroArch/libretro-common/audio/resampler/drivers/sinc_resampler.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,512 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (encoding_utf.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(_XBOX)
|
||||||
|
#include <xtl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define UTF8_WALKBYTE(string) (*((*(string))++))
|
||||||
|
|
||||||
|
static unsigned leading_ones(uint8_t c)
|
||||||
|
{
|
||||||
|
unsigned ones = 0;
|
||||||
|
while (c & 0x80)
|
||||||
|
{
|
||||||
|
ones++;
|
||||||
|
c <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ones;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple implementation. Assumes the sequence is
|
||||||
|
* properly synchronized and terminated. */
|
||||||
|
|
||||||
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
|
const char *in, size_t in_size)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
size_t ret = 0;
|
||||||
|
while (in_size && out_chars)
|
||||||
|
{
|
||||||
|
unsigned extra, shift;
|
||||||
|
uint32_t c;
|
||||||
|
uint8_t first = *in++;
|
||||||
|
unsigned ones = leading_ones(first);
|
||||||
|
|
||||||
|
if (ones > 6 || ones == 1) /* Invalid or desync. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
extra = ones ? ones - 1 : ones;
|
||||||
|
if (1 + extra > in_size) /* Overflow. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
shift = (extra - 1) * 6;
|
||||||
|
c = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
|
||||||
|
|
||||||
|
for (i = 0; i < extra; i++, in++, shift -= 6)
|
||||||
|
c |= (*in & 0x3f) << shift;
|
||||||
|
|
||||||
|
*out++ = c;
|
||||||
|
in_size -= 1 + extra;
|
||||||
|
out_chars--;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||||
|
const uint16_t *in, size_t in_size)
|
||||||
|
{
|
||||||
|
size_t out_pos = 0;
|
||||||
|
size_t in_pos = 0;
|
||||||
|
static const
|
||||||
|
uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
unsigned num_adds;
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
if (in_pos == in_size)
|
||||||
|
{
|
||||||
|
*out_chars = out_pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
value = in[in_pos++];
|
||||||
|
if (value < 0x80)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
out[out_pos] = (char)value;
|
||||||
|
out_pos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value >= 0xD800 && value < 0xE000)
|
||||||
|
{
|
||||||
|
uint32_t c2;
|
||||||
|
|
||||||
|
if (value >= 0xDC00 || in_pos == in_size)
|
||||||
|
break;
|
||||||
|
c2 = in[in_pos++];
|
||||||
|
if (c2 < 0xDC00 || c2 >= 0xE000)
|
||||||
|
break;
|
||||||
|
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (num_adds = 1; num_adds < 5; num_adds++)
|
||||||
|
if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
|
||||||
|
break;
|
||||||
|
if (out)
|
||||||
|
out[out_pos] = (char)(utf8_limits[num_adds - 1]
|
||||||
|
+ (value >> (6 * num_adds)));
|
||||||
|
out_pos++;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
num_adds--;
|
||||||
|
if (out)
|
||||||
|
out[out_pos] = (char)(0x80
|
||||||
|
+ ((value >> (6 * num_adds)) & 0x3F));
|
||||||
|
out_pos++;
|
||||||
|
}while (num_adds != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_chars = out_pos;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Acts mostly like strlcpy.
|
||||||
|
*
|
||||||
|
* Copies the given number of UTF-8 characters,
|
||||||
|
* but at most d_len bytes.
|
||||||
|
*
|
||||||
|
* Always NULL terminates.
|
||||||
|
* Does not copy half a character.
|
||||||
|
*
|
||||||
|
* Returns number of bytes. 's' is assumed valid UTF-8.
|
||||||
|
* Use only if 'chars' is considerably less than 'd_len'. */
|
||||||
|
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||||
|
{
|
||||||
|
const uint8_t *sb = (const uint8_t*)s;
|
||||||
|
const uint8_t *sb_org = sb;
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (*sb && chars-- > 0)
|
||||||
|
{
|
||||||
|
sb++;
|
||||||
|
while ((*sb & 0xC0) == 0x80)
|
||||||
|
sb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
|
||||||
|
{
|
||||||
|
sb = sb_org + d_len-1;
|
||||||
|
while ((*sb & 0xC0) == 0x80)
|
||||||
|
sb--;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(d, sb_org, sb-sb_org);
|
||||||
|
d[sb-sb_org] = '\0';
|
||||||
|
|
||||||
|
return sb-sb_org;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *utf8skip(const char *str, size_t chars)
|
||||||
|
{
|
||||||
|
const uint8_t *strb = (const uint8_t*)str;
|
||||||
|
|
||||||
|
if (!chars)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
strb++;
|
||||||
|
while ((*strb & 0xC0)==0x80)
|
||||||
|
strb++;
|
||||||
|
chars--;
|
||||||
|
}while (chars);
|
||||||
|
|
||||||
|
return (const char*)strb;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t utf8len(const char *string)
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
|
if (!string)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (*string)
|
||||||
|
{
|
||||||
|
if ((*string & 0xC0) != 0x80)
|
||||||
|
ret++;
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
if (first < 128)
|
||||||
|
return first;
|
||||||
|
|
||||||
|
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||||
|
if (first >= 0xE0)
|
||||||
|
{
|
||||||
|
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||||
|
if (first >= 0xF0)
|
||||||
|
{
|
||||||
|
ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
|
||||||
|
return ret | (first & 7) << 18;
|
||||||
|
}
|
||||||
|
return ret | (first & 15) << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret | (first & 31) << 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool utf16_to_char(uint8_t **utf_data,
|
||||||
|
size_t *dest_len, const uint16_t *in)
|
||||||
|
{
|
||||||
|
unsigned len = 0;
|
||||||
|
|
||||||
|
while (in[len] != '\0')
|
||||||
|
len++;
|
||||||
|
|
||||||
|
utf16_conv_utf8(NULL, dest_len, in, len);
|
||||||
|
*dest_len += 1;
|
||||||
|
*utf_data = (uint8_t*)malloc(*dest_len);
|
||||||
|
if (*utf_data == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||||
|
{
|
||||||
|
size_t dest_len = 0;
|
||||||
|
uint8_t *utf16_data = NULL;
|
||||||
|
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
utf16_data[dest_len] = 0;
|
||||||
|
strlcpy(s, (const char*)utf16_data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(utf16_data);
|
||||||
|
utf16_data = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
static char *mb_to_mb_string_alloc(const char *str,
|
||||||
|
enum CodePage cp_in, enum CodePage cp_out)
|
||||||
|
{
|
||||||
|
wchar_t *path_buf_wide = NULL;
|
||||||
|
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
/* Windows 95 will return 0 from these functions with
|
||||||
|
* a UTF8 codepage set without MSLU.
|
||||||
|
*
|
||||||
|
* From an unknown MSDN version (others omit this info):
|
||||||
|
* - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
|
||||||
|
* Translate using UTF-8. When this is set, dwFlags must be zero.
|
||||||
|
* - Windows 95: Under the Microsoft Layer for Unicode,
|
||||||
|
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!path_buf_wide_len)
|
||||||
|
return strdup(str);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* utf8_to_local_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
if (str && *str)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
|
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||||
|
#else
|
||||||
|
/* assume string needs no modification if not on Windows */
|
||||||
|
return strdup(str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* local_to_utf8_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
if (str && *str)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||||
|
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||||
|
#else
|
||||||
|
/* assume string needs no modification if not on Windows */
|
||||||
|
return strdup(str);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
int len = 0;
|
||||||
|
int out_len = 0;
|
||||||
|
#else
|
||||||
|
size_t len = 0;
|
||||||
|
size_t out_len = 0;
|
||||||
|
#endif
|
||||||
|
wchar_t *buf = NULL;
|
||||||
|
|
||||||
|
if (!str || !*str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* fallback to ANSI codepage instead */
|
||||||
|
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_len < 0)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||||
|
len = mbstowcs(NULL, str, 0) + 1;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_len = mbstowcs(buf, str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_len == (size_t)-1)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
int len = 0;
|
||||||
|
#else
|
||||||
|
size_t len = 0;
|
||||||
|
#endif
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
if (!str || !*str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
{
|
||||||
|
UINT code_page = CP_UTF8;
|
||||||
|
len = WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
/* fallback to ANSI codepage instead */
|
||||||
|
if (!len)
|
||||||
|
{
|
||||||
|
code_page = CP_ACP;
|
||||||
|
len = WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, NULL, 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = (char*)calloc(len, sizeof(char));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (WideCharToMultiByte(code_page,
|
||||||
|
0, str, -1, buf, len, NULL, NULL) < 0)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* NOTE: For now, assume non-Windows platforms'
|
||||||
|
* locale is already UTF-8. */
|
||||||
|
len = wcstombs(NULL, str, 0) + 1;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
buf = (char*)calloc(len, sizeof(char));
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (wcstombs(buf, str, len) == (size_t)-1)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
|
@ -0,0 +1,877 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (features_cpu.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <features/features_cpu.h>
|
||||||
|
#include <retro_timers.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PSL1GHT__
|
||||||
|
#include <lv2/systime.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_XBOX360)
|
||||||
|
#include <PPCIntrinsics.h>
|
||||||
|
#elif !defined(__MACH__) && (defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) || defined(__PPC64__) || defined(__powerpc64__))
|
||||||
|
#ifndef _PPU_INTRINSICS_H
|
||||||
|
#include <ppu_intrinsics.h>
|
||||||
|
#endif
|
||||||
|
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(ANDROID) || defined(__QNX__) || defined(DJGPP)
|
||||||
|
/* POSIX_MONOTONIC_CLOCK is not being defined in Android headers despite support being present. */
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__QNX__) && !defined(CLOCK_MONOTONIC)
|
||||||
|
#define CLOCK_MONOTONIC 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PSP)
|
||||||
|
#include <pspkernel.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PSP) || defined(__PSL1GHT__)
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PSP)
|
||||||
|
#include <psprtc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(VITA)
|
||||||
|
#include <psp2/kernel/processmgr.h>
|
||||||
|
#include <psp2/rtc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PS2)
|
||||||
|
#include <ps2sdkapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
#include <sys/sys_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GEKKO
|
||||||
|
#include <ogc/lwp_watchdog.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIIU
|
||||||
|
#include <wiiu/os/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_LIBNX)
|
||||||
|
#include <switch.h>
|
||||||
|
#elif defined(SWITCH)
|
||||||
|
#include <libtransistor/types.h>
|
||||||
|
#include <libtransistor/svc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_3DS)
|
||||||
|
#include <3ds/svc.h>
|
||||||
|
#include <3ds/os.h>
|
||||||
|
#include <3ds/services/cfgu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* iOS/OSX specific. Lacks clock_gettime(), so implement it. */
|
||||||
|
#ifdef __MACH__
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#ifndef CLOCK_MONOTONIC
|
||||||
|
#define CLOCK_MONOTONIC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLOCK_REALTIME
|
||||||
|
#define CLOCK_REALTIME 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* this function is part of iOS 10 now */
|
||||||
|
static int ra_clock_gettime(int clk_ik, struct timespec *t)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
int rv = gettimeofday(&now, NULL);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
t->tv_sec = now.tv_sec;
|
||||||
|
t->tv_nsec = now.tv_usec * 1000;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__MACH__) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
|
||||||
|
#else
|
||||||
|
#define ra_clock_gettime clock_gettime
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BSD) || defined(__APPLE__)
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_perf_counter:
|
||||||
|
*
|
||||||
|
* Gets performance counter.
|
||||||
|
*
|
||||||
|
* Returns: performance counter.
|
||||||
|
**/
|
||||||
|
retro_perf_tick_t cpu_features_get_perf_counter(void)
|
||||||
|
{
|
||||||
|
retro_perf_tick_t time_ticks = 0;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
long tv_sec, tv_usec;
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||||
|
static const unsigned __int64 epoch = 11644473600000000;
|
||||||
|
#else
|
||||||
|
static const unsigned __int64 epoch = 11644473600000000ULL;
|
||||||
|
#endif
|
||||||
|
FILETIME file_time;
|
||||||
|
SYSTEMTIME system_time;
|
||||||
|
ULARGE_INTEGER ularge;
|
||||||
|
|
||||||
|
GetSystemTime(&system_time);
|
||||||
|
SystemTimeToFileTime(&system_time, &file_time);
|
||||||
|
ularge.LowPart = file_time.dwLowDateTime;
|
||||||
|
ularge.HighPart = file_time.dwHighDateTime;
|
||||||
|
|
||||||
|
tv_sec = (long)((ularge.QuadPart - epoch) / 10000000L);
|
||||||
|
tv_usec = (long)(system_time.wMilliseconds * 1000);
|
||||||
|
time_ticks = (1000000 * tv_sec + tv_usec);
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
time_ticks = gettime();
|
||||||
|
#elif !defined(__MACH__) && (defined(_XBOX360) || defined(__powerpc__) || defined(__ppc__) || defined(__POWERPC__) || defined(__PSL1GHT__) || defined(__PPC64__) || defined(__powerpc64__))
|
||||||
|
time_ticks = __mftb();
|
||||||
|
#elif (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0) || defined(__QNX__) || defined(ANDROID)
|
||||||
|
struct timespec tv = {0};
|
||||||
|
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) == 0)
|
||||||
|
time_ticks = (retro_perf_tick_t)tv.tv_sec * 1000000000 +
|
||||||
|
(retro_perf_tick_t)tv.tv_nsec;
|
||||||
|
|
||||||
|
#elif defined(__GNUC__) && defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(_M_X64) || defined(_M_AMD64)
|
||||||
|
__asm__ volatile ("rdtsc" : "=A" (time_ticks));
|
||||||
|
#elif defined(__GNUC__) && defined(__x86_64__) || defined(_M_IX86)
|
||||||
|
unsigned a, d;
|
||||||
|
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d));
|
||||||
|
time_ticks = (retro_perf_tick_t)a | ((retro_perf_tick_t)d << 32);
|
||||||
|
#elif defined(__ARM_ARCH_6__)
|
||||||
|
__asm__ volatile( "mrc p15, 0, %0, c9, c13, 0" : "=r"(time_ticks) );
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
__asm__ volatile( "mrs %0, cntvct_el0" : "=r"(time_ticks) );
|
||||||
|
#elif defined(PSP) || defined(VITA)
|
||||||
|
time_ticks = sceKernelGetSystemTimeWide();
|
||||||
|
#elif defined(PS2)
|
||||||
|
time_ticks = ps2_clock();
|
||||||
|
#elif defined(_3DS)
|
||||||
|
time_ticks = svcGetSystemTick();
|
||||||
|
#elif defined(WIIU)
|
||||||
|
time_ticks = OSGetSystemTime();
|
||||||
|
#elif defined(HAVE_LIBNX)
|
||||||
|
time_ticks = armGetSystemTick();
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
time_ticks = emscripten_get_now() * 1000;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return time_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_time_usec:
|
||||||
|
*
|
||||||
|
* Gets time in microseconds.
|
||||||
|
*
|
||||||
|
* Returns: time in microseconds.
|
||||||
|
**/
|
||||||
|
retro_time_t cpu_features_get_time_usec(void)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
static LARGE_INTEGER freq;
|
||||||
|
LARGE_INTEGER count;
|
||||||
|
|
||||||
|
/* Frequency is guaranteed to not change. */
|
||||||
|
if (!freq.QuadPart && !QueryPerformanceFrequency(&freq))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!QueryPerformanceCounter(&count))
|
||||||
|
return 0;
|
||||||
|
return (count.QuadPart / freq.QuadPart * 1000000) + (count.QuadPart % freq.QuadPart * 1000000 / freq.QuadPart);
|
||||||
|
#elif defined(__PSL1GHT__)
|
||||||
|
return sysGetSystemTime();
|
||||||
|
#elif !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
return sys_time_get_system_time();
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
return ticks_to_microsecs(gettime());
|
||||||
|
#elif defined(WIIU)
|
||||||
|
return ticks_to_us(OSGetSystemTime());
|
||||||
|
#elif defined(SWITCH) || defined(HAVE_LIBNX)
|
||||||
|
return (svcGetSystemTick() * 10) / 192;
|
||||||
|
#elif defined(_3DS)
|
||||||
|
return osGetTime() * 1000;
|
||||||
|
#elif defined(_POSIX_MONOTONIC_CLOCK) || defined(__QNX__) || defined(ANDROID) || defined(__MACH__) || defined(DJGPP)
|
||||||
|
struct timespec tv = {0};
|
||||||
|
if (ra_clock_gettime(CLOCK_MONOTONIC, &tv) < 0)
|
||||||
|
return 0;
|
||||||
|
return tv.tv_sec * INT64_C(1000000) + (tv.tv_nsec + 500) / 1000;
|
||||||
|
#elif defined(EMSCRIPTEN)
|
||||||
|
return emscripten_get_now() * 1000;
|
||||||
|
#elif defined(PS2)
|
||||||
|
return ps2_clock() / PS2_CLOCKS_PER_MSEC * 1000;
|
||||||
|
#elif defined(VITA) || defined(PSP)
|
||||||
|
return sceKernelGetSystemTimeWide();
|
||||||
|
#else
|
||||||
|
#error "Your platform does not have a timer function implemented in cpu_features_get_time_usec(). Cannot continue."
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) || (defined(_M_X64) && _MSC_VER > 1310) || (defined(_M_IX86) && _MSC_VER > 1310)
|
||||||
|
#define CPU_X86
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||||
|
#if (_MSC_VER > 1310)
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPU_X86) && !defined(__MACH__)
|
||||||
|
void x86_cpuid(int func, int flags[4])
|
||||||
|
{
|
||||||
|
/* On Android, we compile RetroArch with PIC, and we
|
||||||
|
* are not allowed to clobber the ebx register. */
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define REG_b "rbx"
|
||||||
|
#define REG_S "rsi"
|
||||||
|
#else
|
||||||
|
#define REG_b "ebx"
|
||||||
|
#define REG_S "esi"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
__asm__ volatile (
|
||||||
|
"mov %%" REG_b ", %%" REG_S "\n"
|
||||||
|
"cpuid\n"
|
||||||
|
"xchg %%" REG_b ", %%" REG_S "\n"
|
||||||
|
: "=a"(flags[0]), "=S"(flags[1]), "=c"(flags[2]), "=d"(flags[3])
|
||||||
|
: "a"(func));
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
__cpuid(flags, func);
|
||||||
|
#else
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("Unknown compiler. Cannot check CPUID with inline assembly.\n");
|
||||||
|
#endif
|
||||||
|
memset(flags, 0, 4 * sizeof(int));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only runs on i686 and above. Needs to be conditionally run. */
|
||||||
|
static uint64_t xgetbv_x86(uint32_t idx)
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
uint32_t eax, edx;
|
||||||
|
__asm__ volatile (
|
||||||
|
/* Older GCC versions (Apple's GCC for example) do
|
||||||
|
* not understand xgetbv instruction.
|
||||||
|
* Stamp out the machine code directly.
|
||||||
|
*/
|
||||||
|
".byte 0x0f, 0x01, 0xd0\n"
|
||||||
|
: "=a"(eax), "=d"(edx) : "c"(idx));
|
||||||
|
return ((uint64_t)edx << 32) | eax;
|
||||||
|
#elif _MSC_FULL_VER >= 160040219
|
||||||
|
/* Intrinsic only works on 2010 SP1 and above. */
|
||||||
|
return _xgetbv(idx);
|
||||||
|
#else
|
||||||
|
#ifndef NDEBUG
|
||||||
|
printf("Unknown compiler. Cannot check xgetbv bits.\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_NEON__)
|
||||||
|
#if defined(__arm__)
|
||||||
|
static void arm_enable_runfast_mode(void)
|
||||||
|
{
|
||||||
|
/* RunFast mode. Enables flush-to-zero and some
|
||||||
|
* floating point optimizations. */
|
||||||
|
static const unsigned x = 0x04086060;
|
||||||
|
static const unsigned y = 0x03000000;
|
||||||
|
int r;
|
||||||
|
__asm__ volatile(
|
||||||
|
"fmrx %0, fpscr \n\t" /* r0 = FPSCR */
|
||||||
|
"and %0, %0, %1 \n\t" /* r0 = r0 & 0x04086060 */
|
||||||
|
"orr %0, %0, %2 \n\t" /* r0 = r0 | 0x03000000 */
|
||||||
|
"fmxr fpscr, %0 \n\t" /* FPSCR = r0 */
|
||||||
|
: "=r"(r)
|
||||||
|
: "r"(x), "r"(y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__linux__) && !defined(CPU_X86)
|
||||||
|
static unsigned char check_arm_cpu_feature(const char* feature)
|
||||||
|
{
|
||||||
|
char line[1024];
|
||||||
|
unsigned char status = 0;
|
||||||
|
RFILE *fp = filestream_open("/proc/cpuinfo",
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (filestream_gets(fp, line, sizeof(line)))
|
||||||
|
{
|
||||||
|
if (strncmp(line, "Features\t: ", 11))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strstr(line + 11, feature))
|
||||||
|
status = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filestream_close(fp);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
/* Parse an decimal integer starting from 'input', but not going further
|
||||||
|
* than 'limit'. Return the value into '*result'.
|
||||||
|
*
|
||||||
|
* NOTE: Does not skip over leading spaces, or deal with sign characters.
|
||||||
|
* NOTE: Ignores overflows.
|
||||||
|
*
|
||||||
|
* The function returns NULL in case of error (bad format), or the new
|
||||||
|
* position after the decimal number in case of success (which will always
|
||||||
|
* be <= 'limit').
|
||||||
|
*/
|
||||||
|
static const char *parse_decimal(const char* input,
|
||||||
|
const char* limit, int* result)
|
||||||
|
{
|
||||||
|
const char* p = input;
|
||||||
|
int val = 0;
|
||||||
|
|
||||||
|
while (p < limit)
|
||||||
|
{
|
||||||
|
int d = (*p - '0');
|
||||||
|
if ((unsigned)d >= 10U)
|
||||||
|
break;
|
||||||
|
val = val*10 + d;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (p == input)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*result = val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a textual list of cpus and store the result inside a CpuList object.
|
||||||
|
* Input format is the following:
|
||||||
|
* - comma-separated list of items (no spaces)
|
||||||
|
* - each item is either a single decimal number (cpu index), or a range made
|
||||||
|
* of two numbers separated by a single dash (-). Ranges are inclusive.
|
||||||
|
*
|
||||||
|
* Examples: 0
|
||||||
|
* 2,4-127,128-143
|
||||||
|
* 0-1
|
||||||
|
*/
|
||||||
|
static void cpulist_parse(CpuList* list, char **buf, ssize_t length)
|
||||||
|
{
|
||||||
|
const char* p = (const char*)buf;
|
||||||
|
const char* end = p + length;
|
||||||
|
|
||||||
|
/* NOTE: the input line coming from sysfs typically contains a
|
||||||
|
* trailing newline, so take care of it in the code below
|
||||||
|
*/
|
||||||
|
while (p < end && *p != '\n')
|
||||||
|
{
|
||||||
|
int val, start_value, end_value;
|
||||||
|
/* Find the end of current item, and put it into 'q' */
|
||||||
|
const char *q = (const char*)memchr(p, ',', end-p);
|
||||||
|
|
||||||
|
if (!q)
|
||||||
|
q = end;
|
||||||
|
|
||||||
|
/* Get first value */
|
||||||
|
if (!(p = parse_decimal(p, q, &start_value)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
end_value = start_value;
|
||||||
|
|
||||||
|
/* If we're not at the end of the item, expect a dash and
|
||||||
|
* and integer; extract end value.
|
||||||
|
*/
|
||||||
|
if (p < q && *p == '-')
|
||||||
|
{
|
||||||
|
if (!(p = parse_decimal(p+1, q, &end_value)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set bits CPU list bits */
|
||||||
|
for (val = start_value; val <= end_value; val++)
|
||||||
|
{
|
||||||
|
if ((unsigned)val < 32)
|
||||||
|
list->mask |= (uint32_t)(UINT32_C(1) << val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Jump to next item */
|
||||||
|
p = q;
|
||||||
|
if (p < end)
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a CPU list from one sysfs file */
|
||||||
|
static void cpulist_read_from(CpuList* list, const char* filename)
|
||||||
|
{
|
||||||
|
ssize_t length;
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
list->mask = 0;
|
||||||
|
|
||||||
|
if (filestream_read_file(filename, (void**)&buf, &length) != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpulist_parse(list, &buf, length);
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_core_amount:
|
||||||
|
*
|
||||||
|
* Gets the amount of available CPU cores.
|
||||||
|
*
|
||||||
|
* Returns: amount of CPU cores available.
|
||||||
|
**/
|
||||||
|
unsigned cpu_features_get_core_amount(void)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
/* Win32 */
|
||||||
|
SYSTEM_INFO sysinfo;
|
||||||
|
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||||
|
GetNativeSystemInfo(&sysinfo);
|
||||||
|
#else
|
||||||
|
GetSystemInfo(&sysinfo);
|
||||||
|
#endif
|
||||||
|
return sysinfo.dwNumberOfProcessors;
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
return 1;
|
||||||
|
#elif defined(PSP) || defined(PS2)
|
||||||
|
return 1;
|
||||||
|
#elif defined(__PSL1GHT__) || !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
return 1; /* Only one PPU, SPUs don't really count */
|
||||||
|
#elif defined(VITA)
|
||||||
|
return 4;
|
||||||
|
#elif defined(HAVE_LIBNX) || defined(SWITCH)
|
||||||
|
return 4;
|
||||||
|
#elif defined(_3DS)
|
||||||
|
u8 device_model = 0xFF;
|
||||||
|
CFGU_GetSystemModel(&device_model);/*(0 = O3DS, 1 = O3DSXL, 2 = N3DS, 3 = 2DS, 4 = N3DSXL, 5 = N2DSXL)*/
|
||||||
|
switch (device_model)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
/*Old 3/2DS*/
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
/*New 3/2DS*/
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/*Unknown Device Or Check Failed*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#elif defined(WIIU)
|
||||||
|
return 3;
|
||||||
|
#elif defined(_SC_NPROCESSORS_ONLN)
|
||||||
|
/* Linux, most UNIX-likes. */
|
||||||
|
long ret = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (ret <= 0)
|
||||||
|
return (unsigned)1;
|
||||||
|
return (unsigned)ret;
|
||||||
|
#elif defined(BSD) || defined(__APPLE__)
|
||||||
|
/* BSD */
|
||||||
|
/* Copypasta from stackoverflow, dunno if it works. */
|
||||||
|
int num_cpu = 0;
|
||||||
|
int mib[4];
|
||||||
|
size_t len = sizeof(num_cpu);
|
||||||
|
|
||||||
|
mib[0] = CTL_HW;
|
||||||
|
mib[1] = HW_AVAILCPU;
|
||||||
|
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||||
|
if (num_cpu < 1)
|
||||||
|
{
|
||||||
|
mib[1] = HW_NCPU;
|
||||||
|
sysctl(mib, 2, &num_cpu, &len, NULL, 0);
|
||||||
|
if (num_cpu < 1)
|
||||||
|
num_cpu = 1;
|
||||||
|
}
|
||||||
|
return num_cpu;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
CpuList cpus_present[1];
|
||||||
|
CpuList cpus_possible[1];
|
||||||
|
int amount = 0;
|
||||||
|
|
||||||
|
cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
|
||||||
|
cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
|
||||||
|
|
||||||
|
/* Compute the intersection of both sets to get the actual number of
|
||||||
|
* CPU cores that can be used on this device by the kernel.
|
||||||
|
*/
|
||||||
|
cpus_present->mask &= cpus_possible->mask;
|
||||||
|
amount = __builtin_popcount(cpus_present->mask);
|
||||||
|
|
||||||
|
if (amount == 0)
|
||||||
|
return 1;
|
||||||
|
return amount;
|
||||||
|
#elif defined(_XBOX360)
|
||||||
|
return 3;
|
||||||
|
#else
|
||||||
|
/* No idea, assume single core. */
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* According to http://en.wikipedia.org/wiki/CPUID */
|
||||||
|
#define VENDOR_INTEL_b 0x756e6547
|
||||||
|
#define VENDOR_INTEL_c 0x6c65746e
|
||||||
|
#define VENDOR_INTEL_d 0x49656e69
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get:
|
||||||
|
*
|
||||||
|
* Gets CPU features..
|
||||||
|
*
|
||||||
|
* Returns: bitmask of all CPU features available.
|
||||||
|
**/
|
||||||
|
uint64_t cpu_features_get(void)
|
||||||
|
{
|
||||||
|
uint64_t cpu = 0;
|
||||||
|
#if defined(CPU_X86) && !defined(__MACH__)
|
||||||
|
int vendor_is_intel = 0;
|
||||||
|
const int avx_flags = (1 << 27) | (1 << 28);
|
||||||
|
#endif
|
||||||
|
#if defined(__MACH__)
|
||||||
|
size_t len = sizeof(size_t);
|
||||||
|
|
||||||
|
if (sysctlbyname("hw.optional.floatingpoint", NULL, &len, NULL, 0) == 0)
|
||||||
|
{
|
||||||
|
cpu |= RETRO_SIMD_CMOV;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CPU_X86)
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.mmx", NULL, &len, NULL, 0) == 0)
|
||||||
|
{
|
||||||
|
cpu |= RETRO_SIMD_MMX;
|
||||||
|
cpu |= RETRO_SIMD_MMXEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse2", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE2;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse3", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE3;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.supplementalsse3", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSSE3;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse4_1", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE4;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.sse4_2", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_SSE42;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.aes", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_AES;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.avx1_0", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_AVX;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.avx2_0", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_AVX2;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.altivec", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_VMX;
|
||||||
|
|
||||||
|
#else
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.neon", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.neon_fp16", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_VFPV3;
|
||||||
|
|
||||||
|
len = sizeof(size_t);
|
||||||
|
if (sysctlbyname("hw.optional.neon_hpfp", NULL, &len, NULL, 0) == 0)
|
||||||
|
cpu |= RETRO_SIMD_VFPV4;
|
||||||
|
#endif
|
||||||
|
#elif defined(_XBOX1)
|
||||||
|
cpu |= RETRO_SIMD_MMX;
|
||||||
|
cpu |= RETRO_SIMD_SSE;
|
||||||
|
cpu |= RETRO_SIMD_MMXEXT;
|
||||||
|
#elif defined(CPU_X86)
|
||||||
|
unsigned max_flag = 0;
|
||||||
|
int flags[4];
|
||||||
|
int vendor_shuffle[3];
|
||||||
|
char vendor[13];
|
||||||
|
uint64_t cpu_flags = 0;
|
||||||
|
x86_cpuid(0, flags);
|
||||||
|
vendor_shuffle[0] = flags[1];
|
||||||
|
vendor_shuffle[1] = flags[3];
|
||||||
|
vendor_shuffle[2] = flags[2];
|
||||||
|
|
||||||
|
vendor[0] = '\0';
|
||||||
|
memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle));
|
||||||
|
|
||||||
|
/* printf("[CPUID]: Vendor: %s\n", vendor); */
|
||||||
|
|
||||||
|
vendor_is_intel = (
|
||||||
|
flags[1] == VENDOR_INTEL_b &&
|
||||||
|
flags[2] == VENDOR_INTEL_c &&
|
||||||
|
flags[3] == VENDOR_INTEL_d);
|
||||||
|
|
||||||
|
max_flag = flags[0];
|
||||||
|
if (max_flag < 1) /* Does CPUID not support func = 1? (unlikely ...) */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
x86_cpuid(1, flags);
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 15))
|
||||||
|
cpu |= RETRO_SIMD_CMOV;
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 23))
|
||||||
|
cpu |= RETRO_SIMD_MMX;
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 25))
|
||||||
|
{
|
||||||
|
/* SSE also implies MMXEXT (according to FFmpeg source). */
|
||||||
|
cpu |= RETRO_SIMD_SSE;
|
||||||
|
cpu |= RETRO_SIMD_MMXEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags[3] & (1 << 26))
|
||||||
|
cpu |= RETRO_SIMD_SSE2;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 0))
|
||||||
|
cpu |= RETRO_SIMD_SSE3;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 9))
|
||||||
|
cpu |= RETRO_SIMD_SSSE3;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 19))
|
||||||
|
cpu |= RETRO_SIMD_SSE4;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 20))
|
||||||
|
cpu |= RETRO_SIMD_SSE42;
|
||||||
|
|
||||||
|
if ((flags[2] & (1 << 23)))
|
||||||
|
cpu |= RETRO_SIMD_POPCNT;
|
||||||
|
|
||||||
|
if (vendor_is_intel && (flags[2] & (1 << 22)))
|
||||||
|
cpu |= RETRO_SIMD_MOVBE;
|
||||||
|
|
||||||
|
if (flags[2] & (1 << 25))
|
||||||
|
cpu |= RETRO_SIMD_AES;
|
||||||
|
|
||||||
|
/* Must only perform xgetbv check if we have
|
||||||
|
* AVX CPU support (guaranteed to have at least i686). */
|
||||||
|
if (((flags[2] & avx_flags) == avx_flags)
|
||||||
|
&& ((xgetbv_x86(0) & 0x6) == 0x6))
|
||||||
|
cpu |= RETRO_SIMD_AVX;
|
||||||
|
|
||||||
|
if (max_flag >= 7)
|
||||||
|
{
|
||||||
|
x86_cpuid(7, flags);
|
||||||
|
if (flags[1] & (1 << 5))
|
||||||
|
cpu |= RETRO_SIMD_AVX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
x86_cpuid(0x80000000, flags);
|
||||||
|
max_flag = flags[0];
|
||||||
|
if (max_flag >= 0x80000001u)
|
||||||
|
{
|
||||||
|
x86_cpuid(0x80000001, flags);
|
||||||
|
if (flags[3] & (1 << 23))
|
||||||
|
cpu |= RETRO_SIMD_MMX;
|
||||||
|
if (flags[3] & (1 << 22))
|
||||||
|
cpu |= RETRO_SIMD_MMXEXT;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
if (check_arm_cpu_feature("neon"))
|
||||||
|
{
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
#if defined(__ARM_NEON__) && defined(__arm__)
|
||||||
|
arm_enable_runfast_mode();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_arm_cpu_feature("vfpv3"))
|
||||||
|
cpu |= RETRO_SIMD_VFPV3;
|
||||||
|
|
||||||
|
if (check_arm_cpu_feature("vfpv4"))
|
||||||
|
cpu |= RETRO_SIMD_VFPV4;
|
||||||
|
|
||||||
|
if (check_arm_cpu_feature("asimd"))
|
||||||
|
{
|
||||||
|
cpu |= RETRO_SIMD_ASIMD;
|
||||||
|
#ifdef __ARM_NEON__
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
#if defined(__arm__)
|
||||||
|
arm_enable_runfast_mode();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
check_arm_cpu_feature("swp");
|
||||||
|
check_arm_cpu_feature("half");
|
||||||
|
check_arm_cpu_feature("thumb");
|
||||||
|
check_arm_cpu_feature("fastmult");
|
||||||
|
check_arm_cpu_feature("vfp");
|
||||||
|
check_arm_cpu_feature("edsp");
|
||||||
|
check_arm_cpu_feature("thumbee");
|
||||||
|
check_arm_cpu_feature("tls");
|
||||||
|
check_arm_cpu_feature("idiva");
|
||||||
|
check_arm_cpu_feature("idivt");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__ARM_NEON__)
|
||||||
|
cpu |= RETRO_SIMD_NEON;
|
||||||
|
#if defined(__arm__)
|
||||||
|
arm_enable_runfast_mode();
|
||||||
|
#endif
|
||||||
|
#elif defined(__ALTIVEC__)
|
||||||
|
cpu |= RETRO_SIMD_VMX;
|
||||||
|
#elif defined(XBOX360)
|
||||||
|
cpu |= RETRO_SIMD_VMX128;
|
||||||
|
#elif defined(PSP) || defined(PS2)
|
||||||
|
cpu |= RETRO_SIMD_VFPU;
|
||||||
|
#elif defined(GEKKO)
|
||||||
|
cpu |= RETRO_SIMD_PS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_features_get_model_name(char *name, int len)
|
||||||
|
{
|
||||||
|
#if defined(CPU_X86) && !defined(__MACH__)
|
||||||
|
union {
|
||||||
|
int i[4];
|
||||||
|
unsigned char s[16];
|
||||||
|
} flags;
|
||||||
|
int i, j;
|
||||||
|
size_t pos = 0;
|
||||||
|
bool start = false;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
x86_cpuid(0x80000000, flags.i);
|
||||||
|
|
||||||
|
if (flags.i[0] < 0x80000004)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
memset(flags.i, 0, sizeof(flags.i));
|
||||||
|
x86_cpuid(0x80000002 + i, flags.i);
|
||||||
|
|
||||||
|
for (j = 0; j < sizeof(flags.s); j++)
|
||||||
|
{
|
||||||
|
if (!start && flags.s[j] == ' ')
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
start = true;
|
||||||
|
|
||||||
|
if (pos == len - 1)
|
||||||
|
{
|
||||||
|
/* truncate if we ran out of room */
|
||||||
|
name[pos] = '\0';
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
name[pos++] = flags.s[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
/* terminate our string */
|
||||||
|
if (pos < (size_t)len)
|
||||||
|
name[pos] = '\0';
|
||||||
|
#elif defined(__MACH__)
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
size_t len_size = len;
|
||||||
|
sysctlbyname("machdep.cpu.brand_string", name, &len_size, NULL, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!name)
|
||||||
|
return;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,171 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (config_file_userdata.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <file/file_path.h>
|
||||||
|
#include <lists/string_list.h>
|
||||||
|
|
||||||
|
#include <file/config_file_userdata.h>
|
||||||
|
|
||||||
|
int config_userdata_get_float(void *userdata, const char *key_str,
|
||||||
|
float *value, float default_value)
|
||||||
|
{
|
||||||
|
bool got;
|
||||||
|
char key[2][256];
|
||||||
|
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||||
|
|
||||||
|
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||||
|
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||||
|
|
||||||
|
got = config_get_float (usr->conf, key[0], value);
|
||||||
|
got = got || config_get_float(usr->conf, key[1], value);
|
||||||
|
|
||||||
|
if (!got)
|
||||||
|
*value = default_value;
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_userdata_get_int(void *userdata, const char *key_str,
|
||||||
|
int *value, int default_value)
|
||||||
|
{
|
||||||
|
bool got;
|
||||||
|
char key[2][256];
|
||||||
|
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||||
|
|
||||||
|
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||||
|
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||||
|
|
||||||
|
got = config_get_int (usr->conf, key[0], value);
|
||||||
|
got = got || config_get_int(usr->conf, key[1], value);
|
||||||
|
|
||||||
|
if (!got)
|
||||||
|
*value = default_value;
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_userdata_get_hex(void *userdata, const char *key_str,
|
||||||
|
unsigned *value, unsigned default_value)
|
||||||
|
{
|
||||||
|
bool got;
|
||||||
|
char key[2][256];
|
||||||
|
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||||
|
|
||||||
|
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||||
|
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||||
|
|
||||||
|
got = config_get_hex(usr->conf, key[0], value);
|
||||||
|
got = got || config_get_hex(usr->conf, key[1], value);
|
||||||
|
|
||||||
|
if (!got)
|
||||||
|
*value = default_value;
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_userdata_get_float_array(void *userdata, const char *key_str,
|
||||||
|
float **values, unsigned *out_num_values,
|
||||||
|
const float *default_values, unsigned num_default_values)
|
||||||
|
{
|
||||||
|
char key[2][256];
|
||||||
|
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||||
|
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||||
|
|
||||||
|
if ( config_get_string(usr->conf, key[0], &str) ||
|
||||||
|
config_get_string(usr->conf, key[1], &str))
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
struct string_list list = {0};
|
||||||
|
string_list_initialize(&list);
|
||||||
|
string_split_noalloc(&list, str, " ");
|
||||||
|
*values = (float*)calloc(list.size, sizeof(float));
|
||||||
|
for (i = 0; i < list.size; i++)
|
||||||
|
(*values)[i] = (float)strtod(list.elems[i].data, NULL);
|
||||||
|
*out_num_values = (unsigned)list.size;
|
||||||
|
string_list_deinitialize(&list);
|
||||||
|
free(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*values = (float*)calloc(num_default_values, sizeof(float));
|
||||||
|
memcpy(*values, default_values, sizeof(float) * num_default_values);
|
||||||
|
*out_num_values = num_default_values;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_userdata_get_int_array(void *userdata, const char *key_str,
|
||||||
|
int **values, unsigned *out_num_values,
|
||||||
|
const int *default_values, unsigned num_default_values)
|
||||||
|
{
|
||||||
|
char key[2][256];
|
||||||
|
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||||
|
char *str = NULL;
|
||||||
|
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||||
|
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||||
|
|
||||||
|
if ( config_get_string(usr->conf, key[0], &str) ||
|
||||||
|
config_get_string(usr->conf, key[1], &str))
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
struct string_list list = {0};
|
||||||
|
string_list_initialize(&list);
|
||||||
|
string_split_noalloc(&list, str, " ");
|
||||||
|
*values = (int*)calloc(list.size, sizeof(int));
|
||||||
|
for (i = 0; i < list.size; i++)
|
||||||
|
(*values)[i] = (int)strtod(list.elems[i].data, NULL);
|
||||||
|
*out_num_values = (unsigned)list.size;
|
||||||
|
string_list_deinitialize(&list);
|
||||||
|
free(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*values = (int*)calloc(num_default_values, sizeof(int));
|
||||||
|
memcpy(*values, default_values, sizeof(int) * num_default_values);
|
||||||
|
*out_num_values = num_default_values;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_userdata_get_string(void *userdata, const char *key_str,
|
||||||
|
char **output, const char *default_output)
|
||||||
|
{
|
||||||
|
char key[2][256];
|
||||||
|
struct config_file_userdata *usr = (struct config_file_userdata*)userdata;
|
||||||
|
char *str = NULL;
|
||||||
|
fill_pathname_join_delim(key[0], usr->prefix[0], key_str, '_', sizeof(key[0]));
|
||||||
|
fill_pathname_join_delim(key[1], usr->prefix[1], key_str, '_', sizeof(key[1]));
|
||||||
|
|
||||||
|
if ( config_get_string(usr->conf, key[0], &str) ||
|
||||||
|
config_get_string(usr->conf, key[1], &str))
|
||||||
|
{
|
||||||
|
*output = str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*output = strdup(default_output);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_userdata_free(void *ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
free(ptr);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,151 @@
|
||||||
|
/* 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 <compat/strl.h>
|
||||||
|
#include <compat/posix_string.h>
|
||||||
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <direct.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h> /* stat() is defined here */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO/FIXME - globals */
|
||||||
|
static retro_vfs_stat_t path_stat_cb = retro_vfs_stat_impl;
|
||||||
|
static retro_vfs_mkdir_t path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||||
|
|
||||||
|
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||||
|
{
|
||||||
|
const struct retro_vfs_interface*
|
||||||
|
vfs_iface = vfs_info->iface;
|
||||||
|
|
||||||
|
path_stat_cb = retro_vfs_stat_impl;
|
||||||
|
path_mkdir_cb = retro_vfs_mkdir_impl;
|
||||||
|
|
||||||
|
if (vfs_info->required_interface_version < PATH_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
path_stat_cb = vfs_iface->stat;
|
||||||
|
path_mkdir_cb = vfs_iface->mkdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
int path_stat(const char *path)
|
||||||
|
{
|
||||||
|
return path_stat_cb(path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_directory:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path is a directory.
|
||||||
|
*
|
||||||
|
* 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 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)
|
||||||
|
|| path_mkdir(basedir))
|
||||||
|
norecurse = true;
|
||||||
|
|
||||||
|
free(basedir);
|
||||||
|
|
||||||
|
if (norecurse)
|
||||||
|
{
|
||||||
|
int ret = path_mkdir_cb(dir);
|
||||||
|
|
||||||
|
/* Don't treat this as an error. */
|
||||||
|
if (ret == -2 && path_is_directory(dir))
|
||||||
|
return true;
|
||||||
|
else if (ret == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,284 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (rhmap.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_ARRAY_RHMAP_H__
|
||||||
|
#define __LIBRETRO_SDK_ARRAY_RHMAP_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file implements a hash map with 32-bit keys.
|
||||||
|
* Based on the implementation from the public domain Bitwise project
|
||||||
|
* by Per Vognsen - https://github.com/pervognsen/bitwise
|
||||||
|
*
|
||||||
|
* It's a super simple type safe hash map for C with no need
|
||||||
|
* to predeclare any type or anything.
|
||||||
|
* Will always allocate memory for twice the amount of max elements
|
||||||
|
* so larger structs should be stored as pointers or indices to an array.
|
||||||
|
* Can be used in C++ with POD types (without any constructor/destructor).
|
||||||
|
*
|
||||||
|
* Be careful not to supply modifying statements to the macro arguments.
|
||||||
|
* Something like RHMAP_FIT(map, i++); would have unintended results.
|
||||||
|
*
|
||||||
|
* Sample usage:
|
||||||
|
*
|
||||||
|
* -- Set 2 elements with string keys and mytype_t values:
|
||||||
|
* mytype_t* map = NULL;
|
||||||
|
* RHMAP_SET_STR(map, "foo", foo_element);
|
||||||
|
* RHMAP_SET_STR(map, "bar", bar_element);
|
||||||
|
* -- now RHMAP_LEN(map) == 2, RHMAP_GET_STR(map, "foo") == foo_element
|
||||||
|
*
|
||||||
|
* -- Check if keys exist:
|
||||||
|
* bool has_foo = RHMAP_HAS_STR(map, "foo");
|
||||||
|
* bool has_baz = RHMAP_HAS_STR(map, "baz");
|
||||||
|
* -- now has_foo == true, has_baz == false
|
||||||
|
*
|
||||||
|
* -- Removing a key:
|
||||||
|
* bool removed = RHMAP_DEL_STR(map, "bar");
|
||||||
|
* bool removed_again = RHMAP_DEL_STR(map, "bar");
|
||||||
|
* -- now RHMAP_LEN(map) == 1, removed == true, removed_again == false
|
||||||
|
*
|
||||||
|
* -- Add/modify via pointer:
|
||||||
|
* mytype_t* p_elem = RHMAP_PTR_STR(map, "qux");
|
||||||
|
* p_elem->a = 123;
|
||||||
|
* -- New keys initially have memory uninitialized
|
||||||
|
* -- Pointers can get invalidated when a key is added/removed
|
||||||
|
*
|
||||||
|
* -- Looking up the index for a given key:
|
||||||
|
* ptrdiff_t idx_foo = RHMAP_IDX_STR(map, "foo");
|
||||||
|
* ptrdiff_t idx_invalid = RHMAP_IDX_STR(map, "invalid");
|
||||||
|
* -- now idx_foo >= 0, idx_invalid == -1, map[idx_foo] == foo_element
|
||||||
|
* -- Indices can change when a key is added/removed
|
||||||
|
*
|
||||||
|
* -- Clear all elements (keep memory allocated):
|
||||||
|
* RHMAP_CLEAR(map);
|
||||||
|
* -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 16
|
||||||
|
*
|
||||||
|
* -- Reserve memory for at least N elements:
|
||||||
|
* RHMAP_FIT(map, 30);
|
||||||
|
* -- now RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 64
|
||||||
|
*
|
||||||
|
* -- Add elements with custom hash keys:
|
||||||
|
* RHMAP_SET(map, my_uint32_hash(key1), some_element);
|
||||||
|
* RHMAP_SET(map, my_uint32_hash(key2), other_element);
|
||||||
|
* -- now RHMAP_LEN(map) == 2, _GET/_HAS/_DEL/_PTR/_IDX also exist
|
||||||
|
*
|
||||||
|
* -- Iterate elements (random order, order can change on insert):
|
||||||
|
* for (size_t i = 0, cap = RHMAP_CAP(map); i != cap, i++)
|
||||||
|
* if (RHMAP_KEY(map, i))
|
||||||
|
* ------ here map[i] is the value of key RHMAP_KEY(map, i)
|
||||||
|
*
|
||||||
|
* -- Set a custom null value (is zeroed by default):
|
||||||
|
* RHMAP_SETNULLVAL(map, map_null);
|
||||||
|
* -- now RHMAP_GET_STR(map, "invalid") == map_null
|
||||||
|
*
|
||||||
|
* -- Free allocated memory:
|
||||||
|
* RHMAP_FREE(map);
|
||||||
|
* -- now map == NULL, RHMAP_LEN(map) == 0, RHMAP_CAP(map) == 0
|
||||||
|
*
|
||||||
|
* -- To handle running out of memory:
|
||||||
|
* bool ran_out_of_memory = !RHMAP_TRYFIT(map, 1000);
|
||||||
|
* -- before setting an element (with SET, PTR or NULLVAL).
|
||||||
|
* -- When out of memory, map will stay unmodified.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h> /* for malloc, realloc */
|
||||||
|
#include <string.h> /* for memcpy, memset */
|
||||||
|
#include <stddef.h> /* for ptrdiff_t, size_t */
|
||||||
|
#include <stdint.h> /* for uint32_t */
|
||||||
|
|
||||||
|
#define RHMAP_LEN(b) ((b) ? RHMAP__HDR(b)->len : 0)
|
||||||
|
#define RHMAP_MAX(b) ((b) ? RHMAP__HDR(b)->maxlen : 0)
|
||||||
|
#define RHMAP_CAP(b) ((b) ? RHMAP__HDR(b)->maxlen + 1 : 0)
|
||||||
|
#define RHMAP_KEY(b, idx) (RHMAP__HDR(b)->keys[idx])
|
||||||
|
#define RHMAP_KEY_STR(b, idx) (RHMAP__HDR(b)->key_strs[idx])
|
||||||
|
#define RHMAP_SETNULLVAL(b, val) (RHMAP__FIT1(b), b[-1] = (val))
|
||||||
|
#define RHMAP_CLEAR(b) ((b) ? (memset(RHMAP__HDR(b)->keys, 0, RHMAP_CAP(b) * sizeof(uint32_t)), RHMAP__HDR(b)->len = 0) : 0)
|
||||||
|
#define RHMAP_FREE(b) ((b) ? (rhmap__free(RHMAP__HDR(b)), (b) = NULL) : 0)
|
||||||
|
#define RHMAP_FIT(b, n) ((!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))) ? 0 : RHMAP__GROW(b, n))
|
||||||
|
#define RHMAP_TRYFIT(b, n) (RHMAP_FIT((b), (n)), (!(n) || ((b) && (size_t)(n) * 2 <= RHMAP_MAX(b))))
|
||||||
|
|
||||||
|
#define RHMAP_SET(b, key, val) RHMAP_SET_FULL(b, key, NULL, val)
|
||||||
|
#define RHMAP_GET(b, key) RHMAP_GET_FULL(b, key, NULL)
|
||||||
|
#define RHMAP_HAS(b, key) RHMAP_HAS_FULL(b, key, NULL)
|
||||||
|
#define RHMAP_DEL(b, key) RHMAP_DEL_FULL(b, key, NULL)
|
||||||
|
#define RHMAP_PTR(b, key) RHMAP_PTR_FULL(b, key, NULL)
|
||||||
|
#define RHMAP_IDX(b, key) RHMAP_IDX_FULL(b, key, NULL)
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define RHMAP__UNUSED __attribute__((__unused__))
|
||||||
|
#else
|
||||||
|
#define RHMAP__UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4505) //unreferenced local function has been removed
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RHMAP_SET_FULL(b, key, str, val) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)] = (val))
|
||||||
|
#define RHMAP_GET_FULL(b, key, str) (RHMAP__FIT1(b), b[rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0)])
|
||||||
|
#define RHMAP_HAS_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) != -1 : 0)
|
||||||
|
#define RHMAP_DEL_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, sizeof(*(b))) != -1 : 0)
|
||||||
|
#define RHMAP_PTR_FULL(b, key, str) (RHMAP__FIT1(b), &b[rhmap__idx(RHMAP__HDR(b), (key), (str), 1, 0)])
|
||||||
|
#define RHMAP_IDX_FULL(b, key, str) ((b) ? rhmap__idx(RHMAP__HDR(b), (key), (str), 0, 0) : -1)
|
||||||
|
|
||||||
|
#define RHMAP_SET_STR(b, string_key, val) RHMAP_SET_FULL(b, rhmap_hash_string(string_key), string_key, val)
|
||||||
|
#define RHMAP_GET_STR(b, string_key) RHMAP_GET_FULL(b, rhmap_hash_string(string_key), string_key)
|
||||||
|
#define RHMAP_HAS_STR(b, string_key) RHMAP_HAS_FULL(b, rhmap_hash_string(string_key), string_key)
|
||||||
|
#define RHMAP_DEL_STR(b, string_key) RHMAP_DEL_FULL(b, rhmap_hash_string(string_key), string_key)
|
||||||
|
#define RHMAP_PTR_STR(b, string_key) RHMAP_PTR_FULL(b, rhmap_hash_string(string_key), string_key)
|
||||||
|
#define RHMAP_IDX_STR(b, string_key) RHMAP_IDX_FULL(b, rhmap_hash_string(string_key), string_key)
|
||||||
|
|
||||||
|
RHMAP__UNUSED static uint32_t rhmap_hash_string(const char* str)
|
||||||
|
{
|
||||||
|
unsigned char c;
|
||||||
|
uint32_t hash = (uint32_t)0x811c9dc5;
|
||||||
|
while ((c = (unsigned char)*(str++)) != '\0')
|
||||||
|
hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
|
||||||
|
return (hash ? hash : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct rhmap__hdr { size_t len, maxlen; uint32_t *keys; char** key_strs; };
|
||||||
|
#define RHMAP__HDR(b) (((struct rhmap__hdr *)&(b)[-1])-1)
|
||||||
|
#define RHMAP__GROW(b, n) (*(void**)(&(b)) = rhmap__grow(RHMAP__HDR(b), (void*)(b), sizeof(*(b)), (size_t)(n)))
|
||||||
|
#define RHMAP__FIT1(b) ((b) && RHMAP_LEN(b) * 2 <= RHMAP_MAX(b) ? 0 : RHMAP__GROW(b, 0))
|
||||||
|
|
||||||
|
RHMAP__UNUSED static void* rhmap__grow(struct rhmap__hdr *old_hdr, void* old_ptr, size_t elem_size, size_t reserve)
|
||||||
|
{
|
||||||
|
struct rhmap__hdr *new_hdr;
|
||||||
|
char *new_vals;
|
||||||
|
size_t new_max = (old_ptr ? old_hdr->maxlen * 2 + 1 : 15);
|
||||||
|
while (new_max && new_max / 2 <= reserve)
|
||||||
|
if (!(new_max = new_max * 2 + 1))
|
||||||
|
return old_ptr; /* overflow */
|
||||||
|
|
||||||
|
new_hdr = (struct rhmap__hdr *)malloc(sizeof(struct rhmap__hdr) + (new_max + 2) * elem_size);
|
||||||
|
if (!new_hdr)
|
||||||
|
return old_ptr; /* out of memory */
|
||||||
|
|
||||||
|
new_hdr->maxlen = new_max;
|
||||||
|
new_hdr->keys = (uint32_t *)calloc(new_max + 1, sizeof(uint32_t));
|
||||||
|
if (!new_hdr->keys)
|
||||||
|
{
|
||||||
|
/* out of memory */
|
||||||
|
free(new_hdr);
|
||||||
|
return old_ptr;
|
||||||
|
}
|
||||||
|
new_hdr->key_strs = (char**)calloc(new_max + 1, sizeof(char*));
|
||||||
|
if (!new_hdr->key_strs)
|
||||||
|
{
|
||||||
|
/* out of memory */
|
||||||
|
free(new_hdr->keys);
|
||||||
|
free(new_hdr);
|
||||||
|
return old_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_vals = ((char*)(new_hdr + 1)) + elem_size;
|
||||||
|
if (old_ptr)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char* old_vals = ((char*)(old_hdr + 1)) + elem_size;
|
||||||
|
for (i = 0; i <= old_hdr->maxlen; i++)
|
||||||
|
{
|
||||||
|
uint32_t key, j;
|
||||||
|
if (!old_hdr->keys[i])
|
||||||
|
continue;
|
||||||
|
for (key = old_hdr->keys[i], j = key;; j++)
|
||||||
|
{
|
||||||
|
if (!new_hdr->keys[j &= new_hdr->maxlen])
|
||||||
|
{
|
||||||
|
new_hdr->keys[j] = key;
|
||||||
|
new_hdr->key_strs[j] = old_hdr->key_strs[i];
|
||||||
|
memcpy(new_vals + j * elem_size, old_vals + i * elem_size, elem_size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(new_vals - elem_size, old_vals - elem_size, elem_size);
|
||||||
|
new_hdr->len = old_hdr->len;
|
||||||
|
free(old_hdr->keys);
|
||||||
|
free(old_hdr->key_strs);
|
||||||
|
free(old_hdr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(new_vals - elem_size, 0, elem_size);
|
||||||
|
new_hdr->len = 0;
|
||||||
|
}
|
||||||
|
return new_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
RHMAP__UNUSED static ptrdiff_t rhmap__idx(struct rhmap__hdr* hdr, uint32_t key, const char * str, int add, size_t del)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
if (!key)
|
||||||
|
return (ptrdiff_t)-1;
|
||||||
|
|
||||||
|
for (i = key;; i++)
|
||||||
|
{
|
||||||
|
if (hdr->keys[i &= hdr->maxlen] == key && (!hdr->key_strs[i] || !str || !strcmp(hdr->key_strs[i], str)))
|
||||||
|
{
|
||||||
|
if (del)
|
||||||
|
{
|
||||||
|
hdr->len--;
|
||||||
|
hdr->keys[i] = 0;
|
||||||
|
free(hdr->key_strs[i]);
|
||||||
|
hdr->key_strs[i] = NULL;
|
||||||
|
while ((key = hdr->keys[i = (i + 1) & hdr->maxlen]) != 0)
|
||||||
|
{
|
||||||
|
if ((key = (uint32_t)rhmap__idx(hdr, key, str, 1, 0)) == i) continue;
|
||||||
|
hdr->len--;
|
||||||
|
hdr->keys[i] = 0;
|
||||||
|
free(hdr->key_strs[i]);
|
||||||
|
hdr->key_strs[i] = NULL;
|
||||||
|
memcpy(((char*)(hdr + 1)) + (key + 1) * del,
|
||||||
|
((char*)(hdr + 1)) + (i + 1) * del, del);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (ptrdiff_t)i;
|
||||||
|
}
|
||||||
|
if (!hdr->keys[i])
|
||||||
|
{
|
||||||
|
if (add) { hdr->len++; hdr->keys[i] = key; if (str) hdr->key_strs[i] = strdup(str); return (ptrdiff_t)i; }
|
||||||
|
return (ptrdiff_t)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RHMAP__UNUSED static void rhmap__free(struct rhmap__hdr* hdr)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i=0;i<hdr->maxlen+1;i++)
|
||||||
|
{
|
||||||
|
free(hdr->key_strs[i]);
|
||||||
|
}
|
||||||
|
free(hdr->key_strs);
|
||||||
|
free(hdr->keys);
|
||||||
|
free(hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,198 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (audio_resampler.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H
|
||||||
|
#define __LIBRETRO_SDK_AUDIO_RESAMPLER_DRIVER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define RESAMPLER_SIMD_SSE (1 << 0)
|
||||||
|
#define RESAMPLER_SIMD_SSE2 (1 << 1)
|
||||||
|
#define RESAMPLER_SIMD_VMX (1 << 2)
|
||||||
|
#define RESAMPLER_SIMD_VMX128 (1 << 3)
|
||||||
|
#define RESAMPLER_SIMD_AVX (1 << 4)
|
||||||
|
#define RESAMPLER_SIMD_NEON (1 << 5)
|
||||||
|
#define RESAMPLER_SIMD_SSE3 (1 << 6)
|
||||||
|
#define RESAMPLER_SIMD_SSSE3 (1 << 7)
|
||||||
|
#define RESAMPLER_SIMD_MMX (1 << 8)
|
||||||
|
#define RESAMPLER_SIMD_MMXEXT (1 << 9)
|
||||||
|
#define RESAMPLER_SIMD_SSE4 (1 << 10)
|
||||||
|
#define RESAMPLER_SIMD_SSE42 (1 << 11)
|
||||||
|
#define RESAMPLER_SIMD_AVX2 (1 << 12)
|
||||||
|
#define RESAMPLER_SIMD_VFPU (1 << 13)
|
||||||
|
#define RESAMPLER_SIMD_PS (1 << 14)
|
||||||
|
|
||||||
|
enum resampler_quality
|
||||||
|
{
|
||||||
|
RESAMPLER_QUALITY_DONTCARE = 0,
|
||||||
|
RESAMPLER_QUALITY_LOWEST,
|
||||||
|
RESAMPLER_QUALITY_LOWER,
|
||||||
|
RESAMPLER_QUALITY_NORMAL,
|
||||||
|
RESAMPLER_QUALITY_HIGHER,
|
||||||
|
RESAMPLER_QUALITY_HIGHEST
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A bit-mask of all supported SIMD instruction sets.
|
||||||
|
* Allows an implementation to pick different
|
||||||
|
* resampler_implementation structs.
|
||||||
|
*/
|
||||||
|
typedef unsigned resampler_simd_mask_t;
|
||||||
|
|
||||||
|
#define RESAMPLER_API_VERSION 1
|
||||||
|
|
||||||
|
struct resampler_data
|
||||||
|
{
|
||||||
|
const float *data_in;
|
||||||
|
float *data_out;
|
||||||
|
|
||||||
|
size_t input_frames;
|
||||||
|
size_t output_frames;
|
||||||
|
|
||||||
|
double ratio;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returns true if config key was found. Otherwise,
|
||||||
|
* returns false, and sets value to default value.
|
||||||
|
*/
|
||||||
|
typedef int (*resampler_config_get_float_t)(void *userdata,
|
||||||
|
const char *key, float *value, float default_value);
|
||||||
|
|
||||||
|
typedef int (*resampler_config_get_int_t)(void *userdata,
|
||||||
|
const char *key, int *value, int default_value);
|
||||||
|
|
||||||
|
/* Allocates an array with values. free() with resampler_config_free_t. */
|
||||||
|
typedef int (*resampler_config_get_float_array_t)(void *userdata,
|
||||||
|
const char *key, float **values, unsigned *out_num_values,
|
||||||
|
const float *default_values, unsigned num_default_values);
|
||||||
|
|
||||||
|
typedef int (*resampler_config_get_int_array_t)(void *userdata,
|
||||||
|
const char *key, int **values, unsigned *out_num_values,
|
||||||
|
const int *default_values, unsigned num_default_values);
|
||||||
|
|
||||||
|
typedef int (*resampler_config_get_string_t)(void *userdata,
|
||||||
|
const char *key, char **output, const char *default_output);
|
||||||
|
|
||||||
|
/* Calls free() in host runtime. Sometimes needed on Windows.
|
||||||
|
* free() on NULL is fine. */
|
||||||
|
typedef void (*resampler_config_free_t)(void *ptr);
|
||||||
|
|
||||||
|
struct resampler_config
|
||||||
|
{
|
||||||
|
resampler_config_get_float_t get_float;
|
||||||
|
resampler_config_get_int_t get_int;
|
||||||
|
|
||||||
|
resampler_config_get_float_array_t get_float_array;
|
||||||
|
resampler_config_get_int_array_t get_int_array;
|
||||||
|
|
||||||
|
resampler_config_get_string_t get_string;
|
||||||
|
/* Avoid problems where resampler plug and host are
|
||||||
|
* linked against different C runtimes. */
|
||||||
|
resampler_config_free_t free;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Bandwidth factor. Will be < 1.0 for downsampling, > 1.0 for upsampling.
|
||||||
|
* Corresponds to expected resampling ratio. */
|
||||||
|
typedef void *(*resampler_init_t)(const struct resampler_config *config,
|
||||||
|
double bandwidth_mod, enum resampler_quality quality,
|
||||||
|
size_t channels, resampler_simd_mask_t mask);
|
||||||
|
|
||||||
|
/* Frees the handle. */
|
||||||
|
typedef void (*resampler_free_t)(void *data);
|
||||||
|
|
||||||
|
/* Processes input data. */
|
||||||
|
typedef void (*resampler_process_t)(void *_data, struct resampler_data *data);
|
||||||
|
|
||||||
|
typedef size_t (*resampler_latency_t)(void *_data);
|
||||||
|
|
||||||
|
typedef struct retro_resampler
|
||||||
|
{
|
||||||
|
resampler_init_t init;
|
||||||
|
resampler_process_t process;
|
||||||
|
resampler_free_t free;
|
||||||
|
resampler_latency_t latency;
|
||||||
|
|
||||||
|
/* Must be RESAMPLER_API_VERSION */
|
||||||
|
unsigned api_version;
|
||||||
|
|
||||||
|
/* Human readable identifier of implementation. */
|
||||||
|
const char *ident;
|
||||||
|
|
||||||
|
/* Computer-friendly short version of ident.
|
||||||
|
* Lower case, no spaces and special characters, etc. */
|
||||||
|
const char *short_ident;
|
||||||
|
} retro_resampler_t;
|
||||||
|
|
||||||
|
typedef struct audio_frame_float
|
||||||
|
{
|
||||||
|
float l;
|
||||||
|
float r;
|
||||||
|
} audio_frame_float_t;
|
||||||
|
|
||||||
|
extern retro_resampler_t sinc_resampler;
|
||||||
|
#ifdef HAVE_CC_RESAMPLER
|
||||||
|
extern retro_resampler_t CC_resampler;
|
||||||
|
#endif
|
||||||
|
extern retro_resampler_t nearest_resampler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_resampler_driver_find_handle:
|
||||||
|
* @index : index of driver to get handle to.
|
||||||
|
*
|
||||||
|
* Returns: handle to audio resampler driver at index. Can be NULL
|
||||||
|
* if nothing found.
|
||||||
|
**/
|
||||||
|
const void *audio_resampler_driver_find_handle(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* audio_resampler_driver_find_ident:
|
||||||
|
* @index : index of driver to get handle to.
|
||||||
|
*
|
||||||
|
* Returns: Human-readable identifier of audio resampler driver at index.
|
||||||
|
* Can be NULL if nothing found.
|
||||||
|
**/
|
||||||
|
const char *audio_resampler_driver_find_ident(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retro_resampler_realloc:
|
||||||
|
* @re : Resampler handle
|
||||||
|
* @backend : Resampler backend that is about to be set.
|
||||||
|
* @ident : Identifier name for resampler we want.
|
||||||
|
* @bw_ratio : Bandwidth ratio.
|
||||||
|
*
|
||||||
|
* Reallocates resampler. Will free previous handle before
|
||||||
|
* allocating a new one. If ident is NULL, first resampler will be used.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool retro_resampler_realloc(void **re, const retro_resampler_t **backend,
|
||||||
|
const char *ident, enum resampler_quality quality, size_t channels,
|
||||||
|
double bw_ratio);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
55
ThirdParty/RetroArch/libretro-common/include/audio/conversion/s16_to_float.h
vendored
Normal file
55
ThirdParty/RetroArch/libretro-common/include/audio/conversion/s16_to_float.h
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* Copyright (C) 2010-2021 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (s16_to_float.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__
|
||||||
|
#define __LIBRETRO_SDK_CONVERSION_S16_TO_FLOAT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert_s16_to_float:
|
||||||
|
* @out : output buffer
|
||||||
|
* @in : input buffer
|
||||||
|
* @samples : size of samples to be converted
|
||||||
|
* @gain : gain applied (.e.g. audio volume)
|
||||||
|
*
|
||||||
|
* Converts from signed integer 16-bit
|
||||||
|
* to floating point.
|
||||||
|
**/
|
||||||
|
void convert_s16_to_float(float *out,
|
||||||
|
const int16_t *in, size_t samples, float gain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert_s16_to_float_init_simd:
|
||||||
|
*
|
||||||
|
* Sets up function pointers for conversion
|
||||||
|
* functions based on CPU features.
|
||||||
|
**/
|
||||||
|
void convert_s16_to_float_init_simd(void);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
55
ThirdParty/RetroArch/libretro-common/include/audio/conversion/s32_to_float.h
vendored
Normal file
55
ThirdParty/RetroArch/libretro-common/include/audio/conversion/s32_to_float.h
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* Copyright (C) 2010-2021 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (s32_to_float.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef __LIBRETRO_SDK_CONVERSION_S32_TO_FLOAT_H__
|
||||||
|
#define __LIBRETRO_SDK_CONVERSION_S32_TO_FLOAT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert_s32_to_float:
|
||||||
|
* @out : output buffer
|
||||||
|
* @in : input buffer
|
||||||
|
* @samples : size of samples to be converted
|
||||||
|
* @gain : gain applied (.e.g. audio volume)
|
||||||
|
*
|
||||||
|
* Converts from signed integer 16-bit
|
||||||
|
* to floating point.
|
||||||
|
**/
|
||||||
|
void convert_s32_to_float(float *out,
|
||||||
|
const int32_t *in, size_t samples, float gain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert_s32_to_float_init_simd:
|
||||||
|
*
|
||||||
|
* Sets up function pointers for conversion
|
||||||
|
* functions based on CPU features.
|
||||||
|
**/
|
||||||
|
void convert_s32_to_float_init_simd(void);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (boolean.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_BOOLEAN_H
|
||||||
|
#define __LIBRETRO_SDK_BOOLEAN_H
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
|
||||||
|
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
|
||||||
|
#define bool unsigned char
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#else
|
||||||
|
#include <stdbool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (fopen_utf8.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
|
||||||
|
/* TODO: enable */
|
||||||
|
/* #define fopen (use fopen_utf8 instead) */
|
||||||
|
void *fopen_utf8(const char * filename, const char * mode);
|
||||||
|
#else
|
||||||
|
#define fopen_utf8 fopen
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,126 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (msvc.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_MSVC_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_MSVC_H
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Pre-MSVC 2015 compilers don't implement snprintf, vsnprintf in a cross-platform manner. */
|
||||||
|
#if _MSC_VER < 1900
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef snprintf
|
||||||
|
#define snprintf c99_snprintf_retro__
|
||||||
|
#endif
|
||||||
|
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
||||||
|
|
||||||
|
#ifndef vsnprintf
|
||||||
|
#define vsnprintf c99_vsnprintf_retro__
|
||||||
|
#endif
|
||||||
|
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef UNICODE /* Do not bother with UNICODE at this time. */
|
||||||
|
#include <direct.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
|
||||||
|
* Cannot duplicate these efforts.
|
||||||
|
*/
|
||||||
|
#ifndef HAVE_SSIZE_T
|
||||||
|
#if defined(_WIN64)
|
||||||
|
typedef __int64 ssize_t;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
typedef int ssize_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define mkdir(dirname, unused) _mkdir(dirname)
|
||||||
|
#define strtoull _strtoui64
|
||||||
|
#undef strcasecmp
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#undef strncasecmp
|
||||||
|
#define strncasecmp _strnicmp
|
||||||
|
|
||||||
|
/* Disable some of the annoying warnings. */
|
||||||
|
#pragma warning(disable : 4800)
|
||||||
|
#pragma warning(disable : 4805)
|
||||||
|
#pragma warning(disable : 4244)
|
||||||
|
#pragma warning(disable : 4305)
|
||||||
|
#pragma warning(disable : 4146)
|
||||||
|
#pragma warning(disable : 4267)
|
||||||
|
#pragma warning(disable : 4723)
|
||||||
|
#pragma warning(disable : 4996)
|
||||||
|
|
||||||
|
/* roundf and va_copy is available since MSVC 2013 */
|
||||||
|
#if _MSC_VER < 1800
|
||||||
|
#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
|
||||||
|
#define va_copy(x, y) ((x) = (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _MSC_VER <= 1310
|
||||||
|
#ifndef __cplusplus
|
||||||
|
/* VC6 math.h doesn't define some functions when in C mode.
|
||||||
|
* Trying to define a prototype gives "undefined reference".
|
||||||
|
* But providing an implementation then gives "function already has body".
|
||||||
|
* So the equivalent of the implementations from math.h are used as
|
||||||
|
* defines here instead, and it seems to work.
|
||||||
|
*/
|
||||||
|
#define cosf(x) ((float)cos((double)x))
|
||||||
|
#define powf(x, y) ((float)pow((double)x, (double)y))
|
||||||
|
#define sinf(x) ((float)sin((double)x))
|
||||||
|
#define ceilf(x) ((float)ceil((double)x))
|
||||||
|
#define floorf(x) ((float)floor((double)x))
|
||||||
|
#define sqrtf(x) ((float)sqrt((double)x))
|
||||||
|
#define fabsf(x) ((float)fabs((double)(x)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _strtoui64
|
||||||
|
#define _strtoui64(x, y, z) (_atoi64(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX _MAX_PATH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIZE_MAX
|
||||||
|
#define SIZE_MAX _UI32_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (posix_string.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef strtok_r
|
||||||
|
#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)
|
||||||
|
|
||||||
|
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#undef strcasecmp
|
||||||
|
#undef strdup
|
||||||
|
#define strcasecmp(a, b) retro_strcasecmp__(a, b)
|
||||||
|
#define strdup(orig) retro_strdup__(orig)
|
||||||
|
int strcasecmp(const char *a, const char *b);
|
||||||
|
char *strdup(const char *orig);
|
||||||
|
|
||||||
|
/* isblank is available since MSVC 2013 */
|
||||||
|
#if _MSC_VER < 1800
|
||||||
|
#undef isblank
|
||||||
|
#define isblank(c) retro_isblank__(c)
|
||||||
|
int isblank(int c);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (strcasestr.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||||
|
#include "../../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRCASESTR
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* Avoid possible naming collisions during link
|
||||||
|
* since we prefer to use the actual name. */
|
||||||
|
#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)
|
||||||
|
|
||||||
|
char *strcasestr(const char *haystack, const char *needle);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,59 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (strl.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
|
||||||
|
#define __LIBRETRO_SDK_COMPAT_STRL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||||
|
#include "../../../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef __MACH__
|
||||||
|
#ifndef HAVE_STRL
|
||||||
|
#define HAVE_STRL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRL
|
||||||
|
/* Avoid possible naming collisions during link since
|
||||||
|
* we prefer to use the actual name. */
|
||||||
|
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
|
||||||
|
|
||||||
|
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
|
||||||
|
|
||||||
|
size_t strlcpy(char *dest, const char *source, size_t size);
|
||||||
|
size_t strlcat(char *dest, const char *source, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *strldup(const char *s, size_t n);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (utf.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_ENCODINGS_UTF_H
|
||||||
|
#define _LIBRETRO_ENCODINGS_UTF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
enum CodePage
|
||||||
|
{
|
||||||
|
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||||
|
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
|
const char *in, size_t in_size);
|
||||||
|
|
||||||
|
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||||
|
const uint16_t *in, size_t in_size);
|
||||||
|
|
||||||
|
size_t utf8len(const char *string);
|
||||||
|
|
||||||
|
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
||||||
|
|
||||||
|
const char *utf8skip(const char *str, size_t chars);
|
||||||
|
|
||||||
|
uint32_t utf8_walk(const char **string);
|
||||||
|
|
||||||
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||||
|
|
||||||
|
char* utf8_to_local_string_alloc(const char *str);
|
||||||
|
|
||||||
|
char* local_to_utf8_string_alloc(const char *str);
|
||||||
|
|
||||||
|
wchar_t* utf8_to_utf16_string_alloc(const char *str);
|
||||||
|
|
||||||
|
char* utf16_to_utf8_string_alloc(const wchar_t *str);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (features_cpu.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_SDK_CPU_INFO_H
|
||||||
|
#define _LIBRETRO_SDK_CPU_INFO_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_perf_counter:
|
||||||
|
*
|
||||||
|
* Gets performance counter.
|
||||||
|
*
|
||||||
|
* Returns: performance counter.
|
||||||
|
**/
|
||||||
|
retro_perf_tick_t cpu_features_get_perf_counter(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_time_usec:
|
||||||
|
*
|
||||||
|
* Gets time in microseconds, from an undefined epoch.
|
||||||
|
* The epoch may change between computers or across reboots.
|
||||||
|
*
|
||||||
|
* Returns: time in microseconds
|
||||||
|
**/
|
||||||
|
retro_time_t cpu_features_get_time_usec(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get:
|
||||||
|
*
|
||||||
|
* Gets CPU features.
|
||||||
|
*
|
||||||
|
* Returns: bitmask of all CPU features available.
|
||||||
|
**/
|
||||||
|
uint64_t cpu_features_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_features_get_core_amount:
|
||||||
|
*
|
||||||
|
* Gets the amount of available CPU cores.
|
||||||
|
*
|
||||||
|
* Returns: amount of CPU cores available.
|
||||||
|
**/
|
||||||
|
unsigned cpu_features_get_core_amount(void);
|
||||||
|
|
||||||
|
void cpu_features_get_model_name(char *name, int len);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,225 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (config_file.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_CONFIG_FILE_H
|
||||||
|
#define __LIBRETRO_SDK_CONFIG_FILE_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#define CONFIG_GET_BOOL_BASE(conf, base, var, key) do { \
|
||||||
|
bool tmp = false; \
|
||||||
|
if (config_get_bool(conf, key, &tmp)) \
|
||||||
|
base->var = tmp; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define CONFIG_GET_INT_BASE(conf, base, var, key) do { \
|
||||||
|
int tmp = 0; \
|
||||||
|
if (config_get_int(conf, key, &tmp)) \
|
||||||
|
base->var = tmp; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define CONFIG_GET_FLOAT_BASE(conf, base, var, key) do { \
|
||||||
|
float tmp = 0.0f; \
|
||||||
|
if (config_get_float(conf, key, &tmp)) \
|
||||||
|
base->var = tmp; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
struct config_file
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
char *reference;
|
||||||
|
struct config_entry_list **entries_map;
|
||||||
|
struct config_entry_list *entries;
|
||||||
|
struct config_entry_list *tail;
|
||||||
|
struct config_entry_list *last;
|
||||||
|
struct config_include_list *includes;
|
||||||
|
unsigned include_depth;
|
||||||
|
bool guaranteed_no_duplicates;
|
||||||
|
bool modified;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct config_file config_file_t;
|
||||||
|
|
||||||
|
struct config_file_cb
|
||||||
|
{
|
||||||
|
void (*config_file_new_entry_cb)(char*, char*);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct config_file_cb config_file_cb_t ;
|
||||||
|
|
||||||
|
/* Config file format
|
||||||
|
* - # are treated as comments. Rest of the line is ignored.
|
||||||
|
* - Format is: key = value. There can be as many spaces as you like in-between.
|
||||||
|
* - Value can be wrapped inside "" for multiword strings. (foo = "hai u")
|
||||||
|
* - #include includes a config file in-place.
|
||||||
|
*
|
||||||
|
* Path is relative to where config file was loaded unless an absolute path is chosen.
|
||||||
|
* Key/value pairs from an #include are read-only, and cannot be modified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Loads a config file. Returns NULL if file doesn't exist.
|
||||||
|
* NULL path will create an empty config file. */
|
||||||
|
config_file_t *config_file_new(const char *path);
|
||||||
|
|
||||||
|
config_file_t *config_file_new_alloc(void);
|
||||||
|
|
||||||
|
void config_file_initialize(struct config_file *conf);
|
||||||
|
|
||||||
|
/* Loads a config file. Returns NULL if file doesn't exist.
|
||||||
|
* NULL path will create an empty config file.
|
||||||
|
* Includes cb callbacks to run custom code during config file processing.*/
|
||||||
|
config_file_t *config_file_new_with_callback(const char *path, config_file_cb_t *cb);
|
||||||
|
|
||||||
|
/* Load a config file from a string.
|
||||||
|
* > WARNING: This will modify 'from_string'.
|
||||||
|
* Pass a copy of source string if original
|
||||||
|
* contents must be preserved */
|
||||||
|
config_file_t *config_file_new_from_string(char *from_string,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
|
config_file_t *config_file_new_from_path_to_string(const char *path);
|
||||||
|
|
||||||
|
/* Frees config file. */
|
||||||
|
void config_file_free(config_file_t *conf);
|
||||||
|
|
||||||
|
void config_file_set_reference_path(config_file_t *conf, char *path);
|
||||||
|
|
||||||
|
bool config_file_deinitialize(config_file_t *conf);
|
||||||
|
|
||||||
|
/* Loads a new config, and appends its data to conf.
|
||||||
|
* The key-value pairs of the new config file takes priority over the old. */
|
||||||
|
bool config_append_file(config_file_t *conf, const char *path);
|
||||||
|
|
||||||
|
/* All extract functions return true when value is valid and exists.
|
||||||
|
* Returns false otherwise. */
|
||||||
|
|
||||||
|
bool config_entry_exists(config_file_t *conf, const char *entry);
|
||||||
|
|
||||||
|
struct config_entry_list
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
char *value;
|
||||||
|
struct config_entry_list *next;
|
||||||
|
/* If we got this from an #include,
|
||||||
|
* do not allow overwrite. */
|
||||||
|
bool readonly;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct config_file_entry
|
||||||
|
{
|
||||||
|
const char *key;
|
||||||
|
const char *value;
|
||||||
|
/* Used intentionally. Opaque here. */
|
||||||
|
const struct config_entry_list *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_entry_list *config_get_entry(
|
||||||
|
const config_file_t *conf, const char *key);
|
||||||
|
|
||||||
|
bool config_get_entry_list_head(config_file_t *conf, struct config_file_entry *entry);
|
||||||
|
bool config_get_entry_list_next(struct config_file_entry *entry);
|
||||||
|
|
||||||
|
/* Extracts a double from config file. */
|
||||||
|
bool config_get_double(config_file_t *conf, const char *entry, double *in);
|
||||||
|
|
||||||
|
/* Extracts a float from config file. */
|
||||||
|
bool config_get_float(config_file_t *conf, const char *entry, float *in);
|
||||||
|
|
||||||
|
/* Extracts an int from config file. */
|
||||||
|
bool config_get_int(config_file_t *conf, const char *entry, int *in);
|
||||||
|
|
||||||
|
/* Extracts an uint from config file. */
|
||||||
|
bool config_get_uint(config_file_t *conf, const char *entry, unsigned *in);
|
||||||
|
|
||||||
|
/* Extracts an size_t from config file. */
|
||||||
|
bool config_get_size_t(config_file_t *conf, const char *key, size_t *in);
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||||
|
/* Extracts an uint64 from config file. */
|
||||||
|
bool config_get_uint64(config_file_t *conf, const char *entry, uint64_t *in);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Extracts an unsigned int from config file treating input as hex. */
|
||||||
|
bool config_get_hex(config_file_t *conf, const char *entry, unsigned *in);
|
||||||
|
|
||||||
|
/* Extracts a single char. If value consists of several chars,
|
||||||
|
* this is an error. */
|
||||||
|
bool config_get_char(config_file_t *conf, const char *entry, char *in);
|
||||||
|
|
||||||
|
/* Extracts an allocated string in *in. This must be free()-d if
|
||||||
|
* this function succeeds. */
|
||||||
|
bool config_get_string(config_file_t *conf, const char *entry, char **in);
|
||||||
|
|
||||||
|
/* Extracts a string to a preallocated buffer. Avoid memory allocation. */
|
||||||
|
bool config_get_array(config_file_t *conf, const char *entry, char *s, size_t len);
|
||||||
|
|
||||||
|
/* Extracts a string to a preallocated buffer. Avoid memory allocation.
|
||||||
|
* Recognized magic like ~/. Similar to config_get_array() otherwise. */
|
||||||
|
bool config_get_path(config_file_t *conf, const char *entry, char *s, size_t len);
|
||||||
|
|
||||||
|
/* Extracts a string to a preallocated buffer. Avoid memory allocation. */
|
||||||
|
bool config_get_config_path(config_file_t *conf, char *s, size_t len);
|
||||||
|
|
||||||
|
/* Extracts a boolean from config.
|
||||||
|
* Valid boolean true are "true" and "1". Valid false are "false" and "0".
|
||||||
|
* Other values will be treated as an error. */
|
||||||
|
bool config_get_bool(config_file_t *conf, const char *entry, bool *in);
|
||||||
|
|
||||||
|
/* Setters. Similar to the getters.
|
||||||
|
* Will not write to entry if the entry was obtained from an #include. */
|
||||||
|
void config_set_double(config_file_t *conf, const char *entry, double value);
|
||||||
|
void config_set_float(config_file_t *conf, const char *entry, float value);
|
||||||
|
void config_set_int(config_file_t *conf, const char *entry, int val);
|
||||||
|
void config_set_hex(config_file_t *conf, const char *entry, unsigned val);
|
||||||
|
void config_set_uint64(config_file_t *conf, const char *entry, uint64_t val);
|
||||||
|
void config_set_char(config_file_t *conf, const char *entry, char val);
|
||||||
|
void config_set_string(config_file_t *conf, const char *entry, const char *val);
|
||||||
|
void config_unset(config_file_t *conf, const char *key);
|
||||||
|
void config_set_path(config_file_t *conf, const char *entry, const char *val);
|
||||||
|
void config_set_bool(config_file_t *conf, const char *entry, bool val);
|
||||||
|
void config_set_uint(config_file_t *conf, const char *key, unsigned int val);
|
||||||
|
|
||||||
|
/* Write the current config to a file. */
|
||||||
|
bool config_file_write(config_file_t *conf, const char *path, bool val);
|
||||||
|
|
||||||
|
/* Dump the current config to an already opened file.
|
||||||
|
* Does not close the file. */
|
||||||
|
void config_file_dump(config_file_t *conf, FILE *file, bool val);
|
||||||
|
|
||||||
|
#ifdef ORBIS
|
||||||
|
void config_file_dump_orbis(config_file_t *conf, int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool config_file_exists(const char *path);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,64 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (config_file_userdata.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H
|
||||||
|
#define _LIBRETRO_SDK_CONFIG_FILE_USERDATA_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <file/config_file.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
struct config_file_userdata
|
||||||
|
{
|
||||||
|
config_file_t *conf;
|
||||||
|
const char *prefix[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
int config_userdata_get_float(void *userdata, const char *key_str,
|
||||||
|
float *value, float default_value);
|
||||||
|
|
||||||
|
int config_userdata_get_int(void *userdata, const char *key_str,
|
||||||
|
int *value, int default_value);
|
||||||
|
|
||||||
|
int config_userdata_get_hex(void *userdata, const char *key_str,
|
||||||
|
unsigned *value, unsigned default_value);
|
||||||
|
|
||||||
|
int config_userdata_get_float_array(void *userdata, const char *key_str,
|
||||||
|
float **values, unsigned *out_num_values,
|
||||||
|
const float *default_values, unsigned num_default_values);
|
||||||
|
|
||||||
|
int config_userdata_get_int_array(void *userdata, const char *key_str,
|
||||||
|
int **values, unsigned *out_num_values,
|
||||||
|
const int *default_values, unsigned num_default_values);
|
||||||
|
|
||||||
|
int config_userdata_get_string(void *userdata, const char *key_str,
|
||||||
|
char **output, const char *default_output);
|
||||||
|
|
||||||
|
void config_userdata_free(void *ptr);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,538 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_path.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_FILE_PATH_H
|
||||||
|
#define __LIBRETRO_SDK_FILE_PATH_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define PATH_REQUIRED_VFS_VERSION 3
|
||||||
|
|
||||||
|
void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||||
|
|
||||||
|
/* Order in this enum is equivalent to negative sort order in filelist
|
||||||
|
* (i.e. DIRECTORY is on top of PLAIN_FILE) */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RARCH_FILETYPE_UNSET,
|
||||||
|
RARCH_PLAIN_FILE,
|
||||||
|
RARCH_COMPRESSED_FILE_IN_ARCHIVE,
|
||||||
|
RARCH_COMPRESSED_ARCHIVE,
|
||||||
|
RARCH_DIRECTORY,
|
||||||
|
RARCH_FILE_UNSUPPORTED
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_compressed_file:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path is a compressed file.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path is a compressed file, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool path_is_compressed_file(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_contains_compressed_file:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path contains a compressed file.
|
||||||
|
*
|
||||||
|
* Currently we only check for hash symbol (#) inside the pathname.
|
||||||
|
* If path is ever expanded to a general URI, we should check for that here.
|
||||||
|
*
|
||||||
|
* Example: Somewhere in the path there might be a compressed file
|
||||||
|
* E.g.: /path/to/file.7z#mygame.img
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path contains compressed file, otherwise false (0).
|
||||||
|
**/
|
||||||
|
#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_archive_delim:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Gets delimiter of an archive file. Only the first '#'
|
||||||
|
* after a compression extension is considered.
|
||||||
|
*
|
||||||
|
* Returns: pointer to the delimiter in the path if it contains
|
||||||
|
* a compressed file, otherwise NULL.
|
||||||
|
*/
|
||||||
|
const char *path_get_archive_delim(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_extension:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Gets extension of file. Only '.'s
|
||||||
|
* after the last slash are considered.
|
||||||
|
*
|
||||||
|
* Returns: extension part from the path.
|
||||||
|
*/
|
||||||
|
const char *path_get_extension(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_remove_extension:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Mutates path by removing its extension. Removes all
|
||||||
|
* text after and including the last '.'.
|
||||||
|
* Only '.'s after the last slash are considered.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 1) If path has an extension, returns path with the
|
||||||
|
* extension removed.
|
||||||
|
* 2) If there is no extension, returns NULL.
|
||||||
|
* 3) If path is empty or NULL, returns NULL
|
||||||
|
*/
|
||||||
|
char *path_remove_extension(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basename:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Get basename from @path.
|
||||||
|
*
|
||||||
|
* Returns: basename from path.
|
||||||
|
**/
|
||||||
|
const char *path_basename(const char *path);
|
||||||
|
const char *path_basename_nocompression(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basedir:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Extracts base directory by mutating path.
|
||||||
|
* Keeps trailing '/'.
|
||||||
|
**/
|
||||||
|
void path_basedir(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_parent_dir:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Extracts parent directory by mutating path.
|
||||||
|
* Assumes that path is a directory. Keeps trailing '/'.
|
||||||
|
* If the path was already at the root directory, returns empty string
|
||||||
|
**/
|
||||||
|
void path_parent_dir(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_resolve_realpath:
|
||||||
|
* @buf : input and output buffer for path
|
||||||
|
* @size : size of buffer
|
||||||
|
* @resolve_symlinks : whether to resolve symlinks or not
|
||||||
|
*
|
||||||
|
* Resolves use of ".", "..", multiple slashes etc in absolute paths.
|
||||||
|
*
|
||||||
|
* Relative paths are rebased on the current working dir.
|
||||||
|
*
|
||||||
|
* Returns: @buf if successful, NULL otherwise.
|
||||||
|
* Note: Not implemented on consoles
|
||||||
|
* Note: Symlinks are only resolved on Unix-likes
|
||||||
|
* Note: The current working dir might not be what you expect,
|
||||||
|
* e.g. on Android it is "/"
|
||||||
|
* Use of fill_pathname_resolve_relative() should be prefered
|
||||||
|
**/
|
||||||
|
char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_relative_to:
|
||||||
|
* @out : buffer to write the relative path to
|
||||||
|
* @path : path to be expressed relatively
|
||||||
|
* @base : relative to this
|
||||||
|
* @size : size of output buffer
|
||||||
|
*
|
||||||
|
* Turns @path into a path relative to @base and writes it to @out.
|
||||||
|
*
|
||||||
|
* @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
|
||||||
|
* Both @path and @base are assumed to be absolute paths without "." or "..".
|
||||||
|
*
|
||||||
|
* E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
|
||||||
|
**/
|
||||||
|
size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_absolute:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if @path is an absolute path or a relative path.
|
||||||
|
*
|
||||||
|
* Returns: true if path is absolute, false if path is relative.
|
||||||
|
**/
|
||||||
|
bool path_is_absolute(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname:
|
||||||
|
* @out_path : output path
|
||||||
|
* @in_path : input path
|
||||||
|
* @replace : what to replace
|
||||||
|
* @size : buffer size of output path
|
||||||
|
*
|
||||||
|
* FIXME: Verify
|
||||||
|
*
|
||||||
|
* Replaces filename extension with 'replace' and outputs result to out_path.
|
||||||
|
* The extension here is considered to be the string from the last '.'
|
||||||
|
* to the end.
|
||||||
|
*
|
||||||
|
* Only '.'s after the last slash are considered as extensions.
|
||||||
|
* If no '.' is present, in_path and replace will simply be concatenated.
|
||||||
|
* 'size' is buffer size of 'out_path'.
|
||||||
|
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
|
||||||
|
* out_path = "/foo/bar/baz/boo.asm"
|
||||||
|
* E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" =>
|
||||||
|
* out_path = "/foo/bar/baz/boo"
|
||||||
|
*/
|
||||||
|
void fill_pathname(char *out_path, const char *in_path,
|
||||||
|
const char *replace, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_dated_filename:
|
||||||
|
* @out_filename : output filename
|
||||||
|
* @ext : extension of output filename
|
||||||
|
* @size : buffer size of output filename
|
||||||
|
*
|
||||||
|
* Creates a 'dated' filename prefixed by 'RetroArch', and
|
||||||
|
* concatenates extension (@ext) to it.
|
||||||
|
*
|
||||||
|
* E.g.:
|
||||||
|
* out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
|
||||||
|
**/
|
||||||
|
size_t fill_dated_filename(char *out_filename,
|
||||||
|
const char *ext, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_str_dated_filename:
|
||||||
|
* @out_filename : output filename
|
||||||
|
* @in_str : input string
|
||||||
|
* @ext : extension of output filename
|
||||||
|
* @size : buffer size of output filename
|
||||||
|
*
|
||||||
|
* Creates a 'dated' filename prefixed by the string @in_str, and
|
||||||
|
* concatenates extension (@ext) to it.
|
||||||
|
*
|
||||||
|
* E.g.:
|
||||||
|
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
|
||||||
|
**/
|
||||||
|
void fill_str_dated_filename(char *out_filename,
|
||||||
|
const char *in_str, const char *ext, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_noext:
|
||||||
|
* @out_path : output path
|
||||||
|
* @in_path : input path
|
||||||
|
* @replace : what to replace
|
||||||
|
* @size : buffer size of output path
|
||||||
|
*
|
||||||
|
* Appends a filename extension 'replace' to 'in_path', and outputs
|
||||||
|
* result in 'out_path'.
|
||||||
|
*
|
||||||
|
* Assumes in_path has no extension. If an extension is still
|
||||||
|
* present in 'in_path', it will be ignored.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
size_t fill_pathname_noext(char *out_path, const char *in_path,
|
||||||
|
const char *replace, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find_last_slash:
|
||||||
|
* @str : input path
|
||||||
|
*
|
||||||
|
* Gets a pointer to the last slash in the input path.
|
||||||
|
*
|
||||||
|
* Returns: a pointer to the last slash in the input path.
|
||||||
|
**/
|
||||||
|
char *find_last_slash(const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_dir:
|
||||||
|
* @in_dir : input directory path
|
||||||
|
* @in_basename : input basename to be appended to @in_dir
|
||||||
|
* @replace : replacement to be appended to @in_basename
|
||||||
|
* @size : size of buffer
|
||||||
|
*
|
||||||
|
* Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
|
||||||
|
* Basename of in_basename is the string after the last '/' or '\\',
|
||||||
|
* i.e the filename without directories.
|
||||||
|
*
|
||||||
|
* If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
|
||||||
|
* 'size' is buffer size of 'in_dir'.
|
||||||
|
*
|
||||||
|
* E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
|
||||||
|
* replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_dir(char *in_dir, const char *in_basename,
|
||||||
|
const char *replace, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_base:
|
||||||
|
* @out : output path
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
* Copies basename of @in_path into @out_path.
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_base_noext(char *out_dir,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_base_ext(char *out,
|
||||||
|
const char *in_path, const char *ext,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_basedir:
|
||||||
|
* @out_dir : output directory
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output directory
|
||||||
|
*
|
||||||
|
* Copies base directory of @in_path into @out_path.
|
||||||
|
* If in_path is a path without any slashes (relative current directory),
|
||||||
|
* @out_path will get path "./".
|
||||||
|
**/
|
||||||
|
void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_basedir_noext(char *out_dir,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_parent_dir_name:
|
||||||
|
* @out_dir : output directory
|
||||||
|
* @in_dir : input directory
|
||||||
|
* @size : size of output directory
|
||||||
|
*
|
||||||
|
* Copies only the parent directory name of @in_dir into @out_dir.
|
||||||
|
* The two buffers must not overlap. Removes trailing '/'.
|
||||||
|
* Returns true on success, false if a slash was not found in the path.
|
||||||
|
**/
|
||||||
|
bool fill_pathname_parent_dir_name(char *out_dir,
|
||||||
|
const char *in_dir, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_parent_dir:
|
||||||
|
* @out_dir : output directory
|
||||||
|
* @in_dir : input directory
|
||||||
|
* @size : size of output directory
|
||||||
|
*
|
||||||
|
* Copies parent directory of @in_dir into @out_dir.
|
||||||
|
* Assumes @in_dir is a directory. Keeps trailing '/'.
|
||||||
|
* If the path was already at the root directory, @out_dir will be an empty string.
|
||||||
|
**/
|
||||||
|
void fill_pathname_parent_dir(char *out_dir,
|
||||||
|
const char *in_dir, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_resolve_relative:
|
||||||
|
* @out_path : output path
|
||||||
|
* @in_refpath : input reference path
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of @out_path
|
||||||
|
*
|
||||||
|
* Joins basedir of @in_refpath together with @in_path.
|
||||||
|
* If @in_path is an absolute path, out_path = in_path.
|
||||||
|
* E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
|
||||||
|
* out_path = "/foo/bar/foobar.cg".
|
||||||
|
**/
|
||||||
|
void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_join:
|
||||||
|
* @out_path : output path
|
||||||
|
* @dir : directory
|
||||||
|
* @path : path
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
* Joins a directory (@dir) and path (@path) together.
|
||||||
|
* Makes sure not to get two consecutive slashes
|
||||||
|
* between directory and path.
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_join(char *out_path, const char *dir,
|
||||||
|
const char *path, size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_special_ext(char *out_path,
|
||||||
|
const char *dir, const char *path,
|
||||||
|
const char *last, const char *ext,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_concat_noext(char *out_path,
|
||||||
|
const char *dir, const char *path,
|
||||||
|
const char *concat,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_concat(char *out_path,
|
||||||
|
const char *dir, const char *path,
|
||||||
|
const char *concat,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_join_noext(char *out_path,
|
||||||
|
const char *dir, const char *path, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_join_delim:
|
||||||
|
* @out_path : output path
|
||||||
|
* @dir : directory
|
||||||
|
* @path : path
|
||||||
|
* @delim : delimiter
|
||||||
|
* @size : size of output path
|
||||||
|
*
|
||||||
|
* Joins a directory (@dir) and path (@path) together
|
||||||
|
* using the given delimiter (@delim).
|
||||||
|
**/
|
||||||
|
size_t fill_pathname_join_delim(char *out_path, const char *dir,
|
||||||
|
const char *path, const char delim, size_t size);
|
||||||
|
|
||||||
|
size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
|
||||||
|
const char *path, const char delim, const char *concat,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_short_pathname_representation:
|
||||||
|
* @out_rep : output representation
|
||||||
|
* @in_path : input path
|
||||||
|
* @size : size of output representation
|
||||||
|
*
|
||||||
|
* Generates a short representation of path. It should only
|
||||||
|
* be used for displaying the result; the output representation is not
|
||||||
|
* binding in any meaningful way (for a normal path, this is the same as basename)
|
||||||
|
* In case of more complex URLs, this should cut everything except for
|
||||||
|
* the main image file.
|
||||||
|
*
|
||||||
|
* E.g.: "/path/to/game.img" -> game.img
|
||||||
|
* "/path/to/myarchive.7z#folder/to/game.img" -> game.img
|
||||||
|
*/
|
||||||
|
size_t fill_short_pathname_representation(char* out_rep,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_short_pathname_representation_noext(char* out_rep,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_expand_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_abbreviate_special(char *out_path,
|
||||||
|
const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void fill_pathname_abbreviated_or_relative(char *out_path, const char *in_refpath, const char *in_path, size_t size);
|
||||||
|
|
||||||
|
void pathname_conform_slashes_to_os(char *path);
|
||||||
|
|
||||||
|
void pathname_make_slashes_portable(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_basedir:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Extracts base directory by mutating path.
|
||||||
|
* Keeps trailing '/'.
|
||||||
|
**/
|
||||||
|
void path_basedir_wrapper(char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_char_is_slash:
|
||||||
|
* @c : character
|
||||||
|
*
|
||||||
|
* Checks if character (@c) is a slash.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if character is a slash, otherwise false (0).
|
||||||
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
|
||||||
|
#else
|
||||||
|
#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_default_slash and path_default_slash_c:
|
||||||
|
*
|
||||||
|
* Gets the default slash separator.
|
||||||
|
*
|
||||||
|
* Returns: default slash separator.
|
||||||
|
*/
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PATH_DEFAULT_SLASH() "\\"
|
||||||
|
#define PATH_DEFAULT_SLASH_C() '\\'
|
||||||
|
#else
|
||||||
|
#define PATH_DEFAULT_SLASH() "/"
|
||||||
|
#define PATH_DEFAULT_SLASH_C() '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fill_pathname_slash:
|
||||||
|
* @path : path
|
||||||
|
* @size : size of path
|
||||||
|
*
|
||||||
|
* Assumes path is a directory. Appends a slash
|
||||||
|
* if not already there.
|
||||||
|
**/
|
||||||
|
void fill_pathname_slash(char *path, size_t size);
|
||||||
|
|
||||||
|
#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
|
||||||
|
void fill_pathname_application_path(char *buf, size_t size);
|
||||||
|
void fill_pathname_application_dir(char *buf, size_t size);
|
||||||
|
void fill_pathname_home_dir(char *buf, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_mkdir:
|
||||||
|
* @dir : directory
|
||||||
|
*
|
||||||
|
* Create directory on filesystem.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if directory could be created, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool path_mkdir(const char *dir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_is_directory:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Checks if path is a directory.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if path is a directory, otherwise false (0).
|
||||||
|
*/
|
||||||
|
bool path_is_directory(const char *path);
|
||||||
|
|
||||||
|
bool path_is_character_special(const char *path);
|
||||||
|
|
||||||
|
int path_stat(const char *path);
|
||||||
|
|
||||||
|
bool path_is_valid(const char *path);
|
||||||
|
|
||||||
|
int32_t path_get_size(const char *path);
|
||||||
|
|
||||||
|
bool is_path_accessible_using_standard_io(const char *path);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (filters.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_SDK_FILTERS_H
|
||||||
|
#define _LIBRETRO_SDK_FILTERS_H
|
||||||
|
|
||||||
|
/* for MSVC; should be benign under any circumstances */
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
#include <retro_math.h>
|
||||||
|
|
||||||
|
static INLINE double sinc(double val)
|
||||||
|
{
|
||||||
|
if (fabs(val) < 0.00001)
|
||||||
|
return 1.0;
|
||||||
|
return sin(val) / val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Paeth prediction filter. */
|
||||||
|
static INLINE int paeth(int a, int b, int c)
|
||||||
|
{
|
||||||
|
int p = a + b - c;
|
||||||
|
int pa = abs(p - a);
|
||||||
|
int pb = abs(p - b);
|
||||||
|
int pc = abs(p - c);
|
||||||
|
|
||||||
|
if (pa <= pb && pa <= pc)
|
||||||
|
return a;
|
||||||
|
else if (pb <= pc)
|
||||||
|
return b;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modified Bessel function of first order.
|
||||||
|
* Check Wiki for mathematical definition ... */
|
||||||
|
static INLINE double besseli0(double x)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
double sum = 0.0;
|
||||||
|
double factorial = 1.0;
|
||||||
|
double factorial_mult = 0.0;
|
||||||
|
double x_pow = 1.0;
|
||||||
|
double two_div_pow = 1.0;
|
||||||
|
double x_sqr = x * x;
|
||||||
|
|
||||||
|
/* Approximate. This is an infinite sum.
|
||||||
|
* Luckily, it converges rather fast. */
|
||||||
|
for (i = 0; i < 18; i++)
|
||||||
|
{
|
||||||
|
sum += x_pow * two_div_pow / (factorial * factorial);
|
||||||
|
|
||||||
|
factorial_mult += 1.0;
|
||||||
|
x_pow *= x_sqr;
|
||||||
|
two_div_pow *= 0.25;
|
||||||
|
factorial *= factorial_mult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE double kaiser_window_function(double index, double beta)
|
||||||
|
{
|
||||||
|
return besseli0(beta * sqrtf(1 - index * index));
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE double lanzcos_window_function(double index)
|
||||||
|
{
|
||||||
|
return sinc(M_PI * index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,186 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (string_list.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_STRING_LIST_H
|
||||||
|
#define __LIBRETRO_SDK_STRING_LIST_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
union string_list_elem_attr
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
int i;
|
||||||
|
void *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string_list_elem
|
||||||
|
{
|
||||||
|
char *data;
|
||||||
|
void *userdata;
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct string_list
|
||||||
|
{
|
||||||
|
struct string_list_elem *elems;
|
||||||
|
size_t size;
|
||||||
|
size_t cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_find_elem:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to find inside the string list.
|
||||||
|
*
|
||||||
|
* Searches for an element (@elem) inside the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if element could be found, otherwise false (0).
|
||||||
|
*/
|
||||||
|
int string_list_find_elem(const struct string_list *list, const char *elem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_find_elem_prefix:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @prefix : prefix to append to @elem
|
||||||
|
* @elem : element to find inside the string list.
|
||||||
|
*
|
||||||
|
* Searches for an element (@elem) inside the string list. Will
|
||||||
|
* also search for the same element prefixed by @prefix.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if element could be found, otherwise false (0).
|
||||||
|
*/
|
||||||
|
bool string_list_find_elem_prefix(const struct string_list *list,
|
||||||
|
const char *prefix, const char *elem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_split:
|
||||||
|
* @str : string to turn into a string list
|
||||||
|
* @delim : delimiter character to use for splitting the string.
|
||||||
|
*
|
||||||
|
* Creates a new string list based on string @str, delimited by @delim.
|
||||||
|
*
|
||||||
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
|
*/
|
||||||
|
struct string_list *string_split(const char *str, const char *delim);
|
||||||
|
|
||||||
|
bool string_split_noalloc(struct string_list *list,
|
||||||
|
const char *str, const char *delim);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_separate:
|
||||||
|
* @str : string to turn into a string list
|
||||||
|
* @delim : delimiter character to use for separating the string.
|
||||||
|
*
|
||||||
|
* Creates a new string list based on string @str, delimited by @delim.
|
||||||
|
* Includes empty strings - i.e. two adjacent delimiters will resolve
|
||||||
|
* to a string list element of "".
|
||||||
|
*
|
||||||
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
|
*/
|
||||||
|
struct string_list *string_separate(char *str, const char *delim);
|
||||||
|
|
||||||
|
bool string_separate_noalloc(struct string_list *list,
|
||||||
|
char *str, const char *delim);
|
||||||
|
|
||||||
|
bool string_list_deinitialize(struct string_list *list);
|
||||||
|
|
||||||
|
bool string_list_initialize(struct string_list *list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_new:
|
||||||
|
*
|
||||||
|
* Creates a new string list. Has to be freed manually.
|
||||||
|
*
|
||||||
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
|
*/
|
||||||
|
struct string_list *string_list_new(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_append:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to add to the string list
|
||||||
|
* @attr : attributes of new element.
|
||||||
|
*
|
||||||
|
* Appends a new element to the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool string_list_append(struct string_list *list, const char *elem,
|
||||||
|
union string_list_elem_attr attr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_append_n:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to add to the string list
|
||||||
|
* @length : read at most this many bytes from elem
|
||||||
|
* @attr : attributes of new element.
|
||||||
|
*
|
||||||
|
* Appends a new element to the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool string_list_append_n(struct string_list *list, const char *elem,
|
||||||
|
unsigned length, union string_list_elem_attr attr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_free
|
||||||
|
* @list : pointer to string list object
|
||||||
|
*
|
||||||
|
* Frees a string list.
|
||||||
|
*/
|
||||||
|
void string_list_free(struct string_list *list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_join_concat:
|
||||||
|
* @buffer : buffer that @list will be joined to.
|
||||||
|
* @size : length of @buffer.
|
||||||
|
* @list : pointer to string list.
|
||||||
|
* @delim : delimiter character for @list.
|
||||||
|
*
|
||||||
|
* A string list will be joined/concatenated as a
|
||||||
|
* string to @buffer, delimited by @delim.
|
||||||
|
*/
|
||||||
|
void string_list_join_concat(char *buffer, size_t size,
|
||||||
|
const struct string_list *list, const char *sep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_set:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @idx : index of element in string list
|
||||||
|
* @str : value for the element.
|
||||||
|
*
|
||||||
|
* Set value of element inside string list.
|
||||||
|
**/
|
||||||
|
void string_list_set(struct string_list *list, unsigned idx,
|
||||||
|
const char *str);
|
||||||
|
|
||||||
|
struct string_list *string_list_clone(const struct string_list *src);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (memalign.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_MEMALIGN_H
|
||||||
|
#define _LIBRETRO_MEMALIGN_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
void *memalign_alloc(size_t boundary, size_t size);
|
||||||
|
|
||||||
|
void *memalign_alloc_aligned(size_t size);
|
||||||
|
|
||||||
|
void memalign_free(void *ptr);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_assert.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RETRO_ASSERT_H
|
||||||
|
#define __RETRO_ASSERT_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef RARCH_INTERNAL
|
||||||
|
#include <stdio.h>
|
||||||
|
#define retro_assert(cond) ((void)( (cond) || (printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__), abort(), 0) ))
|
||||||
|
#else
|
||||||
|
#define retro_assert(cond) assert(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_common_api.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||||
|
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is designed to normalize the libretro-common compiling environment
|
||||||
|
for public API headers. This should be leaner than a normal compiling environment,
|
||||||
|
since it gets #included into other project's sources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------------------------------------ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
|
||||||
|
headers to enable them to get used by c++ sources.
|
||||||
|
However, we want to support building this library as C++ as well, so a
|
||||||
|
special technique is called for.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define RETRO_BEGIN_DECLS
|
||||||
|
#define RETRO_END_DECLS
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
#ifdef CXX_BUILD
|
||||||
|
/* build wants everything to be built as c++, so no extern "C" */
|
||||||
|
#else
|
||||||
|
#undef RETRO_BEGIN_DECLS
|
||||||
|
#undef RETRO_END_DECLS
|
||||||
|
#define RETRO_BEGIN_DECLS extern "C" {
|
||||||
|
#define RETRO_END_DECLS }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* header is included by a C source file, so no extern "C" */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
IMO, this non-standard ssize_t should not be used.
|
||||||
|
However, it's a good example of how to handle something like this.
|
||||||
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#ifndef HAVE_SSIZE_T
|
||||||
|
#define HAVE_SSIZE_T
|
||||||
|
#if defined(_WIN64)
|
||||||
|
typedef __int64 ssize_t;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
typedef int ssize_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#elif defined(__MACH__)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER >= 1800
|
||||||
|
#include <inttypes.h>
|
||||||
|
#else
|
||||||
|
#ifndef PRId64
|
||||||
|
#define PRId64 "I64d"
|
||||||
|
#define PRIu64 "I64u"
|
||||||
|
#define PRIuPTR "Iu"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
|
||||||
|
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
|
||||||
|
/* https://github.com/libretro/RetroArch/issues/6009 */
|
||||||
|
#ifndef __STDC_FORMAT_MACROS
|
||||||
|
#define __STDC_FORMAT_MACROS 1
|
||||||
|
#endif
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
#ifndef PRId64
|
||||||
|
#error "inttypes.h is being screwy"
|
||||||
|
#endif
|
||||||
|
#define STRING_REP_INT64 "%" PRId64
|
||||||
|
#define STRING_REP_UINT64 "%" PRIu64
|
||||||
|
#define STRING_REP_USIZE "%" PRIuPTR
|
||||||
|
|
||||||
|
/*
|
||||||
|
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||||
|
|
||||||
|
rationale: these are used in public APIs, and it is easier to find problems
|
||||||
|
and write code that works the first time portably when theyre included uniformly
|
||||||
|
than to do the analysis from scratch each time you think you need it, for each feature.
|
||||||
|
|
||||||
|
Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
|
||||||
|
then you should pay the price everywhere, so you can see how much grief it will cause.
|
||||||
|
|
||||||
|
Of course, another school of thought is that you should do as little damage as possible
|
||||||
|
in as few places as possible...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
|
||||||
|
#endif
|
|
@ -0,0 +1,114 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_environment.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_ENVIRONMENT_H
|
||||||
|
#define __LIBRETRO_SDK_ENVIRONMENT_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file is designed to create a normalized environment for compiling
|
||||||
|
libretro-common's private implementations, or any other sources which might
|
||||||
|
enjoy use of it's environment (RetroArch for instance).
|
||||||
|
This should be an elaborately crafted environment so that sources don't
|
||||||
|
need to be full of platform-specific workarounds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
#if 0
|
||||||
|
printf("This is C++, version %d.\n", __cplusplus);
|
||||||
|
#endif
|
||||||
|
/* The expected values would be
|
||||||
|
* 199711L, for ISO/IEC 14882:1998 or 14882:2003
|
||||||
|
*/
|
||||||
|
|
||||||
|
#elif defined(__STDC__)
|
||||||
|
/* This is standard C. */
|
||||||
|
|
||||||
|
#if (__STDC__ == 1)
|
||||||
|
/* The implementation is ISO-conforming. */
|
||||||
|
#define __STDC_ISO__
|
||||||
|
#else
|
||||||
|
/* The implementation is not ISO-conforming. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__)
|
||||||
|
#if (__STDC_VERSION__ >= 201112L)
|
||||||
|
/* This is C11. */
|
||||||
|
#define __STDC_C11__
|
||||||
|
#elif (__STDC_VERSION__ >= 199901L)
|
||||||
|
/* This is C99. */
|
||||||
|
#define __STDC_C99__
|
||||||
|
#elif (__STDC_VERSION__ >= 199409L)
|
||||||
|
/* This is C89 with amendment 1. */
|
||||||
|
#define __STDC_C89__
|
||||||
|
#define __STDC_C89_AMENDMENT_1__
|
||||||
|
#else
|
||||||
|
/* This is C89 without amendment 1. */
|
||||||
|
#define __STDC_C89__
|
||||||
|
#endif
|
||||||
|
#else /* !defined(__STDC_VERSION__) */
|
||||||
|
/* This is C89. __STDC_VERSION__ is not defined. */
|
||||||
|
#define __STDC_C89__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* !defined(__STDC__) */
|
||||||
|
/* This is not standard C. __STDC__ is not defined. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
|
||||||
|
/* Try to find out if we're compiling for WinRT or non-WinRT */
|
||||||
|
#if defined(_MSC_VER) && defined(__has_include)
|
||||||
|
#if __has_include(<winapifamily.h>)
|
||||||
|
#define HAVE_WINAPIFAMILY_H 1
|
||||||
|
#else
|
||||||
|
#define HAVE_WINAPIFAMILY_H 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
|
||||||
|
#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_) /* _MSC_VER == 1700 for Visual Studio 2012 */
|
||||||
|
#define HAVE_WINAPIFAMILY_H 1
|
||||||
|
#else
|
||||||
|
#define HAVE_WINAPIFAMILY_H 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_WINAPIFAMILY_H
|
||||||
|
#include <winapifamily.h>
|
||||||
|
#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
|
||||||
|
#else
|
||||||
|
#define WINAPI_FAMILY_WINRT 0
|
||||||
|
#endif /* HAVE_WINAPIFAMILY_H */
|
||||||
|
|
||||||
|
#if WINAPI_FAMILY_WINRT
|
||||||
|
#undef __WINRT__
|
||||||
|
#define __WINRT__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MSVC obviously has to have some non-standard constants... */
|
||||||
|
#if _M_IX86_FP == 1
|
||||||
|
#define __SSE__ 1
|
||||||
|
#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
|
||||||
|
#define __SSE__ 1
|
||||||
|
#define __SSE2__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_inline.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_INLINE_H
|
||||||
|
#define __LIBRETRO_SDK_INLINE_H
|
||||||
|
|
||||||
|
#ifndef INLINE
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__INTEL_COMPILER)
|
||||||
|
#define INLINE __inline
|
||||||
|
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||||
|
#define INLINE inline
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define INLINE __inline__
|
||||||
|
#else
|
||||||
|
#define INLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,190 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_math.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBRETRO_COMMON_MATH_H
|
||||||
|
#define _LIBRETRO_COMMON_MATH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(_WIN32) && defined(_XBOX)
|
||||||
|
#include <Xtl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#if !defined(USE_MATH_DEFINES)
|
||||||
|
#define M_PI 3.14159265358979323846264338327
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* next_pow2:
|
||||||
|
* @v : initial value
|
||||||
|
*
|
||||||
|
* Get next power of 2 value based on initial value.
|
||||||
|
*
|
||||||
|
* Returns: next power of 2 value (derived from @v).
|
||||||
|
**/
|
||||||
|
static INLINE uint32_t next_pow2(uint32_t v)
|
||||||
|
{
|
||||||
|
v--;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
v++;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prev_pow2:
|
||||||
|
* @v : initial value
|
||||||
|
*
|
||||||
|
* Get previous power of 2 value based on initial value.
|
||||||
|
*
|
||||||
|
* Returns: previous power of 2 value (derived from @v).
|
||||||
|
**/
|
||||||
|
static INLINE uint32_t prev_pow2(uint32_t v)
|
||||||
|
{
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
return v - (v >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clamp:
|
||||||
|
* @v : initial value
|
||||||
|
*
|
||||||
|
* Get the clamped value based on initial value.
|
||||||
|
*
|
||||||
|
* Returns: clamped value (derived from @v).
|
||||||
|
**/
|
||||||
|
static INLINE float clamp_value(float v, float min, float max)
|
||||||
|
{
|
||||||
|
return v <= min ? min : v >= max ? max : v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* saturate_value:
|
||||||
|
* @v : initial value
|
||||||
|
*
|
||||||
|
* Get the clamped 0.0-1.0 value based on initial value.
|
||||||
|
*
|
||||||
|
* Returns: clamped 0.0-1.0 value (derived from @v).
|
||||||
|
**/
|
||||||
|
static INLINE float saturate_value(float v)
|
||||||
|
{
|
||||||
|
return clamp_value(v, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dot_product:
|
||||||
|
* @a : left hand vector value
|
||||||
|
* @b : right hand vector value
|
||||||
|
*
|
||||||
|
* Get the dot product of the two passed in vectors.
|
||||||
|
*
|
||||||
|
* Returns: dot product value (derived from @a and @b).
|
||||||
|
**/
|
||||||
|
static INLINE float dot_product(const float* a, const float* b)
|
||||||
|
{
|
||||||
|
return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert_rgb_to_yxy:
|
||||||
|
* @rgb : in RGB colour space value
|
||||||
|
* @Yxy : out Yxy colour space value
|
||||||
|
*
|
||||||
|
* Convert from RGB colour space to Yxy colour space.
|
||||||
|
*
|
||||||
|
* Returns: Yxy colour space value (derived from @rgb).
|
||||||
|
**/
|
||||||
|
static INLINE void convert_rgb_to_yxy(const float* rgb, float* Yxy)
|
||||||
|
{
|
||||||
|
float inv;
|
||||||
|
float xyz[3];
|
||||||
|
float one[3] = {1.0, 1.0, 1.0};
|
||||||
|
float rgb_xyz[3][3] = {
|
||||||
|
{0.4124564, 0.3575761, 0.1804375},
|
||||||
|
{0.2126729, 0.7151522, 0.0721750},
|
||||||
|
{0.0193339, 0.1191920, 0.9503041}
|
||||||
|
};
|
||||||
|
|
||||||
|
xyz[0] = dot_product(rgb_xyz[0], rgb);
|
||||||
|
xyz[1] = dot_product(rgb_xyz[1], rgb);
|
||||||
|
xyz[2] = dot_product(rgb_xyz[2], rgb);
|
||||||
|
|
||||||
|
inv = 1.0f / dot_product(xyz, one);
|
||||||
|
Yxy[0] = xyz[1];
|
||||||
|
Yxy[1] = xyz[0] * inv;
|
||||||
|
Yxy[2] = xyz[1] * inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert_yxy_to_rgb:
|
||||||
|
* @rgb : in Yxy colour space value
|
||||||
|
* @Yxy : out rgb colour space value
|
||||||
|
*
|
||||||
|
* Convert from Yxy colour space to rgb colour space.
|
||||||
|
*
|
||||||
|
* Returns: rgb colour space value (derived from @Yxy).
|
||||||
|
**/
|
||||||
|
static INLINE void convert_yxy_to_rgb(const float* Yxy, float* rgb)
|
||||||
|
{
|
||||||
|
float xyz[3];
|
||||||
|
float xyz_rgb[3][3] = {
|
||||||
|
{3.2404542, -1.5371385, -0.4985314},
|
||||||
|
{-0.9692660, 1.8760108, 0.0415560},
|
||||||
|
{0.0556434, -0.2040259, 1.0572252}
|
||||||
|
};
|
||||||
|
xyz[0] = Yxy[0] * Yxy[1] / Yxy[2];
|
||||||
|
xyz[1] = Yxy[0];
|
||||||
|
xyz[2] = Yxy[0] * (1.0 - Yxy[1] - Yxy[2]) / Yxy[2];
|
||||||
|
|
||||||
|
rgb[0] = dot_product(xyz_rgb[0], xyz);
|
||||||
|
rgb[1] = dot_product(xyz_rgb[1], xyz);
|
||||||
|
rgb[2] = dot_product(xyz_rgb[2], xyz);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,207 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_miscellaneous.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RARCH_MISCELLANEOUS_H
|
||||||
|
#define __RARCH_MISCELLANEOUS_H
|
||||||
|
|
||||||
|
#define RARCH_MAX_SUBSYSTEMS 10
|
||||||
|
#define RARCH_MAX_SUBSYSTEM_ROMS 10
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
#if defined(_XBOX)
|
||||||
|
#include <Xtl.h>
|
||||||
|
#else
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count;i++)
|
||||||
|
a[i] |= b[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count;i++)
|
||||||
|
a[i] &= ~b[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (ptr[i] != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PATH_MAX_LENGTH
|
||||||
|
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS) || defined(__PSL1GHT__) || defined(__PS3__)
|
||||||
|
#define PATH_MAX_LENGTH 512
|
||||||
|
#else
|
||||||
|
#define PATH_MAX_LENGTH 4096
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NAME_MAX_LENGTH
|
||||||
|
#define NAME_MAX_LENGTH 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
#define BITS_GET_ELEM(a, i) ((a).data[i])
|
||||||
|
#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i])
|
||||||
|
|
||||||
|
#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
|
||||||
|
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
|
||||||
|
#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
|
||||||
|
|
||||||
|
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
|
||||||
|
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
|
||||||
|
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
|
||||||
|
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||||
|
|
||||||
|
#define BIT32_SET(a, bit) ((a) |= (UINT32_C(1) << ((bit) & 31)))
|
||||||
|
#define BIT32_CLEAR(a, bit) ((a) &= ~(UINT32_C(1) << ((bit) & 31)))
|
||||||
|
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
|
||||||
|
#define BIT32_CLEAR_ALL(a) ((a) = 0)
|
||||||
|
|
||||||
|
#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
|
||||||
|
#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
|
||||||
|
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
|
||||||
|
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||||
|
|
||||||
|
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (UINT32_C(1) << ((bit) & 31)))
|
||||||
|
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
|
||||||
|
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
|
||||||
|
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
|
||||||
|
|
||||||
|
#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit)
|
||||||
|
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
|
||||||
|
#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit)
|
||||||
|
#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BIT256_SET(a, bit) BIT128_SET(a, bit)
|
||||||
|
#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit)
|
||||||
|
#define BIT256_GET(a, bit) BIT128_GET(a, bit)
|
||||||
|
#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a)
|
||||||
|
|
||||||
|
#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit)
|
||||||
|
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
|
||||||
|
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
||||||
|
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BIT512_SET(a, bit) BIT256_SET(a, bit)
|
||||||
|
#define BIT512_CLEAR(a, bit) BIT256_CLEAR(a, bit)
|
||||||
|
#define BIT512_GET(a, bit) BIT256_GET(a, bit)
|
||||||
|
#define BIT512_CLEAR_ALL(a) BIT256_CLEAR_ALL(a)
|
||||||
|
|
||||||
|
#define BIT512_SET_PTR(a, bit) BIT512_SET(*a, bit)
|
||||||
|
#define BIT512_CLEAR_PTR(a, bit) BIT512_CLEAR(*a, bit)
|
||||||
|
#define BIT512_GET_PTR(a, bit) BIT512_GET(*a, bit)
|
||||||
|
#define BIT512_CLEAR_ALL_PTR(a) BIT512_CLEAR_ALL(*a)
|
||||||
|
|
||||||
|
#define BITS_COPY16_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITS_COPY32_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITS_COPY64_PTR(a,bits) \
|
||||||
|
{ \
|
||||||
|
BIT128_CLEAR_ALL_PTR(a); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||||
|
BITS_GET_ELEM_PTR(a, 1) = (bits >> 32); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper macros and struct to keep track of many booleans. */
|
||||||
|
/* This struct has 256 bits. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t data[8];
|
||||||
|
} retro_bits_t;
|
||||||
|
|
||||||
|
/* This struct has 512 bits. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t data[16];
|
||||||
|
} retro_bits_512_t;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# ifdef _WIN64
|
||||||
|
# define PRI_SIZET PRIu64
|
||||||
|
# else
|
||||||
|
# if _MSC_VER == 1800
|
||||||
|
# define PRI_SIZET PRIu32
|
||||||
|
# else
|
||||||
|
# define PRI_SIZET "u"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#elif defined(PS2)
|
||||||
|
# define PRI_SIZET "u"
|
||||||
|
#else
|
||||||
|
# if (SIZE_MAX == 0xFFFF)
|
||||||
|
# define PRI_SIZET "hu"
|
||||||
|
# elif (SIZE_MAX == 0xFFFFFFFF)
|
||||||
|
# define PRI_SIZET "u"
|
||||||
|
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
|
||||||
|
# define PRI_SIZET "lu"
|
||||||
|
# else
|
||||||
|
# error PRI_SIZET: unknown SIZE_MAX
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,112 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (retro_timers.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_COMMON_TIMERS_H
|
||||||
|
#define __LIBRETRO_COMMON_TIMERS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(XENON)
|
||||||
|
#include <time/time.h>
|
||||||
|
#elif !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
#include <sys/timer.h>
|
||||||
|
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||||
|
#include <unistd.h>
|
||||||
|
#elif defined(WIIU)
|
||||||
|
#include <wiiu/os/thread.h>
|
||||||
|
#elif defined(PSP)
|
||||||
|
#include <pspthreadman.h>
|
||||||
|
#elif defined(VITA)
|
||||||
|
#include <psp2/kernel/threadmgr.h>
|
||||||
|
#elif defined(_3DS)
|
||||||
|
#include <3ds.h>
|
||||||
|
#else
|
||||||
|
#include <time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(_WIN32) && defined(_XBOX)
|
||||||
|
#include <Xtl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
#include <retro_inline.h>
|
||||||
|
|
||||||
|
#ifdef DJGPP
|
||||||
|
#define timespec timeval
|
||||||
|
#define tv_nsec tv_usec
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||||
|
|
||||||
|
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||||
|
{
|
||||||
|
usleep(1000000L * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||||
|
|
||||||
|
if (rmtp)
|
||||||
|
rmtp->tv_sec = rmtp->tv_nsec=0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define nanosleep nanosleepDOS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retro_sleep:
|
||||||
|
* @msec : amount in milliseconds to sleep
|
||||||
|
*
|
||||||
|
* Sleeps for a specified amount of milliseconds (@msec).
|
||||||
|
**/
|
||||||
|
#if defined(PSP) || defined(VITA)
|
||||||
|
#define retro_sleep(msec) (sceKernelDelayThread(1000 * (msec)))
|
||||||
|
#elif defined(_3DS)
|
||||||
|
#define retro_sleep(msec) (svcSleepThread(1000000 * (s64)(msec)))
|
||||||
|
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||||
|
#define retro_sleep(msec) (SleepEx((msec), FALSE))
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define retro_sleep(msec) (Sleep((msec)))
|
||||||
|
#elif defined(XENON)
|
||||||
|
#define retro_sleep(msec) (udelay(1000 * (msec)))
|
||||||
|
#elif !defined(__PSL1GHT__) && defined(__PS3__)
|
||||||
|
#define retro_sleep(msec) (sys_timer_usleep(1000 * (msec)))
|
||||||
|
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||||
|
#define retro_sleep(msec) (usleep(1000 * (msec)))
|
||||||
|
#elif defined(WIIU)
|
||||||
|
#define retro_sleep(msec) (OSSleepTicks(ms_to_ticks((msec))))
|
||||||
|
#else
|
||||||
|
#define retro_sleep(msec) \
|
||||||
|
{ \
|
||||||
|
struct timespec tv = {0}; \
|
||||||
|
tv.tv_sec = msec / 1000; \
|
||||||
|
tv.tv_nsec = (msec % 1000) * 1000000; \
|
||||||
|
nanosleep(&tv, NULL); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_FILE_STREAM_H
|
||||||
|
#define __LIBRETRO_SDK_FILE_STREAM_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct RFILE RFILE;
|
||||||
|
|
||||||
|
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||||
|
|
||||||
|
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||||
|
|
||||||
|
int64_t filestream_get_size(RFILE *stream);
|
||||||
|
|
||||||
|
int64_t filestream_truncate(RFILE *stream, int64_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_open:
|
||||||
|
* @path : path to file
|
||||||
|
* @mode : file mode to use when opening (read/write)
|
||||||
|
* @bufsize : optional buffer size (-1 or 0 to use default)
|
||||||
|
*
|
||||||
|
* Opens a file for reading or writing, depending on the requested mode.
|
||||||
|
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||||
|
**/
|
||||||
|
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
|
||||||
|
|
||||||
|
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
|
||||||
|
|
||||||
|
int64_t filestream_read(RFILE *stream, void *data, int64_t len);
|
||||||
|
|
||||||
|
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
|
||||||
|
|
||||||
|
int64_t filestream_tell(RFILE *stream);
|
||||||
|
|
||||||
|
void filestream_rewind(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_close(RFILE *stream);
|
||||||
|
|
||||||
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
||||||
|
|
||||||
|
char* filestream_gets(RFILE *stream, char *s, size_t len);
|
||||||
|
|
||||||
|
int filestream_getc(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_vscanf(RFILE *stream, const char* format, va_list *args);
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||||
|
|
||||||
|
int filestream_eof(RFILE *stream);
|
||||||
|
|
||||||
|
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||||
|
|
||||||
|
int filestream_putc(RFILE *stream, int c);
|
||||||
|
|
||||||
|
int filestream_vprintf(RFILE *stream, const char* format, va_list args);
|
||||||
|
|
||||||
|
int filestream_printf(RFILE *stream, const char* format, ...);
|
||||||
|
|
||||||
|
int filestream_error(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_flush(RFILE *stream);
|
||||||
|
|
||||||
|
int filestream_delete(const char *path);
|
||||||
|
|
||||||
|
int filestream_rename(const char *old_path, const char *new_path);
|
||||||
|
|
||||||
|
const char* filestream_get_path(RFILE *stream);
|
||||||
|
|
||||||
|
bool filestream_exists(const char *path);
|
||||||
|
|
||||||
|
/* Returned pointer must be freed by the caller. */
|
||||||
|
char* filestream_getline(RFILE *stream);
|
||||||
|
|
||||||
|
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,269 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (stdstring.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_STDSTRING_H
|
||||||
|
#define __LIBRETRO_SDK_STDSTRING_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <retro_inline.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||||
|
|
||||||
|
#define strcpy_literal(a, b) strcpy(a, b)
|
||||||
|
|
||||||
|
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||||
|
|
||||||
|
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||||
|
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||||
|
|
||||||
|
#define TOLOWER(c) ((c) | (lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
#define TOUPPER(c) ((c) & ~(lr_char_props[(unsigned char)(c)] & 0x20))
|
||||||
|
|
||||||
|
/* C standard says \f \v are space, but this one disagrees */
|
||||||
|
#define ISSPACE(c) (lr_char_props[(unsigned char)(c)] & 0x80)
|
||||||
|
|
||||||
|
#define ISDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x40)
|
||||||
|
#define ISALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x20)
|
||||||
|
#define ISLOWER(c) (lr_char_props[(unsigned char)(c)] & 0x04)
|
||||||
|
#define ISUPPER(c) (lr_char_props[(unsigned char)(c)] & 0x02)
|
||||||
|
#define ISALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x60)
|
||||||
|
#define ISUALPHA(c) (lr_char_props[(unsigned char)(c)] & 0x28)
|
||||||
|
#define ISUALNUM(c) (lr_char_props[(unsigned char)(c)] & 0x68)
|
||||||
|
#define IS_XDIGIT(c) (lr_char_props[(unsigned char)(c)] & 0x01)
|
||||||
|
|
||||||
|
/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
|
||||||
|
#define string_is_equal_noncase string_is_equal_case_insensitive
|
||||||
|
|
||||||
|
static INLINE bool string_is_empty(const char *data)
|
||||||
|
{
|
||||||
|
return !data || (*data == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_is_equal(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
return (a && b) ? !strcmp(a, b) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_starts_with_size(const char *str, const char *prefix,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
return (str && prefix) ? !strncmp(prefix, str, size) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_starts_with(const char *str, const char *prefix)
|
||||||
|
{
|
||||||
|
return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_ends_with_size(const char *str, const char *suffix,
|
||||||
|
size_t str_len, size_t suffix_len)
|
||||||
|
{
|
||||||
|
return (str_len < suffix_len) ? false :
|
||||||
|
!memcmp(suffix, str + (str_len - suffix_len), suffix_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_ends_with(const char *str, const char *suffix)
|
||||||
|
{
|
||||||
|
if (!str || !suffix)
|
||||||
|
return false;
|
||||||
|
return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the length of 'str' (c.f. strlen()), but only
|
||||||
|
* checks the first 'size' characters
|
||||||
|
* - If 'str' is NULL, returns 0
|
||||||
|
* - If 'str' is not NULL and no '\0' character is found
|
||||||
|
* in the first 'size' characters, returns 'size' */
|
||||||
|
static INLINE size_t strlen_size(const char *str, size_t size)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
if (str)
|
||||||
|
while (i < size && str[i]) i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||||
|
const char *b)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
const unsigned char *p1 = (const unsigned char*)a;
|
||||||
|
const unsigned char *p2 = (const unsigned char*)b;
|
||||||
|
|
||||||
|
if (!a || !b)
|
||||||
|
return false;
|
||||||
|
if (p1 == p2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||||
|
if (*p1++ == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
return (result == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static INLINE bool string_starts_with_case_insensitive(const char *str,
|
||||||
|
const char *prefix)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
const unsigned char *p1 = (const unsigned char*)str;
|
||||||
|
const unsigned char *p2 = (const unsigned char*)prefix;
|
||||||
|
|
||||||
|
if (!str || !prefix)
|
||||||
|
return false;
|
||||||
|
if (p1 == p2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while ((result = tolower (*p1++) - tolower (*p2)) == 0)
|
||||||
|
if (*p2++ == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
return (result == 0 || *p2 == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_to_upper(char *s);
|
||||||
|
|
||||||
|
char *string_to_lower(char *s);
|
||||||
|
|
||||||
|
char *string_ucwords(char *s);
|
||||||
|
|
||||||
|
char *string_replace_substring(const char *in, const char *pattern,
|
||||||
|
const char *by);
|
||||||
|
|
||||||
|
/* Remove leading whitespaces */
|
||||||
|
char *string_trim_whitespace_left(char *const s);
|
||||||
|
|
||||||
|
/* Remove trailing whitespaces */
|
||||||
|
char *string_trim_whitespace_right(char *const s);
|
||||||
|
|
||||||
|
/* Remove leading and trailing whitespaces */
|
||||||
|
char *string_trim_whitespace(char *const s);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps string specified by 'src' to destination buffer
|
||||||
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* have an on-screen pixel width similar to that of
|
||||||
|
* regular Latin characters - i.e. it will not wrap
|
||||||
|
* correctly any text containing so-called 'wide' Unicode
|
||||||
|
* characters (e.g. CJK languages, emojis, etc.).
|
||||||
|
*
|
||||||
|
* @param dst pointer to destination buffer.
|
||||||
|
* @param dst_size size of destination buffer.
|
||||||
|
* @param src pointer to input string.
|
||||||
|
* @param line_width max number of characters per line.
|
||||||
|
* @param wideglyph_width not used, but is necessary to keep
|
||||||
|
* compatibility with word_wrap_wideglyph().
|
||||||
|
* @param max_lines max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*/
|
||||||
|
void word_wrap(char *dst, size_t dst_size, const char *src,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wraps string specified by 'src' to destination buffer
|
||||||
|
* specified by 'dst' and 'dst_size'.
|
||||||
|
* This function assumes that all glyphs in the string
|
||||||
|
* are:
|
||||||
|
* - EITHER 'non-wide' Unicode glyphs, with an on-screen
|
||||||
|
* pixel width similar to that of regular Latin characters
|
||||||
|
* - OR 'wide' Unicode glyphs (e.g. CJK languages, emojis, etc.)
|
||||||
|
* with an on-screen pixel width defined by 'wideglyph_width'
|
||||||
|
* Note that wrapping may occur in inappropriate locations
|
||||||
|
* if 'src' string contains 'wide' Unicode characters whose
|
||||||
|
* on-screen pixel width deviates greatly from the set
|
||||||
|
* 'wideglyph_width' value.
|
||||||
|
*
|
||||||
|
* @param dst pointer to destination buffer.
|
||||||
|
* @param dst_size size of destination buffer.
|
||||||
|
* @param src pointer to input string.
|
||||||
|
* @param line_width max number of characters per line.
|
||||||
|
* @param wideglyph_width effective width of 'wide' Unicode glyphs.
|
||||||
|
* the value here is normalised relative to the
|
||||||
|
* typical on-screen pixel width of a regular
|
||||||
|
* Latin character:
|
||||||
|
* - a regular Latin character is defined to
|
||||||
|
* have an effective width of 100
|
||||||
|
* - wideglyph_width = 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - e.g. if 'wide' Unicode characters in 'src'
|
||||||
|
* have an on-screen pixel width twice that of
|
||||||
|
* regular Latin characters, wideglyph_width
|
||||||
|
* would be 200
|
||||||
|
* @param max_lines max lines of destination string.
|
||||||
|
* 0 means no limit.
|
||||||
|
*/
|
||||||
|
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src,
|
||||||
|
int line_width, int wideglyph_width, unsigned max_lines);
|
||||||
|
|
||||||
|
/* Splits string into tokens seperated by 'delim'
|
||||||
|
* > Returned token string must be free()'d
|
||||||
|
* > Returns NULL if token is not found
|
||||||
|
* > After each call, 'str' is set to the position after the
|
||||||
|
* last found token
|
||||||
|
* > Tokens *include* empty strings
|
||||||
|
* Usage example:
|
||||||
|
* char *str = "1,2,3,4,5,6,7,,,10,";
|
||||||
|
* char **str_ptr = &str;
|
||||||
|
* char *token = NULL;
|
||||||
|
* while ((token = string_tokenize(str_ptr, ",")))
|
||||||
|
* {
|
||||||
|
* printf("%s\n", token);
|
||||||
|
* free(token);
|
||||||
|
* token = NULL;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
char* string_tokenize(char **str, const char *delim);
|
||||||
|
|
||||||
|
/* Removes every instance of character 'c' from 'str' */
|
||||||
|
void string_remove_all_chars(char *str, char c);
|
||||||
|
|
||||||
|
/* Replaces every instance of character 'find' in 'str'
|
||||||
|
* with character 'replace' */
|
||||||
|
void string_replace_all_chars(char *str, char find, char replace);
|
||||||
|
|
||||||
|
/* Converts string to unsigned integer.
|
||||||
|
* Returns 0 if string is invalid */
|
||||||
|
unsigned string_to_unsigned(const char *str);
|
||||||
|
|
||||||
|
/* Converts hexadecimal string to unsigned integer.
|
||||||
|
* Handles optional leading '0x'.
|
||||||
|
* Returns 0 if string is invalid */
|
||||||
|
unsigned string_hex_to_unsigned(const char *str);
|
||||||
|
|
||||||
|
char *string_init(const char *src);
|
||||||
|
|
||||||
|
void string_set(char **string, const char *src);
|
||||||
|
|
||||||
|
extern const unsigned char lr_char_props[256];
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (rtime.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_RTIME_H__
|
||||||
|
#define __LIBRETRO_SDK_RTIME_H__
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* TODO/FIXME: Move all generic time handling functions
|
||||||
|
* to this file */
|
||||||
|
|
||||||
|
/* Must be called before using rtime_localtime() */
|
||||||
|
void rtime_init(void);
|
||||||
|
|
||||||
|
/* Must be called upon program termination */
|
||||||
|
void rtime_deinit(void);
|
||||||
|
|
||||||
|
/* Thread-safe wrapper for localtime() */
|
||||||
|
struct tm *rtime_localtime(const time_t *timep, struct tm *result);
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,111 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (vfs_implementation.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_VFS_H
|
||||||
|
#define __LIBRETRO_SDK_VFS_H
|
||||||
|
|
||||||
|
#include <retro_common_api.h>
|
||||||
|
#include <boolean.h>
|
||||||
|
|
||||||
|
#ifdef RARCH_INTERNAL
|
||||||
|
#ifndef VFS_FRONTEND
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef void* HANDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CDROM
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int64_t byte_pos;
|
||||||
|
char *cue_buf;
|
||||||
|
size_t cue_len;
|
||||||
|
unsigned cur_lba;
|
||||||
|
unsigned last_frame_lba;
|
||||||
|
unsigned char cur_min;
|
||||||
|
unsigned char cur_sec;
|
||||||
|
unsigned char cur_frame;
|
||||||
|
unsigned char cur_track;
|
||||||
|
unsigned char last_frame[2352];
|
||||||
|
char drive;
|
||||||
|
bool last_frame_valid;
|
||||||
|
} vfs_cdrom_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum vfs_scheme
|
||||||
|
{
|
||||||
|
VFS_SCHEME_NONE = 0,
|
||||||
|
VFS_SCHEME_CDROM
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !(defined(__WINRT__) && defined(__cplusplus_winrt))
|
||||||
|
#ifdef VFS_FRONTEND
|
||||||
|
struct retro_vfs_file_handle
|
||||||
|
#else
|
||||||
|
struct libretro_vfs_implementation_file
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CDROM
|
||||||
|
vfs_cdrom_t cdrom; /* int64_t alignment */
|
||||||
|
#endif
|
||||||
|
int64_t size;
|
||||||
|
uint64_t mappos;
|
||||||
|
uint64_t mapsize;
|
||||||
|
FILE *fp;
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE fh;
|
||||||
|
#endif
|
||||||
|
char *buf;
|
||||||
|
char* orig_path;
|
||||||
|
uint8_t *mapped;
|
||||||
|
int fd;
|
||||||
|
unsigned hints;
|
||||||
|
enum vfs_scheme scheme;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Replace the following symbol with something appropriate
|
||||||
|
* to signify the file is being compiled for a front end instead of a core.
|
||||||
|
* This allows the same code to act as reference implementation
|
||||||
|
* for VFS and as fallbacks for when the front end does not provide VFS functionality.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef VFS_FRONTEND
|
||||||
|
typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
|
||||||
|
#else
|
||||||
|
typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VFS_FRONTEND
|
||||||
|
typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
|
||||||
|
#else
|
||||||
|
typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (vfs_implementation.h).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
|
||||||
|
#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <libretro.h>
|
||||||
|
#include <retro_environment.h>
|
||||||
|
#include <vfs/vfs.h>
|
||||||
|
|
||||||
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
|
||||||
|
|
||||||
|
int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);
|
||||||
|
|
||||||
|
int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);
|
||||||
|
|
||||||
|
int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int retro_vfs_file_remove_impl(const char *path);
|
||||||
|
|
||||||
|
int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);
|
||||||
|
|
||||||
|
const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);
|
||||||
|
|
||||||
|
int retro_vfs_stat_impl(const char *path, int32_t *size);
|
||||||
|
|
||||||
|
int retro_vfs_mkdir_impl(const char *dir);
|
||||||
|
|
||||||
|
libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);
|
||||||
|
|
||||||
|
bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
|
||||||
|
|
||||||
|
#ifdef __WINRT__
|
||||||
|
|
||||||
|
void uwp_set_acl(const wchar_t* path, const wchar_t* AccessString);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RETRO_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,554 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (string_list.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <lists/string_list.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
#include <compat/posix_string.h>
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
|
||||||
|
static bool string_list_deinitialize_internal(struct string_list *list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (list->elems)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < list->size; i++)
|
||||||
|
{
|
||||||
|
if (list->elems[i].data)
|
||||||
|
free(list->elems[i].data);
|
||||||
|
if (list->elems[i].userdata)
|
||||||
|
free(list->elems[i].userdata);
|
||||||
|
list->elems[i].data = NULL;
|
||||||
|
list->elems[i].userdata = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(list->elems);
|
||||||
|
}
|
||||||
|
|
||||||
|
list->elems = NULL;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_capacity:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @cap : new capacity for string list.
|
||||||
|
*
|
||||||
|
* Change maximum capacity of string list's size.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
static bool string_list_capacity(struct string_list *list, size_t cap)
|
||||||
|
{
|
||||||
|
struct string_list_elem *new_data = (struct string_list_elem*)
|
||||||
|
realloc(list->elems, cap * sizeof(*new_data));
|
||||||
|
|
||||||
|
if (!new_data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cap > list->cap)
|
||||||
|
memset(&new_data[list->cap], 0, sizeof(*new_data) * (cap - list->cap));
|
||||||
|
|
||||||
|
list->elems = new_data;
|
||||||
|
list->cap = cap;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_free
|
||||||
|
* @list : pointer to string list object
|
||||||
|
*
|
||||||
|
* Frees a string list.
|
||||||
|
*/
|
||||||
|
void string_list_free(struct string_list *list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string_list_deinitialize_internal(list);
|
||||||
|
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_list_deinitialize(struct string_list *list)
|
||||||
|
{
|
||||||
|
if (!list)
|
||||||
|
return false;
|
||||||
|
if (!string_list_deinitialize_internal(list))
|
||||||
|
return false;
|
||||||
|
list->elems = NULL;
|
||||||
|
list->size = 0;
|
||||||
|
list->cap = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_new:
|
||||||
|
*
|
||||||
|
* Creates a new string list. Has to be freed manually.
|
||||||
|
*
|
||||||
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
|
*/
|
||||||
|
struct string_list *string_list_new(void)
|
||||||
|
{
|
||||||
|
struct string_list_elem *
|
||||||
|
elems = NULL;
|
||||||
|
struct string_list *list = (struct string_list*)
|
||||||
|
malloc(sizeof(*list));
|
||||||
|
if (!list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(elems = (struct string_list_elem*)
|
||||||
|
calloc(32, sizeof(*elems))))
|
||||||
|
{
|
||||||
|
string_list_free(list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list->elems = elems;
|
||||||
|
list->size = 0;
|
||||||
|
list->cap = 32;
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_list_initialize(struct string_list *list)
|
||||||
|
{
|
||||||
|
struct string_list_elem *
|
||||||
|
elems = NULL;
|
||||||
|
if (!list)
|
||||||
|
return false;
|
||||||
|
if (!(elems = (struct string_list_elem*)
|
||||||
|
calloc(32, sizeof(*elems))))
|
||||||
|
{
|
||||||
|
string_list_deinitialize(list);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
list->elems = elems;
|
||||||
|
list->size = 0;
|
||||||
|
list->cap = 32;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_append:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to add to the string list
|
||||||
|
* @attr : attributes of new element.
|
||||||
|
*
|
||||||
|
* Appends a new element to the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool string_list_append(struct string_list *list, const char *elem,
|
||||||
|
union string_list_elem_attr attr)
|
||||||
|
{
|
||||||
|
char *data_dup = NULL;
|
||||||
|
|
||||||
|
/* Note: If 'list' is incorrectly initialised
|
||||||
|
* (i.e. if struct is zero initialised and
|
||||||
|
* string_list_initialize() is not called on
|
||||||
|
* it) capacity will be zero. This will cause
|
||||||
|
* a segfault. Handle this case by forcing the new
|
||||||
|
* capacity to a fixed size of 32 */
|
||||||
|
if (list->size >= list->cap &&
|
||||||
|
!string_list_capacity(list,
|
||||||
|
(list->cap > 0) ? (list->cap * 2) : 32))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data_dup = strdup(elem);
|
||||||
|
if (!data_dup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
list->elems[list->size].data = data_dup;
|
||||||
|
list->elems[list->size].attr = attr;
|
||||||
|
|
||||||
|
list->size++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_append_n:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to add to the string list
|
||||||
|
* @length : read at most this many bytes from elem
|
||||||
|
* @attr : attributes of new element.
|
||||||
|
*
|
||||||
|
* Appends a new element to the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool string_list_append_n(struct string_list *list, const char *elem,
|
||||||
|
unsigned length, union string_list_elem_attr attr)
|
||||||
|
{
|
||||||
|
char *data_dup = NULL;
|
||||||
|
|
||||||
|
if (list->size >= list->cap &&
|
||||||
|
!string_list_capacity(list, list->cap * 2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data_dup = (char*)malloc(length + 1);
|
||||||
|
|
||||||
|
if (!data_dup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
strlcpy(data_dup, elem, length + 1);
|
||||||
|
|
||||||
|
list->elems[list->size].data = data_dup;
|
||||||
|
list->elems[list->size].attr = attr;
|
||||||
|
|
||||||
|
list->size++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_set:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @idx : index of element in string list
|
||||||
|
* @str : value for the element.
|
||||||
|
*
|
||||||
|
* Set value of element inside string list.
|
||||||
|
**/
|
||||||
|
void string_list_set(struct string_list *list,
|
||||||
|
unsigned idx, const char *str)
|
||||||
|
{
|
||||||
|
free(list->elems[idx].data);
|
||||||
|
list->elems[idx].data = strdup(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_join_concat:
|
||||||
|
* @buffer : buffer that @list will be joined to.
|
||||||
|
* @size : length of @buffer.
|
||||||
|
* @list : pointer to string list.
|
||||||
|
* @delim : delimiter character for @list.
|
||||||
|
*
|
||||||
|
* A string list will be joined/concatenated as a
|
||||||
|
* string to @buffer, delimited by @delim.
|
||||||
|
*/
|
||||||
|
void string_list_join_concat(char *buffer, size_t size,
|
||||||
|
const struct string_list *list, const char *delim)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
size_t len = strlen_size(buffer, size);
|
||||||
|
|
||||||
|
/* If buffer is already 'full', nothing
|
||||||
|
* further can be added
|
||||||
|
* > This condition will also be triggered
|
||||||
|
* if buffer is not NUL-terminated,
|
||||||
|
* in which case any attempt to increment
|
||||||
|
* buffer or decrement size would lead to
|
||||||
|
* undefined behaviour */
|
||||||
|
if (len >= size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer += len;
|
||||||
|
size -= len;
|
||||||
|
|
||||||
|
for (i = 0; i < list->size; i++)
|
||||||
|
{
|
||||||
|
strlcat(buffer, list->elems[i].data, size);
|
||||||
|
if ((i + 1) < list->size)
|
||||||
|
strlcat(buffer, delim, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_split:
|
||||||
|
* @str : string to turn into a string list
|
||||||
|
* @delim : delimiter character to use for splitting the string.
|
||||||
|
*
|
||||||
|
* Creates a new string list based on string @str, delimited by @delim.
|
||||||
|
*
|
||||||
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
|
*/
|
||||||
|
struct string_list *string_split(const char *str, const char *delim)
|
||||||
|
{
|
||||||
|
char *save = NULL;
|
||||||
|
char *copy = NULL;
|
||||||
|
const char *tmp = NULL;
|
||||||
|
struct string_list *list = string_list_new();
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
copy = strdup(str);
|
||||||
|
if (!copy)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
tmp = strtok_r(copy, delim, &save);
|
||||||
|
while (tmp)
|
||||||
|
{
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
|
||||||
|
attr.i = 0;
|
||||||
|
|
||||||
|
if (!string_list_append(list, tmp, attr))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
tmp = strtok_r(NULL, delim, &save);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(copy);
|
||||||
|
return list;
|
||||||
|
|
||||||
|
error:
|
||||||
|
string_list_free(list);
|
||||||
|
free(copy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_split_noalloc(struct string_list *list,
|
||||||
|
const char *str, const char *delim)
|
||||||
|
{
|
||||||
|
char *save = NULL;
|
||||||
|
char *copy = NULL;
|
||||||
|
const char *tmp = NULL;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
copy = strdup(str);
|
||||||
|
if (!copy)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tmp = strtok_r(copy, delim, &save);
|
||||||
|
while (tmp)
|
||||||
|
{
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
|
||||||
|
attr.i = 0;
|
||||||
|
|
||||||
|
if (!string_list_append(list, tmp, attr))
|
||||||
|
{
|
||||||
|
free(copy);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = strtok_r(NULL, delim, &save);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(copy);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_separate:
|
||||||
|
* @str : string to turn into a string list
|
||||||
|
* @delim : delimiter character to use for separating the string.
|
||||||
|
*
|
||||||
|
* Creates a new string list based on string @str, delimited by @delim.
|
||||||
|
* Includes empty strings - i.e. two adjacent delimiters will resolve
|
||||||
|
* to a string list element of "".
|
||||||
|
*
|
||||||
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
|
*/
|
||||||
|
struct string_list *string_separate(char *str, const char *delim)
|
||||||
|
{
|
||||||
|
char *token = NULL;
|
||||||
|
char **str_ptr = NULL;
|
||||||
|
struct string_list *list = NULL;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!str || string_is_empty(delim))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
str_ptr = &str;
|
||||||
|
list = string_list_new();
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
token = string_tokenize(str_ptr, delim);
|
||||||
|
while (token)
|
||||||
|
{
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
|
||||||
|
attr.i = 0;
|
||||||
|
|
||||||
|
if (!string_list_append(list, token, attr))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
free(token);
|
||||||
|
token = NULL;
|
||||||
|
|
||||||
|
token = string_tokenize(str_ptr, delim);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (token)
|
||||||
|
free(token);
|
||||||
|
if (list)
|
||||||
|
string_list_free(list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string_separate_noalloc(
|
||||||
|
struct string_list *list,
|
||||||
|
char *str, const char *delim)
|
||||||
|
{
|
||||||
|
char *token = NULL;
|
||||||
|
char **str_ptr = NULL;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (!str || string_is_empty(delim) || !list)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
str_ptr = &str;
|
||||||
|
token = string_tokenize(str_ptr, delim);
|
||||||
|
|
||||||
|
while (token)
|
||||||
|
{
|
||||||
|
union string_list_elem_attr attr;
|
||||||
|
|
||||||
|
attr.i = 0;
|
||||||
|
|
||||||
|
if (!string_list_append(list, token, attr))
|
||||||
|
{
|
||||||
|
free(token);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(token);
|
||||||
|
token = string_tokenize(str_ptr, delim);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_find_elem:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to find inside the string list.
|
||||||
|
*
|
||||||
|
* Searches for an element (@elem) inside the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if element could be found, otherwise false (0).
|
||||||
|
*/
|
||||||
|
int string_list_find_elem(const struct string_list *list, const char *elem)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = 0; i < list->size; i++)
|
||||||
|
{
|
||||||
|
if (string_is_equal_noncase(list->elems[i].data, elem))
|
||||||
|
return (int)(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_find_elem_prefix:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @prefix : prefix to append to @elem
|
||||||
|
* @elem : element to find inside the string list.
|
||||||
|
*
|
||||||
|
* Searches for an element (@elem) inside the string list. Will
|
||||||
|
* also search for the same element prefixed by @prefix.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if element could be found, otherwise false (0).
|
||||||
|
*/
|
||||||
|
bool string_list_find_elem_prefix(const struct string_list *list,
|
||||||
|
const char *prefix, const char *elem)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
char prefixed[255];
|
||||||
|
|
||||||
|
if (!list)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
prefixed[0] = '\0';
|
||||||
|
|
||||||
|
strlcpy(prefixed, prefix, sizeof(prefixed));
|
||||||
|
strlcat(prefixed, elem, sizeof(prefixed));
|
||||||
|
|
||||||
|
for (i = 0; i < list->size; i++)
|
||||||
|
{
|
||||||
|
if (string_is_equal_noncase(list->elems[i].data, elem) ||
|
||||||
|
string_is_equal_noncase(list->elems[i].data, prefixed))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct string_list *string_list_clone(
|
||||||
|
const struct string_list *src)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
struct string_list_elem
|
||||||
|
*elems = NULL;
|
||||||
|
struct string_list
|
||||||
|
*dest = (struct string_list*)
|
||||||
|
malloc(sizeof(struct string_list));
|
||||||
|
|
||||||
|
if (!dest)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dest->elems = NULL;
|
||||||
|
dest->size = src->size;
|
||||||
|
dest->cap = src->cap;
|
||||||
|
if (dest->cap < dest->size)
|
||||||
|
dest->cap = dest->size;
|
||||||
|
|
||||||
|
elems = (struct string_list_elem*)
|
||||||
|
calloc(dest->cap, sizeof(struct string_list_elem));
|
||||||
|
|
||||||
|
if (!elems)
|
||||||
|
{
|
||||||
|
free(dest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest->elems = elems;
|
||||||
|
|
||||||
|
for (i = 0; i < src->size; i++)
|
||||||
|
{
|
||||||
|
const char *_src = src->elems[i].data;
|
||||||
|
size_t len = _src ? strlen(_src) : 0;
|
||||||
|
|
||||||
|
dest->elems[i].data = NULL;
|
||||||
|
dest->elems[i].attr = src->elems[i].attr;
|
||||||
|
|
||||||
|
if (len != 0)
|
||||||
|
{
|
||||||
|
char *result = (char*)malloc(len + 1);
|
||||||
|
strcpy(result, _src);
|
||||||
|
dest->elems[i].data = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (memalign.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <memalign.h>
|
||||||
|
|
||||||
|
void *memalign_alloc(size_t boundary, size_t size)
|
||||||
|
{
|
||||||
|
void **place = NULL;
|
||||||
|
uintptr_t addr = 0;
|
||||||
|
void *ptr = (void*)malloc(boundary + size + sizeof(uintptr_t));
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
addr = ((uintptr_t)ptr + sizeof(uintptr_t) + boundary)
|
||||||
|
& ~(boundary - 1);
|
||||||
|
place = (void**)addr;
|
||||||
|
place[-1] = ptr;
|
||||||
|
|
||||||
|
return (void*)addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void memalign_free(void *ptr)
|
||||||
|
{
|
||||||
|
void **p = NULL;
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p = (void**)ptr;
|
||||||
|
free(p[-1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memalign_alloc_aligned(size_t size)
|
||||||
|
{
|
||||||
|
#if defined(__x86_64__) || defined(__LP64) || defined(__IA64__) || defined(_M_X64) || defined(_M_X64) || defined(_WIN64)
|
||||||
|
return memalign_alloc(64, size);
|
||||||
|
#elif defined(__i386__) || defined(__i486__) || defined(__i686__) || defined(GEKKO) || defined(_M_IX86)
|
||||||
|
return memalign_alloc(32, size);
|
||||||
|
#else
|
||||||
|
return memalign_alloc(32, size);
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,682 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (file_stream.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <compat/msvc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
|
#define VFS_FRONTEND
|
||||||
|
#include <vfs/vfs_implementation.h>
|
||||||
|
|
||||||
|
#define VFS_ERROR_RETURN_VALUE -1
|
||||||
|
|
||||||
|
struct RFILE
|
||||||
|
{
|
||||||
|
struct retro_vfs_file_handle *hfile;
|
||||||
|
bool error_flag;
|
||||||
|
bool eof_flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
static retro_vfs_get_path_t filestream_get_path_cb = NULL;
|
||||||
|
static retro_vfs_open_t filestream_open_cb = NULL;
|
||||||
|
static retro_vfs_close_t filestream_close_cb = NULL;
|
||||||
|
static retro_vfs_size_t filestream_size_cb = NULL;
|
||||||
|
static retro_vfs_truncate_t filestream_truncate_cb = NULL;
|
||||||
|
static retro_vfs_tell_t filestream_tell_cb = NULL;
|
||||||
|
static retro_vfs_seek_t filestream_seek_cb = NULL;
|
||||||
|
static retro_vfs_read_t filestream_read_cb = NULL;
|
||||||
|
static retro_vfs_write_t filestream_write_cb = NULL;
|
||||||
|
static retro_vfs_flush_t filestream_flush_cb = NULL;
|
||||||
|
static retro_vfs_remove_t filestream_remove_cb = NULL;
|
||||||
|
static retro_vfs_rename_t filestream_rename_cb = NULL;
|
||||||
|
|
||||||
|
/* VFS Initialization */
|
||||||
|
|
||||||
|
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||||
|
{
|
||||||
|
const struct retro_vfs_interface *
|
||||||
|
vfs_iface = vfs_info->iface;
|
||||||
|
|
||||||
|
filestream_get_path_cb = NULL;
|
||||||
|
filestream_open_cb = NULL;
|
||||||
|
filestream_close_cb = NULL;
|
||||||
|
filestream_tell_cb = NULL;
|
||||||
|
filestream_size_cb = NULL;
|
||||||
|
filestream_truncate_cb = NULL;
|
||||||
|
filestream_seek_cb = NULL;
|
||||||
|
filestream_read_cb = NULL;
|
||||||
|
filestream_write_cb = NULL;
|
||||||
|
filestream_flush_cb = NULL;
|
||||||
|
filestream_remove_cb = NULL;
|
||||||
|
filestream_rename_cb = NULL;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(vfs_info->required_interface_version <
|
||||||
|
FILESTREAM_REQUIRED_VFS_VERSION)
|
||||||
|
|| !vfs_iface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
filestream_get_path_cb = vfs_iface->get_path;
|
||||||
|
filestream_open_cb = vfs_iface->open;
|
||||||
|
filestream_close_cb = vfs_iface->close;
|
||||||
|
filestream_size_cb = vfs_iface->size;
|
||||||
|
filestream_truncate_cb = vfs_iface->truncate;
|
||||||
|
filestream_tell_cb = vfs_iface->tell;
|
||||||
|
filestream_seek_cb = vfs_iface->seek;
|
||||||
|
filestream_read_cb = vfs_iface->read;
|
||||||
|
filestream_write_cb = vfs_iface->write;
|
||||||
|
filestream_flush_cb = vfs_iface->flush;
|
||||||
|
filestream_remove_cb = vfs_iface->remove;
|
||||||
|
filestream_rename_cb = vfs_iface->rename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback wrappers */
|
||||||
|
bool filestream_exists(const char *path)
|
||||||
|
{
|
||||||
|
RFILE *dummy = NULL;
|
||||||
|
|
||||||
|
if (!path || !*path)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dummy = filestream_open(
|
||||||
|
path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!dummy)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (filestream_close(dummy) != 0)
|
||||||
|
if (dummy)
|
||||||
|
free(dummy);
|
||||||
|
|
||||||
|
dummy = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_get_size(RFILE *stream)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_size_cb)
|
||||||
|
output = filestream_size_cb(stream->hfile);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_size_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_truncate(RFILE *stream, int64_t length)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_truncate_cb)
|
||||||
|
output = filestream_truncate_cb(stream->hfile, length);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_truncate_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, length);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_open:
|
||||||
|
* @path : path to file
|
||||||
|
* @mode : file mode to use when opening (read/write)
|
||||||
|
* @hints :
|
||||||
|
*
|
||||||
|
* Opens a file for reading or writing, depending on the requested mode.
|
||||||
|
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||||
|
**/
|
||||||
|
RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
|
||||||
|
{
|
||||||
|
struct retro_vfs_file_handle *fp = NULL;
|
||||||
|
RFILE* output = NULL;
|
||||||
|
|
||||||
|
if (filestream_open_cb)
|
||||||
|
fp = (struct retro_vfs_file_handle*)
|
||||||
|
filestream_open_cb(path, mode, hints);
|
||||||
|
else
|
||||||
|
fp = (struct retro_vfs_file_handle*)
|
||||||
|
retro_vfs_file_open_impl(path, mode, hints);
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
output = (RFILE*)malloc(sizeof(RFILE));
|
||||||
|
output->error_flag = false;
|
||||||
|
output->eof_flag = false;
|
||||||
|
output->hfile = fp;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* filestream_gets(RFILE *stream, char *s, size_t len)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
char *p = s;
|
||||||
|
if (!stream)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* get max bytes or up to a newline */
|
||||||
|
|
||||||
|
for (len--; len > 0; len--)
|
||||||
|
{
|
||||||
|
if ((c = filestream_getc(stream)) == EOF)
|
||||||
|
break;
|
||||||
|
*p++ = c;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
if (p == s && c == EOF)
|
||||||
|
return NULL;
|
||||||
|
return (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_getc(RFILE *stream)
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
if (stream && filestream_read(stream, &c, 1) == 1)
|
||||||
|
return (int)(unsigned char)c;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_vscanf(RFILE *stream, const char* format, va_list *args)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
char subfmt[64];
|
||||||
|
va_list args_copy;
|
||||||
|
const char * bufiter = buf;
|
||||||
|
int ret = 0;
|
||||||
|
int64_t startpos = filestream_tell(stream);
|
||||||
|
int64_t maxlen = filestream_read(stream, buf, sizeof(buf)-1);
|
||||||
|
|
||||||
|
if (maxlen <= 0)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
buf[maxlen] = '\0';
|
||||||
|
|
||||||
|
/* Have to copy the input va_list here
|
||||||
|
* > Calling va_arg() on 'args' directly would
|
||||||
|
* cause the va_list to have an indeterminate value
|
||||||
|
* in the function calling filestream_vscanf(),
|
||||||
|
* leading to unexpected behaviour */
|
||||||
|
#ifdef __va_copy
|
||||||
|
__va_copy(args_copy, *args);
|
||||||
|
#else
|
||||||
|
va_copy(args_copy, *args);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
int sublen;
|
||||||
|
char* subfmtiter = subfmt;
|
||||||
|
bool asterisk = false;
|
||||||
|
|
||||||
|
*subfmtiter++ = *format++; /* '%' */
|
||||||
|
|
||||||
|
/* %[*][width][length]specifier */
|
||||||
|
|
||||||
|
if (*format == '*')
|
||||||
|
{
|
||||||
|
asterisk = true;
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ISDIGIT((unsigned char)*format))
|
||||||
|
*subfmtiter++ = *format++; /* width */
|
||||||
|
|
||||||
|
/* length */
|
||||||
|
if (*format == 'h' || *format == 'l')
|
||||||
|
{
|
||||||
|
if (format[1] == format[0])
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
*format == 'j' ||
|
||||||
|
*format == 'z' ||
|
||||||
|
*format == 't' ||
|
||||||
|
*format == 'L')
|
||||||
|
{
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* specifier - always a single character (except ]) */
|
||||||
|
if (*format == '[')
|
||||||
|
{
|
||||||
|
while (*format != ']')
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*subfmtiter++ = *format++;
|
||||||
|
|
||||||
|
*subfmtiter++ = '%';
|
||||||
|
*subfmtiter++ = 'n';
|
||||||
|
*subfmtiter++ = '\0';
|
||||||
|
|
||||||
|
if (sizeof(void*) != sizeof(long*))
|
||||||
|
abort(); /* all pointers must have the same size */
|
||||||
|
|
||||||
|
if (asterisk)
|
||||||
|
{
|
||||||
|
int v = sscanf(bufiter, subfmt, &sublen);
|
||||||
|
if (v == EOF)
|
||||||
|
return EOF;
|
||||||
|
if (v != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int v = sscanf(bufiter, subfmt, va_arg(args_copy, void*), &sublen);
|
||||||
|
if (v == EOF)
|
||||||
|
return EOF;
|
||||||
|
if (v != 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret++;
|
||||||
|
bufiter += sublen;
|
||||||
|
}
|
||||||
|
else if (isspace((unsigned char)*format))
|
||||||
|
{
|
||||||
|
while (isspace((unsigned char)*bufiter))
|
||||||
|
bufiter++;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*bufiter != *format)
|
||||||
|
break;
|
||||||
|
bufiter++;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args_copy);
|
||||||
|
filestream_seek(stream, startpos+(bufiter-buf),
|
||||||
|
RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_scanf(RFILE *stream, const char* format, ...)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vscanf(stream, format, &vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_seek_cb)
|
||||||
|
output = filestream_seek_cb(stream->hfile, offset, seek_position);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_seek_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile,
|
||||||
|
offset, seek_position);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
stream->eof_flag = false;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_eof(RFILE *stream)
|
||||||
|
{
|
||||||
|
return stream->eof_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_tell(RFILE *stream)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_size_cb)
|
||||||
|
output = filestream_tell_cb(stream->hfile);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_tell_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filestream_rewind(RFILE *stream)
|
||||||
|
{
|
||||||
|
if (!stream)
|
||||||
|
return;
|
||||||
|
filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
|
||||||
|
stream->error_flag = false;
|
||||||
|
stream->eof_flag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_read(RFILE *stream, void *s, int64_t len)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_read_cb)
|
||||||
|
output = filestream_read_cb(stream->hfile, s, len);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_read_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
if (output < len)
|
||||||
|
stream->eof_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_flush(RFILE *stream)
|
||||||
|
{
|
||||||
|
int output;
|
||||||
|
|
||||||
|
if (filestream_flush_cb)
|
||||||
|
output = filestream_flush_cb(stream->hfile);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_flush_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_delete(const char *path)
|
||||||
|
{
|
||||||
|
if (filestream_remove_cb)
|
||||||
|
return filestream_remove_cb(path);
|
||||||
|
|
||||||
|
return retro_vfs_file_remove_impl(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_rename(const char *old_path, const char *new_path)
|
||||||
|
{
|
||||||
|
if (filestream_rename_cb)
|
||||||
|
return filestream_rename_cb(old_path, new_path);
|
||||||
|
|
||||||
|
return retro_vfs_file_rename_impl(old_path, new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* filestream_get_path(RFILE *stream)
|
||||||
|
{
|
||||||
|
if (filestream_get_path_cb)
|
||||||
|
return filestream_get_path_cb(stream->hfile);
|
||||||
|
|
||||||
|
return retro_vfs_file_get_path_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
|
||||||
|
{
|
||||||
|
int64_t output;
|
||||||
|
|
||||||
|
if (filestream_write_cb)
|
||||||
|
output = filestream_write_cb(stream->hfile, s, len);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_write_impl(
|
||||||
|
(libretro_vfs_implementation_file*)stream->hfile, s, len);
|
||||||
|
|
||||||
|
if (output == VFS_ERROR_RETURN_VALUE)
|
||||||
|
stream->error_flag = true;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_putc(RFILE *stream, int c)
|
||||||
|
{
|
||||||
|
char c_char = (char)c;
|
||||||
|
if (!stream)
|
||||||
|
return EOF;
|
||||||
|
return filestream_write(stream, &c_char, 1) == 1
|
||||||
|
? (int)(unsigned char)c
|
||||||
|
: EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_vprintf(RFILE *stream, const char* format, va_list args)
|
||||||
|
{
|
||||||
|
static char buffer[8 * 1024];
|
||||||
|
int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
|
||||||
|
format, args);
|
||||||
|
|
||||||
|
if (num_chars < 0)
|
||||||
|
return -1;
|
||||||
|
else if (num_chars == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (int)filestream_write(stream, buffer, num_chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_printf(RFILE *stream, const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list vl;
|
||||||
|
int result;
|
||||||
|
va_start(vl, format);
|
||||||
|
result = filestream_vprintf(stream, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_error(RFILE *stream)
|
||||||
|
{
|
||||||
|
if (stream && stream->error_flag)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int filestream_close(RFILE *stream)
|
||||||
|
{
|
||||||
|
int output;
|
||||||
|
struct retro_vfs_file_handle* fp = stream->hfile;
|
||||||
|
|
||||||
|
if (filestream_close_cb)
|
||||||
|
output = filestream_close_cb(fp);
|
||||||
|
else
|
||||||
|
output = retro_vfs_file_close_impl(
|
||||||
|
(libretro_vfs_implementation_file*)fp);
|
||||||
|
|
||||||
|
if (output == 0)
|
||||||
|
free(stream);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_read_file:
|
||||||
|
* @path : path to file.
|
||||||
|
* @buf : buffer to allocate and read the contents of the
|
||||||
|
* file into. Needs to be freed manually.
|
||||||
|
* @len : optional output integer containing bytes read.
|
||||||
|
*
|
||||||
|
* Read the contents of a file into @buf.
|
||||||
|
*
|
||||||
|
* Returns: non zero on success.
|
||||||
|
*/
|
||||||
|
int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
|
||||||
|
{
|
||||||
|
int64_t ret = 0;
|
||||||
|
int64_t content_buf_size = 0;
|
||||||
|
void *content_buf = NULL;
|
||||||
|
RFILE *file = filestream_open(path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_READ,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
*buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
content_buf_size = filestream_get_size(file);
|
||||||
|
|
||||||
|
if (content_buf_size < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
content_buf = malloc((size_t)(content_buf_size + 1));
|
||||||
|
|
||||||
|
if (!content_buf)
|
||||||
|
goto error;
|
||||||
|
if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (filestream_close(file) != 0)
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
*buf = content_buf;
|
||||||
|
|
||||||
|
/* Allow for easy reading of strings to be safe.
|
||||||
|
* Will only work with sane character formatting (Unix). */
|
||||||
|
((char*)content_buf)[ret] = '\0';
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
*len = ret;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (file)
|
||||||
|
if (filestream_close(file) != 0)
|
||||||
|
free(file);
|
||||||
|
if (content_buf)
|
||||||
|
free(content_buf);
|
||||||
|
if (len)
|
||||||
|
*len = -1;
|
||||||
|
*buf = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filestream_write_file:
|
||||||
|
* @path : path to file.
|
||||||
|
* @data : contents to write to the file.
|
||||||
|
* @size : size of the contents.
|
||||||
|
*
|
||||||
|
* Writes data to a file.
|
||||||
|
*
|
||||||
|
* Returns: true (1) on success, false (0) otherwise.
|
||||||
|
*/
|
||||||
|
bool filestream_write_file(const char *path, const void *data, int64_t size)
|
||||||
|
{
|
||||||
|
int64_t ret = 0;
|
||||||
|
RFILE *file = filestream_open(path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
if (!file)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ret = filestream_write(file, data, size);
|
||||||
|
if (filestream_close(file) != 0)
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
if (ret != size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer must be freed by the caller. */
|
||||||
|
char* filestream_getline(RFILE *stream)
|
||||||
|
{
|
||||||
|
char *newline_tmp = NULL;
|
||||||
|
size_t cur_size = 8;
|
||||||
|
size_t idx = 0;
|
||||||
|
int in = 0;
|
||||||
|
char *newline = (char*)malloc(9);
|
||||||
|
|
||||||
|
if (!stream || !newline)
|
||||||
|
{
|
||||||
|
if (newline)
|
||||||
|
free(newline);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
in = filestream_getc(stream);
|
||||||
|
|
||||||
|
while (in != EOF && in != '\n')
|
||||||
|
{
|
||||||
|
if (idx == cur_size)
|
||||||
|
{
|
||||||
|
cur_size *= 2;
|
||||||
|
newline_tmp = (char*)realloc(newline, cur_size + 1);
|
||||||
|
|
||||||
|
if (!newline_tmp)
|
||||||
|
{
|
||||||
|
free(newline);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newline = newline_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
newline[idx++] = in;
|
||||||
|
in = filestream_getc(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
newline[idx] = '\0';
|
||||||
|
return newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
|
||||||
|
{
|
||||||
|
return (libretro_vfs_implementation_file*)stream->hfile;
|
||||||
|
}
|
|
@ -0,0 +1,536 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (stdstring.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <string/stdstring.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
const uint8_t lr_char_props[256] = {
|
||||||
|
/*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x */
|
||||||
|
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x !"#$%&'()*+,-./ */
|
||||||
|
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
|
||||||
|
0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
|
||||||
|
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
|
||||||
|
0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
|
||||||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~ */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex */
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx */
|
||||||
|
};
|
||||||
|
|
||||||
|
char *string_init(const char *src)
|
||||||
|
{
|
||||||
|
return src ? strdup(src) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void string_set(char **string, const char *src)
|
||||||
|
{
|
||||||
|
free(*string);
|
||||||
|
*string = string_init(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *string_to_upper(char *s)
|
||||||
|
{
|
||||||
|
char *cs = (char *)s;
|
||||||
|
for ( ; *cs != '\0'; cs++)
|
||||||
|
*cs = toupper((unsigned char)*cs);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_to_lower(char *s)
|
||||||
|
{
|
||||||
|
char *cs = (char *)s;
|
||||||
|
for ( ; *cs != '\0'; cs++)
|
||||||
|
*cs = tolower((unsigned char)*cs);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_ucwords(char *s)
|
||||||
|
{
|
||||||
|
char *cs = (char *)s;
|
||||||
|
for ( ; *cs != '\0'; cs++)
|
||||||
|
{
|
||||||
|
if (*cs == ' ')
|
||||||
|
*(cs+1) = toupper((unsigned char)*(cs+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
s[0] = toupper((unsigned char)s[0]);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *string_replace_substring(const char *in,
|
||||||
|
const char *pattern, const char *replacement)
|
||||||
|
{
|
||||||
|
size_t numhits, pattern_len, replacement_len, outlen;
|
||||||
|
const char *inat = NULL;
|
||||||
|
const char *inprev = NULL;
|
||||||
|
char *out = NULL;
|
||||||
|
char *outat = NULL;
|
||||||
|
|
||||||
|
/* if either pattern or replacement is NULL,
|
||||||
|
* duplicate in and let caller handle it. */
|
||||||
|
if (!pattern || !replacement)
|
||||||
|
return strdup(in);
|
||||||
|
|
||||||
|
pattern_len = strlen(pattern);
|
||||||
|
replacement_len = strlen(replacement);
|
||||||
|
numhits = 0;
|
||||||
|
inat = in;
|
||||||
|
|
||||||
|
while ((inat = strstr(inat, pattern)))
|
||||||
|
{
|
||||||
|
inat += pattern_len;
|
||||||
|
numhits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
outlen = strlen(in) - pattern_len*numhits + replacement_len*numhits;
|
||||||
|
out = (char *)malloc(outlen+1);
|
||||||
|
|
||||||
|
if (!out)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
outat = out;
|
||||||
|
inat = in;
|
||||||
|
inprev = in;
|
||||||
|
|
||||||
|
while ((inat = strstr(inat, pattern)))
|
||||||
|
{
|
||||||
|
memcpy(outat, inprev, inat-inprev);
|
||||||
|
outat += inat-inprev;
|
||||||
|
memcpy(outat, replacement, replacement_len);
|
||||||
|
outat += replacement_len;
|
||||||
|
inat += pattern_len;
|
||||||
|
inprev = inat;
|
||||||
|
}
|
||||||
|
strcpy(outat, inprev);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove leading whitespaces */
|
||||||
|
char *string_trim_whitespace_left(char *const s)
|
||||||
|
{
|
||||||
|
if (s && *s)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s);
|
||||||
|
char *current = s;
|
||||||
|
|
||||||
|
while (*current && ISSPACE((unsigned char)*current))
|
||||||
|
{
|
||||||
|
++current;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s != current)
|
||||||
|
memmove(s, current, len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove trailing whitespaces */
|
||||||
|
char *string_trim_whitespace_right(char *const s)
|
||||||
|
{
|
||||||
|
if (s && *s)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s);
|
||||||
|
char *current = s + len - 1;
|
||||||
|
|
||||||
|
while (current != s && ISSPACE((unsigned char)*current))
|
||||||
|
{
|
||||||
|
--current;
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove leading and trailing whitespaces */
|
||||||
|
char *string_trim_whitespace(char *const s)
|
||||||
|
{
|
||||||
|
string_trim_whitespace_right(s); /* order matters */
|
||||||
|
string_trim_whitespace_left(s);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void word_wrap(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
|
{
|
||||||
|
char *lastspace = NULL;
|
||||||
|
unsigned counter = 0;
|
||||||
|
unsigned lines = 1;
|
||||||
|
size_t src_len = strlen(src);
|
||||||
|
const char *src_end = src + src_len;
|
||||||
|
|
||||||
|
/* Prevent buffer overflow */
|
||||||
|
if (dst_size < src_len + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Early return if src string length is less
|
||||||
|
* than line width */
|
||||||
|
if (src_len < line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src != '\0')
|
||||||
|
{
|
||||||
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
if (*src == ' ')
|
||||||
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
|
else if (*src == '\n')
|
||||||
|
{
|
||||||
|
/* If newlines embedded in the input,
|
||||||
|
* reset the index */
|
||||||
|
lines++;
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (char_len--)
|
||||||
|
*dst++ = *src++;
|
||||||
|
|
||||||
|
if (counter >= (unsigned)line_width)
|
||||||
|
{
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
if (lastspace && (max_lines == 0 || lines < max_lines))
|
||||||
|
{
|
||||||
|
/* Replace nearest (previous) whitespace
|
||||||
|
* with newline character */
|
||||||
|
*lastspace = '\n';
|
||||||
|
lines++;
|
||||||
|
|
||||||
|
src -= dst - lastspace - 1;
|
||||||
|
dst = lastspace + 1;
|
||||||
|
lastspace = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strcpy(dst, src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void word_wrap_wideglyph(char *dst, size_t dst_size, const char *src, int line_width, int wideglyph_width, unsigned max_lines)
|
||||||
|
{
|
||||||
|
char *lastspace = NULL;
|
||||||
|
char *lastwideglyph = NULL;
|
||||||
|
const char *src_end = src + strlen(src);
|
||||||
|
unsigned lines = 1;
|
||||||
|
/* 'line_width' means max numbers of characters per line,
|
||||||
|
* but this metric is only meaningful when dealing with
|
||||||
|
* 'regular' glyphs that have an on-screen pixel width
|
||||||
|
* similar to that of regular Latin characters.
|
||||||
|
* When handing so-called 'wide' Unicode glyphs, it is
|
||||||
|
* necessary to consider the actual on-screen pixel width
|
||||||
|
* of each character.
|
||||||
|
* In order to do this, we create a distinction between
|
||||||
|
* regular Latin 'non-wide' glyphs and 'wide' glyphs, and
|
||||||
|
* normalise all values relative to the on-screen pixel
|
||||||
|
* width of regular Latin characters:
|
||||||
|
* - Regular 'non-wide' glyphs have a normalised width of 100
|
||||||
|
* - 'line_width' is therefore normalised to 100 * (width_in_characters)
|
||||||
|
* - 'wide' glyphs have a normalised width of
|
||||||
|
* 100 * (wide_character_pixel_width / latin_character_pixel_width)
|
||||||
|
* - When a character is detected, the position in the current
|
||||||
|
* line is incremented by the regular normalised width of 100
|
||||||
|
* - If that character is then determined to be a 'wide'
|
||||||
|
* glyph, the position in the current line is further incremented
|
||||||
|
* by the difference between the normalised 'wide' and 'non-wide'
|
||||||
|
* width values */
|
||||||
|
unsigned counter_normalized = 0;
|
||||||
|
int line_width_normalized = line_width * 100;
|
||||||
|
int additional_counter_normalized = wideglyph_width - 100;
|
||||||
|
|
||||||
|
/* Early return if src string length is less
|
||||||
|
* than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*src != '\0')
|
||||||
|
{
|
||||||
|
unsigned char_len;
|
||||||
|
|
||||||
|
char_len = (unsigned)(utf8skip(src, 1) - src);
|
||||||
|
counter_normalized += 100;
|
||||||
|
|
||||||
|
/* Prevent buffer overflow */
|
||||||
|
if (char_len >= dst_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (*src == ' ')
|
||||||
|
lastspace = dst; /* Remember the location of the whitespace */
|
||||||
|
else if (*src == '\n')
|
||||||
|
{
|
||||||
|
/* If newlines embedded in the input,
|
||||||
|
* reset the index */
|
||||||
|
lines++;
|
||||||
|
counter_normalized = 0;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (char_len >= 3)
|
||||||
|
{
|
||||||
|
/* Remember the location of the first byte
|
||||||
|
* whose length as UTF-8 >= 3*/
|
||||||
|
lastwideglyph = dst;
|
||||||
|
counter_normalized += additional_counter_normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst_size -= char_len;
|
||||||
|
while (char_len--)
|
||||||
|
*dst++ = *src++;
|
||||||
|
|
||||||
|
if (counter_normalized >= (unsigned)line_width_normalized)
|
||||||
|
{
|
||||||
|
counter_normalized = 0;
|
||||||
|
|
||||||
|
if (max_lines != 0 && lines >= max_lines)
|
||||||
|
continue;
|
||||||
|
else if (lastwideglyph && (!lastspace || lastwideglyph > lastspace))
|
||||||
|
{
|
||||||
|
/* Insert newline character */
|
||||||
|
*lastwideglyph = '\n';
|
||||||
|
lines++;
|
||||||
|
src -= dst - lastwideglyph;
|
||||||
|
dst = lastwideglyph + 1;
|
||||||
|
lastwideglyph = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src <= line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (lastspace)
|
||||||
|
{
|
||||||
|
/* Replace nearest (previous) whitespace
|
||||||
|
* with newline character */
|
||||||
|
*lastspace = '\n';
|
||||||
|
lines++;
|
||||||
|
src -= dst - lastspace - 1;
|
||||||
|
dst = lastspace + 1;
|
||||||
|
lastspace = NULL;
|
||||||
|
|
||||||
|
/* Early return if remaining src string
|
||||||
|
* length is less than line width */
|
||||||
|
if (src_end - src < line_width)
|
||||||
|
{
|
||||||
|
strlcpy(dst, src, dst_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Splits string into tokens seperated by 'delim'
|
||||||
|
* > Returned token string must be free()'d
|
||||||
|
* > Returns NULL if token is not found
|
||||||
|
* > After each call, 'str' is set to the position after the
|
||||||
|
* last found token
|
||||||
|
* > Tokens *include* empty strings
|
||||||
|
* Usage example:
|
||||||
|
* char *str = "1,2,3,4,5,6,7,,,10,";
|
||||||
|
* char **str_ptr = &str;
|
||||||
|
* char *token = NULL;
|
||||||
|
* while ((token = string_tokenize(str_ptr, ",")))
|
||||||
|
* {
|
||||||
|
* printf("%s\n", token);
|
||||||
|
* free(token);
|
||||||
|
* token = NULL;
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
char* string_tokenize(char **str, const char *delim)
|
||||||
|
{
|
||||||
|
/* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
|
||||||
|
char *str_ptr = NULL;
|
||||||
|
char *delim_ptr = NULL;
|
||||||
|
char *token = NULL;
|
||||||
|
size_t token_len = 0;
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
if (!str || string_is_empty(delim))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
str_ptr = *str;
|
||||||
|
|
||||||
|
/* Note: we don't check string_is_empty() here,
|
||||||
|
* empty strings are valid */
|
||||||
|
if (!str_ptr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Search for delimiter */
|
||||||
|
delim_ptr = strstr(str_ptr, delim);
|
||||||
|
|
||||||
|
if (delim_ptr)
|
||||||
|
token_len = delim_ptr - str_ptr;
|
||||||
|
else
|
||||||
|
token_len = strlen(str_ptr);
|
||||||
|
|
||||||
|
/* Allocate token string */
|
||||||
|
token = (char *)malloc((token_len + 1) * sizeof(char));
|
||||||
|
|
||||||
|
if (!token)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Copy token */
|
||||||
|
strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
|
||||||
|
token[token_len] = '\0';
|
||||||
|
|
||||||
|
/* Update input string pointer */
|
||||||
|
*str = delim_ptr ? delim_ptr + strlen(delim) : NULL;
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Removes every instance of character 'c' from 'str' */
|
||||||
|
void string_remove_all_chars(char *str, char c)
|
||||||
|
{
|
||||||
|
char *read_ptr = NULL;
|
||||||
|
char *write_ptr = NULL;
|
||||||
|
|
||||||
|
if (string_is_empty(str))
|
||||||
|
return;
|
||||||
|
|
||||||
|
read_ptr = str;
|
||||||
|
write_ptr = str;
|
||||||
|
|
||||||
|
while (*read_ptr != '\0')
|
||||||
|
{
|
||||||
|
*write_ptr = *read_ptr++;
|
||||||
|
write_ptr += (*write_ptr != c) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*write_ptr = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replaces every instance of character 'find' in 'str'
|
||||||
|
* with character 'replace' */
|
||||||
|
void string_replace_all_chars(char *str, char find, char replace)
|
||||||
|
{
|
||||||
|
char *str_ptr = str;
|
||||||
|
|
||||||
|
if (string_is_empty(str))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while ((str_ptr = strchr(str_ptr, find)))
|
||||||
|
*str_ptr++ = replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts string to unsigned integer.
|
||||||
|
* Returns 0 if string is invalid */
|
||||||
|
unsigned string_to_unsigned(const char *str)
|
||||||
|
{
|
||||||
|
const char *ptr = NULL;
|
||||||
|
|
||||||
|
if (string_is_empty(str))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (ptr = str; *ptr != '\0'; ptr++)
|
||||||
|
{
|
||||||
|
if (!ISDIGIT((unsigned char)*ptr))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned)strtoul(str, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Converts hexadecimal string to unsigned integer.
|
||||||
|
* Handles optional leading '0x'.
|
||||||
|
* Returns 0 if string is invalid */
|
||||||
|
unsigned string_hex_to_unsigned(const char *str)
|
||||||
|
{
|
||||||
|
const char *hex_str = str;
|
||||||
|
const char *ptr = NULL;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (string_is_empty(str))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Remove leading '0x', if required */
|
||||||
|
len = strlen(str);
|
||||||
|
|
||||||
|
if (len >= 2)
|
||||||
|
if ((str[0] == '0') &&
|
||||||
|
((str[1] == 'x') || (str[1] == 'X')))
|
||||||
|
hex_str = str + 2;
|
||||||
|
|
||||||
|
if (string_is_empty(hex_str))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Check for valid characters */
|
||||||
|
for (ptr = hex_str; *ptr != '\0'; ptr++)
|
||||||
|
{
|
||||||
|
if (!isxdigit((unsigned char)*ptr))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (unsigned)strtoul(hex_str, NULL, 16);
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* Copyright (C) 2010-2020 The RetroArch team
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
* The following license statement only applies to this file (rtime.c).
|
||||||
|
* ---------------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge,
|
||||||
|
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
#include <rthreads/rthreads.h>
|
||||||
|
#include <retro_assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <time/rtime.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
/* TODO/FIXME - global */
|
||||||
|
slock_t *rtime_localtime_lock = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Must be called before using rtime_localtime() */
|
||||||
|
void rtime_init(void)
|
||||||
|
{
|
||||||
|
rtime_deinit();
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
if (!rtime_localtime_lock)
|
||||||
|
rtime_localtime_lock = slock_new();
|
||||||
|
|
||||||
|
retro_assert(rtime_localtime_lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must be called upon program termination */
|
||||||
|
void rtime_deinit(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
if (rtime_localtime_lock)
|
||||||
|
{
|
||||||
|
slock_free(rtime_localtime_lock);
|
||||||
|
rtime_localtime_lock = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Thread-safe wrapper for localtime() */
|
||||||
|
struct tm *rtime_localtime(const time_t *timep, struct tm *result)
|
||||||
|
{
|
||||||
|
struct tm *time_info = NULL;
|
||||||
|
|
||||||
|
/* Lock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_lock(rtime_localtime_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
time_info = localtime(timep);
|
||||||
|
if (time_info)
|
||||||
|
memcpy(result, time_info, sizeof(struct tm));
|
||||||
|
|
||||||
|
/* Unlock mutex */
|
||||||
|
#ifdef HAVE_THREADS
|
||||||
|
slock_unlock(rtime_localtime_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue