mirror of
https://github.com/Pecusx/libretro-atari800.git
synced 2026-05-20 22:33:22 +02:00
Remove the copy of libretro-common
This commit is contained in:
@@ -1,159 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_fnmatch.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if __TEST_FNMATCH__
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#include <compat/fnmatch.h>
|
||||
|
||||
/* Implemnentation of fnmatch(3) so it can be
|
||||
* distributed to non *nix platforms.
|
||||
*
|
||||
* No flags are implemented ATM.
|
||||
* We don't use them. Add flags as needed. */
|
||||
|
||||
int rl_fnmatch(const char *pattern, const char *string, int flags)
|
||||
{
|
||||
int rv;
|
||||
const char *c = NULL;
|
||||
int charmatch = 0;
|
||||
|
||||
for (c = pattern; *c != '\0'; c++)
|
||||
{
|
||||
/* String ended before pattern */
|
||||
if ((*c != '*') && (*string == '\0'))
|
||||
return FNM_NOMATCH;
|
||||
|
||||
switch (*c)
|
||||
{
|
||||
/* Match any number of unknown chars */
|
||||
case '*':
|
||||
/* Find next node in the pattern
|
||||
* ignoring multiple asterixes
|
||||
*/
|
||||
do {
|
||||
c++;
|
||||
if (*c == '\0')
|
||||
return 0;
|
||||
} while (*c == '*');
|
||||
|
||||
/* Match the remaining pattern
|
||||
* ignoring more and more characters. */
|
||||
do {
|
||||
/* We reached the end of the string without a
|
||||
* match. There is a way to optimize this by
|
||||
* calculating the minimum chars needed to
|
||||
* match the remaining pattern but I don't
|
||||
* think it is worth the work ATM.
|
||||
*/
|
||||
if (*string == '\0')
|
||||
return FNM_NOMATCH;
|
||||
|
||||
rv = rl_fnmatch(c, string, flags);
|
||||
string++;
|
||||
} while (rv != 0);
|
||||
|
||||
return 0;
|
||||
/* Match char from list */
|
||||
case '[':
|
||||
charmatch = 0;
|
||||
for (c++; *c != ']'; c++)
|
||||
{
|
||||
/* Bad format */
|
||||
if (*c == '\0')
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* Match already found */
|
||||
if (charmatch)
|
||||
continue;
|
||||
|
||||
if (*c == *string)
|
||||
charmatch = 1;
|
||||
}
|
||||
|
||||
/* No match in list */
|
||||
if (!charmatch)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
string++;
|
||||
break;
|
||||
/* Has any character */
|
||||
case '?':
|
||||
string++;
|
||||
break;
|
||||
/* Match following character verbatim */
|
||||
case '\\':
|
||||
c++;
|
||||
/* Dangling escape at end of pattern.
|
||||
* FIXME: Was c == '\0' (makes no sense).
|
||||
* Not sure if c == NULL or *c == '\0'
|
||||
* is intended. Assuming *c due to c++ right before. */
|
||||
if (*c == '\0')
|
||||
return FNM_NOMATCH;
|
||||
default:
|
||||
if (*c != *string)
|
||||
return FNM_NOMATCH;
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
/* End of string and end of pattend */
|
||||
if (*string == '\0')
|
||||
return 0;
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
#if __TEST_FNMATCH__
|
||||
int main(void)
|
||||
{
|
||||
assert(rl_fnmatch("TEST", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE?T", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssa]T", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssda]T", "TEsT", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssda]T", "TEdT", 0) == 0);
|
||||
assert(rl_fnmatch("TE[Ssda]T", "TEaT", 0) == 0);
|
||||
assert(rl_fnmatch("TEST*", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TEST**", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE*ST*", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST*", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST*", "TExST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST", "TEST", 0) == 0);
|
||||
assert(rl_fnmatch("TE**ST", "TExST", 0) == 0);
|
||||
assert(rl_fnmatch("TE\\**ST", "TE*xST", 0) == 0);
|
||||
assert(rl_fnmatch("*.*", "test.jpg", 0) == 0);
|
||||
assert(rl_fnmatch("*.jpg", "test.jpg", 0) == 0);
|
||||
assert(rl_fnmatch("*.[Jj][Pp][Gg]", "test.jPg", 0) == 0);
|
||||
assert(rl_fnmatch("*.[Jj]*[Gg]", "test.jPg", 0) == 0);
|
||||
assert(rl_fnmatch("TEST?", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TES[asd", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TEST\\", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TEST*S", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TE**ST", "TExT", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TE\\*T", "TExT", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TES?", "TES", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TE", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("TEST!", "TEST", 0) == FNM_NOMATCH);
|
||||
assert(rl_fnmatch("DSAD", "TEST", 0) == FNM_NOMATCH);
|
||||
}
|
||||
#endif
|
||||
@@ -1,219 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_getopt.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <boolean.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include <compat/getopt.h>
|
||||
#include <compat/strl.h>
|
||||
#include <compat/strcasestr.h>
|
||||
#include <compat/posix_string.h>
|
||||
|
||||
#include <retro_assert.h>
|
||||
|
||||
char *optarg;
|
||||
int optind, opterr, optopt;
|
||||
|
||||
static bool is_short_option(const char *str)
|
||||
{
|
||||
return str[0] == '-' && str[1] != '-';
|
||||
}
|
||||
|
||||
static bool is_long_option(const char *str)
|
||||
{
|
||||
return str[0] == '-' && str[1] == '-';
|
||||
}
|
||||
|
||||
static int find_short_index(char * const *argv)
|
||||
{
|
||||
int idx;
|
||||
for (idx = 0; argv[idx]; idx++)
|
||||
{
|
||||
if (is_short_option(argv[idx]))
|
||||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int find_long_index(char * const *argv)
|
||||
{
|
||||
int idx;
|
||||
for (idx = 0; argv[idx]; idx++)
|
||||
{
|
||||
if (is_long_option(argv[idx]))
|
||||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int parse_short(const char *optstring, char * const *argv)
|
||||
{
|
||||
bool extra_opt, takes_arg, embedded_arg;
|
||||
const char *opt = NULL;
|
||||
char arg = argv[0][1];
|
||||
|
||||
if (arg == ':')
|
||||
return '?';
|
||||
|
||||
opt = strchr(optstring, arg);
|
||||
if (!opt)
|
||||
return '?';
|
||||
|
||||
extra_opt = argv[0][2];
|
||||
takes_arg = opt[1] == ':';
|
||||
|
||||
/* If we take an argument, and we see additional characters,
|
||||
* this is in fact the argument (i.e. -cfoo is same as -c foo). */
|
||||
embedded_arg = extra_opt && takes_arg;
|
||||
|
||||
if (takes_arg)
|
||||
{
|
||||
if (embedded_arg)
|
||||
{
|
||||
optarg = argv[0] + 2;
|
||||
optind++;
|
||||
}
|
||||
else
|
||||
{
|
||||
optarg = argv[1];
|
||||
optind += 2;
|
||||
}
|
||||
|
||||
return optarg ? opt[0] : '?';
|
||||
}
|
||||
|
||||
if (embedded_arg)
|
||||
{
|
||||
/* If we see additional characters,
|
||||
* and they don't take arguments, this
|
||||
* means we have multiple flags in one. */
|
||||
memmove(&argv[0][1], &argv[0][2], strlen(&argv[0][2]) + 1);
|
||||
return opt[0];
|
||||
}
|
||||
|
||||
optind++;
|
||||
return opt[0];
|
||||
}
|
||||
|
||||
static int parse_long(const struct option *longopts, char * const *argv)
|
||||
{
|
||||
size_t indice;
|
||||
const struct option *opt = NULL;
|
||||
for (indice = 0; longopts[indice].name; indice++)
|
||||
{
|
||||
if (!strcmp(longopts[indice].name, &argv[0][2]))
|
||||
{
|
||||
opt = &longopts[indice];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt)
|
||||
return '?';
|
||||
|
||||
/* getopt_long has an "optional" arg, but we don't bother with that. */
|
||||
if (opt->has_arg && !argv[1])
|
||||
return '?';
|
||||
|
||||
if (opt->has_arg)
|
||||
{
|
||||
optarg = argv[1];
|
||||
optind += 2;
|
||||
}
|
||||
else
|
||||
optind++;
|
||||
|
||||
if (opt->flag)
|
||||
{
|
||||
*opt->flag = opt->val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return opt->val;
|
||||
}
|
||||
|
||||
static void shuffle_block(char **begin, char **last, char **end)
|
||||
{
|
||||
ptrdiff_t len = last - begin;
|
||||
const char **tmp = (const char**)calloc(len, sizeof(const char*));
|
||||
|
||||
retro_assert(tmp);
|
||||
|
||||
memcpy((void*)tmp, begin, len * sizeof(const char*));
|
||||
memmove(begin, last, (end - last) * sizeof(const char*));
|
||||
memcpy(end - len, tmp, len * sizeof(const char*));
|
||||
|
||||
free((void*)tmp);
|
||||
}
|
||||
|
||||
int getopt_long(int argc, char *argv[],
|
||||
const char *optstring, const struct option *longopts, int *longindex)
|
||||
{
|
||||
int short_index, long_index;
|
||||
|
||||
(void)longindex;
|
||||
|
||||
if (optind == 0)
|
||||
optind = 1;
|
||||
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
|
||||
short_index = find_short_index(&argv[optind]);
|
||||
long_index = find_long_index(&argv[optind]);
|
||||
|
||||
/* We're done here. */
|
||||
if (short_index == -1 && long_index == -1)
|
||||
return -1;
|
||||
|
||||
/* Reorder argv so that non-options come last.
|
||||
* Non-POSIXy, but that's what getopt does by default. */
|
||||
if ((short_index > 0) && ((short_index < long_index) || (long_index == -1)))
|
||||
{
|
||||
shuffle_block(&argv[optind], &argv[optind + short_index], &argv[argc]);
|
||||
short_index = 0;
|
||||
}
|
||||
else if ((long_index > 0) && ((long_index < short_index)
|
||||
|| (short_index == -1)))
|
||||
{
|
||||
shuffle_block(&argv[optind], &argv[optind + long_index], &argv[argc]);
|
||||
long_index = 0;
|
||||
}
|
||||
|
||||
retro_assert(short_index == 0 || long_index == 0);
|
||||
|
||||
if (short_index == 0)
|
||||
return parse_short(optstring, &argv[optind]);
|
||||
if (long_index == 0)
|
||||
return parse_long(longopts, &argv[optind]);
|
||||
|
||||
return '?';
|
||||
}
|
||||
@@ -1,619 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013, Kenneth MacKay
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <compat/ifaddrs.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
typedef struct NetlinkList
|
||||
{
|
||||
struct NetlinkList *m_next;
|
||||
struct nlmsghdr *m_data;
|
||||
unsigned int m_size;
|
||||
} NetlinkList;
|
||||
|
||||
static int netlink_socket(void)
|
||||
{
|
||||
struct sockaddr_nl l_addr;
|
||||
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
if(l_socket < 0)
|
||||
return -1;
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return l_socket;
|
||||
}
|
||||
|
||||
static int netlink_send(int p_socket, int p_request)
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct nlmsghdr m_hdr;
|
||||
struct rtgenmsg m_msg;
|
||||
} l_data;
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
memset(&l_data, 0, sizeof(l_data));
|
||||
|
||||
l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
|
||||
l_data.m_hdr.nlmsg_type = p_request;
|
||||
l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
||||
l_data.m_hdr.nlmsg_pid = 0;
|
||||
l_data.m_hdr.nlmsg_seq = p_socket;
|
||||
l_data.m_msg.rtgen_family = AF_UNSPEC;
|
||||
|
||||
memset(&l_addr, 0, sizeof(l_addr));
|
||||
l_addr.nl_family = AF_NETLINK;
|
||||
return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
|
||||
}
|
||||
|
||||
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
|
||||
{
|
||||
struct msghdr l_msg;
|
||||
struct iovec l_iov = { p_buffer, p_len };
|
||||
struct sockaddr_nl l_addr;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
l_msg.msg_name = (void *)&l_addr;
|
||||
l_msg.msg_namelen = sizeof(l_addr);
|
||||
l_msg.msg_iov = &l_iov;
|
||||
l_msg.msg_iovlen = 1;
|
||||
l_msg.msg_control = NULL;
|
||||
l_msg.msg_controllen = 0;
|
||||
l_msg.msg_flags = 0;
|
||||
int l_result = recvmsg(p_socket, &l_msg, 0);
|
||||
|
||||
if(l_result < 0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if(l_msg.msg_flags & MSG_TRUNC) /* buffer too small */
|
||||
return -1;
|
||||
return l_result;
|
||||
}
|
||||
}
|
||||
|
||||
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
|
||||
{
|
||||
size_t l_size = 4096;
|
||||
void *l_buffer = NULL;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
free(l_buffer);
|
||||
l_buffer = malloc(l_size);
|
||||
if (l_buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
int l_read = netlink_recv(p_socket, l_buffer, l_size);
|
||||
*p_size = l_read;
|
||||
|
||||
if(l_read == -2)
|
||||
{
|
||||
free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(l_read >= 0)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
struct nlmsghdr *l_hdr;
|
||||
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
continue;
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
*p_done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
free(l_buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return l_buffer;
|
||||
}
|
||||
|
||||
l_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
|
||||
{
|
||||
NetlinkList *l_item = malloc(sizeof(NetlinkList));
|
||||
if (l_item == NULL)
|
||||
return NULL;
|
||||
|
||||
l_item->m_next = NULL;
|
||||
l_item->m_data = p_data;
|
||||
l_item->m_size = p_size;
|
||||
return l_item;
|
||||
}
|
||||
|
||||
static void freeResultList(NetlinkList *p_list)
|
||||
{
|
||||
NetlinkList *l_cur;
|
||||
while(p_list)
|
||||
{
|
||||
l_cur = p_list;
|
||||
p_list = p_list->m_next;
|
||||
free(l_cur->m_data);
|
||||
free(l_cur);
|
||||
}
|
||||
}
|
||||
|
||||
static NetlinkList *getResultList(int p_socket, int p_request)
|
||||
{
|
||||
if(netlink_send(p_socket, p_request) < 0)
|
||||
return NULL;
|
||||
|
||||
NetlinkList *l_list = NULL;
|
||||
NetlinkList *l_end = NULL;
|
||||
int l_size;
|
||||
int l_done = 0;
|
||||
while(!l_done)
|
||||
{
|
||||
NetlinkList *l_item = NULL;
|
||||
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
|
||||
if(!l_hdr)
|
||||
goto error;
|
||||
|
||||
l_item = newListItem(l_hdr, l_size);
|
||||
if (!l_item)
|
||||
goto error;
|
||||
|
||||
if(!l_list)
|
||||
l_list = l_item;
|
||||
else
|
||||
l_end->m_next = l_item;
|
||||
l_end = l_item;
|
||||
}
|
||||
|
||||
return l_list;
|
||||
|
||||
error:
|
||||
freeResultList(l_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t maxSize(size_t a, size_t b)
|
||||
{
|
||||
return (a > b ? a : b);
|
||||
}
|
||||
|
||||
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
case AF_PACKET:
|
||||
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
|
||||
}
|
||||
|
||||
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
|
||||
{
|
||||
switch(p_family)
|
||||
{
|
||||
case AF_INET:
|
||||
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
|
||||
break;
|
||||
case AF_PACKET:
|
||||
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
|
||||
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
|
||||
break;
|
||||
default:
|
||||
memcpy(p_dest->sa_data, p_data, p_size);
|
||||
break;
|
||||
}
|
||||
p_dest->sa_family = p_family;
|
||||
}
|
||||
|
||||
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
|
||||
{
|
||||
if(!*p_resultList)
|
||||
*p_resultList = p_entry;
|
||||
else
|
||||
{
|
||||
struct ifaddrs *l_cur = *p_resultList;
|
||||
while(l_cur->ifa_next)
|
||||
l_cur = l_cur->ifa_next;
|
||||
l_cur->ifa_next = p_entry;
|
||||
}
|
||||
}
|
||||
|
||||
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
|
||||
{
|
||||
struct ifaddrs *l_entry = NULL;
|
||||
struct rtattr *l_rta = NULL;
|
||||
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
size_t l_dataSize = 0;
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
|
||||
break;
|
||||
case IFLA_IFNAME:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
l_dataSize += NLMSG_ALIGN(l_rtaSize);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
|
||||
if (l_entry == NULL)
|
||||
return -1;
|
||||
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = "";
|
||||
|
||||
char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
char *l_name = l_index + sizeof(int);
|
||||
char *l_addr = l_name + l_nameSize;
|
||||
char *l_data = l_addr + l_addrSize;
|
||||
|
||||
// save the interface index so we can look it up when handling the addresses.
|
||||
memcpy(l_index, &l_info->ifi_index, sizeof(int));
|
||||
|
||||
l_entry->ifa_flags = l_info->ifi_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
|
||||
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFLA_ADDRESS:
|
||||
case IFLA_BROADCAST:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
|
||||
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
|
||||
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
|
||||
if(l_rta->rta_type == IFLA_ADDRESS)
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
else
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFLA_IFNAME:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
case IFLA_STATS:
|
||||
memcpy(l_data, l_rtaData, l_rtaDataSize);
|
||||
l_entry->ifa_data = l_data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
|
||||
{
|
||||
int l_num = 0;
|
||||
struct ifaddrs *l_cur = *p_links;
|
||||
while(l_cur && l_num < p_numLinks)
|
||||
{
|
||||
int l_index;
|
||||
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
|
||||
|
||||
memcpy(&l_index, l_indexPtr, sizeof(int));
|
||||
if(l_index == p_index)
|
||||
return l_cur;
|
||||
|
||||
l_cur = l_cur->ifa_next;
|
||||
++l_num;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
size_t l_nameSize = 0;
|
||||
size_t l_addrSize = 0;
|
||||
int l_addedNetmask = 0;
|
||||
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
|
||||
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
|
||||
|
||||
if(l_info->ifa_family == AF_PACKET)
|
||||
return 0;
|
||||
|
||||
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
struct rtattr *l_rta;
|
||||
|
||||
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
|
||||
{
|
||||
/* make room for netmask */
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
l_addedNetmask = 1;
|
||||
}
|
||||
case IFA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
break;
|
||||
case IFA_LABEL:
|
||||
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
|
||||
if (l_entry == NULL)
|
||||
return -1;
|
||||
|
||||
memset(l_entry, 0, sizeof(struct ifaddrs));
|
||||
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
|
||||
|
||||
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
|
||||
char *l_addr = l_name + l_nameSize;
|
||||
|
||||
l_entry->ifa_flags = l_info->ifa_flags;
|
||||
if(l_interface)
|
||||
l_entry->ifa_flags |= l_interface->ifa_flags;
|
||||
|
||||
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
|
||||
for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
|
||||
{
|
||||
void *l_rtaData = RTA_DATA(l_rta);
|
||||
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
|
||||
switch(l_rta->rta_type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_BROADCAST:
|
||||
case IFA_LOCAL:
|
||||
{
|
||||
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
|
||||
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
|
||||
if(l_info->ifa_family == AF_INET6)
|
||||
{
|
||||
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
|
||||
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
|
||||
}
|
||||
|
||||
if(l_rta->rta_type == IFA_ADDRESS)
|
||||
{
|
||||
/* apparently in a point-to-point network IFA_ADDRESS
|
||||
* contains the dest address and IFA_LOCAL contains the local address */
|
||||
if(l_entry->ifa_addr)
|
||||
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
|
||||
else
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else if(l_rta->rta_type == IFA_LOCAL)
|
||||
{
|
||||
if(l_entry->ifa_addr)
|
||||
l_entry->ifa_dstaddr = l_entry->ifa_addr;
|
||||
l_entry->ifa_addr = (struct sockaddr *)l_addr;
|
||||
}
|
||||
else
|
||||
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
|
||||
l_addr += NLMSG_ALIGN(l_addrLen);
|
||||
break;
|
||||
}
|
||||
case IFA_LABEL:
|
||||
strncpy(l_name, l_rtaData, l_rtaDataSize);
|
||||
l_name[l_rtaDataSize] = '\0';
|
||||
l_entry->ifa_name = l_name;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(l_entry->ifa_addr &&
|
||||
( l_entry->ifa_addr->sa_family == AF_INET
|
||||
|| l_entry->ifa_addr->sa_family == AF_INET6))
|
||||
{
|
||||
unsigned i;
|
||||
char l_mask[16];
|
||||
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET
|
||||
? 32 : 128);
|
||||
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix
|
||||
? l_maxPrefix : l_info->ifa_prefixlen);
|
||||
|
||||
l_mask[0] = '\0';
|
||||
|
||||
for(i=0; i<(l_prefix/8); ++i)
|
||||
l_mask[i] = 0xff;
|
||||
if(l_prefix % 8)
|
||||
l_mask[i] = 0xff << (8 - (l_prefix % 8));
|
||||
|
||||
makeSockaddr(l_entry->ifa_addr->sa_family,
|
||||
(struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
|
||||
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
|
||||
}
|
||||
|
||||
addToEnd(p_resultList, l_entry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList,
|
||||
struct ifaddrs **p_resultList)
|
||||
{
|
||||
int l_numLinks = 0;
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
struct nlmsghdr *l_hdr = NULL;
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
continue;
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
break;
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWLINK)
|
||||
{
|
||||
if(interpretLink(l_hdr, p_resultList) == -1)
|
||||
return -1;
|
||||
++l_numLinks;
|
||||
}
|
||||
}
|
||||
}
|
||||
return l_numLinks;
|
||||
}
|
||||
|
||||
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList,
|
||||
struct ifaddrs **p_resultList, int p_numLinks)
|
||||
{
|
||||
pid_t l_pid = getpid();
|
||||
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
|
||||
{
|
||||
struct nlmsghdr *l_hdr = NULL;
|
||||
unsigned int l_nlsize = p_netlinkList->m_size;
|
||||
|
||||
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
|
||||
{
|
||||
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
|
||||
continue;
|
||||
|
||||
if(l_hdr->nlmsg_type == NLMSG_DONE)
|
||||
break;
|
||||
|
||||
if(l_hdr->nlmsg_type == RTM_NEWADDR)
|
||||
{
|
||||
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getifaddrs(struct ifaddrs **ifap)
|
||||
{
|
||||
int l_socket = 0;
|
||||
int l_result = 0;
|
||||
if(!ifap)
|
||||
return -1;
|
||||
*ifap = NULL;
|
||||
|
||||
l_socket = netlink_socket();
|
||||
if(l_socket < 0)
|
||||
return -1;
|
||||
|
||||
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
|
||||
if(!l_linkResults)
|
||||
{
|
||||
close(l_socket);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
|
||||
if(!l_addrResults)
|
||||
{
|
||||
close(l_socket);
|
||||
freeResultList(l_linkResults);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
|
||||
|
||||
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
|
||||
l_result = -1;
|
||||
|
||||
freeResultList(l_linkResults);
|
||||
freeResultList(l_addrResults);
|
||||
close(l_socket);
|
||||
return l_result;
|
||||
}
|
||||
|
||||
void freeifaddrs(struct ifaddrs *ifa)
|
||||
{
|
||||
struct ifaddrs *l_cur = NULL;
|
||||
|
||||
while(ifa)
|
||||
{
|
||||
l_cur = ifa;
|
||||
ifa = ifa->ifa_next;
|
||||
free(l_cur);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_posix_string.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/posix_string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#undef strcasecmp
|
||||
#undef strdup
|
||||
#undef isblank
|
||||
#undef strtok_r
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int retro_strcasecmp__(const char *a, const char *b)
|
||||
{
|
||||
while (*a && *b)
|
||||
{
|
||||
int a_ = tolower(*a);
|
||||
int b_ = tolower(*b);
|
||||
|
||||
if (a_ != b_)
|
||||
return a_ - b_;
|
||||
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
return tolower(*a) - tolower(*b);
|
||||
}
|
||||
|
||||
char *retro_strdup__(const char *orig)
|
||||
{
|
||||
size_t len = strlen(orig) + 1;
|
||||
char *ret = (char*)malloc(len);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
strlcpy(ret, orig, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int retro_isblank__(int c)
|
||||
{
|
||||
return (c == ' ') || (c == '\t');
|
||||
}
|
||||
|
||||
char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
|
||||
{
|
||||
char *first = NULL;
|
||||
if (!saveptr || !delim)
|
||||
return NULL;
|
||||
|
||||
if (str)
|
||||
*saveptr = str;
|
||||
|
||||
do
|
||||
{
|
||||
char *ptr = NULL;
|
||||
first = *saveptr;
|
||||
while (*first && strchr(delim, *first))
|
||||
*first++ = '\0';
|
||||
|
||||
if (*first == '\0')
|
||||
return NULL;
|
||||
|
||||
ptr = first + 1;
|
||||
|
||||
while (*ptr && !strchr(delim, *ptr))
|
||||
ptr++;
|
||||
|
||||
*saveptr = ptr + (*ptr ? 1 : 0);
|
||||
*ptr = '\0';
|
||||
} while (strlen(first) == 0);
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_snprintf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* THIS FILE HAS NOT BEEN VALIDATED ON PLATFORMS BESIDES MSVC */
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#include <retro_common.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 */
|
||||
|
||||
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
#if (_MSC_VER <= 1310)
|
||||
count = _vsnprintf(outBuf, size, format, ap);
|
||||
#else
|
||||
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
|
||||
#endif
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf_retro__(outBuf, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int c89_vscprintf_retro__(const char *format, va_list pargs)
|
||||
{
|
||||
int retval;
|
||||
va_list argcopy;
|
||||
va_copy(argcopy, pargs);
|
||||
retval = vsnprintf(NULL, 0, format, argcopy);
|
||||
va_end(argcopy);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strcasestr.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strcasestr.h>
|
||||
|
||||
/* Pretty much strncasecmp. */
|
||||
static int casencmp(const char *a, const char *b, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int a_lower = tolower(a[i]);
|
||||
int b_lower = tolower(b[i]);
|
||||
if (a_lower != b_lower)
|
||||
return a_lower - b_lower;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcasestr_retro__(const char *haystack, const char *needle)
|
||||
{
|
||||
size_t i, search_off;
|
||||
size_t hay_len = strlen(haystack);
|
||||
size_t needle_len = strlen(needle);
|
||||
|
||||
if (needle_len > hay_len)
|
||||
return NULL;
|
||||
|
||||
search_off = hay_len - needle_len;
|
||||
for (i = 0; i <= search_off; i++)
|
||||
if (!casencmp(haystack + i, needle, needle_len))
|
||||
return (char*)haystack + i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strl.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <compat/posix_string.h>
|
||||
|
||||
/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
|
||||
|
||||
#ifndef __MACH__
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t src_size = 0;
|
||||
size_t n = size;
|
||||
|
||||
if (n)
|
||||
while (--n && (*dest++ = *source++)) src_size++;
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if (size) *dest = '\0';
|
||||
while (*source++) src_size++;
|
||||
}
|
||||
|
||||
return src_size;
|
||||
}
|
||||
|
||||
size_t strlcat(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t len = strlen(dest);
|
||||
|
||||
dest += len;
|
||||
|
||||
if (len > size)
|
||||
size = 0;
|
||||
else
|
||||
size -= len;
|
||||
|
||||
return len + strlcpy(dest, source, size);
|
||||
}
|
||||
#endif
|
||||
@@ -1,897 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <compat/strl.h>
|
||||
#include <file/archive_file.h>
|
||||
#include <file/file_path.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
struct file_archive_file_data
|
||||
{
|
||||
#ifdef HAVE_MMAP
|
||||
int fd;
|
||||
#endif
|
||||
void *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static size_t file_archive_size(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
return data->size;
|
||||
}
|
||||
|
||||
static const uint8_t *file_archive_data(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return NULL;
|
||||
return (const uint8_t*)data->data;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
/* Closes, unmaps and frees. */
|
||||
static void file_archive_free(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->data)
|
||||
munmap(data->data, data->size);
|
||||
if (data->fd >= 0)
|
||||
close(data->fd);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static file_archive_file_data_t* file_archive_open(const char *path)
|
||||
{
|
||||
file_archive_file_data_t *data = (file_archive_file_data_t*)calloc(1, sizeof(*data));
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
data->fd = open(path, O_RDONLY);
|
||||
|
||||
/* Failed to open archive. */
|
||||
if (data->fd < 0)
|
||||
goto error;
|
||||
|
||||
data->size = path_get_size(path);
|
||||
if (!data->size)
|
||||
return data;
|
||||
|
||||
data->data = mmap(NULL, data->size, PROT_READ, MAP_SHARED, data->fd, 0);
|
||||
if (data->data == MAP_FAILED)
|
||||
{
|
||||
data->data = NULL;
|
||||
|
||||
/* Failed to mmap() file */
|
||||
goto error;
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
error:
|
||||
file_archive_free(data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Closes, unmaps and frees. */
|
||||
static void file_archive_free(file_archive_file_data_t *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
if(data->data)
|
||||
free(data->data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static file_archive_file_data_t* file_archive_open(const char *path)
|
||||
{
|
||||
ssize_t ret = -1;
|
||||
bool read_from_file = false;
|
||||
file_archive_file_data_t *data = (file_archive_file_data_t*)
|
||||
calloc(1, sizeof(*data));
|
||||
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
read_from_file = filestream_read_file(path, &data->data, &ret);
|
||||
|
||||
/* Failed to open archive? */
|
||||
if (!read_from_file || ret < 0)
|
||||
goto error;
|
||||
|
||||
data->size = ret;
|
||||
return data;
|
||||
|
||||
error:
|
||||
file_archive_free(data);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int file_archive_get_file_list_cb(
|
||||
const char *path,
|
||||
const char *valid_exts,
|
||||
const uint8_t *cdata,
|
||||
unsigned cmode,
|
||||
uint32_t csize,
|
||||
uint32_t size,
|
||||
uint32_t checksum,
|
||||
struct archive_extract_userdata *userdata)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
int ret = 0;
|
||||
struct string_list *ext_list = NULL;
|
||||
size_t path_len = strlen(path);
|
||||
|
||||
(void)cdata;
|
||||
(void)cmode;
|
||||
(void)csize;
|
||||
(void)size;
|
||||
(void)checksum;
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (!path_len)
|
||||
return 0;
|
||||
|
||||
if (valid_exts)
|
||||
ext_list = string_split(valid_exts, "|");
|
||||
|
||||
if (ext_list)
|
||||
{
|
||||
const char *file_ext = NULL;
|
||||
/* Checks if this entry is a directory or a file. */
|
||||
char last_char = path[path_len-1];
|
||||
|
||||
/* Skip if directory. */
|
||||
if (last_char == '/' || last_char == '\\' )
|
||||
goto error;
|
||||
|
||||
file_ext = path_get_extension(path);
|
||||
|
||||
if (!file_ext)
|
||||
goto error;
|
||||
|
||||
if (!string_list_find_elem_prefix(ext_list, ".", file_ext))
|
||||
{
|
||||
/* keep iterating */
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;
|
||||
string_list_free(ext_list);
|
||||
}
|
||||
|
||||
return string_list_append(userdata->list, path, attr);
|
||||
|
||||
error:
|
||||
string_list_free(ext_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int file_archive_extract_cb(const char *name, const char *valid_exts,
|
||||
const uint8_t *cdata,
|
||||
unsigned cmode, uint32_t csize, uint32_t size,
|
||||
uint32_t checksum, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
const char *ext = path_get_extension(name);
|
||||
|
||||
/* Extract first file that matches our list. */
|
||||
if (ext && string_list_find_elem(userdata->ext, ext))
|
||||
{
|
||||
char new_path[PATH_MAX_LENGTH];
|
||||
char wanted_file[PATH_MAX_LENGTH];
|
||||
const char *delim = NULL;
|
||||
|
||||
new_path[0] = wanted_file[0] = '\0';
|
||||
|
||||
if (userdata->extraction_directory)
|
||||
fill_pathname_join(new_path, userdata->extraction_directory,
|
||||
path_basename(name), sizeof(new_path));
|
||||
else
|
||||
fill_pathname_resolve_relative(new_path, userdata->archive_path,
|
||||
path_basename(name), sizeof(new_path));
|
||||
|
||||
userdata->first_extracted_file_path = strdup(new_path);
|
||||
|
||||
delim = path_get_archive_delim(userdata->archive_path);
|
||||
|
||||
if (delim)
|
||||
{
|
||||
strlcpy(wanted_file, delim + 1, sizeof(wanted_file));
|
||||
|
||||
if (!string_is_equal_noncase(userdata->extracted_file_path,
|
||||
wanted_file))
|
||||
return 1; /* keep searching for the right file */
|
||||
}
|
||||
else
|
||||
strlcpy(wanted_file, userdata->archive_path, sizeof(wanted_file));
|
||||
|
||||
if (file_archive_perform_mode(new_path,
|
||||
valid_exts, cdata, cmode, csize, size,
|
||||
0, userdata))
|
||||
userdata->found_file = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int file_archive_parse_file_init(file_archive_transfer_t *state,
|
||||
const char *file)
|
||||
{
|
||||
char path[PATH_MAX_LENGTH];
|
||||
char *last = NULL;
|
||||
|
||||
path[0] = '\0';
|
||||
|
||||
strlcpy(path, file, sizeof(path));
|
||||
|
||||
last = (char*)path_get_archive_delim(path);
|
||||
|
||||
if (last)
|
||||
*last = '\0';
|
||||
|
||||
state->backend = file_archive_get_file_backend(path);
|
||||
if (!state->backend)
|
||||
return -1;
|
||||
|
||||
state->handle = file_archive_open(path);
|
||||
if (!state->handle)
|
||||
return -1;
|
||||
|
||||
state->archive_size = (int32_t)file_archive_size(state->handle);
|
||||
state->data = file_archive_data(state->handle);
|
||||
state->footer = 0;
|
||||
state->directory = 0;
|
||||
|
||||
return state->backend->archive_parse_file_init(state, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_decompress_data_to_file:
|
||||
* @path : filename path of archive.
|
||||
* @valid_exts : Valid extensions of archive to be parsed.
|
||||
* If NULL, allow all.
|
||||
* @cdata : input data.
|
||||
* @csize : size of input data.
|
||||
* @size : output file size
|
||||
* @checksum : CRC32 checksum from input data.
|
||||
*
|
||||
* Decompress data to file.
|
||||
*
|
||||
* Returns: true (1) on success, otherwise false (0).
|
||||
**/
|
||||
static int file_archive_decompress_data_to_file(
|
||||
file_archive_file_handle_t *handle,
|
||||
int ret,
|
||||
const char *path,
|
||||
const char *valid_exts,
|
||||
const uint8_t *cdata,
|
||||
uint32_t csize,
|
||||
uint32_t size,
|
||||
uint32_t checksum)
|
||||
{
|
||||
if (!handle || ret == -1)
|
||||
{
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if 0
|
||||
handle->real_checksum = handle->backend->stream_crc_calculate(
|
||||
0, handle->data, size);
|
||||
if (handle->real_checksum != checksum)
|
||||
{
|
||||
/* File CRC difers from archive CRC. */
|
||||
printf("File CRC differs from archive CRC. File: 0x%x, Archive: 0x%x.\n",
|
||||
(unsigned)handle->real_checksum, (unsigned)checksum);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!filestream_write_file(path, handle->data, size))
|
||||
{
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (handle)
|
||||
{
|
||||
if (handle->backend)
|
||||
{
|
||||
if (handle->backend->stream_free)
|
||||
handle->backend->stream_free(handle->stream);
|
||||
}
|
||||
|
||||
if (handle->data)
|
||||
free(handle->data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state)
|
||||
{
|
||||
if (!state || !state->handle)
|
||||
return;
|
||||
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT;
|
||||
file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int file_archive_parse_file_iterate(
|
||||
file_archive_transfer_t *state,
|
||||
bool *returnerr,
|
||||
const char *file,
|
||||
const char *valid_exts,
|
||||
file_archive_file_cb file_cb,
|
||||
struct archive_extract_userdata *userdata)
|
||||
{
|
||||
if (!state)
|
||||
return -1;
|
||||
|
||||
switch (state->type)
|
||||
{
|
||||
case ARCHIVE_TRANSFER_NONE:
|
||||
break;
|
||||
case ARCHIVE_TRANSFER_INIT:
|
||||
if (file_archive_parse_file_init(state, file) == 0)
|
||||
{
|
||||
if (userdata)
|
||||
{
|
||||
userdata->context = state->stream;
|
||||
strlcpy(userdata->archive_path, file,
|
||||
sizeof(userdata->archive_path));
|
||||
}
|
||||
state->type = ARCHIVE_TRANSFER_ITERATE;
|
||||
}
|
||||
else
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
|
||||
break;
|
||||
case ARCHIVE_TRANSFER_ITERATE:
|
||||
if (file_archive_get_file_backend(file))
|
||||
{
|
||||
const struct file_archive_file_backend *backend =
|
||||
file_archive_get_file_backend(file);
|
||||
int ret =
|
||||
backend->archive_parse_file_iterate_step(state,
|
||||
valid_exts, userdata, file_cb);
|
||||
|
||||
if (ret != 1)
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT;
|
||||
if (ret == -1)
|
||||
state->type = ARCHIVE_TRANSFER_DEINIT_ERROR;
|
||||
|
||||
/* early return to prevent deinit from never firing */
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
case ARCHIVE_TRANSFER_DEINIT_ERROR:
|
||||
*returnerr = false;
|
||||
case ARCHIVE_TRANSFER_DEINIT:
|
||||
if (state->handle)
|
||||
{
|
||||
file_archive_free(state->handle);
|
||||
state->handle = NULL;
|
||||
}
|
||||
|
||||
if (state->stream && state->backend)
|
||||
{
|
||||
if (state->backend->stream_free)
|
||||
state->backend->stream_free(state->stream);
|
||||
|
||||
if (state->stream)
|
||||
free(state->stream);
|
||||
|
||||
state->stream = NULL;
|
||||
|
||||
if (userdata)
|
||||
userdata->context = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ( state->type == ARCHIVE_TRANSFER_DEINIT ||
|
||||
state->type == ARCHIVE_TRANSFER_DEINIT_ERROR)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_walk:
|
||||
* @file : filename path of archive
|
||||
* @valid_exts : Valid extensions of archive to be parsed.
|
||||
* If NULL, allow all.
|
||||
* @file_cb : file_cb function pointer
|
||||
* @userdata : userdata to pass to file_cb function pointer.
|
||||
*
|
||||
* Low-level file parsing. Enumerates over all files and calls
|
||||
* file_cb with userdata.
|
||||
*
|
||||
* Returns: true (1) on success, otherwise false (0).
|
||||
**/
|
||||
static bool file_archive_walk(const char *file, const char *valid_exts,
|
||||
file_archive_file_cb file_cb, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
file_archive_transfer_t state;
|
||||
bool returnerr = true;
|
||||
|
||||
state.type = ARCHIVE_TRANSFER_INIT;
|
||||
state.archive_size = 0;
|
||||
state.handle = NULL;
|
||||
state.stream = NULL;
|
||||
state.footer = NULL;
|
||||
state.directory = NULL;
|
||||
state.data = NULL;
|
||||
state.backend = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (file_archive_parse_file_iterate(&state, &returnerr, file,
|
||||
valid_exts, file_cb, userdata) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return returnerr;
|
||||
}
|
||||
|
||||
int file_archive_parse_file_progress(file_archive_transfer_t *state)
|
||||
{
|
||||
/* FIXME: this estimate is worse than before */
|
||||
ptrdiff_t delta = 0;
|
||||
|
||||
if (!state || state->archive_size == 0)
|
||||
return 0;
|
||||
|
||||
delta = state->directory - state->data;
|
||||
|
||||
return (int)(delta * 100 / state->archive_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_extract_file:
|
||||
* @archive_path : filename path to archive.
|
||||
* @archive_path_size : size of archive.
|
||||
* @valid_exts : valid extensions for the file.
|
||||
* @extraction_directory : the directory to extract temporary
|
||||
* file to.
|
||||
*
|
||||
* Extract file from archive. If no file inside the archive is
|
||||
* specified, the first file found will be used.
|
||||
*
|
||||
* Returns : true (1) on success, otherwise false (0).
|
||||
**/
|
||||
bool file_archive_extract_file(
|
||||
char *archive_path,
|
||||
size_t archive_path_size,
|
||||
const char *valid_exts,
|
||||
const char *extraction_directory,
|
||||
char *out_path, size_t len)
|
||||
{
|
||||
struct archive_extract_userdata userdata;
|
||||
bool ret = true;
|
||||
struct string_list *list = string_split(valid_exts, "|");
|
||||
|
||||
userdata.archive_path[0] = '\0';
|
||||
userdata.first_extracted_file_path = NULL;
|
||||
userdata.extracted_file_path = NULL;
|
||||
userdata.extraction_directory = extraction_directory;
|
||||
userdata.archive_path_size = archive_path_size;
|
||||
userdata.ext = list;
|
||||
userdata.list = NULL;
|
||||
userdata.found_file = false;
|
||||
userdata.list_only = false;
|
||||
userdata.context = NULL;
|
||||
userdata.archive_name[0] = '\0';
|
||||
userdata.crc = 0;
|
||||
userdata.dec = NULL;
|
||||
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.size = 0;
|
||||
userdata.decomp_state.found = NULL;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!file_archive_walk(archive_path, valid_exts,
|
||||
file_archive_extract_cb, &userdata))
|
||||
{
|
||||
/* Parsing file archive failed. */
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!userdata.found_file)
|
||||
{
|
||||
/* Didn't find any file that matched valid extensions
|
||||
* for libretro implementation. */
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!string_is_empty(userdata.first_extracted_file_path))
|
||||
strlcpy(out_path, userdata.first_extracted_file_path, len);
|
||||
|
||||
end:
|
||||
if (userdata.first_extracted_file_path)
|
||||
free(userdata.first_extracted_file_path);
|
||||
if (list)
|
||||
string_list_free(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_get_file_list:
|
||||
* @path : filename path of archive
|
||||
*
|
||||
* Returns: string listing of files from archive on success, otherwise NULL.
|
||||
**/
|
||||
struct string_list *file_archive_get_file_list(const char *path,
|
||||
const char *valid_exts)
|
||||
{
|
||||
int ret;
|
||||
struct archive_extract_userdata userdata;
|
||||
|
||||
strlcpy(userdata.archive_path, path, sizeof(userdata.archive_path));
|
||||
userdata.first_extracted_file_path = NULL;
|
||||
userdata.extracted_file_path = NULL;
|
||||
userdata.extraction_directory = NULL;
|
||||
userdata.archive_path_size = 0;
|
||||
userdata.ext = NULL;
|
||||
userdata.list = string_list_new();
|
||||
userdata.found_file = false;
|
||||
userdata.list_only = true;
|
||||
userdata.context = NULL;
|
||||
userdata.archive_name[0] = '\0';
|
||||
userdata.crc = 0;
|
||||
userdata.dec = NULL;
|
||||
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.size = 0;
|
||||
userdata.decomp_state.found = NULL;
|
||||
|
||||
if (!userdata.list)
|
||||
goto error;
|
||||
|
||||
ret = file_archive_walk(path, valid_exts,
|
||||
file_archive_get_file_list_cb, &userdata);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (ret != -1)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return userdata.list;
|
||||
|
||||
error:
|
||||
if (userdata.list)
|
||||
string_list_free(userdata.list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool file_archive_perform_mode(const char *path, const char *valid_exts,
|
||||
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
|
||||
uint32_t crc32, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
switch (cmode)
|
||||
{
|
||||
case ARCHIVE_MODE_UNCOMPRESSED:
|
||||
if (!filestream_write_file(path, cdata, size))
|
||||
goto error;
|
||||
break;
|
||||
|
||||
case ARCHIVE_MODE_COMPRESSED:
|
||||
{
|
||||
int ret = 0;
|
||||
file_archive_file_handle_t handle;
|
||||
|
||||
handle.stream = userdata->context;
|
||||
handle.data = NULL;
|
||||
handle.real_checksum = 0;
|
||||
handle.backend = file_archive_get_file_backend(userdata->archive_path);
|
||||
|
||||
if (!handle.backend)
|
||||
goto error;
|
||||
|
||||
if (!handle.backend->stream_decompress_data_to_file_init(&handle,
|
||||
cdata, csize, size))
|
||||
goto error;
|
||||
|
||||
do
|
||||
{
|
||||
ret = handle.backend->stream_decompress_data_to_file_iterate(
|
||||
handle.stream);
|
||||
}while(ret == 0);
|
||||
|
||||
if (!file_archive_decompress_data_to_file(&handle,
|
||||
ret, path, valid_exts,
|
||||
cdata, csize, size, crc32))
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_filename_split:
|
||||
* @str : filename to turn into a string list
|
||||
*
|
||||
* Creates a new string list based on filename @path, delimited by a hash (#).
|
||||
*
|
||||
* Returns: new string list if successful, otherwise NULL.
|
||||
*/
|
||||
static struct string_list *file_archive_filename_split(const char *path)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
struct string_list *list = string_list_new();
|
||||
const char *delim = path_get_archive_delim(path);
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (delim)
|
||||
{
|
||||
/* add archive path to list first */
|
||||
if (!string_list_append_n(list, path, (unsigned)(delim - path), attr))
|
||||
goto error;
|
||||
|
||||
/* now add the path within the archive */
|
||||
delim++;
|
||||
|
||||
if (*delim)
|
||||
{
|
||||
if (!string_list_append(list, delim, attr))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!string_list_append(list, path, attr))
|
||||
goto error;
|
||||
|
||||
return list;
|
||||
|
||||
error:
|
||||
string_list_free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Generic compressed file loader.
|
||||
* Extracts to buf, unless optional_filename != 0
|
||||
* Then extracts to optional_filename and leaves buf alone.
|
||||
*/
|
||||
int file_archive_compressed_read(
|
||||
const char * path, void **buf,
|
||||
const char* optional_filename, ssize_t *length)
|
||||
{
|
||||
const struct file_archive_file_backend *backend = NULL;
|
||||
int ret = 0;
|
||||
struct string_list *str_list = file_archive_filename_split(path);
|
||||
|
||||
/* Safety check.
|
||||
* If optional_filename and optional_filename
|
||||
* exists, we simply return 0,
|
||||
* hoping that optional_filename is the
|
||||
* same as requested.
|
||||
*/
|
||||
if (optional_filename && path_file_exists(optional_filename))
|
||||
{
|
||||
*length = 0;
|
||||
string_list_free(str_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We assure that there is something after the '#' symbol.
|
||||
*
|
||||
* This error condition happens for example, when
|
||||
* path = /path/to/file.7z, or
|
||||
* path = /path/to/file.7z#
|
||||
*/
|
||||
if (str_list->size <= 1)
|
||||
goto error;
|
||||
|
||||
backend = file_archive_get_file_backend(str_list->elems[0].data);
|
||||
|
||||
*length = backend->compressed_file_read(str_list->elems[0].data,
|
||||
str_list->elems[1].data, buf, optional_filename);
|
||||
|
||||
if (*length != -1)
|
||||
ret = 1;
|
||||
|
||||
string_list_free(str_list);
|
||||
return ret;
|
||||
|
||||
error:
|
||||
/* could not extract string and substring. */
|
||||
string_list_free(str_list);
|
||||
*length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend *file_archive_get_zlib_file_backend(void)
|
||||
{
|
||||
#ifdef HAVE_ZLIB
|
||||
return &zlib_backend;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend *file_archive_get_7z_file_backend(void)
|
||||
{
|
||||
#ifdef HAVE_7ZIP
|
||||
return &sevenzip_backend;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend* file_archive_get_file_backend(const char *path)
|
||||
{
|
||||
char newpath[PATH_MAX_LENGTH];
|
||||
const char *file_ext = NULL;
|
||||
char *last = NULL;
|
||||
|
||||
newpath[0] = '\0';
|
||||
|
||||
strlcpy(newpath, path, sizeof(newpath));
|
||||
|
||||
last = (char*)path_get_archive_delim(newpath);
|
||||
|
||||
if (last)
|
||||
*last = '\0';
|
||||
|
||||
file_ext = path_get_extension(newpath);
|
||||
|
||||
#ifdef HAVE_7ZIP
|
||||
if (string_is_equal_noncase(file_ext, "7z"))
|
||||
return &sevenzip_backend;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
if ( string_is_equal_noncase(file_ext, "zip")
|
||||
|| string_is_equal_noncase(file_ext, "apk")
|
||||
)
|
||||
return &zlib_backend;
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_archive_get_file_crc32:
|
||||
* @path : filename path of archive
|
||||
*
|
||||
* Returns: CRC32 of the specified file in the archive, otherwise 0.
|
||||
* If no path within the archive is specified, the first
|
||||
* file found inside is used.
|
||||
**/
|
||||
uint32_t file_archive_get_file_crc32(const char *path)
|
||||
{
|
||||
file_archive_transfer_t state;
|
||||
const struct file_archive_file_backend *backend = file_archive_get_file_backend(path);
|
||||
struct archive_extract_userdata userdata = {{0}};
|
||||
bool returnerr = false;
|
||||
bool contains_compressed = false;
|
||||
const char *archive_path = NULL;
|
||||
|
||||
if (!backend)
|
||||
return 0;
|
||||
|
||||
contains_compressed = path_contains_compressed_file(path);
|
||||
|
||||
if (contains_compressed)
|
||||
{
|
||||
archive_path = path_get_archive_delim(path);
|
||||
|
||||
/* move pointer right after the delimiter to give us the path */
|
||||
if (archive_path)
|
||||
archive_path += 1;
|
||||
}
|
||||
|
||||
state.type = ARCHIVE_TRANSFER_INIT;
|
||||
state.archive_size = 0;
|
||||
state.handle = NULL;
|
||||
state.stream = NULL;
|
||||
state.footer = NULL;
|
||||
state.directory = NULL;
|
||||
state.data = NULL;
|
||||
state.backend = NULL;
|
||||
|
||||
/* Initialize and open archive first.
|
||||
Sets next state type to ITERATE. */
|
||||
file_archive_parse_file_iterate(&state,
|
||||
&returnerr, path, NULL, NULL,
|
||||
&userdata);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Now find the first file in the archive. */
|
||||
if (state.type == ARCHIVE_TRANSFER_ITERATE)
|
||||
file_archive_parse_file_iterate(&state,
|
||||
&returnerr, path, NULL, NULL,
|
||||
&userdata);
|
||||
|
||||
/* If no path specified within archive, stop after
|
||||
* finding the first file.
|
||||
*/
|
||||
if (!contains_compressed)
|
||||
break;
|
||||
|
||||
/* Stop when the right file in the archive is found. */
|
||||
if (archive_path)
|
||||
{
|
||||
if (string_is_equal(userdata.extracted_file_path, archive_path))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
file_archive_parse_file_iterate_stop(&state);
|
||||
|
||||
if (userdata.crc)
|
||||
return userdata.crc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,472 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file_sevenzip.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <file/archive_file.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <encodings/crc32.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <file/file_path.h>
|
||||
#include <compat/strl.h>
|
||||
#include "../../deps/7zip/7z.h"
|
||||
#include "../../deps/7zip/7zCrc.h"
|
||||
#include "../../deps/7zip/7zFile.h"
|
||||
|
||||
#define SEVENZIP_MAGIC "7z\xBC\xAF\x27\x1C"
|
||||
#define SEVENZIP_MAGIC_LEN 6
|
||||
|
||||
struct sevenzip_context_t {
|
||||
CFileInStream archiveStream;
|
||||
CLookToRead lookStream;
|
||||
ISzAlloc allocImp;
|
||||
ISzAlloc allocTempImp;
|
||||
CSzArEx db;
|
||||
size_t temp_size;
|
||||
uint32_t block_index;
|
||||
uint32_t index;
|
||||
uint32_t packIndex;
|
||||
uint8_t *output;
|
||||
file_archive_file_handle_t *handle;
|
||||
};
|
||||
|
||||
static void *sevenzip_stream_alloc_impl(void *p, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void sevenzip_stream_free_impl(void *p, void *address)
|
||||
{
|
||||
(void)p;
|
||||
free(address);
|
||||
}
|
||||
|
||||
static void *sevenzip_stream_alloc_tmp_impl(void *p, size_t size)
|
||||
{
|
||||
(void)p;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void* sevenzip_stream_new(void)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t));
|
||||
|
||||
/* These are the allocation routines - currently using
|
||||
* the non-standard 7zip choices. */
|
||||
sevenzip_context->allocImp.Alloc = sevenzip_stream_alloc_impl;
|
||||
sevenzip_context->allocImp.Free = sevenzip_stream_free_impl;
|
||||
sevenzip_context->allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
|
||||
sevenzip_context->allocTempImp.Free = sevenzip_stream_free_impl;
|
||||
sevenzip_context->block_index = 0xFFFFFFFF;
|
||||
sevenzip_context->output = NULL;
|
||||
sevenzip_context->handle = NULL;
|
||||
|
||||
return sevenzip_context;
|
||||
}
|
||||
|
||||
static void sevenzip_stream_free(void *data)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)data;
|
||||
|
||||
if (!sevenzip_context)
|
||||
return;
|
||||
|
||||
if (sevenzip_context->output)
|
||||
{
|
||||
IAlloc_Free(&sevenzip_context->allocImp, sevenzip_context->output);
|
||||
sevenzip_context->output = NULL;
|
||||
sevenzip_context->handle->data = NULL;
|
||||
}
|
||||
|
||||
SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp);
|
||||
File_Close(&sevenzip_context->archiveStream.file);
|
||||
}
|
||||
|
||||
/* Extract the relative path (needle) from a 7z archive
|
||||
* (path) and allocate a buf for it to write it in.
|
||||
* If optional_outfile is set, extract to that instead
|
||||
* and don't allocate buffer.
|
||||
*/
|
||||
static int sevenzip_file_read(
|
||||
const char *path,
|
||||
const char *needle, void **buf,
|
||||
const char *optional_outfile)
|
||||
{
|
||||
CFileInStream archiveStream;
|
||||
CLookToRead lookStream;
|
||||
ISzAlloc allocImp;
|
||||
ISzAlloc allocTempImp;
|
||||
CSzArEx db;
|
||||
uint8_t *output = 0;
|
||||
long outsize = -1;
|
||||
|
||||
/*These are the allocation routines.
|
||||
* Currently using the non-standard 7zip choices. */
|
||||
allocImp.Alloc = sevenzip_stream_alloc_impl;
|
||||
allocImp.Free = sevenzip_stream_free_impl;
|
||||
allocTempImp.Alloc = sevenzip_stream_alloc_tmp_impl;
|
||||
allocTempImp.Free = sevenzip_stream_free_impl;
|
||||
|
||||
/* Could not open 7zip archive? */
|
||||
if (InFile_Open(&archiveStream.file, path))
|
||||
return -1;
|
||||
|
||||
FileInStream_CreateVTable(&archiveStream);
|
||||
LookToRead_CreateVTable(&lookStream, false);
|
||||
lookStream.realStream = &archiveStream.s;
|
||||
LookToRead_Init(&lookStream);
|
||||
CrcGenerateTable();
|
||||
|
||||
db.db.PackSizes = NULL;
|
||||
db.db.PackCRCsDefined = NULL;
|
||||
db.db.PackCRCs = NULL;
|
||||
db.db.Folders = NULL;
|
||||
db.db.Files = NULL;
|
||||
db.db.NumPackStreams = 0;
|
||||
db.db.NumFolders = 0;
|
||||
db.db.NumFiles = 0;
|
||||
db.startPosAfterHeader = 0;
|
||||
db.dataPos = 0;
|
||||
db.FolderStartPackStreamIndex = NULL;
|
||||
db.PackStreamStartPositions = NULL;
|
||||
db.FolderStartFileIndex = NULL;
|
||||
db.FileIndexToFolderIndexMap = NULL;
|
||||
db.FileNameOffsets = NULL;
|
||||
db.FileNames.data = NULL;
|
||||
db.FileNames.size = 0;
|
||||
|
||||
SzArEx_Init(&db);
|
||||
|
||||
if (SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) == SZ_OK)
|
||||
{
|
||||
uint32_t i;
|
||||
bool file_found = false;
|
||||
uint16_t *temp = NULL;
|
||||
size_t temp_size = 0;
|
||||
uint32_t block_index = 0xFFFFFFFF;
|
||||
SRes res = SZ_OK;
|
||||
|
||||
for (i = 0; i < db.db.NumFiles; i++)
|
||||
{
|
||||
size_t len;
|
||||
char infile[PATH_MAX_LENGTH];
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
const CSzFileItem *f = db.db.Files + i;
|
||||
|
||||
/* We skip over everything which is not a directory.
|
||||
* FIXME: Why continue then if f->IsDir is true?*/
|
||||
if (f->IsDir)
|
||||
continue;
|
||||
|
||||
len = SzArEx_GetFileNameUtf16(&db, i, NULL);
|
||||
|
||||
if (len > temp_size)
|
||||
{
|
||||
if (temp)
|
||||
free(temp);
|
||||
temp_size = len;
|
||||
temp = (uint16_t *)malloc(temp_size * sizeof(temp[0]));
|
||||
|
||||
if (temp == 0)
|
||||
{
|
||||
res = SZ_ERROR_MEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SzArEx_GetFileNameUtf16(&db, i, temp);
|
||||
res = SZ_ERROR_FAIL;
|
||||
infile[0] = '\0';
|
||||
|
||||
if (temp)
|
||||
res = utf16_to_char_string(temp, infile, sizeof(infile))
|
||||
? SZ_OK : SZ_ERROR_FAIL;
|
||||
|
||||
if (string_is_equal(infile, needle))
|
||||
{
|
||||
size_t output_size = 0;
|
||||
|
||||
/*RARCH_LOG_OUTPUT("Opened archive %s. Now trying to extract %s\n",
|
||||
path, needle);*/
|
||||
|
||||
/* C LZMA SDK does not support chunked extraction - see here:
|
||||
* sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/
|
||||
* */
|
||||
file_found = true;
|
||||
res = SzArEx_Extract(&db, &lookStream.s, i, &block_index,
|
||||
&output, &output_size, &offset, &outSizeProcessed,
|
||||
&allocImp, &allocTempImp);
|
||||
|
||||
if (res != SZ_OK)
|
||||
break; /* This goes to the error section. */
|
||||
|
||||
outsize = outSizeProcessed;
|
||||
|
||||
if (optional_outfile != NULL)
|
||||
{
|
||||
const void *ptr = (const void*)(output + offset);
|
||||
|
||||
if (!filestream_write_file(optional_outfile, ptr, outsize))
|
||||
{
|
||||
/*RARCH_ERR("Could not open outfilepath %s.\n",
|
||||
optional_outfile);*/
|
||||
res = SZ_OK;
|
||||
file_found = true;
|
||||
outsize = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*We could either use the 7Zip allocated buffer,
|
||||
* or create our own and use it.
|
||||
* We would however need to realloc anyways, because RetroArch
|
||||
* expects a \0 at the end, therefore we allocate new,
|
||||
* copy and free the old one. */
|
||||
*buf = malloc(outsize + 1);
|
||||
((char*)(*buf))[outsize] = '\0';
|
||||
memcpy(*buf,output + offset,outsize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp)
|
||||
free(temp);
|
||||
IAlloc_Free(&allocImp, output);
|
||||
|
||||
if (!(file_found && res == SZ_OK))
|
||||
{
|
||||
/* Error handling
|
||||
*
|
||||
* Failed to open compressed file inside 7zip archive.
|
||||
*/
|
||||
|
||||
outsize = -1;
|
||||
}
|
||||
}
|
||||
|
||||
SzArEx_Free(&db, &allocImp);
|
||||
File_Close(&archiveStream.file);
|
||||
|
||||
return (int)outsize;
|
||||
}
|
||||
|
||||
static bool sevenzip_stream_decompress_data_to_file_init(
|
||||
file_archive_file_handle_t *handle,
|
||||
const uint8_t *cdata, uint32_t csize, uint32_t size)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)handle->stream;
|
||||
|
||||
if (!sevenzip_context)
|
||||
return false;
|
||||
|
||||
sevenzip_context->handle = handle;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sevenzip_stream_decompress_data_to_file_iterate(void *data)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)data;
|
||||
|
||||
SRes res = SZ_ERROR_FAIL;
|
||||
size_t output_size = 0;
|
||||
size_t offset = 0;
|
||||
size_t outSizeProcessed = 0;
|
||||
|
||||
res = SzArEx_Extract(&sevenzip_context->db,
|
||||
&sevenzip_context->lookStream.s, sevenzip_context->index,
|
||||
&sevenzip_context->block_index, &sevenzip_context->output,
|
||||
&output_size, &offset, &outSizeProcessed,
|
||||
&sevenzip_context->allocImp, &sevenzip_context->allocTempImp);
|
||||
|
||||
if (res != SZ_OK)
|
||||
return 0;
|
||||
|
||||
if (sevenzip_context->handle)
|
||||
sevenzip_context->handle->data = sevenzip_context->output + offset;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sevenzip_parse_file_init(file_archive_transfer_t *state,
|
||||
const char *file)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context =
|
||||
(struct sevenzip_context_t*)sevenzip_stream_new();
|
||||
|
||||
if (state->archive_size < SEVENZIP_MAGIC_LEN)
|
||||
goto error;
|
||||
|
||||
if (string_is_not_equal_fast(state->data, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN))
|
||||
goto error;
|
||||
|
||||
state->stream = sevenzip_context;
|
||||
|
||||
/* could not open 7zip archive? */
|
||||
if (InFile_Open(&sevenzip_context->archiveStream.file, file))
|
||||
goto error;
|
||||
|
||||
FileInStream_CreateVTable(&sevenzip_context->archiveStream);
|
||||
LookToRead_CreateVTable(&sevenzip_context->lookStream, false);
|
||||
sevenzip_context->lookStream.realStream = &sevenzip_context->archiveStream.s;
|
||||
LookToRead_Init(&sevenzip_context->lookStream);
|
||||
CrcGenerateTable();
|
||||
SzArEx_Init(&sevenzip_context->db);
|
||||
|
||||
if (SzArEx_Open(&sevenzip_context->db, &sevenzip_context->lookStream.s,
|
||||
&sevenzip_context->allocImp, &sevenzip_context->allocTempImp) != SZ_OK)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (sevenzip_context)
|
||||
sevenzip_stream_free(sevenzip_context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sevenzip_parse_file_iterate_step_internal(
|
||||
file_archive_transfer_t *state, char *filename,
|
||||
const uint8_t **cdata, unsigned *cmode,
|
||||
uint32_t *size, uint32_t *csize, uint32_t *checksum,
|
||||
unsigned *payback, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)state->stream;
|
||||
const CSzFileItem *file = sevenzip_context->db.db.Files + sevenzip_context->index;
|
||||
|
||||
if (sevenzip_context->index < sevenzip_context->db.db.NumFiles)
|
||||
{
|
||||
size_t len = SzArEx_GetFileNameUtf16(&sevenzip_context->db,
|
||||
sevenzip_context->index, NULL);
|
||||
uint64_t compressed_size = 0;
|
||||
|
||||
if (sevenzip_context->packIndex < sevenzip_context->db.db.NumPackStreams)
|
||||
{
|
||||
compressed_size = sevenzip_context->db.db.PackSizes[sevenzip_context->packIndex];
|
||||
sevenzip_context->packIndex++;
|
||||
}
|
||||
|
||||
if (len < PATH_MAX_LENGTH && !file->IsDir)
|
||||
{
|
||||
char infile[PATH_MAX_LENGTH];
|
||||
SRes res = SZ_ERROR_FAIL;
|
||||
uint16_t *temp = (uint16_t*)malloc(len * sizeof(uint16_t));
|
||||
|
||||
if (!temp)
|
||||
return -1;
|
||||
|
||||
infile[0] = '\0';
|
||||
|
||||
SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->index,
|
||||
temp);
|
||||
|
||||
if (temp)
|
||||
{
|
||||
res = utf16_to_char_string(temp, infile, sizeof(infile))
|
||||
? SZ_OK : SZ_ERROR_FAIL;
|
||||
free(temp);
|
||||
}
|
||||
|
||||
if (res != SZ_OK)
|
||||
return -1;
|
||||
|
||||
strlcpy(filename, infile, PATH_MAX_LENGTH);
|
||||
|
||||
*cmode = ARCHIVE_MODE_COMPRESSED;
|
||||
*checksum = file->Crc;
|
||||
*size = (uint32_t)file->Size;
|
||||
*csize = (uint32_t)compressed_size;
|
||||
}
|
||||
}
|
||||
|
||||
*payback = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sevenzip_parse_file_iterate_step(file_archive_transfer_t *state,
|
||||
const char *valid_exts,
|
||||
struct archive_extract_userdata *userdata, file_archive_file_cb file_cb)
|
||||
{
|
||||
char filename[PATH_MAX_LENGTH];
|
||||
const uint8_t *cdata = NULL;
|
||||
uint32_t checksum = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t csize = 0;
|
||||
unsigned cmode = 0;
|
||||
unsigned payload = 0;
|
||||
struct sevenzip_context_t *sevenzip_context = NULL;
|
||||
int ret;
|
||||
|
||||
filename[0] = '\0';
|
||||
|
||||
ret = sevenzip_parse_file_iterate_step_internal(state, filename,
|
||||
&cdata, &cmode, &size, &csize,
|
||||
&checksum, &payload, userdata);
|
||||
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
userdata->extracted_file_path = filename;
|
||||
userdata->crc = checksum;
|
||||
|
||||
if (file_cb && !file_cb(filename, valid_exts, cdata, cmode,
|
||||
csize, size, checksum, userdata))
|
||||
return 0;
|
||||
|
||||
sevenzip_context = (struct sevenzip_context_t*)state->stream;
|
||||
|
||||
sevenzip_context->index += payload;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc,
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
return encoding_crc32(crc, data, length);
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend sevenzip_backend = {
|
||||
sevenzip_stream_new,
|
||||
sevenzip_stream_free,
|
||||
sevenzip_stream_decompress_data_to_file_init,
|
||||
sevenzip_stream_decompress_data_to_file_iterate,
|
||||
sevenzip_stream_crc32_calculate,
|
||||
sevenzip_file_read,
|
||||
sevenzip_parse_file_init,
|
||||
sevenzip_parse_file_iterate_step,
|
||||
"7z"
|
||||
};
|
||||
@@ -1,391 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file_zlib.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <file/archive_file.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <streams/trans_stream.h>
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/crc32.h>
|
||||
|
||||
/* Only for MAX_WBITS */
|
||||
#include <compat/zlib.h>
|
||||
|
||||
#ifndef CENTRAL_FILE_HEADER_SIGNATURE
|
||||
#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50
|
||||
#endif
|
||||
|
||||
#ifndef END_OF_CENTRAL_DIR_SIGNATURE
|
||||
#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50
|
||||
#endif
|
||||
|
||||
static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
|
||||
{
|
||||
unsigned i;
|
||||
uint32_t val = 0;
|
||||
|
||||
size *= 8;
|
||||
for (i = 0; i < size; i += 8)
|
||||
val |= (uint32_t)*data++ << i;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void *zlib_stream_new(void)
|
||||
{
|
||||
return zlib_inflate_backend.stream_new();
|
||||
}
|
||||
|
||||
static void zlib_stream_free(void *stream)
|
||||
{
|
||||
zlib_inflate_backend.stream_free(stream);
|
||||
}
|
||||
|
||||
static bool zlib_stream_decompress_data_to_file_init(
|
||||
file_archive_file_handle_t *handle,
|
||||
const uint8_t *cdata, uint32_t csize, uint32_t size)
|
||||
{
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
handle->stream = zlib_inflate_backend.stream_new();
|
||||
|
||||
if (!handle->stream)
|
||||
goto error;
|
||||
|
||||
if (zlib_inflate_backend.define)
|
||||
zlib_inflate_backend.define(handle->stream, "window_bits", (uint32_t)-MAX_WBITS);
|
||||
|
||||
handle->data = (uint8_t*)malloc(size);
|
||||
|
||||
if (!handle->data)
|
||||
goto error;
|
||||
|
||||
zlib_inflate_backend.set_in(handle->stream,
|
||||
(const uint8_t*)cdata, csize);
|
||||
zlib_inflate_backend.set_out(handle->stream,
|
||||
handle->data, size);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
if (handle->stream)
|
||||
zlib_inflate_backend.stream_free(handle->stream);
|
||||
if (handle->data)
|
||||
free(handle->data);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int zlib_stream_decompress_data_to_file_iterate(void *stream)
|
||||
{
|
||||
bool zstatus;
|
||||
uint32_t rd, wn;
|
||||
enum trans_stream_error terror;
|
||||
|
||||
if (!stream)
|
||||
return -1;
|
||||
|
||||
zstatus = zlib_inflate_backend.trans(stream, false, &rd, &wn, &terror);
|
||||
|
||||
if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
|
||||
return -1;
|
||||
|
||||
if (zstatus && !terror)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t zlib_stream_crc32_calculate(uint32_t crc,
|
||||
const uint8_t *data, size_t length)
|
||||
{
|
||||
return encoding_crc32(crc, data, length);
|
||||
}
|
||||
|
||||
static bool zip_file_decompressed_handle(
|
||||
file_archive_file_handle_t *handle,
|
||||
const uint8_t *cdata, uint32_t csize,
|
||||
uint32_t size, uint32_t crc32)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
handle->backend = &zlib_backend;
|
||||
|
||||
if (!handle->backend->stream_decompress_data_to_file_init(
|
||||
handle, cdata, csize, size))
|
||||
return false;
|
||||
|
||||
do
|
||||
{
|
||||
ret = handle->backend->stream_decompress_data_to_file_iterate(
|
||||
handle->stream);
|
||||
}while(ret == 0);
|
||||
|
||||
#if 0
|
||||
handle->real_checksum = handle->backend->stream_crc_calculate(0,
|
||||
handle->data, size);
|
||||
|
||||
if (handle->real_checksum != crc32)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
if (handle->stream)
|
||||
free(handle->stream);
|
||||
|
||||
return true;
|
||||
#if 0
|
||||
error:
|
||||
if (handle->stream)
|
||||
free(handle->stream);
|
||||
if (handle->data)
|
||||
free(handle->data);
|
||||
|
||||
handle->stream = NULL;
|
||||
handle->data = NULL;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Extract the relative path (needle) from a
|
||||
* ZIP archive (path) and allocate a buffer for it to write it in.
|
||||
*
|
||||
* optional_outfile if not NULL will be used to extract the file to.
|
||||
* buf will be 0 then.
|
||||
*/
|
||||
|
||||
static int zip_file_decompressed(
|
||||
const char *name, const char *valid_exts,
|
||||
const uint8_t *cdata, unsigned cmode,
|
||||
uint32_t csize, uint32_t size,
|
||||
uint32_t crc32, struct archive_extract_userdata *userdata)
|
||||
{
|
||||
/* Ignore directories. */
|
||||
if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\')
|
||||
return 1;
|
||||
|
||||
#if 0
|
||||
RARCH_LOG("[deflate] Path: %s, CRC32: 0x%x\n", name, crc32);
|
||||
#endif
|
||||
|
||||
if (strstr(name, userdata->decomp_state.needle))
|
||||
{
|
||||
bool goto_error = false;
|
||||
file_archive_file_handle_t handle = {0};
|
||||
|
||||
userdata->decomp_state.found = true;
|
||||
|
||||
if (zip_file_decompressed_handle(&handle,
|
||||
cdata, csize, size, crc32))
|
||||
{
|
||||
if (userdata->decomp_state.opt_file != 0)
|
||||
{
|
||||
/* Called in case core has need_fullpath enabled. */
|
||||
char *buf = (char*)malloc(size);
|
||||
|
||||
if (buf)
|
||||
{
|
||||
/*RARCH_LOG("%s: %s\n",
|
||||
msg_hash_to_str(MSG_EXTRACTING_FILE),
|
||||
userdata->decomp_state.opt_file);*/
|
||||
memcpy(buf, handle.data, size);
|
||||
|
||||
if (!filestream_write_file(userdata->decomp_state.opt_file, buf, size))
|
||||
goto_error = true;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
userdata->decomp_state.size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Called in case core has need_fullpath disabled.
|
||||
* Will copy decompressed content directly into
|
||||
* RetroArch's ROM buffer. */
|
||||
*userdata->decomp_state.buf = malloc(size);
|
||||
memcpy(*userdata->decomp_state.buf, handle.data, size);
|
||||
|
||||
userdata->decomp_state.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle.data)
|
||||
free(handle.data);
|
||||
|
||||
if (goto_error)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zip_file_read(
|
||||
const char *path,
|
||||
const char *needle, void **buf,
|
||||
const char *optional_outfile)
|
||||
{
|
||||
file_archive_transfer_t zlib;
|
||||
struct archive_extract_userdata userdata = {{0}};
|
||||
bool returnerr = true;
|
||||
int ret = 0;
|
||||
|
||||
zlib.type = ARCHIVE_TRANSFER_INIT;
|
||||
|
||||
userdata.decomp_state.needle = NULL;
|
||||
userdata.decomp_state.opt_file = NULL;
|
||||
userdata.decomp_state.found = false;
|
||||
userdata.decomp_state.buf = buf;
|
||||
|
||||
if (needle)
|
||||
userdata.decomp_state.needle = strdup(needle);
|
||||
if (optional_outfile)
|
||||
userdata.decomp_state.opt_file = strdup(optional_outfile);
|
||||
|
||||
do
|
||||
{
|
||||
ret = file_archive_parse_file_iterate(&zlib, &returnerr, path,
|
||||
"", zip_file_decompressed, &userdata);
|
||||
if (!returnerr)
|
||||
break;
|
||||
}while(ret == 0 && !userdata.decomp_state.found);
|
||||
|
||||
file_archive_parse_file_iterate_stop(&zlib);
|
||||
|
||||
if (userdata.decomp_state.opt_file)
|
||||
free(userdata.decomp_state.opt_file);
|
||||
if (userdata.decomp_state.needle)
|
||||
free(userdata.decomp_state.needle);
|
||||
|
||||
if (!userdata.decomp_state.found)
|
||||
return -1;
|
||||
|
||||
return (int)userdata.decomp_state.size;
|
||||
}
|
||||
|
||||
static int zip_parse_file_init(file_archive_transfer_t *state,
|
||||
const char *file)
|
||||
{
|
||||
if (state->archive_size < 22)
|
||||
return -1;
|
||||
|
||||
state->footer = state->data + state->archive_size - 22;
|
||||
|
||||
for (;; state->footer--)
|
||||
{
|
||||
if (state->footer <= state->data + 22)
|
||||
return -1;
|
||||
if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE)
|
||||
{
|
||||
unsigned comment_len = read_le(state->footer + 20, 2);
|
||||
if (state->footer + 22 + comment_len == state->data + state->archive_size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
state->directory = state->data + read_le(state->footer + 16, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zip_parse_file_iterate_step_internal(
|
||||
file_archive_transfer_t *state, char *filename,
|
||||
const uint8_t **cdata,
|
||||
unsigned *cmode, uint32_t *size, uint32_t *csize,
|
||||
uint32_t *checksum, unsigned *payback)
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t namelength, extralength, commentlength,
|
||||
offsetNL, offsetEL;
|
||||
uint32_t signature = read_le(state->directory + 0, 4);
|
||||
|
||||
if (signature != CENTRAL_FILE_HEADER_SIGNATURE)
|
||||
return 0;
|
||||
|
||||
*cmode = read_le(state->directory + 10, 2); /* compression mode, 0 = store, 8 = deflate */
|
||||
*checksum = read_le(state->directory + 16, 4); /* CRC32 */
|
||||
*csize = read_le(state->directory + 20, 4); /* compressed size */
|
||||
*size = read_le(state->directory + 24, 4); /* uncompressed size */
|
||||
|
||||
namelength = read_le(state->directory + 28, 2); /* file name length */
|
||||
extralength = read_le(state->directory + 30, 2); /* extra field length */
|
||||
commentlength = read_le(state->directory + 32, 2); /* file comment length */
|
||||
|
||||
if (namelength >= PATH_MAX_LENGTH)
|
||||
return -1;
|
||||
|
||||
memcpy(filename, state->directory + 46, namelength); /* file name */
|
||||
|
||||
offset = read_le(state->directory + 42, 4); /* relative offset of local file header */
|
||||
offsetNL = read_le(state->data + offset + 26, 2); /* file name length */
|
||||
offsetEL = read_le(state->data + offset + 28, 2); /* extra field length */
|
||||
|
||||
*cdata = state->data + offset + 30 + offsetNL + offsetEL;
|
||||
|
||||
*payback = 46 + namelength + extralength + commentlength;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int zip_parse_file_iterate_step(file_archive_transfer_t *state,
|
||||
const char *valid_exts, struct archive_extract_userdata *userdata,
|
||||
file_archive_file_cb file_cb)
|
||||
{
|
||||
char filename[PATH_MAX_LENGTH] = {0};
|
||||
const uint8_t *cdata = NULL;
|
||||
uint32_t checksum = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t csize = 0;
|
||||
unsigned cmode = 0;
|
||||
unsigned payload = 0;
|
||||
int ret = zip_parse_file_iterate_step_internal(
|
||||
state, filename, &cdata, &cmode, &size, &csize, &checksum, &payload);
|
||||
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
||||
userdata->extracted_file_path = filename;
|
||||
userdata->crc = checksum;
|
||||
|
||||
if (file_cb && !file_cb(filename, valid_exts, cdata, cmode,
|
||||
csize, size, checksum, userdata))
|
||||
return 0;
|
||||
|
||||
state->directory += payload;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const struct file_archive_file_backend zlib_backend = {
|
||||
zlib_stream_new,
|
||||
zlib_stream_free,
|
||||
zlib_stream_decompress_data_to_file_init,
|
||||
zlib_stream_decompress_data_to_file_iterate,
|
||||
zlib_stream_crc32_calculate,
|
||||
zip_file_read,
|
||||
zip_parse_file_init,
|
||||
zip_parse_file_iterate_step,
|
||||
"zlib"
|
||||
};
|
||||
@@ -1,996 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (config_file.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if !defined(_WIN32) && !defined(__CELLOS_LV2__) && !defined(_XBOX)
|
||||
#include <sys/param.h> /* PATH_MAX */
|
||||
#elif defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_XBOX)
|
||||
#include <xtl.h>
|
||||
#endif
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <compat/strl.h>
|
||||
#include <compat/posix_string.h>
|
||||
#include <compat/msvc.h>
|
||||
#include <file/config_file.h>
|
||||
#include <file/file_path.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <rhash.h>
|
||||
|
||||
#define MAX_INCLUDE_DEPTH 16
|
||||
|
||||
struct config_entry_list
|
||||
{
|
||||
/* If we got this from an #include,
|
||||
* do not allow overwrite. */
|
||||
bool readonly;
|
||||
uint32_t key_hash;
|
||||
|
||||
char *key;
|
||||
char *value;
|
||||
struct config_entry_list *next;
|
||||
};
|
||||
|
||||
struct config_include_list
|
||||
{
|
||||
char *path;
|
||||
struct config_include_list *next;
|
||||
};
|
||||
|
||||
struct config_file
|
||||
{
|
||||
char *path;
|
||||
struct config_entry_list *entries;
|
||||
struct config_entry_list *tail;
|
||||
unsigned include_depth;
|
||||
|
||||
struct config_include_list *includes;
|
||||
};
|
||||
|
||||
static config_file_t *config_file_new_internal(
|
||||
const char *path, unsigned depth);
|
||||
|
||||
static char *getaline(FILE *file)
|
||||
{
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
int in = getc(file);
|
||||
|
||||
if (!newline)
|
||||
return NULL;
|
||||
|
||||
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 = getc(file);
|
||||
}
|
||||
newline[idx] = '\0';
|
||||
return newline;
|
||||
}
|
||||
|
||||
static char *strip_comment(char *str)
|
||||
{
|
||||
/* Remove everything after comment.
|
||||
* Keep #s inside string literals. */
|
||||
char *string_end = str + strlen(str);
|
||||
bool cut_comment = true;
|
||||
|
||||
while (!string_is_empty(str))
|
||||
{
|
||||
char *comment = NULL;
|
||||
char *literal = strchr(str, '\"');
|
||||
if (!literal)
|
||||
literal = string_end;
|
||||
comment = (char*)strchr(str, '#');
|
||||
|
||||
if (!comment)
|
||||
comment = string_end;
|
||||
|
||||
if (cut_comment && literal < comment)
|
||||
{
|
||||
cut_comment = false;
|
||||
str = literal + 1;
|
||||
}
|
||||
else if (!cut_comment && literal)
|
||||
{
|
||||
cut_comment = true;
|
||||
str = literal + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*comment = '\0';
|
||||
str = comment;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *extract_value(char *line, bool is_value)
|
||||
{
|
||||
char *save = NULL;
|
||||
char *tok = NULL;
|
||||
|
||||
if (is_value)
|
||||
{
|
||||
while (isspace((int)*line))
|
||||
line++;
|
||||
|
||||
/* If we don't have an equal sign here,
|
||||
* we've got an invalid string. */
|
||||
if (*line != '=')
|
||||
return NULL;
|
||||
|
||||
line++;
|
||||
}
|
||||
|
||||
while (isspace((int)*line))
|
||||
line++;
|
||||
|
||||
/* We have a full string. Read until next ". */
|
||||
if (*line == '"')
|
||||
{
|
||||
line++;
|
||||
tok = strtok_r(line, "\"", &save);
|
||||
if (!tok)
|
||||
return NULL;
|
||||
return strdup(tok);
|
||||
}
|
||||
else if (*line == '\0') /* Nothing */
|
||||
return NULL;
|
||||
|
||||
/* We don't have that. Read until next space. */
|
||||
tok = strtok_r(line, " \n\t\f\r\v", &save);
|
||||
if (tok)
|
||||
return strdup(tok);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Move semantics? */
|
||||
static void add_child_list(config_file_t *parent, config_file_t *child)
|
||||
{
|
||||
struct config_entry_list *list = child->entries;
|
||||
if (parent->entries)
|
||||
{
|
||||
struct config_entry_list *head = parent->entries;
|
||||
while (head->next)
|
||||
head = head->next;
|
||||
|
||||
/* set list readonly */
|
||||
while (list)
|
||||
{
|
||||
list->readonly = true;
|
||||
list = list->next;
|
||||
}
|
||||
head->next = child->entries;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set list readonly */
|
||||
while (list)
|
||||
{
|
||||
list->readonly = true;
|
||||
list = list->next;
|
||||
}
|
||||
parent->entries = child->entries;
|
||||
}
|
||||
|
||||
child->entries = NULL;
|
||||
|
||||
/* Rebase tail. */
|
||||
if (parent->entries)
|
||||
{
|
||||
struct config_entry_list *head =
|
||||
(struct config_entry_list*)parent->entries;
|
||||
|
||||
while (head->next)
|
||||
head = head->next;
|
||||
parent->tail = head;
|
||||
}
|
||||
else
|
||||
parent->tail = NULL;
|
||||
}
|
||||
|
||||
static void add_sub_conf(config_file_t *conf, char *path)
|
||||
{
|
||||
char real_path[PATH_MAX_LENGTH];
|
||||
config_file_t *sub_conf = NULL;
|
||||
struct config_include_list *head = conf->includes;
|
||||
struct config_include_list *node = (struct config_include_list*)malloc(sizeof(*node));
|
||||
|
||||
if (node)
|
||||
{
|
||||
node->next = NULL;
|
||||
/* Add include list */
|
||||
node->path = strdup(path);
|
||||
|
||||
if (head)
|
||||
{
|
||||
while (head->next)
|
||||
head = head->next;
|
||||
|
||||
head->next = node;
|
||||
}
|
||||
else
|
||||
conf->includes = node;
|
||||
}
|
||||
|
||||
real_path[0] = '\0';
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!string_is_empty(conf->path))
|
||||
fill_pathname_resolve_relative(real_path, conf->path,
|
||||
path, sizeof(real_path));
|
||||
#else
|
||||
#ifndef __CELLOS_LV2__
|
||||
if (*path == '~')
|
||||
{
|
||||
const char *home = getenv("HOME");
|
||||
strlcpy(real_path, home ? home : "", sizeof(real_path));
|
||||
strlcat(real_path, path + 1, sizeof(real_path));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!string_is_empty(conf->path))
|
||||
fill_pathname_resolve_relative(real_path, conf->path,
|
||||
path, sizeof(real_path));
|
||||
#endif
|
||||
|
||||
sub_conf = (config_file_t*)
|
||||
config_file_new_internal(real_path, conf->include_depth + 1);
|
||||
if (!sub_conf)
|
||||
{
|
||||
free(path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pilfer internal list. */
|
||||
add_child_list(conf, sub_conf);
|
||||
config_file_free(sub_conf);
|
||||
free(path);
|
||||
}
|
||||
|
||||
static bool parse_line(config_file_t *conf,
|
||||
struct config_entry_list *list, char *line)
|
||||
{
|
||||
char *comment = NULL;
|
||||
char *key_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
char *key = (char*)malloc(9);
|
||||
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
comment = strip_comment(line);
|
||||
|
||||
/* Starting line with # and include includes config files. */
|
||||
if ((comment == line) && (conf->include_depth < MAX_INCLUDE_DEPTH))
|
||||
{
|
||||
comment++;
|
||||
if (strstr(comment, "include ") == comment)
|
||||
{
|
||||
char *line = comment + strlen("include ");
|
||||
char *path = extract_value(line, false);
|
||||
if (path)
|
||||
add_sub_conf(conf, path);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (conf->include_depth >= MAX_INCLUDE_DEPTH)
|
||||
{
|
||||
fprintf(stderr, "!!! #include depth exceeded for config. Might be a cycle.\n");
|
||||
}
|
||||
|
||||
/* Skips to first character. */
|
||||
while (isspace((int)*line))
|
||||
line++;
|
||||
|
||||
while (isgraph((int)*line))
|
||||
{
|
||||
if (idx == cur_size)
|
||||
{
|
||||
cur_size *= 2;
|
||||
key_tmp = (char*)realloc(key, cur_size + 1);
|
||||
|
||||
if (!key_tmp)
|
||||
goto error;
|
||||
|
||||
key = key_tmp;
|
||||
}
|
||||
|
||||
key[idx++] = *line++;
|
||||
}
|
||||
key[idx] = '\0';
|
||||
list->key = key;
|
||||
list->key_hash = djb2_calculate(key);
|
||||
|
||||
list->value = extract_value(line, true);
|
||||
if (!list->value)
|
||||
{
|
||||
list->key = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
free(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
static config_file_t *config_file_new_internal(
|
||||
const char *path, unsigned depth)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
|
||||
if (!conf)
|
||||
return NULL;
|
||||
|
||||
conf->path = NULL;
|
||||
conf->entries = NULL;
|
||||
conf->tail = NULL;
|
||||
conf->includes = NULL;
|
||||
conf->include_depth = 0;
|
||||
|
||||
if (!path || !*path)
|
||||
return conf;
|
||||
|
||||
if (path_is_directory(path))
|
||||
goto error;
|
||||
|
||||
conf->path = strdup(path);
|
||||
if (!conf->path)
|
||||
goto error;
|
||||
|
||||
conf->include_depth = depth;
|
||||
file = fopen(path, "r");
|
||||
|
||||
if (!file)
|
||||
{
|
||||
free(conf->path);
|
||||
goto error;
|
||||
}
|
||||
setvbuf(file, NULL, _IOFBF, 0x4000);
|
||||
|
||||
while (!feof(file))
|
||||
{
|
||||
char *line = NULL;
|
||||
struct config_entry_list *list = (struct config_entry_list*)malloc(sizeof(*list));
|
||||
|
||||
if (!list)
|
||||
{
|
||||
config_file_free(conf);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->readonly = false;
|
||||
list->key_hash = 0;
|
||||
list->key = NULL;
|
||||
list->value = NULL;
|
||||
list->next = NULL;
|
||||
|
||||
line = getaline(file);
|
||||
|
||||
if (!line)
|
||||
{
|
||||
free(list);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*line && parse_line(conf, list, line))
|
||||
{
|
||||
if (conf->entries)
|
||||
conf->tail->next = list;
|
||||
else
|
||||
conf->entries = list;
|
||||
|
||||
conf->tail = list;
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
if (list != conf->tail)
|
||||
free(list);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return conf;
|
||||
|
||||
error:
|
||||
free(conf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void config_file_free(config_file_t *conf)
|
||||
{
|
||||
struct config_include_list *inc_tmp = NULL;
|
||||
struct config_entry_list *tmp = NULL;
|
||||
if (!conf)
|
||||
return;
|
||||
|
||||
tmp = conf->entries;
|
||||
while (tmp)
|
||||
{
|
||||
struct config_entry_list *hold = NULL;
|
||||
if (tmp->key)
|
||||
free(tmp->key);
|
||||
if (tmp->value)
|
||||
free(tmp->value);
|
||||
|
||||
tmp->value = NULL;
|
||||
tmp->key = NULL;
|
||||
|
||||
hold = tmp;
|
||||
tmp = tmp->next;
|
||||
|
||||
if (hold)
|
||||
free(hold);
|
||||
}
|
||||
|
||||
inc_tmp = (struct config_include_list*)conf->includes;
|
||||
while (inc_tmp)
|
||||
{
|
||||
struct config_include_list *hold = NULL;
|
||||
free(inc_tmp->path);
|
||||
hold = (struct config_include_list*)inc_tmp;
|
||||
inc_tmp = inc_tmp->next;
|
||||
free(hold);
|
||||
}
|
||||
|
||||
if (conf->path)
|
||||
free(conf->path);
|
||||
free(conf);
|
||||
}
|
||||
|
||||
bool config_append_file(config_file_t *conf, const char *path)
|
||||
{
|
||||
config_file_t *new_conf = config_file_new(path);
|
||||
if (!new_conf)
|
||||
return false;
|
||||
|
||||
if (new_conf->tail)
|
||||
{
|
||||
new_conf->tail->next = conf->entries;
|
||||
conf->entries = new_conf->entries; /* Pilfer. */
|
||||
new_conf->entries = NULL;
|
||||
}
|
||||
|
||||
config_file_free(new_conf);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
config_file_t *config_file_new_from_string(const char *from_string)
|
||||
{
|
||||
size_t i;
|
||||
struct string_list *lines = NULL;
|
||||
struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
|
||||
if (!conf)
|
||||
return NULL;
|
||||
|
||||
if (!from_string)
|
||||
return conf;
|
||||
|
||||
conf->path = NULL;
|
||||
conf->entries = NULL;
|
||||
conf->tail = NULL;
|
||||
conf->includes = NULL;
|
||||
conf->include_depth = 0;
|
||||
|
||||
lines = string_split(from_string, "\n");
|
||||
if (!lines)
|
||||
return conf;
|
||||
|
||||
for (i = 0; i < lines->size; i++)
|
||||
{
|
||||
struct config_entry_list *list = (struct config_entry_list*)malloc(sizeof(*list));
|
||||
char *line = lines->elems[i].data;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
string_list_free(lines);
|
||||
config_file_free(conf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->readonly = false;
|
||||
list->key_hash = 0;
|
||||
list->key = NULL;
|
||||
list->value = NULL;
|
||||
list->next = NULL;
|
||||
|
||||
if (line && conf)
|
||||
{
|
||||
if (*line && parse_line(conf, list, line))
|
||||
{
|
||||
if (conf->entries)
|
||||
conf->tail->next = list;
|
||||
else
|
||||
conf->entries = list;
|
||||
|
||||
conf->tail = list;
|
||||
}
|
||||
}
|
||||
|
||||
if (list != conf->tail)
|
||||
free(list);
|
||||
}
|
||||
|
||||
string_list_free(lines);
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
config_file_t *config_file_new(const char *path)
|
||||
{
|
||||
return config_file_new_internal(path, 0);
|
||||
}
|
||||
|
||||
|
||||
static struct config_entry_list *config_get_entry(const config_file_t *conf,
|
||||
const char *key, struct config_entry_list **prev)
|
||||
{
|
||||
struct config_entry_list *entry;
|
||||
struct config_entry_list *previous = NULL;
|
||||
|
||||
uint32_t hash = djb2_calculate(key);
|
||||
|
||||
if (prev)
|
||||
previous = *prev;
|
||||
|
||||
for (entry = conf->entries; entry; entry = entry->next)
|
||||
{
|
||||
if (hash == entry->key_hash && string_is_equal(key, entry->key))
|
||||
return entry;
|
||||
|
||||
previous = entry;
|
||||
}
|
||||
|
||||
if (prev)
|
||||
*prev = previous;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool config_get_double(config_file_t *conf, const char *key, double *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
*in = strtod(entry->value, NULL);
|
||||
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
bool config_get_float(config_file_t *conf, const char *key, float *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
/* strtof() is C99/POSIX. Just use the more portable kind. */
|
||||
*in = (float)strtod(entry->value, NULL);
|
||||
}
|
||||
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
bool config_get_int(config_file_t *conf, const char *key, int *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
errno = 0;
|
||||
|
||||
if (entry)
|
||||
{
|
||||
int val = (int)strtol(entry->value, NULL, 0);
|
||||
|
||||
if (errno == 0)
|
||||
*in = val;
|
||||
}
|
||||
|
||||
return entry != NULL && errno == 0;
|
||||
}
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||
bool config_get_uint64(config_file_t *conf, const char *key, uint64_t *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
errno = 0;
|
||||
|
||||
if (entry)
|
||||
{
|
||||
uint64_t val = strtoull(entry->value, NULL, 0);
|
||||
|
||||
if (errno == 0)
|
||||
*in = val;
|
||||
}
|
||||
|
||||
return entry != NULL && errno == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool config_get_uint(config_file_t *conf, const char *key, unsigned *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
errno = 0;
|
||||
|
||||
if (entry)
|
||||
{
|
||||
unsigned val = (unsigned)strtoul(entry->value, NULL, 0);
|
||||
|
||||
if (errno == 0)
|
||||
*in = val;
|
||||
}
|
||||
|
||||
return entry != NULL && errno == 0;
|
||||
}
|
||||
|
||||
bool config_get_hex(config_file_t *conf, const char *key, unsigned *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
errno = 0;
|
||||
|
||||
if (entry)
|
||||
{
|
||||
unsigned val = (unsigned)strtoul(entry->value, NULL, 16);
|
||||
|
||||
if (errno == 0)
|
||||
*in = val;
|
||||
}
|
||||
|
||||
return entry != NULL && errno == 0;
|
||||
}
|
||||
|
||||
bool config_get_char(config_file_t *conf, const char *key, char *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
if (entry->value[0] && entry->value[1])
|
||||
return false;
|
||||
|
||||
*in = *entry->value;
|
||||
}
|
||||
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
bool config_get_string(config_file_t *conf, const char *key, char **str)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
*str = strdup(entry->value);
|
||||
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
bool config_get_config_path(config_file_t *conf, char *s, size_t len)
|
||||
{
|
||||
if (!conf)
|
||||
return false;
|
||||
|
||||
return strlcpy(s, conf->path, len);
|
||||
}
|
||||
|
||||
bool config_get_array(config_file_t *conf, const char *key,
|
||||
char *buf, size_t size)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
return strlcpy(buf, entry->value, size) < size;
|
||||
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
bool config_get_path(config_file_t *conf, const char *key,
|
||||
char *buf, size_t size)
|
||||
{
|
||||
#if defined(RARCH_CONSOLE)
|
||||
return config_get_array(conf, key, buf, size);
|
||||
#else
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
fill_pathname_expand_special(buf, entry->value, size);
|
||||
|
||||
return entry != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool config_get_bool(config_file_t *conf, const char *key, bool *in)
|
||||
{
|
||||
const struct config_entry_list *entry = config_get_entry(conf, key, NULL);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
if (string_is_equal_fast(entry->value, "true", 4))
|
||||
*in = true;
|
||||
else if (string_is_equal_fast(entry->value, "1", 1))
|
||||
*in = true;
|
||||
else if (string_is_equal_fast(entry->value, "false", 5))
|
||||
*in = false;
|
||||
else if (string_is_equal_fast(entry->value, "0", 1))
|
||||
*in = false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
void config_set_string(config_file_t *conf, const char *key, const char *val)
|
||||
{
|
||||
struct config_entry_list *last = conf->entries;
|
||||
struct config_entry_list *entry = config_get_entry(conf, key, &last);
|
||||
|
||||
if (entry && !entry->readonly)
|
||||
{
|
||||
free(entry->value);
|
||||
entry->value = strdup(val);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!val)
|
||||
return;
|
||||
|
||||
entry = (struct config_entry_list*)malloc(sizeof(*entry));
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
entry->readonly = false;
|
||||
entry->key_hash = 0;
|
||||
entry->key = strdup(key);
|
||||
entry->value = strdup(val);
|
||||
entry->next = NULL;
|
||||
|
||||
if (last)
|
||||
last->next = entry;
|
||||
else
|
||||
conf->entries = entry;
|
||||
}
|
||||
|
||||
void config_unset(config_file_t *conf, const char *key)
|
||||
{
|
||||
struct config_entry_list *last = conf->entries;
|
||||
struct config_entry_list *entry = config_get_entry(conf, key, &last);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
entry->key = NULL;
|
||||
entry->value = NULL;
|
||||
free(entry->key);
|
||||
free(entry->value);
|
||||
}
|
||||
|
||||
void config_set_path(config_file_t *conf, const char *entry, const char *val)
|
||||
{
|
||||
#if defined(RARCH_CONSOLE)
|
||||
config_set_string(conf, entry, val);
|
||||
#else
|
||||
char buf[PATH_MAX_LENGTH];
|
||||
|
||||
buf[0] = '\0';
|
||||
fill_pathname_abbreviate_special(buf, val, sizeof(buf));
|
||||
config_set_string(conf, entry, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void config_set_double(config_file_t *conf, const char *key, double val)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
buf[0] = '\0';
|
||||
#ifdef __cplusplus
|
||||
snprintf(buf, sizeof(buf), "%f", (float)val);
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||
snprintf(buf, sizeof(buf), "%lf", val);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%f", (float)val);
|
||||
#endif
|
||||
config_set_string(conf, key, buf);
|
||||
}
|
||||
|
||||
void config_set_float(config_file_t *conf, const char *key, float val)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
buf[0] = '\0';
|
||||
snprintf(buf, sizeof(buf), "%f", val);
|
||||
config_set_string(conf, key, buf);
|
||||
}
|
||||
|
||||
void config_set_int(config_file_t *conf, const char *key, int val)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
buf[0] = '\0';
|
||||
snprintf(buf, sizeof(buf), "%d", val);
|
||||
config_set_string(conf, key, buf);
|
||||
}
|
||||
|
||||
void config_set_hex(config_file_t *conf, const char *key, unsigned val)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
buf[0] = '\0';
|
||||
snprintf(buf, sizeof(buf), "%x", val);
|
||||
config_set_string(conf, key, buf);
|
||||
}
|
||||
|
||||
void config_set_uint64(config_file_t *conf, const char *key, uint64_t val)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
buf[0] = '\0';
|
||||
#ifdef _WIN32
|
||||
snprintf(buf, sizeof(buf), "%I64u", val);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "%llu", (long long unsigned)val);
|
||||
#endif
|
||||
config_set_string(conf, key, buf);
|
||||
}
|
||||
|
||||
void config_set_char(config_file_t *conf, const char *key, char val)
|
||||
{
|
||||
char buf[2];
|
||||
|
||||
buf[0] = '\0';
|
||||
snprintf(buf, sizeof(buf), "%c", val);
|
||||
config_set_string(conf, key, buf);
|
||||
}
|
||||
|
||||
void config_set_bool(config_file_t *conf, const char *key, bool val)
|
||||
{
|
||||
config_set_string(conf, key, val ? "true" : "false");
|
||||
}
|
||||
|
||||
bool config_file_write(config_file_t *conf, const char *path)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
if (path && !string_is_empty(path))
|
||||
{
|
||||
file = fopen(path, "w");
|
||||
if (!file)
|
||||
return false;
|
||||
#ifdef WIIU
|
||||
/* TODO: use FBF everywhere once https://i.imgur.com/muVhNeF.jpg is fixed */
|
||||
setvbuf(file, NULL, _IONBF, 0x4000);
|
||||
#else
|
||||
setvbuf(file, NULL, _IOFBF, 0x4000);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
file = stdout;
|
||||
|
||||
config_file_dump(conf, file);
|
||||
|
||||
if (path)
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void config_file_dump(config_file_t *conf, FILE *file)
|
||||
{
|
||||
struct config_entry_list *list = NULL;
|
||||
struct config_include_list *includes = conf->includes;
|
||||
|
||||
while (includes)
|
||||
{
|
||||
fprintf(file, "#include \"%s\"\n", includes->path);
|
||||
includes = includes->next;
|
||||
}
|
||||
|
||||
list = (struct config_entry_list*)conf->entries;
|
||||
|
||||
while (list)
|
||||
{
|
||||
if (!list->readonly && list->key)
|
||||
fprintf(file, "%s = \"%s\"\n", list->key, list->value);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
bool config_entry_exists(config_file_t *conf, const char *entry)
|
||||
{
|
||||
struct config_entry_list *list = conf->entries;
|
||||
|
||||
while (list)
|
||||
{
|
||||
if (string_is_equal(entry, list->key))
|
||||
return true;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool config_get_entry_list_head(config_file_t *conf,
|
||||
struct config_file_entry *entry)
|
||||
{
|
||||
const struct config_entry_list *head = conf->entries;
|
||||
|
||||
if (!head)
|
||||
return false;
|
||||
|
||||
entry->key = head->key;
|
||||
entry->value = head->value;
|
||||
entry->next = head->next;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool config_get_entry_list_next(struct config_file_entry *entry)
|
||||
{
|
||||
const struct config_entry_list *next = entry->next;
|
||||
|
||||
if (!next)
|
||||
return false;
|
||||
|
||||
entry->key = next->key;
|
||||
entry->value = next->value;
|
||||
entry->next = next->next;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool config_file_exists(const char *path)
|
||||
{
|
||||
config_file_t *config = config_file_new(path);
|
||||
if (!config)
|
||||
return false;
|
||||
|
||||
config_file_free(config);
|
||||
return true;
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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_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 = string_split(str, " ");
|
||||
*values = (float*)calloc(list->size, sizeof(float));
|
||||
for (i = 0; i < list->size; i++)
|
||||
(*values)[i] = (float)strtod(list->elems[i].data, NULL);
|
||||
*out_num_values = (unsigned)list->size;
|
||||
string_list_free(list);
|
||||
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 = string_split(str, " ");
|
||||
*values = (int*)calloc(list->size, sizeof(int));
|
||||
for (i = 0; i < list->size; i++)
|
||||
(*values)[i] = (int)strtod(list->elems[i].data, NULL);
|
||||
*out_num_values = (unsigned)list->size;
|
||||
string_list_free(list);
|
||||
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);
|
||||
}
|
||||
@@ -1,886 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_path.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <file/file_path.h>
|
||||
|
||||
#ifndef __MACH__
|
||||
#include <compat/strl.h>
|
||||
#include <compat/posix_string.h>
|
||||
#endif
|
||||
#include <compat/strcasestr.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifdef _MSC_VER
|
||||
#define setmode _setmode
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#ifdef _XBOX
|
||||
#include <xtl.h>
|
||||
#define INVALID_FILE_ATTRIBUTES -1
|
||||
#else
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200
|
||||
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(VITA)
|
||||
#define SCE_ERROR_ERRNO_EEXIST 0x80010011
|
||||
#include <psp2/io/fcntl.h>
|
||||
#include <psp2/io/dirent.h>
|
||||
#include <psp2/io/stat.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(PSP)
|
||||
#include <pspkernel.h>
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
#include <kernel/image.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <cell/cell_fs.h>
|
||||
#endif
|
||||
|
||||
#if defined(VITA)
|
||||
#define FIO_S_ISDIR SCE_S_ISDIR
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
enum stat_mode
|
||||
{
|
||||
IS_DIRECTORY = 0,
|
||||
IS_CHARACTER_SPECIAL,
|
||||
IS_VALID
|
||||
};
|
||||
|
||||
static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
|
||||
{
|
||||
#if defined(VITA) || defined(PSP)
|
||||
SceIoStat buf;
|
||||
char *tmp = strdup(path);
|
||||
size_t len = strlen(tmp);
|
||||
if (tmp[len-1] == '/')
|
||||
tmp[len-1]='\0';
|
||||
|
||||
if (sceIoGetstat(tmp, &buf) < 0)
|
||||
{
|
||||
free(tmp);
|
||||
return false;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsStat buf;
|
||||
if (cellFsStat(path, &buf) < 0)
|
||||
return false;
|
||||
#elif defined(_WIN32)
|
||||
struct _stat buf;
|
||||
DWORD file_info = GetFileAttributes(path);
|
||||
|
||||
_stat(path, &buf);
|
||||
|
||||
if (file_info == INVALID_FILE_ATTRIBUTES)
|
||||
return false;
|
||||
#else
|
||||
struct stat buf;
|
||||
if (stat(path, &buf) < 0)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (size)
|
||||
*size = (int32_t)buf.st_size;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case IS_DIRECTORY:
|
||||
#if defined(VITA) || defined(PSP)
|
||||
return FIO_S_ISDIR(buf.st_mode);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return ((buf.st_mode & S_IFMT) == S_IFDIR);
|
||||
#elif defined(_WIN32)
|
||||
return (file_info & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
case IS_CHARACTER_SPECIAL:
|
||||
#if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(_WIN32)
|
||||
return false;
|
||||
#else
|
||||
return S_ISCHR(buf.st_mode);
|
||||
#endif
|
||||
case IS_VALID:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(path, IS_DIRECTORY, NULL);
|
||||
}
|
||||
|
||||
bool path_is_character_special(const char *path)
|
||||
{
|
||||
return path_stat(path, IS_CHARACTER_SPECIAL, NULL);
|
||||
}
|
||||
|
||||
bool path_is_valid(const char *path)
|
||||
{
|
||||
return path_stat(path, IS_VALID, NULL);
|
||||
}
|
||||
|
||||
int32_t path_get_size(const char *path)
|
||||
{
|
||||
int32_t filesize = 0;
|
||||
if (path_stat(path, IS_VALID, &filesize))
|
||||
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)
|
||||
{
|
||||
/* Use heap. Real chance of stack overflow if we recurse too hard. */
|
||||
char *basedir = strdup(dir);
|
||||
const char *target = NULL;
|
||||
bool sret = false;
|
||||
bool norecurse = false;
|
||||
|
||||
if (!basedir)
|
||||
return false;
|
||||
|
||||
path_parent_dir(basedir);
|
||||
if (!*basedir || !strcmp(basedir, dir))
|
||||
goto end;
|
||||
|
||||
if (path_is_directory(basedir))
|
||||
{
|
||||
target = dir;
|
||||
norecurse = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
target = basedir;
|
||||
sret = path_mkdir(basedir);
|
||||
|
||||
if (sret)
|
||||
{
|
||||
target = dir;
|
||||
norecurse = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (norecurse)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
int ret = _mkdir(dir);
|
||||
#elif defined(IOS)
|
||||
int ret = mkdir(dir, 0755);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
int ret = sceIoMkdir(dir, 0777);
|
||||
#elif defined(__QNX__)
|
||||
int ret = mkdir(dir, 0777);
|
||||
#else
|
||||
int ret = mkdir(dir, 0750);
|
||||
#endif
|
||||
|
||||
/* Don't treat this as an error. */
|
||||
#if defined(VITA)
|
||||
if ((ret == SCE_ERROR_ERRNO_EEXIST) && path_is_directory(dir))
|
||||
ret = 0;
|
||||
#elif defined(PSP) || defined(_3DS) || defined(WIIU)
|
||||
if ((ret == -1) && path_is_directory(dir))
|
||||
ret = 0;
|
||||
#else
|
||||
if (ret < 0 && errno == EEXIST && path_is_directory(dir))
|
||||
ret = 0;
|
||||
#endif
|
||||
if (ret < 0)
|
||||
printf("mkdir(%s) error: %s.\n", dir, strerror(errno));
|
||||
sret = (ret == 0);
|
||||
}
|
||||
|
||||
end:
|
||||
if (target && !sret)
|
||||
printf("Failed to create directory: \"%s\".\n", target);
|
||||
free(basedir);
|
||||
return sret;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_get_archive_delim:
|
||||
* @path : path
|
||||
*
|
||||
* Find 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 path inside a compressed file, otherwise NULL.
|
||||
*/
|
||||
const char *path_get_archive_delim(const char *path)
|
||||
{
|
||||
const char *last = find_last_slash(path);
|
||||
const char *delim = NULL;
|
||||
|
||||
if (last)
|
||||
{
|
||||
delim = strcasestr(last, ".zip#");
|
||||
|
||||
if (!delim)
|
||||
delim = strcasestr(last, ".apk#");
|
||||
}
|
||||
|
||||
if (delim)
|
||||
return delim + 4;
|
||||
|
||||
if (last)
|
||||
delim = strcasestr(last, ".7z#");
|
||||
|
||||
if (delim)
|
||||
return delim + 3;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
const char *ext = strrchr(path_basename(path), '.');
|
||||
if (!ext)
|
||||
return "";
|
||||
return ext + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_remove_extension:
|
||||
* @path : path
|
||||
*
|
||||
* Removes the extension from the path and returns the result.
|
||||
* Removes all text after and including the last '.'.
|
||||
* Only '.'s after the last slash are considered.
|
||||
*
|
||||
* Returns: path with the extension part removed.
|
||||
*/
|
||||
char *path_remove_extension(char *path)
|
||||
{
|
||||
char *last = (char*)strrchr(path_basename(path), '.');
|
||||
if (!last)
|
||||
return NULL;
|
||||
if (*last)
|
||||
*last = '\0';
|
||||
return last;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
const char *ext = path_get_extension(path);
|
||||
|
||||
if ( strcasestr(ext, "zip")
|
||||
|| strcasestr(ext, "apk")
|
||||
|| strcasestr(ext, "7z"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_file_exists:
|
||||
* @path : path
|
||||
*
|
||||
* Checks if a file already exists at the specified path (@path).
|
||||
*
|
||||
* Returns: true (1) if file already exists, otherwise false (0).
|
||||
*/
|
||||
bool path_file_exists(const char *path)
|
||||
{
|
||||
FILE *dummy;
|
||||
|
||||
if (!path || !*path)
|
||||
return false;
|
||||
|
||||
dummy = fopen(path, "rb");
|
||||
|
||||
if (!dummy)
|
||||
return false;
|
||||
|
||||
fclose(dummy);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
char tmp_path[PATH_MAX_LENGTH];
|
||||
char *tok = NULL;
|
||||
|
||||
tmp_path[0] = '\0';
|
||||
|
||||
strlcpy(tmp_path, in_path, sizeof(tmp_path));
|
||||
if ((tok = (char*)strrchr(path_basename(tmp_path), '.')))
|
||||
*tok = '\0';
|
||||
|
||||
fill_pathname_noext(out_path, tmp_path, replace, 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.
|
||||
*
|
||||
*/
|
||||
void fill_pathname_noext(char *out_path, const char *in_path,
|
||||
const char *replace, size_t size)
|
||||
{
|
||||
strlcpy(out_path, in_path, size);
|
||||
strlcat(out_path, replace, size);
|
||||
}
|
||||
|
||||
char *find_last_slash(const char *str)
|
||||
{
|
||||
const char *slash = strrchr(str, '/');
|
||||
#ifdef _WIN32
|
||||
const char *backslash = strrchr(str, '\\');
|
||||
|
||||
if (backslash && ((slash && backslash > slash) || !slash))
|
||||
slash = backslash;
|
||||
#endif
|
||||
|
||||
return (char*)slash;
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_pathname_slash:
|
||||
* @path : path
|
||||
* @size : size of path
|
||||
*
|
||||
* Assumes path is a directory. Appends a slash
|
||||
* if not already there.
|
||||
**/
|
||||
void fill_pathname_slash(char *path, size_t size)
|
||||
{
|
||||
size_t path_len = strlen(path);
|
||||
const char *last_slash = find_last_slash(path);
|
||||
|
||||
/* Try to preserve slash type. */
|
||||
if (last_slash && (last_slash != (path + path_len - 1)))
|
||||
{
|
||||
char join_str[2];
|
||||
|
||||
join_str[0] = '\0';
|
||||
|
||||
strlcpy(join_str, last_slash, sizeof(join_str));
|
||||
strlcat(path, join_str, size);
|
||||
}
|
||||
else if (!last_slash)
|
||||
strlcat(path, path_default_slash(), size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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"
|
||||
**/
|
||||
void fill_pathname_dir(char *in_dir, const char *in_basename,
|
||||
const char *replace, size_t size)
|
||||
{
|
||||
const char *base = NULL;
|
||||
|
||||
fill_pathname_slash(in_dir, size);
|
||||
base = path_basename(in_basename);
|
||||
strlcat(in_dir, base, size);
|
||||
strlcat(in_dir, replace, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_pathname_base:
|
||||
* @out : output path
|
||||
* @in_path : input path
|
||||
* @size : size of output path
|
||||
*
|
||||
* Copies basename of @in_path into @out_path.
|
||||
**/
|
||||
void fill_pathname_base(char *out, const char *in_path, size_t size)
|
||||
{
|
||||
const char *ptr = path_basename(in_path);
|
||||
|
||||
if (!ptr)
|
||||
ptr = in_path;
|
||||
|
||||
strlcpy(out, ptr, size);
|
||||
}
|
||||
|
||||
void fill_pathname_base_noext(char *out, const char *in_path, size_t size)
|
||||
{
|
||||
fill_pathname_base(out, in_path, size);
|
||||
path_remove_extension(out);
|
||||
}
|
||||
|
||||
void fill_pathname_base_ext(char *out, const char *in_path, const char *ext,
|
||||
size_t size)
|
||||
{
|
||||
fill_pathname_base_noext(out, in_path, size);
|
||||
strlcat(out, ext, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_pathname_basedir:
|
||||
* @out_dir : output directory
|
||||
* @in_path : input path
|
||||
* @size : size of output directory
|
||||
*
|
||||
* Copies base directory of @in_path into @out_path.
|
||||
* If in_path is a path without any slashes (relative current directory),
|
||||
* @out_path will get path "./".
|
||||
**/
|
||||
void fill_pathname_basedir(char *out_dir,
|
||||
const char *in_path, size_t size)
|
||||
{
|
||||
if (out_dir != in_path)
|
||||
strlcpy(out_dir, in_path, size);
|
||||
path_basedir(out_dir);
|
||||
}
|
||||
|
||||
void fill_pathname_basedir_noext(char *out_dir,
|
||||
const char *in_path, size_t size)
|
||||
{
|
||||
fill_pathname_basedir(out_dir, in_path, size);
|
||||
path_remove_extension(out_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 '/'.
|
||||
**/
|
||||
void fill_pathname_parent_dir(char *out_dir,
|
||||
const char *in_dir, size_t size)
|
||||
{
|
||||
if (out_dir != in_dir)
|
||||
strlcpy(out_dir, in_dir, size);
|
||||
path_parent_dir(out_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}"
|
||||
**/
|
||||
void fill_dated_filename(char *out_filename,
|
||||
const char *ext, size_t size)
|
||||
{
|
||||
time_t cur_time = time(NULL);
|
||||
|
||||
strftime(out_filename, size,
|
||||
"RetroArch-%m%d-%H%M%S.", localtime(&cur_time));
|
||||
strlcat(out_filename, ext, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_str_dated_filename:
|
||||
* @out_filename : output filename
|
||||
* @in_str : input string
|
||||
* @ext : extension of output filename
|
||||
* @size : buffer size of output filename
|
||||
*
|
||||
* Creates a 'dated' filename prefixed by the string @in_str, and
|
||||
* concatenates extension (@ext) to it.
|
||||
*
|
||||
* E.g.:
|
||||
* out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
|
||||
**/
|
||||
void fill_str_dated_filename(char *out_filename,
|
||||
const char *in_str, const char *ext, size_t size)
|
||||
{
|
||||
char format[256];
|
||||
time_t cur_time = time(NULL);
|
||||
|
||||
format[0] = '\0';
|
||||
|
||||
strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", localtime(&cur_time));
|
||||
strlcpy(out_filename, in_str, size);
|
||||
strlcat(out_filename, format, size);
|
||||
strlcat(out_filename, ext, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* path_basedir:
|
||||
* @path : path
|
||||
*
|
||||
* Extracts base directory by mutating path.
|
||||
* Keeps trailing '/'.
|
||||
**/
|
||||
void path_basedir(char *path)
|
||||
{
|
||||
char *last = NULL;
|
||||
if (strlen(path) < 2)
|
||||
return;
|
||||
|
||||
last = find_last_slash(path);
|
||||
|
||||
if (last)
|
||||
last[1] = '\0';
|
||||
else
|
||||
snprintf(path, 3, ".%s", path_default_slash());
|
||||
}
|
||||
|
||||
/**
|
||||
* path_parent_dir:
|
||||
* @path : path
|
||||
*
|
||||
* Extracts parent directory by mutating path.
|
||||
* Assumes that path is a directory. Keeps trailing '/'.
|
||||
**/
|
||||
void path_parent_dir(char *path)
|
||||
{
|
||||
size_t len = strlen(path);
|
||||
if (len && path_char_is_slash(path[len - 1]))
|
||||
path[len - 1] = '\0';
|
||||
path_basedir(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* path_basename:
|
||||
* @path : path
|
||||
*
|
||||
* Get basename from @path.
|
||||
*
|
||||
* Returns: basename from path.
|
||||
**/
|
||||
const char *path_basename(const char *path)
|
||||
{
|
||||
/* We cut either at the first compression-related hash
|
||||
* or the last slash; whichever comes last */
|
||||
const char *last = find_last_slash(path);
|
||||
const char *delim = path_get_archive_delim(path);
|
||||
|
||||
if (delim)
|
||||
return delim + 1;
|
||||
|
||||
if (last)
|
||||
return last + 1;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (path[0] == '/')
|
||||
return true;
|
||||
#ifdef _WIN32
|
||||
/* Many roads lead to Rome ... */
|
||||
if (( strstr(path, "\\\\") == path)
|
||||
|| strstr(path, ":/")
|
||||
|| strstr(path, ":\\")
|
||||
|| strstr(path, ":\\\\"))
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* path_resolve_realpath:
|
||||
* @buf : buffer for path
|
||||
* @size : size of buffer
|
||||
*
|
||||
* Turns relative paths into absolute path.
|
||||
* If relative, rebases on current working dir.
|
||||
**/
|
||||
void path_resolve_realpath(char *buf, size_t size)
|
||||
{
|
||||
#ifndef RARCH_CONSOLE
|
||||
char tmp[PATH_MAX_LENGTH];
|
||||
|
||||
tmp[0] = '\0';
|
||||
|
||||
strlcpy(tmp, buf, sizeof(tmp));
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!_fullpath(buf, tmp, size))
|
||||
strlcpy(buf, tmp, size);
|
||||
#else
|
||||
|
||||
/* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf.
|
||||
* Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways.
|
||||
* POSIX 2008 can automatically allocate for you,
|
||||
* but don't rely on that. */
|
||||
if (!realpath(tmp, buf))
|
||||
strlcpy(buf, tmp, size);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* fill_pathname_resolve_relative:
|
||||
* @out_path : output path
|
||||
* @in_refpath : input reference path
|
||||
* @in_path : input path
|
||||
* @size : size of @out_path
|
||||
*
|
||||
* Joins basedir of @in_refpath together with @in_path.
|
||||
* If @in_path is an absolute path, out_path = in_path.
|
||||
* E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
|
||||
* out_path = "/foo/bar/foobar.cg".
|
||||
**/
|
||||
void fill_pathname_resolve_relative(char *out_path,
|
||||
const char *in_refpath, const char *in_path, size_t size)
|
||||
{
|
||||
if (path_is_absolute(in_path))
|
||||
{
|
||||
strlcpy(out_path, in_path, size);
|
||||
return;
|
||||
}
|
||||
|
||||
fill_pathname_basedir(out_path, in_refpath, size);
|
||||
strlcat(out_path, in_path, 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.
|
||||
**/
|
||||
void fill_pathname_join(char *out_path,
|
||||
const char *dir, const char *path, size_t size)
|
||||
{
|
||||
if (out_path != dir)
|
||||
strlcpy(out_path, dir, size);
|
||||
|
||||
if (*out_path)
|
||||
fill_pathname_slash(out_path, size);
|
||||
|
||||
strlcat(out_path, path, size);
|
||||
}
|
||||
|
||||
void fill_pathname_join_special_ext(char *out_path,
|
||||
const char *dir, const char *path,
|
||||
const char *last, const char *ext,
|
||||
size_t size)
|
||||
{
|
||||
fill_pathname_join(out_path, dir, path, size);
|
||||
if (*out_path)
|
||||
fill_pathname_slash(out_path, size);
|
||||
|
||||
strlcat(out_path, last, size);
|
||||
strlcat(out_path, ext, size);
|
||||
}
|
||||
|
||||
void fill_pathname_join_concat(char *out_path,
|
||||
const char *dir, const char *path,
|
||||
const char *concat,
|
||||
size_t size)
|
||||
{
|
||||
fill_pathname_join(out_path, dir, path, size);
|
||||
strlcat(out_path, concat, size);
|
||||
}
|
||||
|
||||
void fill_pathname_join_noext(char *out_path,
|
||||
const char *dir, const char *path, size_t size)
|
||||
{
|
||||
fill_pathname_join(out_path, dir, path, size);
|
||||
path_remove_extension(out_path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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).
|
||||
**/
|
||||
void fill_pathname_join_delim(char *out_path, const char *dir,
|
||||
const char *path, const char delim, size_t size)
|
||||
{
|
||||
size_t copied = strlcpy(out_path, dir, size);
|
||||
|
||||
out_path[copied] = delim;
|
||||
out_path[copied+1] = '\0';
|
||||
|
||||
strlcat(out_path, path, size);
|
||||
}
|
||||
|
||||
void fill_pathname_join_delim_concat(char *out_path, const char *dir,
|
||||
const char *path, const char delim, const char *concat,
|
||||
size_t size)
|
||||
{
|
||||
fill_pathname_join_delim(out_path, dir, path, delim, size);
|
||||
strlcat(out_path, concat, 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
|
||||
*/
|
||||
void fill_short_pathname_representation(char* out_rep,
|
||||
const char *in_path, size_t size)
|
||||
{
|
||||
char path_short[PATH_MAX_LENGTH];
|
||||
|
||||
path_short[0] = '\0';
|
||||
|
||||
fill_pathname(path_short, path_basename(in_path), "",
|
||||
sizeof(path_short));
|
||||
|
||||
strlcpy(out_rep, path_short, size);
|
||||
}
|
||||
|
||||
void fill_short_pathname_representation_noext(char* out_rep,
|
||||
const char *in_path, size_t size)
|
||||
{
|
||||
fill_short_pathname_representation(out_rep, in_path, size);
|
||||
path_remove_extension(out_rep);
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <file/nbio.h>
|
||||
|
||||
struct nbio_t
|
||||
{
|
||||
FILE* f;
|
||||
void* data;
|
||||
size_t progress;
|
||||
size_t len;
|
||||
/*
|
||||
* possible values:
|
||||
* NBIO_READ, NBIO_WRITE - obvious
|
||||
* -1 - currently doing nothing
|
||||
* -2 - the pointer was reallocated since the last operation
|
||||
*/
|
||||
signed char op;
|
||||
signed char mode;
|
||||
};
|
||||
|
||||
static const char * modes[]={ "rb", "wb", "r+b", "rb", "wb", "r+b" };
|
||||
|
||||
struct nbio_t* nbio_open(const char * filename, unsigned mode)
|
||||
{
|
||||
void *buf = NULL;
|
||||
struct nbio_t* handle = NULL;
|
||||
size_t len = 0;
|
||||
FILE* f = fopen(filename, modes[mode]);
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
handle = (struct nbio_t*)malloc(sizeof(struct nbio_t));
|
||||
|
||||
if (!handle)
|
||||
goto error;
|
||||
|
||||
handle->f = f;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case NBIO_WRITE:
|
||||
case BIO_WRITE:
|
||||
break;
|
||||
default:
|
||||
fseek(handle->f, 0, SEEK_END);
|
||||
len = ftell(handle->f);
|
||||
break;
|
||||
}
|
||||
|
||||
handle->mode = mode;
|
||||
|
||||
if (len)
|
||||
buf = malloc(len);
|
||||
|
||||
if (!buf)
|
||||
goto error;
|
||||
|
||||
handle->data = buf;
|
||||
handle->len = len;
|
||||
handle->progress = handle->len;
|
||||
handle->op = -2;
|
||||
|
||||
return handle;
|
||||
|
||||
error:
|
||||
if (handle)
|
||||
free(handle);
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nbio_begin_read(struct nbio_t* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
puts("ERROR - attempted file read operation while busy");
|
||||
abort();
|
||||
}
|
||||
|
||||
fseek(handle->f, 0, SEEK_SET);
|
||||
|
||||
handle->op = NBIO_READ;
|
||||
handle->progress = 0;
|
||||
}
|
||||
|
||||
void nbio_begin_write(struct nbio_t* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
puts("ERROR - attempted file write operation while busy");
|
||||
abort();
|
||||
}
|
||||
|
||||
fseek(handle->f, 0, SEEK_SET);
|
||||
handle->op = NBIO_WRITE;
|
||||
handle->progress = 0;
|
||||
}
|
||||
|
||||
bool nbio_iterate(struct nbio_t* handle)
|
||||
{
|
||||
size_t amount = 65536;
|
||||
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
if (amount > handle->len - handle->progress)
|
||||
amount = handle->len - handle->progress;
|
||||
|
||||
switch (handle->op)
|
||||
{
|
||||
case NBIO_READ:
|
||||
if (handle->mode == BIO_READ)
|
||||
{
|
||||
amount = handle->len;
|
||||
fread((char*)handle->data, 1, amount, handle->f);
|
||||
}
|
||||
else
|
||||
fread((char*)handle->data + handle->progress, 1, amount, handle->f);
|
||||
break;
|
||||
case NBIO_WRITE:
|
||||
if (handle->mode == BIO_WRITE)
|
||||
{
|
||||
size_t written = 0;
|
||||
amount = handle->len;
|
||||
written = fwrite((char*)handle->data, 1, amount, handle->f);
|
||||
if (written != amount)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
fwrite((char*)handle->data + handle->progress, 1, amount, handle->f);
|
||||
break;
|
||||
}
|
||||
|
||||
handle->progress += amount;
|
||||
|
||||
if (handle->progress == handle->len)
|
||||
handle->op = -1;
|
||||
return (handle->op < 0);
|
||||
}
|
||||
|
||||
void nbio_resize(struct nbio_t* handle, size_t len)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
puts("ERROR - attempted file resize operation while busy");
|
||||
abort();
|
||||
}
|
||||
if (len < handle->len)
|
||||
{
|
||||
puts("ERROR - attempted file shrink operation, not implemented");
|
||||
abort();
|
||||
}
|
||||
|
||||
handle->len = len;
|
||||
handle->data = realloc(handle->data, handle->len);
|
||||
handle->op = -1;
|
||||
handle->progress = handle->len;
|
||||
}
|
||||
|
||||
void* nbio_get_ptr(struct nbio_t* handle, size_t* len)
|
||||
{
|
||||
if (!handle)
|
||||
return NULL;
|
||||
if (len)
|
||||
*len = handle->len;
|
||||
if (handle->op == -1)
|
||||
return handle->data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nbio_cancel(struct nbio_t* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
handle->op = -1;
|
||||
handle->progress = handle->len;
|
||||
}
|
||||
|
||||
void nbio_free(struct nbio_t* handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
if (handle->op >= 0)
|
||||
{
|
||||
puts("ERROR - attempted free() while busy");
|
||||
abort();
|
||||
}
|
||||
fclose(handle->f);
|
||||
free(handle->data);
|
||||
|
||||
handle->f = NULL;
|
||||
handle->data = NULL;
|
||||
free(handle);
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_dirent.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_common.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <retro_dirent.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# ifdef _MSC_VER
|
||||
# define setmode _setmode
|
||||
# endif
|
||||
#include <sys/stat.h>
|
||||
# ifdef _XBOX
|
||||
# include <xtl.h>
|
||||
# define INVALID_FILE_ATTRIBUTES -1
|
||||
# else
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
# include <direct.h>
|
||||
# include <windows.h>
|
||||
# endif
|
||||
#elif defined(VITA)
|
||||
# include <psp2/io/fcntl.h>
|
||||
# include <psp2/io/dirent.h>
|
||||
#include <psp2/io/stat.h>
|
||||
#else
|
||||
# if defined(PSP)
|
||||
# include <pspiofilemgr.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <dirent.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <cell/cell_fs.h>
|
||||
#endif
|
||||
|
||||
#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
|
||||
#include <unistd.h> /* stat() is defined here */
|
||||
#endif
|
||||
|
||||
struct RDIR
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
WIN32_FIND_DATA entry;
|
||||
HANDLE directory;
|
||||
bool next;
|
||||
char path[PATH_MAX_LENGTH];
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
SceUID directory;
|
||||
SceIoDirent entry;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsErrno error;
|
||||
int directory;
|
||||
CellFsDirent entry;
|
||||
#else
|
||||
DIR *directory;
|
||||
const struct dirent *entry;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct RDIR *retro_opendir(const char *name)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
char path_buf[1024];
|
||||
#endif
|
||||
struct RDIR *rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
|
||||
|
||||
if (!rdir)
|
||||
return NULL;
|
||||
|
||||
#if defined(_WIN32)
|
||||
path_buf[0] = '\0';
|
||||
snprintf(path_buf, sizeof(path_buf), "%s\\*", name);
|
||||
rdir->directory = FindFirstFile(path_buf, &rdir->entry);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
rdir->directory = sceIoDopen(name);
|
||||
#elif defined(_3DS)
|
||||
rdir->directory = (name && *name)? opendir(name) : NULL;
|
||||
rdir->entry = NULL;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
rdir->error = cellFsOpendir(name, &rdir->directory);
|
||||
#else
|
||||
rdir->directory = opendir(name);
|
||||
rdir->entry = NULL;
|
||||
#endif
|
||||
|
||||
return rdir;
|
||||
}
|
||||
|
||||
bool retro_dirent_error(struct RDIR *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return (rdir->directory == INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
return (rdir->directory < 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
return (rdir->error != CELL_FS_SUCCEEDED);
|
||||
#else
|
||||
return !(rdir->directory);
|
||||
#endif
|
||||
}
|
||||
|
||||
int retro_readdir(struct RDIR *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if(rdir->next)
|
||||
return (FindNextFile(rdir->directory, &rdir->entry) != 0);
|
||||
|
||||
rdir->next = true;
|
||||
return (rdir->directory != INVALID_HANDLE_VALUE);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
return (sceIoDread(rdir->directory, &rdir->entry) > 0);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
uint64_t nread;
|
||||
rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
|
||||
return (nread != 0);
|
||||
#else
|
||||
return ((rdir->entry = readdir(rdir->directory)) != NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *retro_dirent_get_name(struct RDIR *rdir)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return rdir->entry.cFileName;
|
||||
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
|
||||
return rdir->entry.d_name;
|
||||
#else
|
||||
return rdir->entry->d_name;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* retro_dirent_is_dir:
|
||||
* @rdir : pointer to the directory entry.
|
||||
* @path : path to the directory entry.
|
||||
*
|
||||
* Is the directory listing entry a directory?
|
||||
*
|
||||
* Returns: true if directory listing entry is
|
||||
* a directory, false if not.
|
||||
*/
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *path)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
|
||||
return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
const SceIoDirent *entry = (const SceIoDirent*)&rdir->entry;
|
||||
#if defined(PSP)
|
||||
return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
|
||||
#elif defined(VITA)
|
||||
return SCE_S_ISDIR(entry->d_stat.st_mode);
|
||||
#endif
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
CellFsDirent *entry = (CellFsDirent*)&rdir->entry;
|
||||
return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
|
||||
#else
|
||||
struct stat buf;
|
||||
#if defined(DT_DIR)
|
||||
const struct dirent *entry = (const struct dirent*)rdir->entry;
|
||||
if (entry->d_type == DT_DIR)
|
||||
return true;
|
||||
/* This can happen on certain file systems. */
|
||||
if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
|
||||
return false;
|
||||
#endif
|
||||
/* dirent struct doesn't have d_type, do it the slow way ... */
|
||||
if (stat(path, &buf) < 0)
|
||||
return false;
|
||||
return S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void retro_dirent_include_hidden(struct RDIR *rdir, bool include_hidden)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (include_hidden)
|
||||
rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
else
|
||||
rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
|
||||
#endif
|
||||
}
|
||||
|
||||
void retro_closedir(struct RDIR *rdir)
|
||||
{
|
||||
if (!rdir)
|
||||
return;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (rdir->directory != INVALID_HANDLE_VALUE)
|
||||
FindClose(rdir->directory);
|
||||
#elif defined(VITA) || defined(PSP)
|
||||
sceIoDclose(rdir->directory);
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
rdir->error = cellFsClosedir(rdir->directory);
|
||||
#else
|
||||
if (rdir->directory)
|
||||
closedir(rdir->directory);
|
||||
#endif
|
||||
|
||||
free(rdir);
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 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) && !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
|
||||
@@ -1,84 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (apple_compat.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __APPLE_COMPAT_H
|
||||
#define __APPLE_COMPAT_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4)
|
||||
typedef int NSInteger;
|
||||
typedef unsigned NSUInteger;
|
||||
typedef float CGFloat;
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
/* Compatibility with non-Clang compilers. */
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef CF_RETURNS_RETAINED
|
||||
#if __has_feature(attribute_cf_returns_retained)
|
||||
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
|
||||
#else
|
||||
#define CF_RETURNS_RETAINED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NS_INLINE
|
||||
#define NS_INLINE inline
|
||||
#endif
|
||||
|
||||
NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)
|
||||
{
|
||||
#if __has_feature(objc_arc)
|
||||
return (__bridge_retained CFTypeRef)X;
|
||||
#else
|
||||
return X;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef IOS
|
||||
#ifndef __IPHONE_5_0
|
||||
#warning "This project uses features only available in iOS SDK 5.0 and later."
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <GLKit/GLKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __OBJC__
|
||||
#include <objc/objc-runtime.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fnmatch.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_FNMATCH_H__
|
||||
#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__
|
||||
|
||||
#define FNM_NOMATCH 1
|
||||
|
||||
int rl_fnmatch(const char *pattern, const char *string, int flags);
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (getopt.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_GETOPT_H
|
||||
#define __LIBRETRO_SDK_COMPAT_GETOPT_H
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
/* Custom implementation of the GNU getopt_long for portability.
|
||||
* Not designed to be fully compatible, but compatible with
|
||||
* the features RetroArch uses. */
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
#include <getopt.h>
|
||||
#else
|
||||
/* Avoid possible naming collisions during link since we
|
||||
* prefer to use the actual name. */
|
||||
#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
struct option
|
||||
{
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* argv[] is declared with char * const argv[] in GNU,
|
||||
* but this makes no sense, as non-POSIX getopt_long
|
||||
* mutates argv (non-opts are moved to the end). */
|
||||
int getopt_long(int argc, char *argv[],
|
||||
const char *optstring, const struct option *longopts, int *longindex);
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
/* If these are variously #defined, then we have bigger problems */
|
||||
#ifndef no_argument
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
#endif
|
||||
|
||||
/* HAVE_GETOPT_LONG */
|
||||
#endif
|
||||
|
||||
/* pragma once */
|
||||
#endif
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1999
|
||||
* Berkeley Software Design, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
|
||||
*/
|
||||
|
||||
#ifndef _IFADDRS_H_
|
||||
#define _IFADDRS_H_
|
||||
|
||||
struct ifaddrs
|
||||
{
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
|
||||
* to be included it must be included before this header file.
|
||||
*/
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
extern int getifaddrs(struct ifaddrs **ifap);
|
||||
extern void freeifaddrs(struct ifaddrs *ifa);
|
||||
|
||||
#endif
|
||||
@@ -1,85 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (intrinsics.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_INTRINSICS_H
|
||||
#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#if (_MSC_VER > 1310)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* Count Leading Zero, unsigned 16bit input value */
|
||||
static INLINE unsigned compat_clz_u16(uint16_t val)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
return __builtin_clz(val << 16 | 0x8000);
|
||||
#else
|
||||
unsigned ret = 0;
|
||||
|
||||
while(!(val & 0x8000) && ret < 16)
|
||||
{
|
||||
val <<= 1;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Count Trailing Zero */
|
||||
static INLINE int compat_ctz(unsigned x)
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(RARCH_CONSOLE)
|
||||
return __builtin_ctz(x);
|
||||
#elif _MSC_VER >= 1400 && !defined(_XBOX)
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse((unsigned long*)&r, x);
|
||||
return (int)r;
|
||||
#else
|
||||
/* Only checks at nibble granularity,
|
||||
* because that's what we need. */
|
||||
if (x & 0x000f)
|
||||
return 0;
|
||||
if (x & 0x00f0)
|
||||
return 4;
|
||||
if (x & 0x0f00)
|
||||
return 8;
|
||||
if (x & 0xf000)
|
||||
return 12;
|
||||
return 16;
|
||||
#endif
|
||||
}
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,132 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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 in a cross-platform manner. */
|
||||
#if _MSC_VER < 1900
|
||||
#include <stdlib.h>
|
||||
#ifndef snprintf
|
||||
#define snprintf c99_snprintf_retro__
|
||||
#endif
|
||||
|
||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
||||
#endif
|
||||
|
||||
/* Pre-MSVC 2010 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
|
||||
#if _MSC_VER < 1600
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#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>
|
||||
#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 <= 1200
|
||||
#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))
|
||||
#endif
|
||||
|
||||
#ifndef _vscprintf
|
||||
#define _vscprintf c89_vscprintf_retro__
|
||||
int c89_vscprintf_retro__(const char *format, va_list pargs);
|
||||
#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
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/* ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
* Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
*
|
||||
* Copyright (c) 2006-2008 Alexander Chemeris
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_STDINT_H
|
||||
#define __RARCH_STDINT_H
|
||||
|
||||
#if _MSC_VER && (_MSC_VER < 1600)
|
||||
/* Pre-MSVC 2010 needs an implementation of stdint.h. */
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
* compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
* or compiler give many errors like this:
|
||||
*
|
||||
* error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#if _MSC_VER <= 1200
|
||||
extern "C++" {
|
||||
#else
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Define _W64 macros to mark types changing their size, like intptr_t. */
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* 7.18.1 Integer types. */
|
||||
|
||||
/* 7.18.1.1 Exact-width integer types. */
|
||||
|
||||
/* Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
* realize that, e.g. char has the same size as __int8
|
||||
* so we give up on __intX for them.
|
||||
*/
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
/* 7.18.1.2 Minimum-width integer types. */
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
/* 7.18.1.3 Fastest minimum-width integer types. */
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
/* 7.18.1.4 Integer types capable of holding object pointers. */
|
||||
#ifdef _WIN64 /* [ */
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else /* _WIN64 ][ */
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif /* _WIN64 ] */
|
||||
|
||||
/* 7.18.1.5 Greatest-width integer types. */
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
/* 7.18.2 Limits of specified-width integer types. */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
|
||||
/* [ See footnote 220 at page 257 and footnote 221 at page 259. */
|
||||
|
||||
/* 7.18.2.1 Limits of exact-width integer types. */
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
/* 7.18.2.2 Limits of minimum-width integer types. */
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.2.3 Limits of fastest minimum-width integer types. */
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.2.4 Limits of integer types capable of holding object pointers. */
|
||||
#ifdef _WIN64 /* [ */
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else /* _WIN64 ][ */
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif /* _WIN64 ] */
|
||||
|
||||
/* 7.18.2.5 Limits of greatest-width integer types */
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.3 Limits of other integer types */
|
||||
|
||||
#ifdef _WIN64 /* [ */
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else /* _WIN64 ][ */
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif /* _WIN64 ] */
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX /* [ */
|
||||
# ifdef _WIN64 /* [ */
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else /* _WIN64 ][ */
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif /* _WIN64 ] */
|
||||
#endif /* SIZE_MAX ] */
|
||||
|
||||
/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */
|
||||
#ifndef WCHAR_MIN /* [ */
|
||||
# define WCHAR_MIN 0
|
||||
#endif /* WCHAR_MIN ] */
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif /* WCHAR_MAX ] */
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif /* __STDC_LIMIT_MACROS ] */
|
||||
|
||||
/* 7.18.4 Limits of other integer types */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
|
||||
/* [ See footnote 224 at page 260 */
|
||||
|
||||
/* 7.18.4.1 Macros for minimum-width integer constants */
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
/* 7.18.4.2 Macros for greatest-width integer constants */
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
|
||||
#endif
|
||||
/* __STDC_CONSTANT_MACROS ] */
|
||||
|
||||
#else
|
||||
/* Sanity for everything else. */
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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
|
||||
@@ -1,49 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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>
|
||||
|
||||
#ifdef 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
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,483 +0,0 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2013 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
* Even better than compiling with -DZ_PREFIX would be to use configure to set
|
||||
* this permanently in zconf.h using "./configure --zprefix".
|
||||
*/
|
||||
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
|
||||
# define Z_PREFIX_SET
|
||||
|
||||
/* all linked symbols */
|
||||
# define _dist_code z__dist_code
|
||||
# define _length_code z__length_code
|
||||
# define _tr_align z__tr_align
|
||||
# define _tr_flush_bits z__tr_flush_bits
|
||||
# define _tr_flush_block z__tr_flush_block
|
||||
# define _tr_init z__tr_init
|
||||
# define _tr_stored_block z__tr_stored_block
|
||||
# define _tr_tally z__tr_tally
|
||||
# define adler32 z_adler32
|
||||
# define adler32_combine z_adler32_combine
|
||||
# define adler32_combine64 z_adler32_combine64
|
||||
# ifndef Z_SOLO
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compressBound z_compressBound
|
||||
# endif
|
||||
# define crc32 z_crc32
|
||||
# define crc32_combine z_crc32_combine
|
||||
# define crc32_combine64 z_crc32_combine64
|
||||
# define deflate z_deflate
|
||||
# define deflateBound z_deflateBound
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define deflateInit2_ z_deflateInit2_
|
||||
# define deflateInit_ z_deflateInit_
|
||||
# define deflateParams z_deflateParams
|
||||
# define deflatePending z_deflatePending
|
||||
# define deflatePrime z_deflatePrime
|
||||
# define deflateReset z_deflateReset
|
||||
# define deflateResetKeep z_deflateResetKeep
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateSetHeader z_deflateSetHeader
|
||||
# define deflateTune z_deflateTune
|
||||
# define deflate_copyright z_deflate_copyright
|
||||
# define get_crc_table z_get_crc_table
|
||||
# ifndef Z_SOLO
|
||||
# define gz_error z_gz_error
|
||||
# define gz_intmax z_gz_intmax
|
||||
# define gz_strwinerror z_gz_strwinerror
|
||||
# define gzbuffer z_gzbuffer
|
||||
# define gzclearerr z_gzclearerr
|
||||
# define gzclose z_gzclose
|
||||
# define gzclose_r z_gzclose_r
|
||||
# define gzclose_w z_gzclose_w
|
||||
# define gzdirect z_gzdirect
|
||||
# define gzdopen z_gzdopen
|
||||
# define gzeof z_gzeof
|
||||
# define gzerror z_gzerror
|
||||
# define gzflush z_gzflush
|
||||
# define gzgetc z_gzgetc
|
||||
# define gzgetc_ z_gzgetc_
|
||||
# define gzgets z_gzgets
|
||||
# define gzoffset z_gzoffset
|
||||
# define gzoffset64 z_gzoffset64
|
||||
# define gzopen z_gzopen
|
||||
# define gzopen64 z_gzopen64
|
||||
# ifdef _WIN32
|
||||
# define gzopen_w z_gzopen_w
|
||||
# endif
|
||||
# define gzprintf z_gzprintf
|
||||
# define gzvprintf z_gzvprintf
|
||||
# define gzputc z_gzputc
|
||||
# define gzputs z_gzputs
|
||||
# define gzread z_gzread
|
||||
# define gzrewind z_gzrewind
|
||||
# define gzseek z_gzseek
|
||||
# define gzseek64 z_gzseek64
|
||||
# define gzsetparams z_gzsetparams
|
||||
# define gztell z_gztell
|
||||
# define gztell64 z_gztell64
|
||||
# define gzungetc z_gzungetc
|
||||
# define gzwrite z_gzwrite
|
||||
# endif
|
||||
# define inflate z_inflate
|
||||
# define inflateBack z_inflateBack
|
||||
# define inflateBackEnd z_inflateBackEnd
|
||||
# define inflateBackInit_ z_inflateBackInit_
|
||||
# define inflateCopy z_inflateCopy
|
||||
# define inflateEnd z_inflateEnd
|
||||
# define inflateGetHeader z_inflateGetHeader
|
||||
# define inflateInit2_ z_inflateInit2_
|
||||
# define inflateInit_ z_inflateInit_
|
||||
# define inflateMark z_inflateMark
|
||||
# define inflatePrime z_inflatePrime
|
||||
# define inflateReset z_inflateReset
|
||||
# define inflateReset2 z_inflateReset2
|
||||
# define inflateSetDictionary z_inflateSetDictionary
|
||||
# define inflateGetDictionary z_inflateGetDictionary
|
||||
# define inflateSync z_inflateSync
|
||||
# define inflateSyncPoint z_inflateSyncPoint
|
||||
# define inflateUndermine z_inflateUndermine
|
||||
# define inflateResetKeep z_inflateResetKeep
|
||||
# define inflate_copyright z_inflate_copyright
|
||||
# define inflate_fast z_inflate_fast
|
||||
# define inflate_table z_inflate_table
|
||||
# ifndef Z_SOLO
|
||||
# define uncompress z_uncompress
|
||||
# endif
|
||||
# define zError z_zError
|
||||
# ifndef Z_SOLO
|
||||
# define zcalloc z_zcalloc
|
||||
# define zcfree z_zcfree
|
||||
# endif
|
||||
# define zlibCompileFlags z_zlibCompileFlags
|
||||
# define zlibVersion z_zlibVersion
|
||||
|
||||
/* all zlib typedefs in zlib.h and zconf.h */
|
||||
# define Byte z_Byte
|
||||
# define Bytef z_Bytef
|
||||
# define alloc_func z_alloc_func
|
||||
# define charf z_charf
|
||||
# define free_func z_free_func
|
||||
# ifndef Z_SOLO
|
||||
# define gzFile z_gzFile
|
||||
# endif
|
||||
# define gz_header z_gz_header
|
||||
# define gz_headerp z_gz_headerp
|
||||
# define in_func z_in_func
|
||||
# define intf z_intf
|
||||
# define out_func z_out_func
|
||||
# define uInt z_uInt
|
||||
# define uIntf z_uIntf
|
||||
# define uLong z_uLong
|
||||
# define uLongf z_uLongf
|
||||
# define voidp z_voidp
|
||||
# define voidpc z_voidpc
|
||||
# define voidpf z_voidpf
|
||||
|
||||
/* all zlib structs in zlib.h and zconf.h */
|
||||
# define gz_header_s z_gz_header_s
|
||||
# define internal_state z_internal_state
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
# define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
# define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
|
||||
# ifndef WIN32
|
||||
# define WIN32
|
||||
# endif
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
# ifndef SYS16BIT
|
||||
# define SYS16BIT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
# define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
# ifndef STDC
|
||||
# define STDC
|
||||
# endif
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# ifndef STDC99
|
||||
# define STDC99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
# define const /* note: need a more gentle solution here */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
# define z_const const
|
||||
#else
|
||||
# define z_const
|
||||
#endif
|
||||
|
||||
/* Some Mac compilers merge all .h files incorrectly: */
|
||||
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
|
||||
# define NO_DUMMY_DECL
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
# ifdef MAXSEG_64K
|
||||
# define MAX_MEM_LEVEL 8
|
||||
# else
|
||||
# define MAX_MEM_LEVEL 9
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
# ifdef STDC
|
||||
# define OF(args) args
|
||||
# else
|
||||
# define OF(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef Z_ARG /* function prototypes for stdarg */
|
||||
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# define Z_ARG(args) args
|
||||
# else
|
||||
# define Z_ARG(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef _MSC_VER
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef __BORLANDC__
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
# ifdef ZLIB_DLL
|
||||
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXTERN extern __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXTERN extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
# ifdef ZLIB_WINAPI
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
# include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
# define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
|
||||
# include <limits.h>
|
||||
# if (UINT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned
|
||||
# elif (ULONG_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned long
|
||||
# elif (USHRT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned short
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
#ifdef STDC
|
||||
# ifndef Z_SOLO
|
||||
# include <sys/types.h> /* for off_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# ifndef Z_SOLO
|
||||
# include <stdarg.h> /* for va_list */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef Z_SOLO
|
||||
# include <stddef.h> /* for wchar_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
|
||||
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
|
||||
* though the former does not conform to the LFS document), but considering
|
||||
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
|
||||
* equivalently requesting no 64-bit operations
|
||||
*/
|
||||
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
|
||||
# undef _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef Z_SOLO
|
||||
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
||||
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||
# ifdef VMS
|
||||
# include <unixio.h> /* for off_t */
|
||||
# endif
|
||||
# ifndef z_off_t
|
||||
# define z_off_t off_t
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
|
||||
# define Z_LFS64
|
||||
#endif
|
||||
|
||||
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
|
||||
# define Z_LARGE64
|
||||
#endif
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
|
||||
# define Z_WANT64
|
||||
#endif
|
||||
|
||||
#if !defined(SEEK_SET) && !defined(Z_SOLO)
|
||||
# define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
# define SEEK_CUR 1 /* Seek from current position. */
|
||||
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
#pragma map(deflateInit_,"DEIN")
|
||||
#pragma map(deflateInit2_,"DEIN2")
|
||||
#pragma map(deflateEnd,"DEEND")
|
||||
#pragma map(deflateBound,"DEBND")
|
||||
#pragma map(inflateInit_,"ININ")
|
||||
#pragma map(inflateInit2_,"ININ2")
|
||||
#pragma map(inflateEnd,"INEND")
|
||||
#pragma map(inflateSync,"INSY")
|
||||
#pragma map(inflateSetDictionary,"INSEDI")
|
||||
#pragma map(compressBound,"CMBND")
|
||||
#pragma map(inflate_table,"INTABL")
|
||||
#pragma map(inflate_fast,"INFA")
|
||||
#pragma map(inflate_copyright,"INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
@@ -1,483 +0,0 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2013 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
* Even better than compiling with -DZ_PREFIX would be to use configure to set
|
||||
* this permanently in zconf.h using "./configure --zprefix".
|
||||
*/
|
||||
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
|
||||
# define Z_PREFIX_SET
|
||||
|
||||
/* all linked symbols */
|
||||
# define _dist_code z__dist_code
|
||||
# define _length_code z__length_code
|
||||
# define _tr_align z__tr_align
|
||||
# define _tr_flush_bits z__tr_flush_bits
|
||||
# define _tr_flush_block z__tr_flush_block
|
||||
# define _tr_init z__tr_init
|
||||
# define _tr_stored_block z__tr_stored_block
|
||||
# define _tr_tally z__tr_tally
|
||||
# define adler32 z_adler32
|
||||
# define adler32_combine z_adler32_combine
|
||||
# define adler32_combine64 z_adler32_combine64
|
||||
# ifndef Z_SOLO
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compressBound z_compressBound
|
||||
# endif
|
||||
# define crc32 z_crc32
|
||||
# define crc32_combine z_crc32_combine
|
||||
# define crc32_combine64 z_crc32_combine64
|
||||
# define deflate z_deflate
|
||||
# define deflateBound z_deflateBound
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define deflateInit2_ z_deflateInit2_
|
||||
# define deflateInit_ z_deflateInit_
|
||||
# define deflateParams z_deflateParams
|
||||
# define deflatePending z_deflatePending
|
||||
# define deflatePrime z_deflatePrime
|
||||
# define deflateReset z_deflateReset
|
||||
# define deflateResetKeep z_deflateResetKeep
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateSetHeader z_deflateSetHeader
|
||||
# define deflateTune z_deflateTune
|
||||
# define deflate_copyright z_deflate_copyright
|
||||
# define get_crc_table z_get_crc_table
|
||||
# ifndef Z_SOLO
|
||||
# define gz_error z_gz_error
|
||||
# define gz_intmax z_gz_intmax
|
||||
# define gz_strwinerror z_gz_strwinerror
|
||||
# define gzbuffer z_gzbuffer
|
||||
# define gzclearerr z_gzclearerr
|
||||
# define gzclose z_gzclose
|
||||
# define gzclose_r z_gzclose_r
|
||||
# define gzclose_w z_gzclose_w
|
||||
# define gzdirect z_gzdirect
|
||||
# define gzdopen z_gzdopen
|
||||
# define gzeof z_gzeof
|
||||
# define gzerror z_gzerror
|
||||
# define gzflush z_gzflush
|
||||
# define gzgetc z_gzgetc
|
||||
# define gzgetc_ z_gzgetc_
|
||||
# define gzgets z_gzgets
|
||||
# define gzoffset z_gzoffset
|
||||
# define gzoffset64 z_gzoffset64
|
||||
# define gzopen z_gzopen
|
||||
# define gzopen64 z_gzopen64
|
||||
# ifdef _WIN32
|
||||
# define gzopen_w z_gzopen_w
|
||||
# endif
|
||||
# define gzprintf z_gzprintf
|
||||
# define gzvprintf z_gzvprintf
|
||||
# define gzputc z_gzputc
|
||||
# define gzputs z_gzputs
|
||||
# define gzread z_gzread
|
||||
# define gzrewind z_gzrewind
|
||||
# define gzseek z_gzseek
|
||||
# define gzseek64 z_gzseek64
|
||||
# define gzsetparams z_gzsetparams
|
||||
# define gztell z_gztell
|
||||
# define gztell64 z_gztell64
|
||||
# define gzungetc z_gzungetc
|
||||
# define gzwrite z_gzwrite
|
||||
# endif
|
||||
# define inflate z_inflate
|
||||
# define inflateBack z_inflateBack
|
||||
# define inflateBackEnd z_inflateBackEnd
|
||||
# define inflateBackInit_ z_inflateBackInit_
|
||||
# define inflateCopy z_inflateCopy
|
||||
# define inflateEnd z_inflateEnd
|
||||
# define inflateGetHeader z_inflateGetHeader
|
||||
# define inflateInit2_ z_inflateInit2_
|
||||
# define inflateInit_ z_inflateInit_
|
||||
# define inflateMark z_inflateMark
|
||||
# define inflatePrime z_inflatePrime
|
||||
# define inflateReset z_inflateReset
|
||||
# define inflateReset2 z_inflateReset2
|
||||
# define inflateSetDictionary z_inflateSetDictionary
|
||||
# define inflateGetDictionary z_inflateGetDictionary
|
||||
# define inflateSync z_inflateSync
|
||||
# define inflateSyncPoint z_inflateSyncPoint
|
||||
# define inflateUndermine z_inflateUndermine
|
||||
# define inflateResetKeep z_inflateResetKeep
|
||||
# define inflate_copyright z_inflate_copyright
|
||||
# define inflate_fast z_inflate_fast
|
||||
# define inflate_table z_inflate_table
|
||||
# ifndef Z_SOLO
|
||||
# define uncompress z_uncompress
|
||||
# endif
|
||||
# define zError z_zError
|
||||
# ifndef Z_SOLO
|
||||
# define zcalloc z_zcalloc
|
||||
# define zcfree z_zcfree
|
||||
# endif
|
||||
# define zlibCompileFlags z_zlibCompileFlags
|
||||
# define zlibVersion z_zlibVersion
|
||||
|
||||
/* all zlib typedefs in zlib.h and zconf.h */
|
||||
# define Byte z_Byte
|
||||
# define Bytef z_Bytef
|
||||
# define alloc_func z_alloc_func
|
||||
# define charf z_charf
|
||||
# define free_func z_free_func
|
||||
# ifndef Z_SOLO
|
||||
# define gzFile z_gzFile
|
||||
# endif
|
||||
# define gz_header z_gz_header
|
||||
# define gz_headerp z_gz_headerp
|
||||
# define in_func z_in_func
|
||||
# define intf z_intf
|
||||
# define out_func z_out_func
|
||||
# define uInt z_uInt
|
||||
# define uIntf z_uIntf
|
||||
# define uLong z_uLong
|
||||
# define uLongf z_uLongf
|
||||
# define voidp z_voidp
|
||||
# define voidpc z_voidpc
|
||||
# define voidpf z_voidpf
|
||||
|
||||
/* all zlib structs in zlib.h and zconf.h */
|
||||
# define gz_header_s z_gz_header_s
|
||||
# define internal_state z_internal_state
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
# define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
# define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
|
||||
# ifndef WIN32
|
||||
# define WIN32
|
||||
# endif
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
# ifndef SYS16BIT
|
||||
# define SYS16BIT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
# define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
# ifndef STDC
|
||||
# define STDC
|
||||
# endif
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# ifndef STDC99
|
||||
# define STDC99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
# define const /* note: need a more gentle solution here */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
# define z_const const
|
||||
#else
|
||||
# define z_const
|
||||
#endif
|
||||
|
||||
/* Some Mac compilers merge all .h files incorrectly: */
|
||||
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
|
||||
# define NO_DUMMY_DECL
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
# ifdef MAXSEG_64K
|
||||
# define MAX_MEM_LEVEL 8
|
||||
# else
|
||||
# define MAX_MEM_LEVEL 9
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
# ifdef STDC
|
||||
# define OF(args) args
|
||||
# else
|
||||
# define OF(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef Z_ARG /* function prototypes for stdarg */
|
||||
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# define Z_ARG(args) args
|
||||
# else
|
||||
# define Z_ARG(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef _MSC_VER
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef __BORLANDC__
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
# ifdef ZLIB_DLL
|
||||
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXTERN extern __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXTERN extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
# ifdef ZLIB_WINAPI
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
# include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
# define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
|
||||
# include <limits.h>
|
||||
# if (UINT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned
|
||||
# elif (ULONG_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned long
|
||||
# elif (USHRT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned short
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
#ifdef STDC
|
||||
# ifndef Z_SOLO
|
||||
# include <sys/types.h> /* for off_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# ifndef Z_SOLO
|
||||
# include <stdarg.h> /* for va_list */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef Z_SOLO
|
||||
# include <stddef.h> /* for wchar_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
|
||||
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
|
||||
* though the former does not conform to the LFS document), but considering
|
||||
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
|
||||
* equivalently requesting no 64-bit operations
|
||||
*/
|
||||
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
|
||||
# undef _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef Z_SOLO
|
||||
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
||||
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||
# ifdef VMS
|
||||
# include <unixio.h> /* for off_t */
|
||||
# endif
|
||||
# ifndef z_off_t
|
||||
# define z_off_t off_t
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
|
||||
# define Z_LFS64
|
||||
#endif
|
||||
|
||||
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
|
||||
# define Z_LARGE64
|
||||
#endif
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
|
||||
# define Z_WANT64
|
||||
#endif
|
||||
|
||||
#if !defined(SEEK_SET) && !defined(Z_SOLO)
|
||||
# define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
# define SEEK_CUR 1 /* Seek from current position. */
|
||||
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
#pragma map(deflateInit_,"DEIN")
|
||||
#pragma map(deflateInit2_,"DEIN2")
|
||||
#pragma map(deflateEnd,"DEEND")
|
||||
#pragma map(deflateBound,"DEBND")
|
||||
#pragma map(inflateInit_,"ININ")
|
||||
#pragma map(inflateInit2_,"ININ2")
|
||||
#pragma map(inflateEnd,"INEND")
|
||||
#pragma map(inflateSync,"INSY")
|
||||
#pragma map(inflateSetDictionary,"INSEDI")
|
||||
#pragma map(compressBound,"CMBND")
|
||||
#pragma map(inflate_table,"INTABL")
|
||||
#pragma map(inflate_fast,"INFA")
|
||||
#pragma map(inflate_copyright,"INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,253 +0,0 @@
|
||||
#ifndef _COMPAT_ZUTIL_H
|
||||
#define _COMPAT_ZUTIL_H
|
||||
|
||||
#ifdef WANT_ZLIB
|
||||
|
||||
/* zutil.h -- internal interface and configuration of the compression library
|
||||
* Copyright (C) 1995-2013 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* WARNING: this file should *not* be used by applications. It is
|
||||
part of the implementation of the compression library and is
|
||||
subject to change. Applications should only use zlib.h.
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZUTIL_H
|
||||
#define ZUTIL_H
|
||||
|
||||
#ifdef HAVE_HIDDEN
|
||||
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
|
||||
#else
|
||||
# define ZLIB_INTERNAL
|
||||
#endif
|
||||
|
||||
#include <compat/zlib.h>
|
||||
|
||||
#if defined(STDC) && !defined(Z_SOLO)
|
||||
# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
|
||||
# include <stddef.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef Z_SOLO
|
||||
typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
|
||||
#endif
|
||||
|
||||
#ifndef local
|
||||
# define local static
|
||||
#endif
|
||||
/* compile with -Dlocal if your debugger can't find static symbols */
|
||||
|
||||
typedef unsigned char uch;
|
||||
typedef uch FAR uchf;
|
||||
typedef unsigned short ush;
|
||||
typedef ush FAR ushf;
|
||||
typedef unsigned long ulg;
|
||||
|
||||
extern char z_errmsg[10][21]; /* indexed by 2-zlib_error */
|
||||
/* (array size given to avoid silly warnings with Visual C++) */
|
||||
/* (array entry size given to avoid silly string cast warnings) */
|
||||
|
||||
#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
|
||||
|
||||
#define ERR_RETURN(strm,err) \
|
||||
return (strm->msg = ERR_MSG(err), (err))
|
||||
/* To be used only when the state is known to be valid */
|
||||
|
||||
/* common constants */
|
||||
|
||||
#ifndef DEF_WBITS
|
||||
# define DEF_WBITS MAX_WBITS
|
||||
#endif
|
||||
/* default windowBits for decompression. MAX_WBITS is for compression only */
|
||||
|
||||
#if MAX_MEM_LEVEL >= 8
|
||||
# define DEF_MEM_LEVEL 8
|
||||
#else
|
||||
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
|
||||
#endif
|
||||
/* default memLevel */
|
||||
|
||||
#define STORED_BLOCK 0
|
||||
#define STATIC_TREES 1
|
||||
#define DYN_TREES 2
|
||||
/* The three kinds of block type */
|
||||
|
||||
#define MIN_MATCH 3
|
||||
#define MAX_MATCH 258
|
||||
/* The minimum and maximum match lengths */
|
||||
|
||||
#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
|
||||
|
||||
/* target dependencies */
|
||||
|
||||
#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
|
||||
# define OS_CODE 0x00
|
||||
# ifndef Z_SOLO
|
||||
# if defined(__TURBOC__) || defined(__BORLANDC__)
|
||||
# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
|
||||
/* Allow compilation with ANSI keywords only enabled */
|
||||
void _Cdecl farfree( void *block );
|
||||
void *_Cdecl farmalloc( unsigned long nbytes );
|
||||
# else
|
||||
# include <alloc.h>
|
||||
# endif
|
||||
# else /* MSC or DJGPP */
|
||||
# include <malloc.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef AMIGA
|
||||
# define OS_CODE 0x01
|
||||
#endif
|
||||
|
||||
#if defined(VAXC) || defined(VMS)
|
||||
# define OS_CODE 0x02
|
||||
# define F_OPEN(name, mode) \
|
||||
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
|
||||
#endif
|
||||
|
||||
#if defined(ATARI) || defined(atarist)
|
||||
# define OS_CODE 0x05
|
||||
#endif
|
||||
|
||||
#ifdef OS2
|
||||
# define OS_CODE 0x06
|
||||
# if defined(M_I86) && !defined(Z_SOLO)
|
||||
# include <malloc.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(MACOS) || defined(TARGET_OS_MAC)
|
||||
# define OS_CODE 0x07
|
||||
# ifndef Z_SOLO
|
||||
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
|
||||
# include <unix.h> /* for fdopen */
|
||||
# else
|
||||
# ifndef fdopen
|
||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef TOPS20
|
||||
# define OS_CODE 0x0a
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
|
||||
# define OS_CODE 0x0b
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __50SERIES /* Prime/PRIMOS */
|
||||
# define OS_CODE 0x0f
|
||||
#endif
|
||||
|
||||
#if defined(_BEOS_) || defined(RISCOS)
|
||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
|
||||
# if defined(_WIN32_WCE)
|
||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||
# ifndef _PTRDIFF_T_DEFINED
|
||||
typedef int ptrdiff_t;
|
||||
# define _PTRDIFF_T_DEFINED
|
||||
# endif
|
||||
# else
|
||||
# define fdopen(fd,type) _fdopen(fd,type)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__) && !defined(MSDOS)
|
||||
#pragma warn -8004
|
||||
#pragma warn -8008
|
||||
#pragma warn -8066
|
||||
#endif
|
||||
|
||||
/* provide prototypes for these when building zlib without LFS */
|
||||
#if !defined(_WIN32) && \
|
||||
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
|
||||
uLong adler32_combine64 (uLong, uLong, z_off_t);
|
||||
uLong crc32_combine64 (uLong, uLong, z_off_t);
|
||||
#endif
|
||||
|
||||
/* common defaults */
|
||||
|
||||
#ifndef OS_CODE
|
||||
# define OS_CODE 0x03 /* assume Unix */
|
||||
#endif
|
||||
|
||||
#ifndef F_OPEN
|
||||
# define F_OPEN(name, mode) fopen((name), (mode))
|
||||
#endif
|
||||
|
||||
/* functions */
|
||||
|
||||
#if defined(pyr) || defined(Z_SOLO)
|
||||
# define NO_MEMCPY
|
||||
#endif
|
||||
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
|
||||
/* Use our own functions for small and medium model with MSC <= 5.0.
|
||||
* You may have to use the same strategy for Borland C (untested).
|
||||
* The __SC__ check is for Symantec.
|
||||
*/
|
||||
# define NO_MEMCPY
|
||||
#endif
|
||||
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
|
||||
# define HAVE_MEMCPY
|
||||
#endif
|
||||
#ifdef HAVE_MEMCPY
|
||||
# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
|
||||
# define zmemcpy _fmemcpy
|
||||
# define zmemcmp _fmemcmp
|
||||
# define zmemzero(dest, len) _fmemset(dest, 0, len)
|
||||
# else
|
||||
# define zmemcpy memcpy
|
||||
# define zmemcmp memcmp
|
||||
# define zmemzero(dest, len) memset(dest, 0, len)
|
||||
# endif
|
||||
#else
|
||||
void ZLIB_INTERNAL zmemcpy (Bytef* dest, const Bytef* source, uInt len);
|
||||
int ZLIB_INTERNAL zmemcmp (const Bytef* s1, const Bytef* s2, uInt len);
|
||||
void ZLIB_INTERNAL zmemzero (Bytef* dest, uInt len);
|
||||
#endif
|
||||
|
||||
/* Diagnostic functions */
|
||||
# define Assert(cond,msg)
|
||||
# define Trace(x)
|
||||
# define Tracev(x)
|
||||
# define Tracevv(x)
|
||||
# define Tracec(c,x)
|
||||
# define Tracecv(c,x)
|
||||
|
||||
#ifndef Z_SOLO
|
||||
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items,
|
||||
unsigned size);
|
||||
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr);
|
||||
#endif
|
||||
|
||||
#define ZALLOC(strm, items, size) \
|
||||
(*((strm)->zalloc))((strm)->opaque, (items), (size))
|
||||
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
|
||||
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
|
||||
|
||||
/* Reverse the bytes in a 32-bit value */
|
||||
#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
|
||||
(((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
|
||||
|
||||
#endif /* ZUTIL_H */
|
||||
|
||||
#else
|
||||
#include <zutil.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,213 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (archive_file.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBRETRO_SDK_ARCHIVE_FILE_H__
|
||||
#define LIBRETRO_SDK_ARCHIVE_FILE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
enum file_archive_transfer_type
|
||||
{
|
||||
ARCHIVE_TRANSFER_NONE = 0,
|
||||
ARCHIVE_TRANSFER_INIT,
|
||||
ARCHIVE_TRANSFER_ITERATE,
|
||||
ARCHIVE_TRANSFER_DEINIT,
|
||||
ARCHIVE_TRANSFER_DEINIT_ERROR
|
||||
};
|
||||
|
||||
typedef struct file_archive_handle
|
||||
{
|
||||
void *stream;
|
||||
uint8_t *data;
|
||||
uint32_t real_checksum;
|
||||
const struct file_archive_file_backend *backend;
|
||||
} file_archive_file_handle_t;
|
||||
|
||||
typedef struct file_archive_file_data file_archive_file_data_t;
|
||||
|
||||
typedef struct file_archive_transfer
|
||||
{
|
||||
enum file_archive_transfer_type type;
|
||||
int32_t archive_size;
|
||||
file_archive_file_data_t *handle;
|
||||
void *stream;
|
||||
const uint8_t *footer;
|
||||
const uint8_t *directory;
|
||||
const uint8_t *data;
|
||||
const struct file_archive_file_backend *backend;
|
||||
} file_archive_transfer_t;
|
||||
|
||||
enum file_archive_compression_mode
|
||||
{
|
||||
ARCHIVE_MODE_UNCOMPRESSED = 0,
|
||||
ARCHIVE_MODE_COMPRESSED = 8
|
||||
};
|
||||
|
||||
struct decomp_state_t
|
||||
{
|
||||
char *opt_file;
|
||||
char *needle;
|
||||
void **buf;
|
||||
size_t size;
|
||||
bool found;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *source_file;
|
||||
char *subdir;
|
||||
char *target_dir;
|
||||
char *target_file;
|
||||
char *valid_ext;
|
||||
|
||||
char *callback_error;
|
||||
|
||||
file_archive_transfer_t archive;
|
||||
} decompress_state_t;
|
||||
|
||||
struct archive_extract_userdata
|
||||
{
|
||||
char archive_path[PATH_MAX_LENGTH];
|
||||
char *first_extracted_file_path;
|
||||
char *extracted_file_path;
|
||||
const char *extraction_directory;
|
||||
size_t archive_path_size;
|
||||
struct string_list *ext;
|
||||
struct string_list *list;
|
||||
bool found_file;
|
||||
bool list_only;
|
||||
void *context;
|
||||
char archive_name[PATH_MAX_LENGTH];
|
||||
uint32_t crc;
|
||||
struct decomp_state_t decomp_state;
|
||||
decompress_state_t *dec;
|
||||
};
|
||||
|
||||
/* Returns true when parsing should continue. False to stop. */
|
||||
typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts,
|
||||
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
|
||||
uint32_t crc32, struct archive_extract_userdata *userdata);
|
||||
|
||||
struct file_archive_file_backend
|
||||
{
|
||||
void *(*stream_new)(void);
|
||||
void (*stream_free)(void *);
|
||||
bool (*stream_decompress_data_to_file_init)(
|
||||
file_archive_file_handle_t *, const uint8_t *, uint32_t, uint32_t);
|
||||
int (*stream_decompress_data_to_file_iterate)(void *);
|
||||
uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t);
|
||||
int (*compressed_file_read)(const char *path, const char *needle, void **buf,
|
||||
const char *optional_outfile);
|
||||
int (*archive_parse_file_init)(
|
||||
file_archive_transfer_t *state,
|
||||
const char *file);
|
||||
int (*archive_parse_file_iterate_step)(
|
||||
file_archive_transfer_t *state,
|
||||
const char *valid_exts,
|
||||
struct archive_extract_userdata *userdata,
|
||||
file_archive_file_cb file_cb);
|
||||
const char *ident;
|
||||
};
|
||||
|
||||
int file_archive_parse_file_iterate(
|
||||
file_archive_transfer_t *state,
|
||||
bool *returnerr,
|
||||
const char *file,
|
||||
const char *valid_exts,
|
||||
file_archive_file_cb file_cb,
|
||||
struct archive_extract_userdata *userdata);
|
||||
|
||||
void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state);
|
||||
|
||||
int file_archive_parse_file_progress(file_archive_transfer_t *state);
|
||||
|
||||
/**
|
||||
* file_archive_extract_file:
|
||||
* @archive_path : filename path to ZIP archive.
|
||||
* @archive_path_size : size of ZIP archive.
|
||||
* @valid_exts : valid extensions for a file.
|
||||
* @extraction_directory : the directory to extract the temporary
|
||||
* file to.
|
||||
*
|
||||
* Extract file from archive. If no file inside the archive is
|
||||
* specified, the first file found will be used.
|
||||
*
|
||||
* Returns : true (1) on success, otherwise false (0).
|
||||
**/
|
||||
bool file_archive_extract_file(char *archive_path, size_t archive_path_size,
|
||||
const char *valid_exts, const char *extraction_dir,
|
||||
char *out_path, size_t len);
|
||||
|
||||
/**
|
||||
* file_archive_get_file_list:
|
||||
* @path : filename path of archive
|
||||
* @valid_exts : Valid extensions of archive to be parsed.
|
||||
* If NULL, allow all.
|
||||
*
|
||||
* Returns: string listing of files from archive on success, otherwise NULL.
|
||||
**/
|
||||
struct string_list* file_archive_get_file_list(const char *path, const char *valid_exts);
|
||||
|
||||
bool file_archive_perform_mode(const char *name, const char *valid_exts,
|
||||
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
|
||||
uint32_t crc32, struct archive_extract_userdata *userdata);
|
||||
|
||||
int file_archive_compressed_read(
|
||||
const char* path, void **buf,
|
||||
const char* optional_filename, ssize_t *length);
|
||||
|
||||
const struct file_archive_file_backend* file_archive_get_zlib_file_backend(void);
|
||||
const struct file_archive_file_backend* file_archive_get_7z_file_backend(void);
|
||||
|
||||
const struct file_archive_file_backend* file_archive_get_file_backend(const char *path);
|
||||
|
||||
/**
|
||||
* file_archive_get_file_crc32:
|
||||
* @path : filename path of archive
|
||||
*
|
||||
* Returns: CRC32 of the specified file in the archive, otherwise 0.
|
||||
* If no path within the archive is specified, the first
|
||||
* file found inside is used.
|
||||
**/
|
||||
uint32_t file_archive_get_file_crc32(const char *path);
|
||||
|
||||
extern const struct file_archive_file_backend zlib_backend;
|
||||
extern const struct file_archive_file_backend sevenzip_backend;
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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)
|
||||
|
||||
typedef struct config_file config_file_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);
|
||||
|
||||
/* Load a config file from a string. */
|
||||
config_file_t *config_file_new_from_string(const char *from_string);
|
||||
|
||||
/* Frees config file. */
|
||||
void config_file_free(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;
|
||||
struct config_file_entry
|
||||
{
|
||||
const char *key;
|
||||
const char *value;
|
||||
/* Used intentionally. Opaque here. */
|
||||
const struct config_entry_list *next;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
#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);
|
||||
|
||||
/* Write the current config to a file. */
|
||||
bool config_file_write(config_file_t *conf, const char *path);
|
||||
|
||||
/* 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 config_file_exists(const char *path);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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_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
|
||||
@@ -1,471 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 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 <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* 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_file_exists:
|
||||
* @path : path
|
||||
*
|
||||
* Checks if a file already exists at the specified path (@path).
|
||||
*
|
||||
* Returns: true (1) if file already exists, otherwise false (0).
|
||||
*/
|
||||
bool path_file_exists(const char *path);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* Removes the extension from the path and returns the result.
|
||||
* Removes all text after and including the last '.'.
|
||||
* Only '.'s after the last slash are considered.
|
||||
*
|
||||
* Returns: path with the extension part removed.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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 '/'.
|
||||
**/
|
||||
void path_parent_dir(char *path);
|
||||
|
||||
/**
|
||||
* path_resolve_realpath:
|
||||
* @buf : buffer for path
|
||||
* @size : size of buffer
|
||||
*
|
||||
* Turns relative paths into absolute path.
|
||||
* If relative, rebases on current working dir.
|
||||
**/
|
||||
void path_resolve_realpath(char *buf, 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}"
|
||||
**/
|
||||
void 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.
|
||||
*
|
||||
*/
|
||||
void 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"
|
||||
**/
|
||||
void 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.
|
||||
**/
|
||||
void 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);
|
||||
|
||||
void 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:
|
||||
* @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 '/'.
|
||||
**/
|
||||
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.
|
||||
**/
|
||||
void fill_pathname_join(char *out_path, const char *dir,
|
||||
const char *path, size_t size);
|
||||
|
||||
void fill_pathname_join_special_ext(char *out_path,
|
||||
const char *dir, const char *path,
|
||||
const char *last, const char *ext,
|
||||
size_t size);
|
||||
|
||||
void 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).
|
||||
**/
|
||||
void fill_pathname_join_delim(char *out_path, const char *dir,
|
||||
const char *path, const char delim, size_t size);
|
||||
|
||||
void 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
|
||||
*/
|
||||
void 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);
|
||||
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
* Gets the default slash separator.
|
||||
*
|
||||
* Returns: default slash separator.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define path_default_slash() "\\"
|
||||
#else
|
||||
#define path_default_slash() "/"
|
||||
#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);
|
||||
|
||||
#ifndef RARCH_CONSOLE
|
||||
void fill_pathname_application_path(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);
|
||||
|
||||
bool path_is_valid(const char *path);
|
||||
|
||||
int32_t path_get_size(const char *path);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,102 +0,0 @@
|
||||
/* Copyright (C) 2010-2017 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (nbio.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_NBIO_H
|
||||
#define __LIBRETRO_SDK_NBIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifndef NBIO_READ
|
||||
#define NBIO_READ 0
|
||||
#endif
|
||||
|
||||
#ifndef NBIO_WRITE
|
||||
#define NBIO_WRITE 1
|
||||
#endif
|
||||
|
||||
#ifndef NBIO_UPDATE
|
||||
#define NBIO_UPDATE 2
|
||||
#endif
|
||||
|
||||
#ifndef BIO_READ
|
||||
#define BIO_READ 3
|
||||
#endif
|
||||
|
||||
#ifndef BIO_WRITE
|
||||
#define BIO_WRITE 4
|
||||
#endif
|
||||
|
||||
struct nbio_t;
|
||||
|
||||
/*
|
||||
* Creates an nbio structure for performing the given operation on the given file.
|
||||
*/
|
||||
struct nbio_t* nbio_open(const char * filename, unsigned mode);
|
||||
|
||||
/*
|
||||
* Starts reading the given file. When done, it will be available in nbio_get_ptr.
|
||||
* Can not be done if the structure was created with nbio_write.
|
||||
*/
|
||||
void nbio_begin_read(struct nbio_t* handle);
|
||||
|
||||
/*
|
||||
* Starts writing to the given file. Before this, you should've copied the data to nbio_get_ptr.
|
||||
* Can not be done if the structure was created with nbio_read.
|
||||
*/
|
||||
void nbio_begin_write(struct nbio_t* handle);
|
||||
|
||||
/*
|
||||
* Performs part of the requested operation, or checks how it's going.
|
||||
* When it returns true, it's done.
|
||||
*/
|
||||
bool nbio_iterate(struct nbio_t* handle);
|
||||
|
||||
/*
|
||||
* Resizes the file up to the given size; cannot shrink.
|
||||
* Can not be done if the structure was created with nbio_read.
|
||||
*/
|
||||
void nbio_resize(struct nbio_t* handle, size_t len);
|
||||
|
||||
/*
|
||||
* Returns a pointer to the file data. Writable only if structure was not created with nbio_read.
|
||||
* If any operation is in progress, the pointer will be NULL, but len will still be correct.
|
||||
*/
|
||||
void* nbio_get_ptr(struct nbio_t* handle, size_t* len);
|
||||
|
||||
/*
|
||||
* Stops any pending operation, allowing the object to be freed.
|
||||
*/
|
||||
void nbio_cancel(struct nbio_t* handle);
|
||||
|
||||
/*
|
||||
* Deletes the nbio structure and its associated pointer.
|
||||
*/
|
||||
void nbio_free(struct nbio_t* handle);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,79 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (libco.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBCO_H
|
||||
#define LIBCO_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#ifdef LIBCO_C
|
||||
#ifdef LIBCO_MP
|
||||
#define thread_local __thread
|
||||
#else
|
||||
#define thread_local
|
||||
#endif
|
||||
#endif
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef void* cothread_t;
|
||||
|
||||
/**
|
||||
* co_active:
|
||||
*
|
||||
* Gets the currently active context.
|
||||
*
|
||||
* Returns: active context.
|
||||
**/
|
||||
cothread_t co_active(void);
|
||||
|
||||
/**
|
||||
* co_create:
|
||||
* @int : stack size
|
||||
* @funcptr : thread entry function callback
|
||||
*
|
||||
* Create a co_thread.
|
||||
*
|
||||
* Returns: cothread if successful, otherwise NULL.
|
||||
*/
|
||||
cothread_t co_create(unsigned int, void (*)(void));
|
||||
|
||||
/**
|
||||
* co_delete:
|
||||
* @cothread : cothread object
|
||||
*
|
||||
* Frees a co_thread.
|
||||
*/
|
||||
void co_delete(cothread_t cothread);
|
||||
|
||||
/**
|
||||
* co_switch:
|
||||
* @cothread : cothread object to switch to
|
||||
*
|
||||
* Do a context switch to @cothread.
|
||||
*/
|
||||
void co_switch(cothread_t cothread);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
/* ifndef LIBCO_H */
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_common.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_COMMON_RETRO_COMMON_H
|
||||
#define _LIBRETRO_COMMON_RETRO_COMMON_H
|
||||
|
||||
/*
|
||||
This file is designed to normalize the libretro-common compiling environment.
|
||||
It is not to be used in public API headers, as they should be designed as leanly as possible.
|
||||
Nonetheless.. in the meantime, if you do something like use ssize_t, which is not fully portable,
|
||||
in a public API, you may need this.
|
||||
*/
|
||||
|
||||
/* conditional compilation is handled inside here */
|
||||
#include <compat/msvc.h>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 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 _WIN32
|
||||
#define STRING_REP_INT64 "%I64u"
|
||||
#define STRING_REP_UINT64 "%I64u"
|
||||
#define STRING_REP_ULONG "%Iu"
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||
#define STRING_REP_INT64 "%llu"
|
||||
#define STRING_REP_UINT64 "%llu"
|
||||
#define STRING_REP_ULONG "%zu"
|
||||
#else
|
||||
#define STRING_REP_INT64 "%llu"
|
||||
#define STRING_REP_UINT64 "%llu"
|
||||
#define STRING_REP_ULONG "%lu"
|
||||
#endif
|
||||
|
||||
/*
|
||||
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
|
||||
@@ -1,78 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 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
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
/* Copyright (C) 2010-2015 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(__cplusplus) && defined(_WIN32)
|
||||
#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
|
||||
@@ -1,194 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 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
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <sys/timer.h>
|
||||
#elif defined(XENON)
|
||||
#include <time/time.h>
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
#include <unistd.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>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
#include <retro_inline.h>
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(GEKKO)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
#else
|
||||
#define PATH_MAX_LENGTH 4096
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#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 RARCH_SCALE_BASE 256
|
||||
|
||||
/**
|
||||
* retro_sleep:
|
||||
* @msec : amount in milliseconds to sleep
|
||||
*
|
||||
* Sleeps for a specified amount of milliseconds (@msec).
|
||||
**/
|
||||
static INLINE void retro_sleep(unsigned msec)
|
||||
{
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
sys_timer_usleep(1000 * msec);
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
sceKernelDelayThread(1000 * msec);
|
||||
#elif defined(_3DS)
|
||||
svcSleepThread(1000000 * (s64)msec);
|
||||
#elif defined(_WIN32)
|
||||
Sleep(msec);
|
||||
#elif defined(XENON)
|
||||
udelay(1000 * msec);
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
usleep(1000 * msec);
|
||||
#else
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = msec / 1000;
|
||||
tv.tv_nsec = (msec % 1000) * 1000000;
|
||||
nanosleep(&tv, NULL);
|
||||
#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);
|
||||
}
|
||||
|
||||
/**
|
||||
* db_to_gain:
|
||||
* @db : Decibels.
|
||||
*
|
||||
* Converts decibels to voltage gain.
|
||||
*
|
||||
* Returns: voltage gain value.
|
||||
**/
|
||||
static INLINE float db_to_gain(float db)
|
||||
{
|
||||
return powf(10.0f, db / 20.0f);
|
||||
}
|
||||
|
||||
/* Helper macros and struct to keep track of many booleans.
|
||||
* To check for multiple bits, use &&, not &.
|
||||
* For OR, | can be used. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t data[8];
|
||||
} retro_bits_t;
|
||||
|
||||
#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] & (1 << ((bit) & 7)))
|
||||
|
||||
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
|
||||
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
|
||||
#define BIT16_GET(a, bit) (!!((a) & (1 << ((bit) & 15))))
|
||||
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
|
||||
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
|
||||
#define BIT32_GET(a, bit) (!!((a) & (1 << ((bit) & 31))))
|
||||
#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) & (UINT64_C(1) << ((bit) & 63))))
|
||||
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31))
|
||||
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
|
||||
#define BIT128_GET(a, bit) ((a).data[(bit) >> 5] & (1 << ((bit) & 31)))
|
||||
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a));
|
||||
|
||||
#endif
|
||||
@@ -1,52 +0,0 @@
|
||||
/* Copyright (C) 2010-2015 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rsemaphore.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_SEMAPHORE_H
|
||||
#define __LIBRETRO_SDK_SEMAPHORE_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct ssem ssem_t;
|
||||
|
||||
/**
|
||||
* ssem_create:
|
||||
* @value : initial value for the semaphore
|
||||
*
|
||||
* Create a new semaphore.
|
||||
*
|
||||
* Returns: pointer to new semaphore if successful, otherwise NULL.
|
||||
*/
|
||||
ssem_t *ssem_new(int value);
|
||||
|
||||
void ssem_free(ssem_t *semaphore);
|
||||
|
||||
int ssem_get(ssem_t *semaphore);
|
||||
|
||||
void ssem_wait(ssem_t *semaphore);
|
||||
|
||||
void ssem_signal(ssem_t *semaphore);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif /* __LIBRETRO_SDK_SEMAPHORE_H */
|
||||
@@ -1,188 +0,0 @@
|
||||
/* Copyright (C) 2010-2015 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rthreads.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_RTHREADS_H__
|
||||
#define __LIBRETRO_SDK_RTHREADS_H__
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <stdint.h>
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct sthread sthread_t;
|
||||
typedef struct slock slock_t;
|
||||
typedef struct scond scond_t;
|
||||
|
||||
/**
|
||||
* sthread_create:
|
||||
* @start_routine : thread entry callback function
|
||||
* @userdata : pointer to userdata that will be made
|
||||
* available in thread entry callback function
|
||||
*
|
||||
* Create a new thread.
|
||||
*
|
||||
* Returns: pointer to new thread if successful, otherwise NULL.
|
||||
*/
|
||||
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);
|
||||
|
||||
/**
|
||||
* sthread_detach:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Detach a thread. When a detached thread terminates, its
|
||||
* resource sare automatically released back to the system
|
||||
* without the need for another thread to join with the
|
||||
* terminated thread.
|
||||
*
|
||||
* Returns: 0 on success, otherwise it returns a non-zero error number.
|
||||
*/
|
||||
int sthread_detach(sthread_t *thread);
|
||||
|
||||
/**
|
||||
* sthread_join:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Join with a terminated thread. Waits for the thread specified by
|
||||
* @thread to terminate. If that thread has already terminated, then
|
||||
* it will return immediately. The thread specified by @thread must
|
||||
* be joinable.
|
||||
*
|
||||
* Returns: 0 on success, otherwise it returns a non-zero error number.
|
||||
*/
|
||||
void sthread_join(sthread_t *thread);
|
||||
|
||||
/**
|
||||
* sthread_isself:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Join with a terminated thread. Waits for the thread specified by
|
||||
* @thread to terminate. If that thread has already terminated, then
|
||||
* it will return immediately. The thread specified by @thread must
|
||||
* be joinable.
|
||||
*
|
||||
* Returns: true (1) if calling thread is the specified thread
|
||||
*/
|
||||
bool sthread_isself(sthread_t *thread);
|
||||
|
||||
/**
|
||||
* slock_new:
|
||||
*
|
||||
* Create and initialize a new mutex. Must be manually
|
||||
* freed.
|
||||
*
|
||||
* Returns: pointer to a new mutex if successful, otherwise NULL.
|
||||
**/
|
||||
slock_t *slock_new(void);
|
||||
|
||||
/**
|
||||
* slock_free:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Frees a mutex.
|
||||
**/
|
||||
void slock_free(slock_t *lock);
|
||||
|
||||
/**
|
||||
* slock_lock:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Locks a mutex. If a mutex is already locked by
|
||||
* another thread, the calling thread shall block until
|
||||
* the mutex becomes available.
|
||||
**/
|
||||
void slock_lock(slock_t *lock);
|
||||
|
||||
/**
|
||||
* slock_unlock:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Unlocks a mutex.
|
||||
**/
|
||||
void slock_unlock(slock_t *lock);
|
||||
|
||||
/**
|
||||
* scond_new:
|
||||
*
|
||||
* Creates and initializes a condition variable. Must
|
||||
* be manually freed.
|
||||
*
|
||||
* Returns: pointer to new condition variable on success,
|
||||
* otherwise NULL.
|
||||
**/
|
||||
scond_t *scond_new(void);
|
||||
|
||||
/**
|
||||
* scond_free:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Frees a condition variable.
|
||||
**/
|
||||
void scond_free(scond_t *cond);
|
||||
|
||||
/**
|
||||
* scond_wait:
|
||||
* @cond : pointer to condition variable object
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Block on a condition variable (i.e. wait on a condition).
|
||||
**/
|
||||
void scond_wait(scond_t *cond, slock_t *lock);
|
||||
|
||||
/**
|
||||
* scond_wait_timeout:
|
||||
* @cond : pointer to condition variable object
|
||||
* @lock : pointer to mutex object
|
||||
* @timeout_us : timeout (in microseconds)
|
||||
*
|
||||
* Try to block on a condition variable (i.e. wait on a condition) until
|
||||
* @timeout_us elapses.
|
||||
*
|
||||
* Returns: false (0) if timeout elapses before condition variable is
|
||||
* signaled or broadcast, otherwise true (1).
|
||||
**/
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);
|
||||
|
||||
/**
|
||||
* scond_broadcast:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Broadcast a condition. Unblocks all threads currently blocked
|
||||
* on the specified condition variable @cond.
|
||||
**/
|
||||
int scond_broadcast(scond_t *cond);
|
||||
|
||||
/**
|
||||
* scond_signal:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Signal a condition. Unblocks at least one of the threads currently blocked
|
||||
* on the specified condition variable @cond.
|
||||
**/
|
||||
void scond_signal(scond_t *cond);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
libco.aarch64 (2017-06-26)
|
||||
author: webgeek1234
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef IOS
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local uint64_t co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle;
|
||||
|
||||
asm (
|
||||
".globl co_switch_aarch64\n"
|
||||
".globl _co_switch_aarch64\n"
|
||||
"co_switch_aarch64:\n"
|
||||
"_co_switch_aarch64:\n"
|
||||
" stp x8, x9, [x1]\n"
|
||||
" stp x10, x11, [x1, #16]\n"
|
||||
" stp x12, x13, [x1, #32]\n"
|
||||
" stp x14, x15, [x1, #48]\n"
|
||||
" str x19, [x1, #72]\n"
|
||||
" stp x20, x21, [x1, #80]\n"
|
||||
" stp x22, x23, [x1, #96]\n"
|
||||
" stp x24, x25, [x1, #112]\n"
|
||||
" stp x26, x27, [x1, #128]\n"
|
||||
" stp x28, x29, [x1, #144]\n"
|
||||
" mov x16, sp\n"
|
||||
" stp x16, x30, [x1, #160]\n"
|
||||
|
||||
" ldp x8, x9, [x0]\n"
|
||||
" ldp x10, x11, [x0, #16]\n"
|
||||
" ldp x12, x13, [x0, #32]\n"
|
||||
" ldp x14, x15, [x0, #48]\n"
|
||||
" ldr x19, [x0, #72]\n"
|
||||
" ldp x20, x21, [x0, #80]\n"
|
||||
" ldp x22, x23, [x0, #96]\n"
|
||||
" ldp x24, x25, [x0, #112]\n"
|
||||
" ldp x26, x27, [x0, #128]\n"
|
||||
" ldp x28, x29, [x0, #144]\n"
|
||||
" ldp x16, x17, [x0, #160]\n"
|
||||
" mov sp, x16\n"
|
||||
" br x17\n"
|
||||
);
|
||||
|
||||
/* ASM */
|
||||
void co_switch_aarch64(cothread_t handle, cothread_t current);
|
||||
|
||||
static void crash(void)
|
||||
{
|
||||
/* Called only if cothread_t entrypoint returns. */
|
||||
assert(0);
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void))
|
||||
{
|
||||
size = (size + 1023) & ~1023;
|
||||
cothread_t handle = 0;
|
||||
#if HAVE_POSIX_MEMALIGN >= 1
|
||||
if (posix_memalign(&handle, 1024, size + 512) < 0)
|
||||
return 0;
|
||||
#else
|
||||
handle = memalign(1024, size + 512);
|
||||
#endif
|
||||
|
||||
if (!handle)
|
||||
return handle;
|
||||
|
||||
uint64_t *ptr = (uint64_t*)handle;
|
||||
/* Non-volatiles. */
|
||||
ptr[0] = 0; /* x8 */
|
||||
ptr[1] = 0; /* x9 */
|
||||
ptr[2] = 0; /* x10 */
|
||||
ptr[3] = 0; /* x11 */
|
||||
ptr[4] = 0; /* x12 */
|
||||
ptr[5] = 0; /* x13 */
|
||||
ptr[6] = 0; /* x14 */
|
||||
ptr[7] = 0; /* x15 */
|
||||
ptr[8] = 0; /* padding */
|
||||
ptr[9] = 0; /* x19 */
|
||||
ptr[10] = 0; /* x20 */
|
||||
ptr[11] = 0; /* x21 */
|
||||
ptr[12] = 0; /* x22 */
|
||||
ptr[13] = 0; /* x23 */
|
||||
ptr[14] = 0; /* x24 */
|
||||
ptr[15] = 0; /* x25 */
|
||||
ptr[16] = 0; /* x26 */
|
||||
ptr[17] = 0; /* x27 */
|
||||
ptr[18] = 0; /* x28 */
|
||||
ptr[20] = (uintptr_t)ptr + size + 512 - 16; /* x30, stack pointer */
|
||||
ptr[19] = ptr[20]; /* x29, frame pointer */
|
||||
ptr[21] = (uintptr_t)entrypoint; /* PC (link register x31 gets saved here). */
|
||||
return handle;
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_active_handle)
|
||||
co_active_handle = co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
cothread_t co_previous_handle = co_active();
|
||||
co_switch_aarch64(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
libco.amd64 (2009-10-12)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__GNUC__) && !defined(_WIN32) && !defined(__cplusplus)
|
||||
#define CO_USE_INLINE_ASM
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local long long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
#ifndef CO_USE_INLINE_ASM
|
||||
static void (*co_swap)(cothread_t, cothread_t) = 0;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* ABI: Win64 */
|
||||
static unsigned char co_swap_function[] = {
|
||||
0x48, 0x89, 0x22, /* mov [rdx],rsp */
|
||||
0x48, 0x8b, 0x21, /* mov rsp,[rcx] */
|
||||
0x58, /* pop rax */
|
||||
0x48, 0x89, 0x6a, 0x08, /* mov [rdx+0x8],rbp */
|
||||
0x48, 0x89, 0x72, 0x10, /* mov [rdx+0x10],rsi */
|
||||
0x48, 0x89, 0x7a, 0x18, /* mov [rdx+0x18],rdi */
|
||||
0x48, 0x89, 0x5a, 0x20, /* mov [rdx+0x20],rbx */
|
||||
0x4c, 0x89, 0x62, 0x28, /* mov [rdx+0x28],r12 */
|
||||
0x4c, 0x89, 0x6a, 0x30, /* mov [rdx+0x30],r13 */
|
||||
0x4c, 0x89, 0x72, 0x38, /* mov [rdx+0x38],r14 */
|
||||
0x4c, 0x89, 0x7a, 0x40, /* mov [rdx+0x40],r15 */
|
||||
0x48, 0x81, 0xc2, 0x80, 0x00, 0x00, 0x00, /* add rdx,0x80 */
|
||||
0x48, 0x83, 0xe2, 0xf0, /* and rdx,-0x10 */
|
||||
0x0f, 0x29, 0x32, /* movaps [rdx],xmm6 */
|
||||
0x0f, 0x29, 0x7a, 0x10, /* movaps [rdx+0x10],xmm7 */
|
||||
0x44, 0x0f, 0x29, 0x42, 0x20, /* movaps [rdx+0x20],xmm8 */
|
||||
0x44, 0x0f, 0x29, 0x4a, 0x30, /* movaps [rdx+0x30],xmm9 */
|
||||
0x44, 0x0f, 0x29, 0x52, 0x40, /* movaps [rdx+0x40],xmm10 */
|
||||
0x44, 0x0f, 0x29, 0x5a, 0x50, /* movaps [rdx+0x50],xmm11 */
|
||||
0x44, 0x0f, 0x29, 0x62, 0x60, /* movaps [rdx+0x60],xmm12 */
|
||||
0x44, 0x0f, 0x29, 0x6a, 0x70, /* movaps [rdx+0x70],xmm13 */
|
||||
0x44, 0x0f, 0x29, 0xb2, 0x80, 0x00, 0x00, 0x00, /* movaps [rdx+0x80],xmm14 */
|
||||
0x44, 0x0f, 0x29, 0xba, 0x90, 0x00, 0x00, 0x00, /* movaps [rdx+0x90],xmm15 */
|
||||
0x48, 0x8b, 0x69, 0x08, /* mov rbp,[rcx+0x8] */
|
||||
0x48, 0x8b, 0x71, 0x10, /* mov rsi,[rcx+0x10] */
|
||||
0x48, 0x8b, 0x79, 0x18, /* mov rdi,[rcx+0x18] */
|
||||
0x48, 0x8b, 0x59, 0x20, /* mov rbx,[rcx+0x20] */
|
||||
0x4c, 0x8b, 0x61, 0x28, /* mov r12,[rcx+0x28] */
|
||||
0x4c, 0x8b, 0x69, 0x30, /* mov r13,[rcx+0x30] */
|
||||
0x4c, 0x8b, 0x71, 0x38, /* mov r14,[rcx+0x38] */
|
||||
0x4c, 0x8b, 0x79, 0x40, /* mov r15,[rcx+0x40] */
|
||||
0x48, 0x81, 0xc1, 0x80, 0x00, 0x00, 0x00, /* add rcx,0x80 */
|
||||
0x48, 0x83, 0xe1, 0xf0, /* and rcx,-0x10 */
|
||||
0x0f, 0x29, 0x31, /* movaps [rcx],xmm6 */
|
||||
0x0f, 0x29, 0x79, 0x10, /* movaps [rcx+0x10],xmm7 */
|
||||
0x44, 0x0f, 0x29, 0x41, 0x20, /* movaps [rcx+0x20],xmm8 */
|
||||
0x44, 0x0f, 0x29, 0x49, 0x30, /* movaps [rcx+0x30],xmm9 */
|
||||
0x44, 0x0f, 0x29, 0x51, 0x40, /* movaps [rcx+0x40],xmm10 */
|
||||
0x44, 0x0f, 0x29, 0x59, 0x50, /* movaps [rcx+0x50],xmm11 */
|
||||
0x44, 0x0f, 0x29, 0x61, 0x60, /* movaps [rcx+0x60],xmm12 */
|
||||
0x44, 0x0f, 0x29, 0x69, 0x70, /* movaps [rcx+0x70],xmm13 */
|
||||
0x44, 0x0f, 0x29, 0xb1, 0x80, 0x00, 0x00, 0x00, /* movaps [rcx+0x80],xmm14 */
|
||||
0x44, 0x0f, 0x29, 0xb9, 0x90, 0x00, 0x00, 0x00, /* movaps [rcx+0x90],xmm15 */
|
||||
0xff, 0xe0, /* jmp rax */
|
||||
};
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static void co_init(void)
|
||||
{
|
||||
DWORD old_privileges;
|
||||
VirtualProtect(co_swap_function,
|
||||
sizeof(co_swap_function), PAGE_EXECUTE_READWRITE, &old_privileges);
|
||||
}
|
||||
#else
|
||||
/* ABI: SystemV */
|
||||
#ifndef CO_USE_INLINE_ASM
|
||||
static unsigned char co_swap_function[] = {
|
||||
0x48, 0x89, 0x26, /* mov [rsi],rsp */
|
||||
0x48, 0x8b, 0x27, /* mov rsp,[rdi] */
|
||||
0x58, /* pop rax */
|
||||
0x48, 0x89, 0x6e, 0x08, /* mov [rsi+0x08],rbp */
|
||||
0x48, 0x89, 0x5e, 0x10, /* mov [rsi+0x10],rbx */
|
||||
0x4c, 0x89, 0x66, 0x18, /* mov [rsi+0x18],r12 */
|
||||
0x4c, 0x89, 0x6e, 0x20, /* mov [rsi+0x20],r13 */
|
||||
0x4c, 0x89, 0x76, 0x28, /* mov [rsi+0x28],r14 */
|
||||
0x4c, 0x89, 0x7e, 0x30, /* mov [rsi+0x30],r15 */
|
||||
0x48, 0x8b, 0x6f, 0x08, /* mov rbp,[rdi+0x08] */
|
||||
0x48, 0x8b, 0x5f, 0x10, /* mov rbx,[rdi+0x10] */
|
||||
0x4c, 0x8b, 0x67, 0x18, /* mov r12,[rdi+0x18] */
|
||||
0x4c, 0x8b, 0x6f, 0x20, /* mov r13,[rdi+0x20] */
|
||||
0x4c, 0x8b, 0x77, 0x28, /* mov r14,[rdi+0x28] */
|
||||
0x4c, 0x8b, 0x7f, 0x30, /* mov r15,[rdi+0x30] */
|
||||
0xff, 0xe0, /* jmp rax */
|
||||
};
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static void co_init(void)
|
||||
{
|
||||
unsigned long long addr = (unsigned long long)co_swap_function;
|
||||
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
|
||||
unsigned long long size = (addr - base) + sizeof(co_swap_function);
|
||||
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
}
|
||||
#else
|
||||
static void co_init(void) {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void crash(void)
|
||||
{
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_active_handle)
|
||||
co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void))
|
||||
{
|
||||
cothread_t handle;
|
||||
|
||||
#ifndef CO_USE_INLINE_ASM
|
||||
if(!co_swap)
|
||||
{
|
||||
co_init();
|
||||
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!co_active_handle)
|
||||
co_active_handle = &co_active_buffer;
|
||||
size += 512; /* allocate additional space for storage */
|
||||
size &= ~15; /* align stack to 16-byte boundary */
|
||||
|
||||
if((handle = (cothread_t)malloc(size)))
|
||||
{
|
||||
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
|
||||
*--p = (long long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long long)entrypoint; /* start of function */
|
||||
*(long long*)handle = (long long)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
free(handle);
|
||||
}
|
||||
|
||||
#ifndef CO_USE_INLINE_ASM
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
register cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
#define ASM_PREFIX "_"
|
||||
#else
|
||||
#define ASM_PREFIX ""
|
||||
#endif
|
||||
__asm__(
|
||||
".intel_syntax noprefix \n"
|
||||
".globl " ASM_PREFIX "co_switch \n"
|
||||
ASM_PREFIX "co_switch: \n"
|
||||
"mov rsi, [rip+" ASM_PREFIX "co_active_handle]\n"
|
||||
"mov [rsi],rsp \n"
|
||||
"mov [rsi+0x08],rbp \n"
|
||||
"mov [rsi+0x10],rbx \n"
|
||||
"mov [rsi+0x18],r12 \n"
|
||||
"mov [rsi+0x20],r13 \n"
|
||||
"mov [rsi+0x28],r14 \n"
|
||||
"mov [rsi+0x30],r15 \n"
|
||||
"mov [rip+" ASM_PREFIX "co_active_handle], rdi\n"
|
||||
"mov rsp,[rdi] \n"
|
||||
"mov rbp,[rdi+0x08] \n"
|
||||
"mov rbx,[rdi+0x10] \n"
|
||||
"mov r12,[rdi+0x18] \n"
|
||||
"mov r13,[rdi+0x20] \n"
|
||||
"mov r14,[rdi+0x28] \n"
|
||||
"mov r15,[rdi+0x30] \n"
|
||||
"ret \n"
|
||||
".att_syntax \n"
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
libco.armeabi (2013-04-05)
|
||||
author: Themaister
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local uint32_t co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle;
|
||||
|
||||
__asm__ (
|
||||
#if defined(__thumb2__)
|
||||
".thumb\n"
|
||||
".align 2\n"
|
||||
".globl co_switch_arm\n"
|
||||
".globl _co_switch_arm\n"
|
||||
"co_switch_arm:\n"
|
||||
"_co_switch_arm:\n"
|
||||
" mov r3, sp\n"
|
||||
" stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
|
||||
" stmia r1!, {r3, lr}\n"
|
||||
" ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
|
||||
" ldmfd r0!, { r3 }\n"
|
||||
" mov sp, r3\n"
|
||||
" ldmfd r0!, { r3 }\n"
|
||||
" mov pc, r3\n"
|
||||
#else
|
||||
".arm\n"
|
||||
".align 4\n"
|
||||
".globl co_switch_arm\n"
|
||||
".globl _co_switch_arm\n"
|
||||
"co_switch_arm:\n"
|
||||
"_co_switch_arm:\n"
|
||||
" stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n"
|
||||
" ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n"
|
||||
#endif
|
||||
);
|
||||
|
||||
/* ASM */
|
||||
void co_switch_arm(cothread_t handle, cothread_t current);
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void))
|
||||
{
|
||||
size = (size + 1023) & ~1023;
|
||||
cothread_t handle = 0;
|
||||
#if defined(__APPLE__) || HAVE_POSIX_MEMALIGN >= 1
|
||||
if (posix_memalign(&handle, 1024, size + 256) < 0)
|
||||
return 0;
|
||||
#else
|
||||
handle = memalign(1024, size + 256);
|
||||
#endif
|
||||
|
||||
if (!handle)
|
||||
return handle;
|
||||
|
||||
uint32_t *ptr = (uint32_t*)handle;
|
||||
/* Non-volatiles. */
|
||||
ptr[0] = 0; /* r4 */
|
||||
ptr[1] = 0; /* r5 */
|
||||
ptr[2] = 0; /* r6 */
|
||||
ptr[3] = 0; /* r7 */
|
||||
ptr[4] = 0; /* r8 */
|
||||
ptr[5] = 0; /* r9 */
|
||||
ptr[6] = 0; /* r10 */
|
||||
ptr[7] = 0; /* r11 */
|
||||
/* Align stack to 64-bit */
|
||||
ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */
|
||||
ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */
|
||||
return handle;
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_active_handle)
|
||||
co_active_handle = co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
cothread_t co_previous_handle = co_active();
|
||||
co_switch_arm(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
libco.win (2008-01-28)
|
||||
authors: Nach, byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local cothread_t co_active_ = 0;
|
||||
|
||||
static void __stdcall co_thunk(void *coentry)
|
||||
{
|
||||
((void (*)(void))coentry)();
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if(!co_active_)
|
||||
{
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
|
||||
#else
|
||||
ConvertThreadToFiber(0);
|
||||
#endif
|
||||
co_active_ = GetCurrentFiber();
|
||||
}
|
||||
return co_active_;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
|
||||
{
|
||||
if(!co_active_)
|
||||
{
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
ConvertThreadToFiberEx(0, FIBER_FLAG_FLOAT_SWITCH);
|
||||
#else
|
||||
ConvertThreadToFiber(0);
|
||||
#endif
|
||||
co_active_ = GetCurrentFiber();
|
||||
}
|
||||
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
return (cothread_t)CreateFiberEx(heapsize, heapsize, FIBER_FLAG_FLOAT_SWITCH, co_thunk, (void*)coentry);
|
||||
#else
|
||||
return (cothread_t)CreateFiber(heapsize, co_thunk, (void*)coentry);
|
||||
#endif
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread)
|
||||
{
|
||||
DeleteFiber(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread)
|
||||
{
|
||||
co_active_ = cothread;
|
||||
SwitchToFiber(cothread);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
libco
|
||||
auto-selection module
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#if defined _MSC_VER
|
||||
#include <Windows.h>
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
#include "fiber.c"
|
||||
#elif defined _M_IX86
|
||||
#include "x86.c"
|
||||
#elif defined _M_AMD64
|
||||
#include "amd64.c"
|
||||
#else
|
||||
#include "fiber.c"
|
||||
#endif
|
||||
#elif defined __GNUC__
|
||||
#if defined __i386__
|
||||
#include "x86.c"
|
||||
#elif defined __amd64__
|
||||
#include "amd64.c"
|
||||
#elif defined _ARCH_PPC
|
||||
#include "ppc.c"
|
||||
#elif defined(__aarch64__)
|
||||
#include "aarch64.c"
|
||||
#elif defined(PSP)
|
||||
#include "psp1.c"
|
||||
#elif defined VITA
|
||||
#include "scefiber.c"
|
||||
#elif defined(__ARM_EABI__) || defined(__arm__)
|
||||
#include "armeabi.c"
|
||||
#else
|
||||
#include "sjlj.c"
|
||||
#endif
|
||||
#else
|
||||
#error "libco: unsupported processor, compiler or operating system"
|
||||
#endif
|
||||
@@ -1,407 +0,0 @@
|
||||
/*
|
||||
libco.ppc (2010-10-17)
|
||||
author: blargg
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
/* PowerPC 32/64 using embedded or external asm, with optional
|
||||
floating-point and AltiVec save/restore */
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LIBCO_MPROTECT (__unix__ && !LIBCO_PPC_ASM)
|
||||
|
||||
#if LIBCO_MPROTECT
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
/* State format (offsets in 32-bit words)
|
||||
|
||||
+0 Pointer to swap code
|
||||
Rest of function descriptor for entry function
|
||||
+8 PC
|
||||
+10 SP
|
||||
Special regs
|
||||
GPRs
|
||||
FPRs
|
||||
VRs
|
||||
stack
|
||||
*/
|
||||
|
||||
enum { state_size = 1024 };
|
||||
enum { above_stack = 2048 };
|
||||
enum { stack_align = 256 };
|
||||
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
|
||||
/**** Determine environment ****/
|
||||
|
||||
#define LIBCO_PPC64 (_ARCH_PPC64 || __PPC64__ || __ppc64__ || __powerpc64__)
|
||||
|
||||
/* Whether function calls are indirect through a descriptor,
|
||||
or are directly to function */
|
||||
#ifndef LIBCO_PPCDESC
|
||||
#if !_CALL_SYSV && (_CALL_AIX || _CALL_AIXDESC || LIBCO_PPC64)
|
||||
#define LIBCO_PPCDESC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LIBCO_PPC_ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
|
||||
/* Swap code is in ppc.S */
|
||||
void co_swap_asm( cothread_t, cothread_t );
|
||||
#define CO_SWAP_ASM( x, y ) co_swap_asm( x, y )
|
||||
|
||||
#else
|
||||
|
||||
/* Swap code is here in array. Please leave dieassembly comments,
|
||||
as they make it easy to see what it does, and reorder instructions
|
||||
if one wants to see whether that improves performance. */
|
||||
static const uint32_t libco_ppc_code [] = {
|
||||
#if LIBCO_PPC64
|
||||
0x7d000026, /* mfcr r8 */
|
||||
0xf8240028, /* std r1,40(r4) */
|
||||
0x7d2802a6, /* mflr r9 */
|
||||
0xf9c40048, /* std r14,72(r4) */
|
||||
0xf9e40050, /* std r15,80(r4) */
|
||||
0xfa040058, /* std r16,88(r4) */
|
||||
0xfa240060, /* std r17,96(r4) */
|
||||
0xfa440068, /* std r18,104(r4) */
|
||||
0xfa640070, /* std r19,112(r4) */
|
||||
0xfa840078, /* std r20,120(r4) */
|
||||
0xfaa40080, /* std r21,128(r4) */
|
||||
0xfac40088, /* std r22,136(r4) */
|
||||
0xfae40090, /* std r23,144(r4) */
|
||||
0xfb040098, /* std r24,152(r4) */
|
||||
0xfb2400a0, /* std r25,160(r4) */
|
||||
0xfb4400a8, /* std r26,168(r4) */
|
||||
0xfb6400b0, /* std r27,176(r4) */
|
||||
0xfb8400b8, /* std r28,184(r4) */
|
||||
0xfba400c0, /* std r29,192(r4) */
|
||||
0xfbc400c8, /* std r30,200(r4) */
|
||||
0xfbe400d0, /* std r31,208(r4) */
|
||||
0xf9240020, /* std r9,32(r4) */
|
||||
0xe8e30020, /* ld r7,32(r3) */
|
||||
0xe8230028, /* ld r1,40(r3) */
|
||||
0x48000009, /* bl 1 */
|
||||
0x7fe00008, /* trap */
|
||||
0x91040030,/*1:stw r8,48(r4) */
|
||||
0x80c30030, /* lwz r6,48(r3) */
|
||||
0x7ce903a6, /* mtctr r7 */
|
||||
0xe9c30048, /* ld r14,72(r3) */
|
||||
0xe9e30050, /* ld r15,80(r3) */
|
||||
0xea030058, /* ld r16,88(r3) */
|
||||
0xea230060, /* ld r17,96(r3) */
|
||||
0xea430068, /* ld r18,104(r3) */
|
||||
0xea630070, /* ld r19,112(r3) */
|
||||
0xea830078, /* ld r20,120(r3) */
|
||||
0xeaa30080, /* ld r21,128(r3) */
|
||||
0xeac30088, /* ld r22,136(r3) */
|
||||
0xeae30090, /* ld r23,144(r3) */
|
||||
0xeb030098, /* ld r24,152(r3) */
|
||||
0xeb2300a0, /* ld r25,160(r3) */
|
||||
0xeb4300a8, /* ld r26,168(r3) */
|
||||
0xeb6300b0, /* ld r27,176(r3) */
|
||||
0xeb8300b8, /* ld r28,184(r3) */
|
||||
0xeba300c0, /* ld r29,192(r3) */
|
||||
0xebc300c8, /* ld r30,200(r3) */
|
||||
0xebe300d0, /* ld r31,208(r3) */
|
||||
0x7ccff120, /* mtcr r6 */
|
||||
#else
|
||||
0x7d000026, /* mfcr r8 */
|
||||
0x90240028, /* stw r1,40(r4) */
|
||||
0x7d2802a6, /* mflr r9 */
|
||||
0x91a4003c, /* stw r13,60(r4) */
|
||||
0x91c40040, /* stw r14,64(r4) */
|
||||
0x91e40044, /* stw r15,68(r4) */
|
||||
0x92040048, /* stw r16,72(r4) */
|
||||
0x9224004c, /* stw r17,76(r4) */
|
||||
0x92440050, /* stw r18,80(r4) */
|
||||
0x92640054, /* stw r19,84(r4) */
|
||||
0x92840058, /* stw r20,88(r4) */
|
||||
0x92a4005c, /* stw r21,92(r4) */
|
||||
0x92c40060, /* stw r22,96(r4) */
|
||||
0x92e40064, /* stw r23,100(r4) */
|
||||
0x93040068, /* stw r24,104(r4) */
|
||||
0x9324006c, /* stw r25,108(r4) */
|
||||
0x93440070, /* stw r26,112(r4) */
|
||||
0x93640074, /* stw r27,116(r4) */
|
||||
0x93840078, /* stw r28,120(r4) */
|
||||
0x93a4007c, /* stw r29,124(r4) */
|
||||
0x93c40080, /* stw r30,128(r4) */
|
||||
0x93e40084, /* stw r31,132(r4) */
|
||||
0x91240020, /* stw r9,32(r4) */
|
||||
0x80e30020, /* lwz r7,32(r3) */
|
||||
0x80230028, /* lwz r1,40(r3) */
|
||||
0x48000009, /* bl 1 */
|
||||
0x7fe00008, /* trap */
|
||||
0x91040030,/*1:stw r8,48(r4) */
|
||||
0x80c30030, /* lwz r6,48(r3) */
|
||||
0x7ce903a6, /* mtctr r7 */
|
||||
0x81a3003c, /* lwz r13,60(r3) */
|
||||
0x81c30040, /* lwz r14,64(r3) */
|
||||
0x81e30044, /* lwz r15,68(r3) */
|
||||
0x82030048, /* lwz r16,72(r3) */
|
||||
0x8223004c, /* lwz r17,76(r3) */
|
||||
0x82430050, /* lwz r18,80(r3) */
|
||||
0x82630054, /* lwz r19,84(r3) */
|
||||
0x82830058, /* lwz r20,88(r3) */
|
||||
0x82a3005c, /* lwz r21,92(r3) */
|
||||
0x82c30060, /* lwz r22,96(r3) */
|
||||
0x82e30064, /* lwz r23,100(r3) */
|
||||
0x83030068, /* lwz r24,104(r3) */
|
||||
0x8323006c, /* lwz r25,108(r3) */
|
||||
0x83430070, /* lwz r26,112(r3) */
|
||||
0x83630074, /* lwz r27,116(r3) */
|
||||
0x83830078, /* lwz r28,120(r3) */
|
||||
0x83a3007c, /* lwz r29,124(r3) */
|
||||
0x83c30080, /* lwz r30,128(r3) */
|
||||
0x83e30084, /* lwz r31,132(r3) */
|
||||
0x7ccff120, /* mtcr r6 */
|
||||
#endif
|
||||
|
||||
#ifndef LIBCO_PPC_NOFP
|
||||
0xd9c400e0, /* stfd f14,224(r4) */
|
||||
0xd9e400e8, /* stfd f15,232(r4) */
|
||||
0xda0400f0, /* stfd f16,240(r4) */
|
||||
0xda2400f8, /* stfd f17,248(r4) */
|
||||
0xda440100, /* stfd f18,256(r4) */
|
||||
0xda640108, /* stfd f19,264(r4) */
|
||||
0xda840110, /* stfd f20,272(r4) */
|
||||
0xdaa40118, /* stfd f21,280(r4) */
|
||||
0xdac40120, /* stfd f22,288(r4) */
|
||||
0xdae40128, /* stfd f23,296(r4) */
|
||||
0xdb040130, /* stfd f24,304(r4) */
|
||||
0xdb240138, /* stfd f25,312(r4) */
|
||||
0xdb440140, /* stfd f26,320(r4) */
|
||||
0xdb640148, /* stfd f27,328(r4) */
|
||||
0xdb840150, /* stfd f28,336(r4) */
|
||||
0xdba40158, /* stfd f29,344(r4) */
|
||||
0xdbc40160, /* stfd f30,352(r4) */
|
||||
0xdbe40168, /* stfd f31,360(r4) */
|
||||
0xc9c300e0, /* lfd f14,224(r3) */
|
||||
0xc9e300e8, /* lfd f15,232(r3) */
|
||||
0xca0300f0, /* lfd f16,240(r3) */
|
||||
0xca2300f8, /* lfd f17,248(r3) */
|
||||
0xca430100, /* lfd f18,256(r3) */
|
||||
0xca630108, /* lfd f19,264(r3) */
|
||||
0xca830110, /* lfd f20,272(r3) */
|
||||
0xcaa30118, /* lfd f21,280(r3) */
|
||||
0xcac30120, /* lfd f22,288(r3) */
|
||||
0xcae30128, /* lfd f23,296(r3) */
|
||||
0xcb030130, /* lfd f24,304(r3) */
|
||||
0xcb230138, /* lfd f25,312(r3) */
|
||||
0xcb430140, /* lfd f26,320(r3) */
|
||||
0xcb630148, /* lfd f27,328(r3) */
|
||||
0xcb830150, /* lfd f28,336(r3) */
|
||||
0xcba30158, /* lfd f29,344(r3) */
|
||||
0xcbc30160, /* lfd f30,352(r3) */
|
||||
0xcbe30168, /* lfd f31,360(r3) */
|
||||
#endif
|
||||
|
||||
#ifdef __ALTIVEC__
|
||||
0x7ca042a6, /* mfvrsave r5 */
|
||||
0x39040180, /* addi r8,r4,384 */
|
||||
0x39240190, /* addi r9,r4,400 */
|
||||
0x70a00fff, /* andi. r0,r5,4095 */
|
||||
0x90a40034, /* stw r5,52(r4) */
|
||||
0x4182005c, /* beq- 2 */
|
||||
0x7e8041ce, /* stvx v20,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ea049ce, /* stvx v21,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7ec041ce, /* stvx v22,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ee049ce, /* stvx v23,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f0041ce, /* stvx v24,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f2049ce, /* stvx v25,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f4041ce, /* stvx v26,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f6049ce, /* stvx v27,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f8041ce, /* stvx v28,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7fa049ce, /* stvx v29,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7fc041ce, /* stvx v30,r0,r8 */
|
||||
0x7fe049ce, /* stvx v31,r0,r9 */
|
||||
0x80a30034,/*2:lwz r5,52(r3) */
|
||||
0x39030180, /* addi r8,r3,384 */
|
||||
0x39230190, /* addi r9,r3,400 */
|
||||
0x70a00fff, /* andi. r0,r5,4095 */
|
||||
0x7ca043a6, /* mtvrsave r5 */
|
||||
0x4d820420, /* beqctr */
|
||||
0x7e8040ce, /* lvx v20,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ea048ce, /* lvx v21,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7ec040ce, /* lvx v22,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7ee048ce, /* lvx v23,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f0040ce, /* lvx v24,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f2048ce, /* lvx v25,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f4040ce, /* lvx v26,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7f6048ce, /* lvx v27,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7f8040ce, /* lvx v28,r0,r8 */
|
||||
0x39080020, /* addi r8,r8,32 */
|
||||
0x7fa048ce, /* lvx v29,r0,r9 */
|
||||
0x39290020, /* addi r9,r9,32 */
|
||||
0x7fc040ce, /* lvx v30,r0,r8 */
|
||||
0x7fe048ce, /* lvx v31,r0,r9 */
|
||||
#endif
|
||||
|
||||
0x4e800420, /* bctr */
|
||||
};
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
/* Function call goes through indirect descriptor */
|
||||
#define CO_SWAP_ASM( x, y ) \
|
||||
((void (*)( cothread_t, cothread_t )) (uintptr_t) x)( x, y )
|
||||
#else
|
||||
/* Function call goes directly to code */
|
||||
#define CO_SWAP_ASM( x, y ) \
|
||||
((void (*)( cothread_t, cothread_t )) (uintptr_t) libco_ppc_code)( x, y )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static uint32_t* co_create_( unsigned size, uintptr_t entry )
|
||||
{
|
||||
uint32_t* t = (uint32_t*) malloc( size );
|
||||
|
||||
(void) entry;
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
if ( t )
|
||||
{
|
||||
/* Copy entry's descriptor */
|
||||
memcpy( t, (void*) entry, sizeof (void*) * 3 );
|
||||
|
||||
/* Set function pointer to swap routine */
|
||||
#ifdef LIBCO_PPC_ASM
|
||||
*(const void**) t = *(void**) &co_swap_asm;
|
||||
#else
|
||||
*(const void**) t = libco_ppc_code;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
cothread_t co_create( unsigned int size, void (*entry_)( void ) )
|
||||
{
|
||||
uintptr_t entry = (uintptr_t) entry_;
|
||||
uint32_t* t = NULL;
|
||||
|
||||
/* Be sure main thread was successfully allocated */
|
||||
if ( co_active() )
|
||||
{
|
||||
size += state_size + above_stack + stack_align;
|
||||
t = co_create_( size, entry );
|
||||
}
|
||||
|
||||
if ( t )
|
||||
{
|
||||
uintptr_t sp;
|
||||
int shift;
|
||||
|
||||
/* Save current registers into new thread, so that any special ones will
|
||||
have proper values when thread is begun */
|
||||
CO_SWAP_ASM( t, t );
|
||||
|
||||
#if LIBCO_PPCDESC
|
||||
/* Get real address */
|
||||
entry = (uintptr_t) *(void**) entry;
|
||||
#endif
|
||||
|
||||
/* Put stack near end of block, and align */
|
||||
sp = (uintptr_t) t + size - above_stack;
|
||||
sp -= sp % stack_align;
|
||||
|
||||
/* On PPC32, we save and restore GPRs as 32 bits. For PPC64, we
|
||||
save and restore them as 64 bits, regardless of the size the ABI
|
||||
uses. So, we manually write pointers at the proper size. We always
|
||||
save and restore at the same address, and since PPC is big-endian,
|
||||
we must put the low byte first on PPC32. */
|
||||
|
||||
/* If uintptr_t is 32 bits, >>32 is undefined behavior, so we do two shifts
|
||||
and don't have to care how many bits uintptr_t is. */
|
||||
#if LIBCO_PPC64
|
||||
shift = 16;
|
||||
#else
|
||||
shift = 0;
|
||||
#endif
|
||||
|
||||
/* Set up so entry will be called on next swap */
|
||||
t [8] = (uint32_t) (entry >> shift >> shift);
|
||||
t [9] = (uint32_t) entry;
|
||||
|
||||
t [10] = (uint32_t) (sp >> shift >> shift);
|
||||
t [11] = (uint32_t) sp;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void co_delete( cothread_t t )
|
||||
{
|
||||
free(t);
|
||||
}
|
||||
|
||||
static void co_init_( void )
|
||||
{
|
||||
#if LIBCO_MPROTECT
|
||||
/* TODO: pre- and post-pad PPC code so that this doesn't make other
|
||||
data executable and writable */
|
||||
long page_size = sysconf( _SC_PAGESIZE );
|
||||
if ( page_size > 0 )
|
||||
{
|
||||
uintptr_t align = page_size;
|
||||
uintptr_t begin = (uintptr_t) libco_ppc_code;
|
||||
uintptr_t end = begin + sizeof libco_ppc_code;
|
||||
|
||||
/* Align beginning and end */
|
||||
end += align - 1;
|
||||
end -= end % align;
|
||||
begin -= begin % align;
|
||||
|
||||
mprotect( (void*) begin, end - begin, PROT_READ | PROT_WRITE | PROT_EXEC );
|
||||
}
|
||||
#endif
|
||||
|
||||
co_active_handle = co_create_( state_size, (uintptr_t) &co_switch );
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_active_handle)
|
||||
co_init_();
|
||||
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
void co_switch(cothread_t t)
|
||||
{
|
||||
cothread_t old = co_active_handle;
|
||||
co_active_handle = t;
|
||||
|
||||
CO_SWAP_ASM( t, old );
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <pspthreadman.h>
|
||||
|
||||
/* Since cothread_t is a void pointer it must contain an address. We can't return a reference to a local variable
|
||||
* because it would go out of scope, so we create a static variable instead so we can return a reference to it.
|
||||
*/
|
||||
static SceUID active_thread_id = 0;
|
||||
|
||||
cothread_t co_active()
|
||||
{
|
||||
active_thread_id = sceKernelGetThreadId();
|
||||
return &active_thread_id;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void))
|
||||
{
|
||||
/* Similar scenario as with active_thread_id except there will only be one active_thread_id while there could be many
|
||||
* new threads each with their own handle, so we create them on the heap instead and delete them manually when they're
|
||||
* no longer needed in co_delete().
|
||||
*/
|
||||
cothread_t handle = malloc(sizeof(cothread_t));
|
||||
|
||||
/* SceKernelThreadEntry has a different signature than entrypoint, but in practice this seems to work */
|
||||
SceUID new_thread_id = sceKernelCreateThread("cothread", (SceKernelThreadEntry)entrypoint, 0x12, size, 0, NULL);
|
||||
sceKernelStartThread(new_thread_id, 0, NULL);
|
||||
|
||||
*(SceUID *)handle = new_thread_id;
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
sceKernelTerminateDeleteThread(*(SceUID *)handle);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
sceKernelWakeupThread(*(SceUID *)handle);
|
||||
/* Sleep the currently active thread so the new thread can start */
|
||||
sceKernelSleepThread();
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
libco.arm (2015-06-18)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include "libco.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <psp2/kernel/sysmem.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FOUR_KB_ALIGN(x) align(x, 12)
|
||||
#define MB_ALIGN(x) align(x, 20)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int align(int x, int n)
|
||||
{
|
||||
return (((x >> n) + 1) << n);
|
||||
}
|
||||
|
||||
static thread_local unsigned long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
static void(*co_swap)(cothread_t, cothread_t) = 0;
|
||||
static int block;
|
||||
static uint32_t co_swap_function[] = {
|
||||
0xe8a16ff0, /* stmia r1!, {r4-r11,sp,lr} */
|
||||
0xe8b0aff0, /* ldmia r0!, {r4-r11,sp,pc} */
|
||||
0xe12fff1e, /* bx lr */
|
||||
};
|
||||
|
||||
static void co_init(void)
|
||||
{
|
||||
int ret;
|
||||
void *base;
|
||||
|
||||
block = sceKernelAllocMemBlockForVM("libco",
|
||||
MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
|
||||
if (block < 0)
|
||||
return;
|
||||
|
||||
/* get base address */
|
||||
ret = sceKernelGetMemBlockBase(block, &base);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
/* set domain to be writable by user */
|
||||
ret = sceKernelOpenVMDomain();
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
memcpy(base, co_swap_function, sizeof co_swap_function);
|
||||
|
||||
/* set domain back to read-only */
|
||||
ret = sceKernelCloseVMDomain();
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
/* flush icache */
|
||||
ret = sceKernelSyncVMDomain(block, base,
|
||||
MB_ALIGN(FOUR_KB_ALIGN(sizeof co_swap_function)));
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
co_swap = (void(*)(cothread_t, cothread_t))base;
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void(*entrypoint)(void))
|
||||
{
|
||||
unsigned long* handle = 0;
|
||||
if (!co_swap)
|
||||
co_init();
|
||||
if (!co_active_handle) co_active_handle = &co_active_buffer;
|
||||
size += 256;
|
||||
size &= ~15;
|
||||
|
||||
if ((handle = (unsigned long*)malloc(size)))
|
||||
{
|
||||
unsigned long* p = (unsigned long*)((unsigned char*)handle + size);
|
||||
handle[8] = (unsigned long)p;
|
||||
handle[9] = (unsigned long)entrypoint;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
free(handle);
|
||||
sceKernelFreeMemBlock(block);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
libco.win (2016-09-06)
|
||||
authors: frangarcj
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <stdlib.h>
|
||||
#include <psp2/sysmodule.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local cothread_t co_active_ = 0;
|
||||
|
||||
typedef struct SceFiber {
|
||||
char reserved[128];
|
||||
} SceFiber __attribute__( ( aligned ( 8 ) ) ) ;
|
||||
|
||||
int32_t _sceFiberInitializeImpl(SceFiber* fiber, char* name, void* entry, uint32_t argOnInitialize, void* addrContext, int32_t sizeContext, void* params);
|
||||
|
||||
int32_t sceFiberFinalize(SceFiber* fiber);
|
||||
|
||||
int32_t sceFiberRun(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
|
||||
|
||||
int32_t sceFiberSwitch(SceFiber* fiber, uint32_t argOnRunTo, uint32_t* argOnRun);
|
||||
|
||||
int32_t sceFiberReturnToThread(uint32_t argOnReturn, uint32_t* argOnRun);
|
||||
|
||||
static void co_thunk(uint32_t argOnInitialize, uint32_t argOnRun)
|
||||
{
|
||||
((void (*)(void))argOnInitialize)();
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if(!co_active_)
|
||||
{
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
|
||||
co_active_ = (cothread_t)1;
|
||||
}
|
||||
return co_active_;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
|
||||
{
|
||||
SceFiber* tailFiber = malloc(sizeof(SceFiber));
|
||||
char * m_contextBuffer = malloc(sizeof(char)*heapsize);
|
||||
if(!co_active_)
|
||||
{
|
||||
sceSysmoduleLoadModule(SCE_SYSMODULE_FIBER);
|
||||
co_active_ = (cothread_t)1;
|
||||
}
|
||||
|
||||
//_sceFiberInitializeImpl
|
||||
int ret = _sceFiberInitializeImpl(tailFiber, "tailFiber", co_thunk, (uint32_t)coentry, (void*) m_contextBuffer, heapsize, NULL);
|
||||
if(ret==0){
|
||||
return (cothread_t)tailFiber;
|
||||
}else{
|
||||
return (cothread_t)ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread)
|
||||
{
|
||||
if(cothread == (cothread_t)1){
|
||||
return;
|
||||
}
|
||||
sceFiberFinalize((SceFiber*)cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread)
|
||||
{
|
||||
|
||||
uint32_t argOnReturn = 0;
|
||||
if(cothread == (cothread_t)1){
|
||||
co_active_ = cothread;
|
||||
sceFiberReturnToThread(0, NULL);
|
||||
}else{
|
||||
SceFiber* theFiber = (SceFiber*)cothread;
|
||||
if(co_active_ == (cothread_t)1){
|
||||
co_active_ = cothread;
|
||||
sceFiberRun(theFiber, 0, &argOnReturn);
|
||||
}else{
|
||||
co_active_ = cothread;
|
||||
sceFiberSwitch(theFiber, 0, &argOnReturn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
libco.sjlj (2008-01-28)
|
||||
author: Nach
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note this was designed for UNIX systems. Based on ideas expressed in a paper
|
||||
* by Ralf Engelschall.
|
||||
* For SJLJ on other systems, one would want to rewrite springboard() and
|
||||
* co_create() and hack the jmb_buf stack pointer.
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sigjmp_buf context;
|
||||
void (*coentry)(void);
|
||||
void *stack;
|
||||
} cothread_struct;
|
||||
|
||||
static thread_local cothread_struct co_primary;
|
||||
static thread_local cothread_struct *creating, *co_running = 0;
|
||||
|
||||
static void springboard(int ignored)
|
||||
{
|
||||
if(sigsetjmp(creating->context, 0))
|
||||
co_running->coentry();
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_running)
|
||||
co_running = &co_primary;
|
||||
return (cothread_t)co_running;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*coentry)(void))
|
||||
{
|
||||
if(!co_running)
|
||||
co_running = &co_primary;
|
||||
|
||||
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
|
||||
if(thread)
|
||||
{
|
||||
stack_t stack;
|
||||
stack_t old_stack;
|
||||
|
||||
struct sigaction handler = {{0}};
|
||||
struct sigaction old_handler = {{0}};
|
||||
|
||||
thread->coentry = thread->stack = 0;
|
||||
|
||||
stack.ss_flags = 0;
|
||||
stack.ss_size = size;
|
||||
thread->stack = stack.ss_sp = malloc(size);
|
||||
|
||||
if(stack.ss_sp && !sigaltstack(&stack, &old_stack))
|
||||
{
|
||||
handler.sa_handler = springboard;
|
||||
handler.sa_flags = SA_ONSTACK;
|
||||
sigemptyset(&handler.sa_mask);
|
||||
creating = thread;
|
||||
|
||||
if(!sigaction(SIGUSR1, &handler, &old_handler))
|
||||
{
|
||||
if(!raise(SIGUSR1))
|
||||
thread->coentry = coentry;
|
||||
sigaltstack(&old_stack, 0);
|
||||
sigaction(SIGUSR1, &old_handler, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(thread->coentry != coentry)
|
||||
{
|
||||
co_delete(thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread)
|
||||
{
|
||||
if (cothread)
|
||||
{
|
||||
if(((cothread_struct*)cothread)->stack)
|
||||
free(((cothread_struct*)cothread)->stack);
|
||||
free(cothread);
|
||||
}
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread)
|
||||
{
|
||||
if (!sigsetjmp(co_running->context, 0))
|
||||
{
|
||||
co_running = (cothread_struct*)cothread;
|
||||
siglongjmp(co_running->context, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
libco.ucontext (2008-01-28)
|
||||
author: Nach
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING: the overhead of POSIX ucontext is very high,
|
||||
* assembly versions of libco or libco_sjlj should be much faster
|
||||
*
|
||||
* This library only exists for two reasons:
|
||||
* 1 - as an initial test for the viability of a ucontext implementation
|
||||
* 2 - to demonstrate the power and speed of libco over existing implementations,
|
||||
* such as pth (which defaults to wrapping ucontext on unix targets)
|
||||
*
|
||||
* Use this library only as a *last resort*
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <stdlib.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static thread_local ucontext_t co_primary;
|
||||
static thread_local ucontext_t *co_running = 0;
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if (!co_running)
|
||||
co_running = &co_primary;
|
||||
return (cothread_t)co_running;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)(void))
|
||||
{
|
||||
if (!co_running)
|
||||
co_running = &co_primary;
|
||||
ucontext_t *thread = (ucontext_t*)malloc(sizeof(ucontext_t));
|
||||
|
||||
if(thread)
|
||||
{
|
||||
if((!getcontext(thread) && !(thread->uc_stack.ss_sp = 0)) && (thread->uc_stack.ss_sp = malloc(heapsize)))
|
||||
{
|
||||
thread->uc_link = co_running;
|
||||
thread->uc_stack.ss_size = heapsize;
|
||||
makecontext(thread, coentry, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
co_delete((cothread_t)thread);
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread)
|
||||
{
|
||||
if (!cothread)
|
||||
return;
|
||||
|
||||
if(((ucontext_t*)cothread)->uc_stack.ss_sp)
|
||||
free(((ucontext_t*)cothread)->uc_stack.ss_sp);
|
||||
free(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread)
|
||||
{
|
||||
ucontext_t *old_thread = co_running;
|
||||
|
||||
co_running = (ucontext_t*)cothread;
|
||||
swapcontext(old_thread, co_running);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
libco.x86 (2009-10-12)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define LIBCO_C
|
||||
#include <libco.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define fastcall __fastcall
|
||||
#elif defined(__GNUC__)
|
||||
#define fastcall __attribute__((fastcall))
|
||||
#else
|
||||
#error "libco: please define fastcall macro"
|
||||
#endif
|
||||
|
||||
static thread_local long co_active_buffer[64];
|
||||
static thread_local cothread_t co_active_handle = 0;
|
||||
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
|
||||
|
||||
//ABI: fastcall
|
||||
static unsigned char co_swap_function[] = {
|
||||
0x89, 0x22, /* mov [edx],esp */
|
||||
0x8b, 0x21, /* mov esp,[ecx] */
|
||||
0x58, /* pop eax */
|
||||
0x89, 0x6a, 0x04, /* mov [edx+0x04],ebp */
|
||||
0x89, 0x72, 0x08, /* mov [edx+0x08],esi */
|
||||
0x89, 0x7a, 0x0c, /* mov [edx+0x0c],edi */
|
||||
0x89, 0x5a, 0x10, /* mov [edx+0x10],ebx */
|
||||
0x8b, 0x69, 0x04, /* mov ebp,[ecx+0x04] */
|
||||
0x8b, 0x71, 0x08, /* mov esi,[ecx+0x08] */
|
||||
0x8b, 0x79, 0x0c, /* mov edi,[ecx+0x0c] */
|
||||
0x8b, 0x59, 0x10, /* mov ebx,[ecx+0x10] */
|
||||
0xff, 0xe0, /* jmp eax */
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
static void co_init(void)
|
||||
{
|
||||
DWORD old_privileges;
|
||||
VirtualProtect(co_swap_function,
|
||||
sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
|
||||
}
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
static void co_init(void)
|
||||
{
|
||||
unsigned long addr = (unsigned long)co_swap_function;
|
||||
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
|
||||
unsigned long size = (addr - base) + sizeof co_swap_function;
|
||||
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void crash(void)
|
||||
{
|
||||
assert(0); /* called only if cothread_t entrypoint returns */
|
||||
}
|
||||
|
||||
cothread_t co_active(void)
|
||||
{
|
||||
if(!co_active_handle)
|
||||
co_active_handle = &co_active_buffer;
|
||||
return co_active_handle;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int size, void (*entrypoint)(void))
|
||||
{
|
||||
cothread_t handle;
|
||||
if(!co_swap)
|
||||
{
|
||||
co_init();
|
||||
co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
|
||||
}
|
||||
|
||||
if(!co_active_handle)
|
||||
co_active_handle = &co_active_buffer;
|
||||
|
||||
size += 256; /* allocate additional space for storage */
|
||||
size &= ~15; /* align stack to 16-byte boundary */
|
||||
|
||||
if((handle = (cothread_t)malloc(size)))
|
||||
{
|
||||
long *p = (long*)((char*)handle + size); /* seek to top of stack */
|
||||
*--p = (long)crash; /* crash if entrypoint returns */
|
||||
*--p = (long)entrypoint; /* start of function */
|
||||
*(long*)handle = (long)p; /* stack pointer */
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t handle)
|
||||
{
|
||||
free(handle);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t handle)
|
||||
{
|
||||
register cothread_t co_previous_handle = co_active_handle;
|
||||
co_swap(co_active_handle = handle, co_previous_handle);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,185 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (gx_pthread.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _GX_PTHREAD_WRAP_GX_
|
||||
#define _GX_PTHREAD_WRAP_GX_
|
||||
|
||||
#include <ogcsys.h>
|
||||
#include <gccore.h>
|
||||
#include <ogc/cond.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#ifndef OSThread
|
||||
#define OSThread lwp_t
|
||||
#endif
|
||||
|
||||
#ifndef OSCond
|
||||
#define OSCond lwpq_t
|
||||
#endif
|
||||
|
||||
#ifndef OSThreadQueue
|
||||
#define OSThreadQueue lwpq_t
|
||||
#endif
|
||||
|
||||
#ifndef OSInitMutex
|
||||
#define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
|
||||
#endif
|
||||
|
||||
#ifndef OSLockMutex
|
||||
#define OSLockMutex(mutex) LWP_MutexLock(mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSUnlockMutex
|
||||
#define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSTryLockMutex
|
||||
#define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSInitCond
|
||||
#define OSInitCond(cond) LWP_CondInit(cond)
|
||||
#endif
|
||||
|
||||
#ifndef OSWaitCond
|
||||
#define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
|
||||
#endif
|
||||
|
||||
#ifndef OSInitThreadQueue
|
||||
#define OSInitThreadQueue(queue) LWP_InitQueue(queue)
|
||||
#endif
|
||||
|
||||
#ifndef OSSleepThread
|
||||
#define OSSleepThread(queue) LWP_ThreadSleep(queue)
|
||||
#endif
|
||||
|
||||
#ifndef OSJoinThread
|
||||
#define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
|
||||
#endif
|
||||
|
||||
#ifndef OSCreateThread
|
||||
#define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
|
||||
#endif
|
||||
|
||||
#define STACKSIZE (8 * 1024)
|
||||
|
||||
typedef OSThread pthread_t;
|
||||
typedef mutex_t pthread_mutex_t;
|
||||
typedef void* pthread_mutexattr_t;
|
||||
typedef int pthread_attr_t;
|
||||
typedef OSCond pthread_cond_t;
|
||||
typedef OSCond pthread_condattr_t;
|
||||
|
||||
static INLINE int pthread_create(pthread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
|
||||
{
|
||||
*thread = 0;
|
||||
return OSCreateThread(thread, start_routine, 0 /* unused */, arg,
|
||||
0, STACKSIZE, 64, 0 /* unused */);
|
||||
}
|
||||
|
||||
static INLINE pthread_t pthread_self(void)
|
||||
{
|
||||
/* zero 20-mar-2016: untested */
|
||||
return LWP_GetSelf();
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||
const pthread_mutexattr_t *attr)
|
||||
{
|
||||
return OSInitMutex(mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
return LWP_MutexDestroy(*mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSLockMutex(*mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSUnlockMutex(*mutex);
|
||||
}
|
||||
|
||||
static INLINE void pthread_exit(void *retval)
|
||||
{
|
||||
/* FIXME: No LWP equivalent for this? */
|
||||
(void)retval;
|
||||
}
|
||||
|
||||
static INLINE int pthread_detach(pthread_t thread)
|
||||
{
|
||||
/* FIXME: pthread_detach equivalent missing? */
|
||||
(void)thread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE int pthread_join(pthread_t thread, void **retval)
|
||||
{
|
||||
return OSJoinThread(thread, retval);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSTryLockMutex(*mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_wait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex)
|
||||
{
|
||||
return OSWaitCond(*cond, *mutex);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
return LWP_CondTimedWait(*cond, *mutex, abstime);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *attr)
|
||||
{
|
||||
return OSInitCond(cond);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
return LWP_CondSignal(*cond);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
return LWP_CondBroadcast(*cond);
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
return LWP_CondDestroy(*cond);
|
||||
}
|
||||
|
||||
extern int pthread_equal(pthread_t t1, pthread_t t2);
|
||||
|
||||
#endif
|
||||
@@ -1,318 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (psp_pthread.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */
|
||||
#ifndef _PSP_PTHREAD_WRAP__
|
||||
#define _PSP_PTHREAD_WRAP__
|
||||
|
||||
#ifdef VITA
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <pspkernel.h>
|
||||
#include <pspthreadman.h>
|
||||
#include <pspthreadman_kernel.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#define STACKSIZE (8 * 1024)
|
||||
|
||||
typedef SceUID pthread_t;
|
||||
typedef SceUID pthread_mutex_t;
|
||||
typedef void* pthread_mutexattr_t;
|
||||
typedef int pthread_attr_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SceUID mutex;
|
||||
SceUID sema;
|
||||
int waiting;
|
||||
} pthread_cond_t;
|
||||
|
||||
typedef SceUID pthread_condattr_t;
|
||||
|
||||
/* Use pointer values to create unique names for threads/mutexes */
|
||||
char name_buffer[256];
|
||||
|
||||
typedef void* (*sthreadEntry)(void *argp);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* arg;
|
||||
sthreadEntry start_routine;
|
||||
} sthread_args_struct;
|
||||
|
||||
|
||||
static int psp_thread_wrap(SceSize args, void *argp)
|
||||
{
|
||||
sthread_args_struct* sthread_args = (sthread_args_struct*)argp;
|
||||
|
||||
return (int)sthread_args->start_routine(sthread_args->arg);
|
||||
}
|
||||
|
||||
static INLINE int pthread_create(pthread_t *thread,
|
||||
const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
|
||||
{
|
||||
sprintf(name_buffer, "0x%08X", (uint32_t) thread);
|
||||
|
||||
#ifdef VITA
|
||||
*thread = sceKernelCreateThread(name_buffer, psp_thread_wrap,
|
||||
0x10000100, 0x10000, 0, 0, NULL);
|
||||
#else
|
||||
*thread = sceKernelCreateThread(name_buffer,
|
||||
psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);
|
||||
#endif
|
||||
|
||||
sthread_args_struct sthread_args;
|
||||
sthread_args.arg = arg;
|
||||
sthread_args.start_routine = start_routine;
|
||||
|
||||
return sceKernelStartThread(*thread, sizeof(sthread_args), &sthread_args);
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
|
||||
const pthread_mutexattr_t *attr)
|
||||
{
|
||||
sprintf(name_buffer, "0x%08X", (uint32_t) mutex);
|
||||
|
||||
#ifdef VITA
|
||||
*mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
|
||||
if(*mutex<0)
|
||||
return *mutex;
|
||||
return 0;
|
||||
#else
|
||||
return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
return sceKernelDeleteMutex(*mutex);
|
||||
#else
|
||||
return sceKernelDeleteSema(*mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = sceKernelLockMutex(*mutex, 1, 0);
|
||||
//sceClibPrintf("pthread_mutex_lock: %x\n",ret);
|
||||
return ret;
|
||||
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = sceKernelUnlockMutex(*mutex, 1);
|
||||
//sceClibPrintf("pthread_mutex_unlock: %x\n",ret);
|
||||
return ret;
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static INLINE int pthread_join(pthread_t thread, void **retval)
|
||||
{
|
||||
|
||||
#ifdef VITA
|
||||
int res = sceKernelWaitThreadEnd(thread, 0, 0);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
return sceKernelDeleteThread(thread);
|
||||
#else
|
||||
SceUInt timeout = (SceUInt)-1;
|
||||
sceKernelWaitThreadEnd(thread, &timeout);
|
||||
exit_status = sceKernelGetThreadExitStatus(thread);
|
||||
sceKernelDeleteThread(thread);
|
||||
return exit_status;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_wait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = pthread_mutex_lock(&cond->mutex);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
++cond->waiting;
|
||||
pthread_mutex_unlock(mutex);
|
||||
pthread_mutex_unlock(&cond->mutex);
|
||||
|
||||
ret = sceKernelWaitSema(cond->sema, 1, 0);
|
||||
if (ret < 0) {
|
||||
sceClibPrintf("Premature wakeup: %08X", ret);
|
||||
}
|
||||
pthread_mutex_lock(mutex);
|
||||
return ret;
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
sceKernelDelayThread(10000);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
|
||||
pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = pthread_mutex_lock(&cond->mutex);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
++cond->waiting;
|
||||
pthread_mutex_unlock(mutex);
|
||||
pthread_mutex_unlock(&cond->mutex);
|
||||
|
||||
SceUInt timeout = 0;
|
||||
|
||||
timeout = abstime->tv_sec;
|
||||
timeout += abstime->tv_nsec / 1.0e6;
|
||||
|
||||
ret = sceKernelWaitSema(cond->sema, 1, &timeout);
|
||||
if (ret < 0) {
|
||||
sceClibPrintf("Premature wakeup: %08X", ret);
|
||||
}
|
||||
pthread_mutex_lock(mutex);
|
||||
return ret;
|
||||
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_init(pthread_cond_t *cond,
|
||||
const pthread_condattr_t *attr)
|
||||
{
|
||||
#ifdef VITA
|
||||
|
||||
pthread_mutex_init(&cond->mutex,NULL);
|
||||
sceClibPrintf("pthread_cond_init: mutex %x\n",cond->mutex);
|
||||
if(cond->mutex<0){
|
||||
return cond->mutex;
|
||||
}
|
||||
sprintf(name_buffer, "0x%08X", (uint32_t) cond);
|
||||
//cond->sema = sceKernelCreateCond(name_buffer, 0, cond->mutex, 0);
|
||||
cond->sema = sceKernelCreateSema(name_buffer, 0, 0, 1, 0);
|
||||
sceClibPrintf("pthread_cond_init: sema %x\n",cond->sema);
|
||||
if(cond->sema<0){
|
||||
pthread_mutex_destroy(&cond->mutex);
|
||||
return cond->sema;
|
||||
}
|
||||
|
||||
cond->waiting = 0;
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_signal(pthread_cond_t *cond)
|
||||
{
|
||||
#ifdef VITA
|
||||
pthread_mutex_lock(&cond->mutex);
|
||||
if (cond->waiting) {
|
||||
--cond->waiting;
|
||||
int ret = sceKernelSignalSema(cond->sema, 1);
|
||||
sceClibPrintf("pthread_cond_signal: %x\n",ret);
|
||||
}
|
||||
pthread_mutex_unlock(&cond->mutex);
|
||||
return 0;
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
|
||||
{
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
|
||||
{
|
||||
#ifdef VITA
|
||||
int ret = sceKernelDeleteSema(cond->sema);
|
||||
if(ret < 0)
|
||||
return ret;
|
||||
|
||||
return sceKernelDeleteMutex(cond->mutex);
|
||||
#else
|
||||
/* FIXME: stub */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static INLINE int pthread_detach(pthread_t thread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INLINE void pthread_exit(void *retval)
|
||||
{
|
||||
#ifdef VITA
|
||||
sceKernelExitDeleteThread(sceKernelGetThreadId());
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE pthread_t pthread_self(void)
|
||||
{
|
||||
/* zero 20-mar-2016: untested */
|
||||
return sceKernelGetThreadId();
|
||||
}
|
||||
|
||||
static INLINE int pthread_equal(pthread_t t1, pthread_t t2)
|
||||
{
|
||||
return t1 == t2;
|
||||
}
|
||||
|
||||
#endif //_PSP_PTHREAD_WRAP__
|
||||
@@ -1,133 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rsemaphore.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef __unix__
|
||||
#define _POSIX_C_SOURCE 199309
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
#include <rthreads/rsemaphore.h>
|
||||
|
||||
struct ssem
|
||||
{
|
||||
int value;
|
||||
int wakeups;
|
||||
slock_t *mutex;
|
||||
scond_t *cond;
|
||||
};
|
||||
|
||||
ssem_t *ssem_new(int value)
|
||||
{
|
||||
ssem_t *semaphore = (ssem_t*)calloc(1, sizeof(*semaphore));
|
||||
|
||||
if (!semaphore)
|
||||
goto error;
|
||||
|
||||
semaphore->value = value;
|
||||
semaphore->wakeups = 0;
|
||||
semaphore->mutex = slock_new();
|
||||
|
||||
if (!semaphore->mutex)
|
||||
goto error;
|
||||
|
||||
semaphore->cond = scond_new();
|
||||
|
||||
if (!semaphore->cond)
|
||||
goto error;
|
||||
|
||||
return semaphore;
|
||||
|
||||
error:
|
||||
if (semaphore)
|
||||
{
|
||||
if (semaphore->mutex)
|
||||
slock_free(semaphore->mutex);
|
||||
semaphore->mutex = NULL;
|
||||
free((void*)semaphore);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ssem_free(ssem_t *semaphore)
|
||||
{
|
||||
if (!semaphore)
|
||||
return;
|
||||
|
||||
scond_free(semaphore->cond);
|
||||
slock_free(semaphore->mutex);
|
||||
free((void*)semaphore);
|
||||
}
|
||||
|
||||
int ssem_get(ssem_t *semaphore)
|
||||
{
|
||||
int val = 0;
|
||||
if (!semaphore)
|
||||
return 0;
|
||||
|
||||
slock_lock(semaphore->mutex);
|
||||
|
||||
val = semaphore->value;
|
||||
|
||||
slock_unlock(semaphore->mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void ssem_wait(ssem_t *semaphore)
|
||||
{
|
||||
if (!semaphore)
|
||||
return;
|
||||
|
||||
slock_lock(semaphore->mutex);
|
||||
semaphore->value--;
|
||||
|
||||
if (semaphore->value < 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
scond_wait(semaphore->cond, semaphore->mutex);
|
||||
}while (semaphore->wakeups < 1);
|
||||
|
||||
semaphore->wakeups--;
|
||||
}
|
||||
|
||||
slock_unlock(semaphore->mutex);
|
||||
}
|
||||
|
||||
void ssem_signal(ssem_t *semaphore)
|
||||
{
|
||||
if (!semaphore)
|
||||
return;
|
||||
|
||||
slock_lock(semaphore->mutex);
|
||||
semaphore->value++;
|
||||
|
||||
if (semaphore->value <= 0)
|
||||
{
|
||||
semaphore->wakeups++;
|
||||
scond_signal(semaphore->cond);
|
||||
}
|
||||
|
||||
slock_unlock(semaphore->mutex);
|
||||
}
|
||||
@@ -1,474 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (rthreads.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef __unix__
|
||||
#define _POSIX_C_SOURCE 199309
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
/* with RETRO_WIN32_USE_PTHREADS, pthreads can be used even on win32. Maybe only supported in MSVC>=2005 */
|
||||
|
||||
#if defined(_WIN32) && !defined(RETRO_WIN32_USE_PTHREADS)
|
||||
#define USE_WIN32_THREADS
|
||||
#ifdef _XBOX
|
||||
#include <xtl.h>
|
||||
#else
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#elif defined(GEKKO)
|
||||
#include "gx_pthread.h"
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
#include "psp_pthread.h"
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
#include <pthread.h>
|
||||
#include <sys/sys_time.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(VITA)
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
void (*func)(void*);
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
struct sthread
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
HANDLE thread;
|
||||
#else
|
||||
pthread_t id;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct slock
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
HANDLE lock;
|
||||
#else
|
||||
pthread_mutex_t lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct scond
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
HANDLE event;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
static DWORD CALLBACK thread_wrap(void *data_)
|
||||
#else
|
||||
static void *thread_wrap(void *data_)
|
||||
#endif
|
||||
{
|
||||
struct thread_data *data = (struct thread_data*)data_;
|
||||
if (!data)
|
||||
return 0;
|
||||
data->func(data->userdata);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_create:
|
||||
* @start_routine : thread entry callback function
|
||||
* @userdata : pointer to userdata that will be made
|
||||
* available in thread entry callback function
|
||||
*
|
||||
* Create a new thread.
|
||||
*
|
||||
* Returns: pointer to new thread if successful, otherwise NULL.
|
||||
*/
|
||||
sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
|
||||
{
|
||||
bool thread_created = false;
|
||||
struct thread_data *data = NULL;
|
||||
sthread_t *thread = (sthread_t*)calloc(1, sizeof(*thread));
|
||||
|
||||
if (!thread)
|
||||
return NULL;
|
||||
|
||||
data = (struct thread_data*)calloc(1, sizeof(*data));
|
||||
if (!data)
|
||||
goto error;
|
||||
|
||||
data->func = thread_func;
|
||||
data->userdata = userdata;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
thread->thread = CreateThread(NULL, 0, thread_wrap, data, 0, NULL);
|
||||
thread_created = !!thread->thread;
|
||||
#else
|
||||
thread_created = pthread_create(&thread->id, NULL, thread_wrap, data) == 0;
|
||||
#endif
|
||||
|
||||
if (!thread_created)
|
||||
goto error;
|
||||
|
||||
return thread;
|
||||
|
||||
error:
|
||||
if (data)
|
||||
free(data);
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_detach:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Detach a thread. When a detached thread terminates, its
|
||||
* resource sare automatically released back to the system
|
||||
* without the need for another thread to join with the
|
||||
* terminated thread.
|
||||
*
|
||||
* Returns: 0 on success, otherwise it returns a non-zero error number.
|
||||
*/
|
||||
int sthread_detach(sthread_t *thread)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
CloseHandle(thread->thread);
|
||||
free(thread);
|
||||
return 0;
|
||||
#else
|
||||
return pthread_detach(thread->id);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_join:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Join with a terminated thread. Waits for the thread specified by
|
||||
* @thread to terminate. If that thread has already terminated, then
|
||||
* it will return immediately. The thread specified by @thread must
|
||||
* be joinable.
|
||||
*
|
||||
* Returns: 0 on success, otherwise it returns a non-zero error number.
|
||||
*/
|
||||
void sthread_join(sthread_t *thread)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
WaitForSingleObject(thread->thread, INFINITE);
|
||||
CloseHandle(thread->thread);
|
||||
#else
|
||||
pthread_join(thread->id, NULL);
|
||||
#endif
|
||||
free(thread);
|
||||
}
|
||||
|
||||
/**
|
||||
* sthread_isself:
|
||||
* @thread : pointer to thread object
|
||||
*
|
||||
* Join with a terminated thread. Waits for the thread specified by
|
||||
* @thread to terminate. If that thread has already terminated, then
|
||||
* it will return immediately. The thread specified by @thread must
|
||||
* be joinable.
|
||||
*
|
||||
* Returns: true (1) if calling thread is the specified thread
|
||||
*/
|
||||
bool sthread_isself(sthread_t *thread)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
return GetCurrentThread() == thread->thread;
|
||||
#else
|
||||
return pthread_equal(pthread_self(),thread->id);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_new:
|
||||
*
|
||||
* Create and initialize a new mutex. Must be manually
|
||||
* freed.
|
||||
*
|
||||
* Returns: pointer to a new mutex if successful, otherwise NULL.
|
||||
**/
|
||||
slock_t *slock_new(void)
|
||||
{
|
||||
slock_t *lock = (slock_t*)calloc(1, sizeof(*lock));
|
||||
if (!lock)
|
||||
return NULL;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
lock->lock = CreateMutex(NULL, FALSE, NULL);
|
||||
if (!lock->lock)
|
||||
goto error;
|
||||
#else
|
||||
if ((pthread_mutex_init(&lock->lock, NULL) < 0))
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
return lock;
|
||||
|
||||
error:
|
||||
slock_free(lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_free:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Frees a mutex.
|
||||
**/
|
||||
void slock_free(slock_t *lock)
|
||||
{
|
||||
if (!lock)
|
||||
return;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
CloseHandle(lock->lock);
|
||||
#else
|
||||
pthread_mutex_destroy(&lock->lock);
|
||||
#endif
|
||||
free(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_lock:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Locks a mutex. If a mutex is already locked by
|
||||
* another thread, the calling thread shall block until
|
||||
* the mutex becomes available.
|
||||
**/
|
||||
void slock_lock(slock_t *lock)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
WaitForSingleObject(lock->lock, INFINITE);
|
||||
#else
|
||||
pthread_mutex_lock(&lock->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* slock_unlock:
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Unlocks a mutex.
|
||||
**/
|
||||
void slock_unlock(slock_t *lock)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
ReleaseMutex(lock->lock);
|
||||
#else
|
||||
pthread_mutex_unlock(&lock->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_new:
|
||||
*
|
||||
* Creates and initializes a condition variable. Must
|
||||
* be manually freed.
|
||||
*
|
||||
* Returns: pointer to new condition variable on success,
|
||||
* otherwise NULL.
|
||||
**/
|
||||
scond_t *scond_new(void)
|
||||
{
|
||||
bool event_created = false;
|
||||
scond_t *cond = (scond_t*)calloc(1, sizeof(*cond));
|
||||
|
||||
if (!cond)
|
||||
return NULL;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
cond->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
event_created = !!cond->event;
|
||||
#else
|
||||
event_created = (pthread_cond_init(&cond->cond, NULL) == 0);
|
||||
#endif
|
||||
|
||||
if (!event_created)
|
||||
goto error;
|
||||
|
||||
return cond;
|
||||
|
||||
error:
|
||||
free(cond);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_free:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Frees a condition variable.
|
||||
**/
|
||||
void scond_free(scond_t *cond)
|
||||
{
|
||||
if (!cond)
|
||||
return;
|
||||
|
||||
#ifdef USE_WIN32_THREADS
|
||||
CloseHandle(cond->event);
|
||||
#else
|
||||
pthread_cond_destroy(&cond->cond);
|
||||
#endif
|
||||
free(cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_wait:
|
||||
* @cond : pointer to condition variable object
|
||||
* @lock : pointer to mutex object
|
||||
*
|
||||
* Block on a condition variable (i.e. wait on a condition).
|
||||
**/
|
||||
void scond_wait(scond_t *cond, slock_t *lock)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
WaitForSingleObject(cond->event, 0);
|
||||
|
||||
SignalObjectAndWait(lock->lock, cond->event, INFINITE, FALSE);
|
||||
slock_lock(lock);
|
||||
#else
|
||||
pthread_cond_wait(&cond->cond, &lock->lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_broadcast:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Broadcast a condition. Unblocks all threads currently blocked
|
||||
* on the specified condition variable @cond.
|
||||
**/
|
||||
int scond_broadcast(scond_t *cond)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
/* FIXME _- check how this function should differ
|
||||
* from scond_signal implementation. */
|
||||
SetEvent(cond->event);
|
||||
return 0;
|
||||
#else
|
||||
return pthread_cond_broadcast(&cond->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_signal:
|
||||
* @cond : pointer to condition variable object
|
||||
*
|
||||
* Signal a condition. Unblocks at least one of the threads currently blocked
|
||||
* on the specified condition variable @cond.
|
||||
**/
|
||||
void scond_signal(scond_t *cond)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
SetEvent(cond->event);
|
||||
#else
|
||||
pthread_cond_signal(&cond->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* scond_wait_timeout:
|
||||
* @cond : pointer to condition variable object
|
||||
* @lock : pointer to mutex object
|
||||
* @timeout_us : timeout (in microseconds)
|
||||
*
|
||||
* Try to block on a condition variable (i.e. wait on a condition) until
|
||||
* @timeout_us elapses.
|
||||
*
|
||||
* Returns: false (0) if timeout elapses before condition variable is
|
||||
* signaled or broadcast, otherwise true (1).
|
||||
**/
|
||||
bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
|
||||
{
|
||||
#ifdef USE_WIN32_THREADS
|
||||
DWORD ret;
|
||||
|
||||
WaitForSingleObject(cond->event, 0);
|
||||
ret = SignalObjectAndWait(lock->lock, cond->event,
|
||||
(DWORD)(timeout_us) / 1000, FALSE);
|
||||
|
||||
slock_lock(lock);
|
||||
return ret == WAIT_OBJECT_0;
|
||||
#else
|
||||
int ret;
|
||||
int64_t seconds, remainder;
|
||||
struct timespec now = {0};
|
||||
|
||||
#ifdef __MACH__
|
||||
/* OSX doesn't have clock_gettime. */
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
now.tv_sec = mts.tv_sec;
|
||||
now.tv_nsec = mts.tv_nsec;
|
||||
#elif defined(__CELLOS_LV2__)
|
||||
sys_time_sec_t s;
|
||||
sys_time_nsec_t n;
|
||||
|
||||
sys_time_get_current_time(&s, &n);
|
||||
now.tv_sec = s;
|
||||
now.tv_nsec = n;
|
||||
#elif defined(__mips__) || defined(VITA)
|
||||
struct timeval tm;
|
||||
|
||||
gettimeofday(&tm, NULL);
|
||||
now.tv_sec = tm.tv_sec;
|
||||
now.tv_nsec = tm.tv_usec * 1000;
|
||||
#elif defined(RETRO_WIN32_USE_PTHREADS)
|
||||
_ftime64_s(&now);
|
||||
#elif !defined(GEKKO)
|
||||
/* timeout on libogc is duration, not end time. */
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
#endif
|
||||
|
||||
seconds = timeout_us / INT64_C(1000000);
|
||||
remainder = timeout_us % INT64_C(1000000);
|
||||
|
||||
now.tv_sec += seconds;
|
||||
now.tv_nsec += remainder * INT64_C(1000);
|
||||
|
||||
ret = pthread_cond_timedwait(&cond->cond, &lock->lock, &now);
|
||||
return (ret == 0);
|
||||
#endif
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* Copyright (C) 2010-2016 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (xenon_sdl_threads.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;)
|
||||
|
||||
#include "SDL_thread.h"
|
||||
#include "SDL_mutex.h"
|
||||
#include <stdlib.h>
|
||||
#include <boolean.h>
|
||||
|
||||
SDL_cond *SDL_CreateCond(void)
|
||||
{
|
||||
bool *sleeping = calloc(1, sizeof(*sleeping));
|
||||
return (SDL_cond*)sleeping;
|
||||
}
|
||||
|
||||
void SDL_DestroyCond(SDL_cond *sleeping)
|
||||
{
|
||||
free(sleeping);
|
||||
}
|
||||
|
||||
int SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)
|
||||
{
|
||||
(void)lock;
|
||||
volatile bool *sleeping = (volatile bool*)cond;
|
||||
|
||||
SDL_mutexV(lock);
|
||||
*sleeping = true;
|
||||
while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */
|
||||
SDL_mutexP(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDL_CondSignal(SDL_cond *cond)
|
||||
{
|
||||
*(volatile bool*)cond = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user