diff --git a/desmume/src/libretro-common/compat/compat_ifaddrs.c b/desmume/src/libretro-common/compat/compat_ifaddrs.c index e06802689..e793c94e4 100644 --- a/desmume/src/libretro-common/compat/compat_ifaddrs.c +++ b/desmume/src/libretro-common/compat/compat_ifaddrs.c @@ -1,661 +1,661 @@ -/* -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 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct NetlinkList -{ - struct NetlinkList *m_next; - struct nlmsghdr *m_data; - unsigned int m_size; -} NetlinkList; - -static int netlink_socket(void) -{ - int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if(l_socket < 0) - { - return -1; - } - - struct sockaddr_nl l_addr; - 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; - - 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; - - struct sockaddr_nl l_addr; - 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 was 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) - { - struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); - if(!l_hdr) - { // error - freeResultList(l_list); - return NULL; - } - - NetlinkList *l_item = newListItem(l_hdr, l_size); - if (!l_item) - { - freeResultList(l_list); - return NULL; - } - if(!l_list) - { - l_list = l_item; - } - else - { - l_end->m_next = l_item; - } - l_end = l_item; - } - return l_list; -} - -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: - 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 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)); - struct rtattr *l_rta; - 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; - } - } - - struct ifaddrs *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) - { - char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); - int l_index; - memcpy(&l_index, l_indexPtr, sizeof(int)); - if(l_index == p_index) - { - return l_cur; - } - - l_cur = l_cur->ifa_next; - ++l_num; - } - return NULL; -} - -static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) -{ - struct 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_nameSize = 0; - size_t l_addrSize = 0; - - int l_addedNetmask = 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 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); - char l_mask[16] = {0}; - unsigned i; - 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) - { - unsigned int l_nlsize = p_netlinkList->m_size; - struct nlmsghdr *l_hdr; - 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) - { - unsigned int l_nlsize = p_netlinkList->m_size; - struct nlmsghdr *l_hdr; - 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) -{ - if(!ifap) - { - return -1; - } - *ifap = NULL; - - int 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_result = 0; - 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; - while(ifa) - { - l_cur = ifa; - ifa = ifa->ifa_next; - free(l_cur); - } -} +/* +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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(void) +{ + int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(l_socket < 0) + { + return -1; + } + + struct sockaddr_nl l_addr; + 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; + + 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; + + struct sockaddr_nl l_addr; + 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 was 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) + { + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + if(!l_hdr) + { // error + freeResultList(l_list); + return NULL; + } + + NetlinkList *l_item = newListItem(l_hdr, l_size); + if (!l_item) + { + freeResultList(l_list); + return NULL; + } + if(!l_list) + { + l_list = l_item; + } + else + { + l_end->m_next = l_item; + } + l_end = l_item; + } + return l_list; +} + +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: + 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 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)); + struct rtattr *l_rta; + 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; + } + } + + struct ifaddrs *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) + { + char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs); + int l_index; + memcpy(&l_index, l_indexPtr, sizeof(int)); + if(l_index == p_index) + { + return l_cur; + } + + l_cur = l_cur->ifa_next; + ++l_num; + } + return NULL; +} + +static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks) +{ + struct 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_nameSize = 0; + size_t l_addrSize = 0; + + int l_addedNetmask = 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 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); + char l_mask[16] = {0}; + unsigned i; + 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) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + 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) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + 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) +{ + if(!ifap) + { + return -1; + } + *ifap = NULL; + + int 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_result = 0; + 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; + while(ifa) + { + l_cur = ifa; + ifa = ifa->ifa_next; + free(l_cur); + } +} diff --git a/desmume/src/libretro-common/file/archive_file.c b/desmume/src/libretro-common/file/archive_file.c index e31d9ef2d..edd6c9442 100644 --- a/desmume/src/libretro-common/file/archive_file.c +++ b/desmume/src/libretro-common/file/archive_file.c @@ -1,693 +1,693 @@ -/* Copyright (C) 2010-2016 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 -#include -#include - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef HAVE_MMAP -#include -#include -#include - -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#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 - -struct zip_extract_userdata -{ - char *zip_path; - char *first_extracted_file_path; - const char *extraction_directory; - size_t zip_path_size; - struct string_list *ext; - bool found_content; -}; - -enum file_archive_compression_mode -{ - ZLIB_MODE_UNCOMPRESSED = 0, - ZLIB_MODE_DEFLATE = 8 -}; - -typedef struct -{ -#ifdef HAVE_MMAP - int fd; -#endif - void *data; - size_t size; -} file_archive_file_data_t; - -#ifdef HAVE_MMAP -/* Closes, unmaps and frees. */ -static void file_archive_free(void *handle) -{ - file_archive_file_data_t *data = (file_archive_file_data_t*)handle; - - if (!data) - return; - - if (data->data) - munmap(data->data, data->size); - if (data->fd >= 0) - close(data->fd); - free(data); -} - -static const uint8_t *file_archive_data(void *handle) -{ - file_archive_file_data_t *data = (file_archive_file_data_t*)handle; - if (!data) - return NULL; - return (const uint8_t*)data->data; -} - -static size_t file_archive_size(void *handle) -{ - file_archive_file_data_t *data = (file_archive_file_data_t*)handle; - if (!data) - return 0; - return data->size; -} - -static void *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(void *handle) -{ - file_archive_file_data_t *data = (file_archive_file_data_t*)handle; - if (!data) - return; - free(data->data); - free(data); -} - -static const uint8_t *file_archive_data(void *handle) -{ - file_archive_file_data_t *data = (file_archive_file_data_t*)handle; - if (!data) - return NULL; - return (const uint8_t*)data->data; -} - -static size_t file_archive_size(void *handle) -{ - file_archive_file_data_t *data = (file_archive_file_data_t*)handle; - if (!data) - return 0; - return data->size; -} - -static void *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 = retro_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, - void *userdata) -{ - union string_list_elem_attr attr; - struct string_list *ext_list = NULL; - const char *file_ext = NULL; - struct string_list *list = (struct string_list*)userdata; - - (void)cdata; - (void)cmode; - (void)csize; - (void)size; - (void)checksum; - (void)valid_exts; - (void)file_ext; - (void)ext_list; - - memset(&attr, 0, sizeof(attr)); - - if (valid_exts) - ext_list = string_split(valid_exts, "|"); - - if (ext_list) - { - /* Checks if this entry is a directory or a file. */ - char last_char = path[strlen(path)-1]; - - /* Skip if directory. */ - if (last_char == '/' || last_char == '\\' ) - goto error; - - file_ext = path_get_extension(path); - - if (!file_ext || - !string_list_find_elem_prefix(ext_list, ".", file_ext)) - goto error; - - attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE; - string_list_free(ext_list); - } - - return string_list_append(list, path, attr); - -error: - string_list_free(ext_list); - return 0; -} - -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, void *userdata) -{ - const char *ext = path_get_extension(name); - struct zip_extract_userdata *data = (struct zip_extract_userdata*)userdata; - - /* Extract first content that matches our list. */ - if (ext && string_list_find_elem(data->ext, ext)) - { - char new_path[PATH_MAX_LENGTH] = {0}; - - if (data->extraction_directory) - fill_pathname_join(new_path, data->extraction_directory, - path_basename(name), sizeof(new_path)); - else - fill_pathname_resolve_relative(new_path, data->zip_path, - path_basename(name), sizeof(new_path)); - - data->first_extracted_file_path = strdup(new_path); - data->found_content = file_archive_perform_mode(new_path, - valid_exts, cdata, cmode, csize, size, - 0, NULL); - return 0; - } - - return 1; -} - -static 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 int file_archive_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); - *checksum = read_le(state->directory + 16, 4); - *csize = read_le(state->directory + 20, 4); - *size = read_le(state->directory + 24, 4); - - namelength = read_le(state->directory + 28, 2); - extralength = read_le(state->directory + 30, 2); - commentlength = read_le(state->directory + 32, 2); - - if (namelength >= PATH_MAX_LENGTH) - return -1; - - memcpy(filename, state->directory + 46, namelength); - - offset = read_le(state->directory + 42, 4); - offsetNL = read_le(state->data + offset + 26, 2); - offsetEL = read_le(state->data + offset + 28, 2); - - *cdata = state->data + offset + 30 + offsetNL + offsetEL; - - *payback = 46 + namelength + extralength + commentlength; - - return 1; -} - -static int file_archive_parse_file_iterate_step(file_archive_transfer_t *state, - const char *valid_exts, void *userdata, file_archive_file_cb file_cb) -{ - const uint8_t *cdata = NULL; - uint32_t checksum = 0; - uint32_t size = 0; - uint32_t csize = 0; - unsigned cmode = 0; - unsigned payload = 0; - char filename[PATH_MAX_LENGTH] = {0}; - int ret = file_archive_parse_file_iterate_step_internal(state, filename, - &cdata, &cmode, &size, &csize, - &checksum, &payload); - - if (ret != 1) - return ret; - -#if 0 - RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + - offsetNL + offsetEL, csize, size); -#endif - - if (!file_cb(filename, valid_exts, cdata, cmode, - csize, size, checksum, userdata)) - return 0; - - state->directory += payload; - - return 1; -} - -static int file_archive_parse_file_init(file_archive_transfer_t *state, - const char *file) -{ - state->backend = file_archive_get_default_file_backend(); - - if (!state->backend) - return -1; - - state->handle = file_archive_open(file); - if (!state->handle) - return -1; - - state->zip_size = file_archive_size(state->handle); - if (state->zip_size < 22) - return -1; - - state->data = file_archive_data(state->handle); - state->footer = state->data + state->zip_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->zip_size) - break; - } - } - - state->directory = state->data + read_le(state->footer + 16, 4); - - return 0; -} - -/** - * 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) - { - handle->backend->stream_free(handle->stream); - free(handle->stream); - } - - if (!handle || ret == -1) - { - ret = 0; - goto end; - } - - handle->real_checksum = handle->backend->stream_crc_calculate( - 0, handle->data, size); - -#if 0 - if (handle->real_checksum != checksum) - { - /* File CRC difers from ZIP CRC. */ - printf("File CRC differs from ZIP CRC. File: 0x%x, ZIP: 0x%x.\n", - (unsigned)handle->real_checksum, (unsigned)checksum); - } -#endif - - if (!retro_write_file(path, handle->data, size)) - { - ret = false; - goto end; - } - -end: - if (handle->data) - free(handle->data); - return ret; -} - -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, - void *userdata) -{ - if (!state) - return -1; - - switch (state->type) - { - case ZLIB_TRANSFER_NONE: - break; - case ZLIB_TRANSFER_INIT: - if (file_archive_parse_file_init(state, file) == 0) - state->type = ZLIB_TRANSFER_ITERATE; - else - state->type = ZLIB_TRANSFER_DEINIT_ERROR; - break; - case ZLIB_TRANSFER_ITERATE: - { - int ret = file_archive_parse_file_iterate_step(state, - valid_exts, userdata, file_cb); - if (ret != 1) - state->type = ZLIB_TRANSFER_DEINIT; - if (ret == -1) - state->type = ZLIB_TRANSFER_DEINIT_ERROR; - } - break; - case ZLIB_TRANSFER_DEINIT_ERROR: - *returnerr = false; - case ZLIB_TRANSFER_DEINIT: - if (state->handle) - file_archive_free(state->handle); - state->handle = NULL; - break; - } - - if (state->type == ZLIB_TRANSFER_DEINIT || - state->type == ZLIB_TRANSFER_DEINIT_ERROR) - return -1; - - return 0; -} - -void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state) -{ - if (!state || !state->handle) - return; - - state->type = ZLIB_TRANSFER_DEINIT; - file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL); -} - -/** - * file_archive_parse_file: - * @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_parse_file(const char *file, const char *valid_exts, - file_archive_file_cb file_cb, void *userdata) -{ - file_archive_transfer_t state = {0}; - bool returnerr = true; - - state.type = ZLIB_TRANSFER_INIT; - - for (;;) - { - int ret = file_archive_parse_file_iterate(&state, &returnerr, file, - valid_exts, file_cb, userdata); - - if (ret != 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 = state->directory - state->data; - return delta * 100 / state->zip_size; -} - -/** - * file_archive_extract_first_content_file: - * @zip_path : filename path to ZIP archive. - * @zip_path_size : size of ZIP archive. - * @valid_exts : valid extensions for a content file. - * @extraction_directory : the directory to extract temporary - * unzipped content to. - * - * Extract first content file from archive. - * - * Returns : true (1) on success, otherwise false (0). - **/ -bool file_archive_extract_first_content_file( - char *zip_path, - size_t zip_path_size, - const char *valid_exts, - const char *extraction_directory, - char *out_path, size_t len) -{ - struct string_list *list = NULL; - bool ret = true; - struct zip_extract_userdata userdata = {0}; - - /* We cannot unzip if the libretro - * implementation does not have any valid extensions. */ - if (!valid_exts) - return false; - - list = string_split(valid_exts, "|"); - if (!list) - { - ret = false; - goto end; - } - - userdata.zip_path = zip_path; - userdata.zip_path_size = zip_path_size; - userdata.extraction_directory = extraction_directory; - userdata.ext = list; - - if (!file_archive_parse_file(zip_path, valid_exts, - file_archive_extract_cb, &userdata)) - { - /* Parsing file archive failed. */ - ret = false; - goto end; - } - - if (!userdata.found_content) - { - /* Didn't find any content that matched valid extensions - * for libretro implementation. */ - ret = false; - goto end; - } - - if (*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) -{ - struct string_list *list = string_list_new(); - - if (!list) - goto error; - - if (!file_archive_parse_file(path, valid_exts, - file_archive_get_file_list_cb, list)) - goto error; - - return list; - -error: - if (list) - string_list_free(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, void *userdata) -{ - switch (cmode) - { - case ZLIB_MODE_UNCOMPRESSED: - if (!retro_write_file(path, cdata, size)) - return false; - break; - - case ZLIB_MODE_DEFLATE: - { - int ret = 0; - file_archive_file_handle_t handle = {0}; - handle.backend = file_archive_get_default_file_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 (!file_archive_decompress_data_to_file(&handle, - ret, path, valid_exts, - cdata, csize, size, crc32)) - return false; - } - break; - default: - return false; - } - - return true; -} - -const struct file_archive_file_backend *file_archive_get_default_file_backend(void) -{ - return &zlib_backend; -} +/* Copyright (C) 2010-2016 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 +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_MMAP +#include +#include +#include + +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#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 + +struct zip_extract_userdata +{ + char *zip_path; + char *first_extracted_file_path; + const char *extraction_directory; + size_t zip_path_size; + struct string_list *ext; + bool found_content; +}; + +enum file_archive_compression_mode +{ + ZLIB_MODE_UNCOMPRESSED = 0, + ZLIB_MODE_DEFLATE = 8 +}; + +typedef struct +{ +#ifdef HAVE_MMAP + int fd; +#endif + void *data; + size_t size; +} file_archive_file_data_t; + +#ifdef HAVE_MMAP +/* Closes, unmaps and frees. */ +static void file_archive_free(void *handle) +{ + file_archive_file_data_t *data = (file_archive_file_data_t*)handle; + + if (!data) + return; + + if (data->data) + munmap(data->data, data->size); + if (data->fd >= 0) + close(data->fd); + free(data); +} + +static const uint8_t *file_archive_data(void *handle) +{ + file_archive_file_data_t *data = (file_archive_file_data_t*)handle; + if (!data) + return NULL; + return (const uint8_t*)data->data; +} + +static size_t file_archive_size(void *handle) +{ + file_archive_file_data_t *data = (file_archive_file_data_t*)handle; + if (!data) + return 0; + return data->size; +} + +static void *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(void *handle) +{ + file_archive_file_data_t *data = (file_archive_file_data_t*)handle; + if (!data) + return; + free(data->data); + free(data); +} + +static const uint8_t *file_archive_data(void *handle) +{ + file_archive_file_data_t *data = (file_archive_file_data_t*)handle; + if (!data) + return NULL; + return (const uint8_t*)data->data; +} + +static size_t file_archive_size(void *handle) +{ + file_archive_file_data_t *data = (file_archive_file_data_t*)handle; + if (!data) + return 0; + return data->size; +} + +static void *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 = retro_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, + void *userdata) +{ + union string_list_elem_attr attr; + struct string_list *ext_list = NULL; + const char *file_ext = NULL; + struct string_list *list = (struct string_list*)userdata; + + (void)cdata; + (void)cmode; + (void)csize; + (void)size; + (void)checksum; + (void)valid_exts; + (void)file_ext; + (void)ext_list; + + memset(&attr, 0, sizeof(attr)); + + if (valid_exts) + ext_list = string_split(valid_exts, "|"); + + if (ext_list) + { + /* Checks if this entry is a directory or a file. */ + char last_char = path[strlen(path)-1]; + + /* Skip if directory. */ + if (last_char == '/' || last_char == '\\' ) + goto error; + + file_ext = path_get_extension(path); + + if (!file_ext || + !string_list_find_elem_prefix(ext_list, ".", file_ext)) + goto error; + + attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE; + string_list_free(ext_list); + } + + return string_list_append(list, path, attr); + +error: + string_list_free(ext_list); + return 0; +} + +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, void *userdata) +{ + const char *ext = path_get_extension(name); + struct zip_extract_userdata *data = (struct zip_extract_userdata*)userdata; + + /* Extract first content that matches our list. */ + if (ext && string_list_find_elem(data->ext, ext)) + { + char new_path[PATH_MAX_LENGTH] = {0}; + + if (data->extraction_directory) + fill_pathname_join(new_path, data->extraction_directory, + path_basename(name), sizeof(new_path)); + else + fill_pathname_resolve_relative(new_path, data->zip_path, + path_basename(name), sizeof(new_path)); + + data->first_extracted_file_path = strdup(new_path); + data->found_content = file_archive_perform_mode(new_path, + valid_exts, cdata, cmode, csize, size, + 0, NULL); + return 0; + } + + return 1; +} + +static 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 int file_archive_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); + *checksum = read_le(state->directory + 16, 4); + *csize = read_le(state->directory + 20, 4); + *size = read_le(state->directory + 24, 4); + + namelength = read_le(state->directory + 28, 2); + extralength = read_le(state->directory + 30, 2); + commentlength = read_le(state->directory + 32, 2); + + if (namelength >= PATH_MAX_LENGTH) + return -1; + + memcpy(filename, state->directory + 46, namelength); + + offset = read_le(state->directory + 42, 4); + offsetNL = read_le(state->data + offset + 26, 2); + offsetEL = read_le(state->data + offset + 28, 2); + + *cdata = state->data + offset + 30 + offsetNL + offsetEL; + + *payback = 46 + namelength + extralength + commentlength; + + return 1; +} + +static int file_archive_parse_file_iterate_step(file_archive_transfer_t *state, + const char *valid_exts, void *userdata, file_archive_file_cb file_cb) +{ + const uint8_t *cdata = NULL; + uint32_t checksum = 0; + uint32_t size = 0; + uint32_t csize = 0; + unsigned cmode = 0; + unsigned payload = 0; + char filename[PATH_MAX_LENGTH] = {0}; + int ret = file_archive_parse_file_iterate_step_internal(state, filename, + &cdata, &cmode, &size, &csize, + &checksum, &payload); + + if (ret != 1) + return ret; + +#if 0 + RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + + offsetNL + offsetEL, csize, size); +#endif + + if (!file_cb(filename, valid_exts, cdata, cmode, + csize, size, checksum, userdata)) + return 0; + + state->directory += payload; + + return 1; +} + +static int file_archive_parse_file_init(file_archive_transfer_t *state, + const char *file) +{ + state->backend = file_archive_get_default_file_backend(); + + if (!state->backend) + return -1; + + state->handle = file_archive_open(file); + if (!state->handle) + return -1; + + state->zip_size = file_archive_size(state->handle); + if (state->zip_size < 22) + return -1; + + state->data = file_archive_data(state->handle); + state->footer = state->data + state->zip_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->zip_size) + break; + } + } + + state->directory = state->data + read_le(state->footer + 16, 4); + + return 0; +} + +/** + * 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) + { + handle->backend->stream_free(handle->stream); + free(handle->stream); + } + + if (!handle || ret == -1) + { + ret = 0; + goto end; + } + + handle->real_checksum = handle->backend->stream_crc_calculate( + 0, handle->data, size); + +#if 0 + if (handle->real_checksum != checksum) + { + /* File CRC difers from ZIP CRC. */ + printf("File CRC differs from ZIP CRC. File: 0x%x, ZIP: 0x%x.\n", + (unsigned)handle->real_checksum, (unsigned)checksum); + } +#endif + + if (!retro_write_file(path, handle->data, size)) + { + ret = false; + goto end; + } + +end: + if (handle->data) + free(handle->data); + return ret; +} + +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, + void *userdata) +{ + if (!state) + return -1; + + switch (state->type) + { + case ZLIB_TRANSFER_NONE: + break; + case ZLIB_TRANSFER_INIT: + if (file_archive_parse_file_init(state, file) == 0) + state->type = ZLIB_TRANSFER_ITERATE; + else + state->type = ZLIB_TRANSFER_DEINIT_ERROR; + break; + case ZLIB_TRANSFER_ITERATE: + { + int ret = file_archive_parse_file_iterate_step(state, + valid_exts, userdata, file_cb); + if (ret != 1) + state->type = ZLIB_TRANSFER_DEINIT; + if (ret == -1) + state->type = ZLIB_TRANSFER_DEINIT_ERROR; + } + break; + case ZLIB_TRANSFER_DEINIT_ERROR: + *returnerr = false; + case ZLIB_TRANSFER_DEINIT: + if (state->handle) + file_archive_free(state->handle); + state->handle = NULL; + break; + } + + if (state->type == ZLIB_TRANSFER_DEINIT || + state->type == ZLIB_TRANSFER_DEINIT_ERROR) + return -1; + + return 0; +} + +void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state) +{ + if (!state || !state->handle) + return; + + state->type = ZLIB_TRANSFER_DEINIT; + file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL); +} + +/** + * file_archive_parse_file: + * @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_parse_file(const char *file, const char *valid_exts, + file_archive_file_cb file_cb, void *userdata) +{ + file_archive_transfer_t state = {0}; + bool returnerr = true; + + state.type = ZLIB_TRANSFER_INIT; + + for (;;) + { + int ret = file_archive_parse_file_iterate(&state, &returnerr, file, + valid_exts, file_cb, userdata); + + if (ret != 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 = state->directory - state->data; + return delta * 100 / state->zip_size; +} + +/** + * file_archive_extract_first_content_file: + * @zip_path : filename path to ZIP archive. + * @zip_path_size : size of ZIP archive. + * @valid_exts : valid extensions for a content file. + * @extraction_directory : the directory to extract temporary + * unzipped content to. + * + * Extract first content file from archive. + * + * Returns : true (1) on success, otherwise false (0). + **/ +bool file_archive_extract_first_content_file( + char *zip_path, + size_t zip_path_size, + const char *valid_exts, + const char *extraction_directory, + char *out_path, size_t len) +{ + struct string_list *list = NULL; + bool ret = true; + struct zip_extract_userdata userdata = {0}; + + /* We cannot unzip if the libretro + * implementation does not have any valid extensions. */ + if (!valid_exts) + return false; + + list = string_split(valid_exts, "|"); + if (!list) + { + ret = false; + goto end; + } + + userdata.zip_path = zip_path; + userdata.zip_path_size = zip_path_size; + userdata.extraction_directory = extraction_directory; + userdata.ext = list; + + if (!file_archive_parse_file(zip_path, valid_exts, + file_archive_extract_cb, &userdata)) + { + /* Parsing file archive failed. */ + ret = false; + goto end; + } + + if (!userdata.found_content) + { + /* Didn't find any content that matched valid extensions + * for libretro implementation. */ + ret = false; + goto end; + } + + if (*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) +{ + struct string_list *list = string_list_new(); + + if (!list) + goto error; + + if (!file_archive_parse_file(path, valid_exts, + file_archive_get_file_list_cb, list)) + goto error; + + return list; + +error: + if (list) + string_list_free(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, void *userdata) +{ + switch (cmode) + { + case ZLIB_MODE_UNCOMPRESSED: + if (!retro_write_file(path, cdata, size)) + return false; + break; + + case ZLIB_MODE_DEFLATE: + { + int ret = 0; + file_archive_file_handle_t handle = {0}; + handle.backend = file_archive_get_default_file_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 (!file_archive_decompress_data_to_file(&handle, + ret, path, valid_exts, + cdata, csize, size, crc32)) + return false; + } + break; + default: + return false; + } + + return true; +} + +const struct file_archive_file_backend *file_archive_get_default_file_backend(void) +{ + return &zlib_backend; +} diff --git a/desmume/src/libretro-common/file/archive_file_zlib.c b/desmume/src/libretro-common/file/archive_file_zlib.c index 42f3ba92c..71d05a6a1 100644 --- a/desmume/src/libretro-common/file/archive_file_zlib.c +++ b/desmume/src/libretro-common/file/archive_file_zlib.c @@ -1,213 +1,213 @@ -/* Copyright (C) 2010-2016 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 - -#include -#include -#include - -static void *zlib_stream_new(void) -{ - return (z_stream*)calloc(1, sizeof(z_stream)); -} - -static void zlib_stream_free(void *data) -{ - z_stream *ret = (z_stream*)data; - if (ret) - inflateEnd(ret); -} - -static void zlib_stream_set(void *data, - uint32_t avail_in, - uint32_t avail_out, - const uint8_t *next_in, - uint8_t *next_out - ) -{ - z_stream *stream = (z_stream*)data; - - if (!stream) - return; - - stream->avail_in = avail_in; - stream->avail_out = avail_out; - - stream->next_in = (uint8_t*)next_in; - stream->next_out = next_out; -} - -static uint32_t zlib_stream_get_avail_in(void *data) -{ - z_stream *stream = (z_stream*)data; - - if (!stream) - return 0; - - return stream->avail_in; -} - -static uint32_t zlib_stream_get_avail_out(void *data) -{ - z_stream *stream = (z_stream*)data; - - if (!stream) - return 0; - - return stream->avail_out; -} - -static uint64_t zlib_stream_get_total_out(void *data) -{ - z_stream *stream = (z_stream*)data; - - if (!stream) - return 0; - - return stream->total_out; -} - -static void zlib_stream_decrement_total_out(void *data, unsigned subtraction) -{ - z_stream *stream = (z_stream*)data; - - if (stream) - stream->total_out -= subtraction; -} - -static void zlib_stream_compress_free(void *data) -{ - z_stream *ret = (z_stream*)data; - if (ret) - deflateEnd(ret); -} - -static int zlib_stream_compress_data_to_file(void *data) -{ - int zstatus; - z_stream *stream = (z_stream*)data; - - if (!stream) - return -1; - - zstatus = deflate(stream, Z_FINISH); - - if (zstatus == Z_STREAM_END) - return 1; - - return 0; -} - -static bool zlib_stream_decompress_init(void *data) -{ - z_stream *stream = (z_stream*)data; - - if (!stream) - return false; - if (inflateInit(stream) != Z_OK) - return false; - return true; -} - -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; - - if (!(handle->stream = (z_stream*)zlib_stream_new())) - goto error; - - if (inflateInit2((z_streamp)handle->stream, -MAX_WBITS) != Z_OK) - goto error; - - handle->data = (uint8_t*)malloc(size); - - if (!handle->data) - goto error; - - zlib_stream_set(handle->stream, csize, size, - (const uint8_t*)cdata, handle->data); - - return true; - -error: - zlib_stream_free(handle->stream); - free(handle->stream); - if (handle->data) - free(handle->data); - - return false; -} - -static int zlib_stream_decompress_data_to_file_iterate(void *data) -{ - int zstatus; - z_stream *stream = (z_stream*)data; - - if (!stream) - return -1; - - zstatus = inflate(stream, Z_NO_FLUSH); - - if (zstatus == Z_STREAM_END) - return 1; - - if (zstatus != Z_OK && zstatus != Z_BUF_ERROR) - return -1; - - return 0; -} - -static void zlib_stream_compress_init(void *data, int level) -{ - z_stream *stream = (z_stream*)data; - - if (stream) - deflateInit(stream, level); -} - -static uint32_t zlib_stream_crc32_calculate(uint32_t crc, - const uint8_t *data, size_t length) -{ - return crc32(crc, data, length); -} - -const struct file_archive_file_backend zlib_backend = { - zlib_stream_new, - zlib_stream_free, - zlib_stream_set, - zlib_stream_get_avail_in, - zlib_stream_get_avail_out, - zlib_stream_get_total_out, - zlib_stream_decrement_total_out, - zlib_stream_decompress_init, - zlib_stream_decompress_data_to_file_init, - zlib_stream_decompress_data_to_file_iterate, - zlib_stream_compress_init, - zlib_stream_compress_free, - zlib_stream_compress_data_to_file, - zlib_stream_crc32_calculate, - "zlib" -}; +/* Copyright (C) 2010-2016 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 + +#include +#include +#include + +static void *zlib_stream_new(void) +{ + return (z_stream*)calloc(1, sizeof(z_stream)); +} + +static void zlib_stream_free(void *data) +{ + z_stream *ret = (z_stream*)data; + if (ret) + inflateEnd(ret); +} + +static void zlib_stream_set(void *data, + uint32_t avail_in, + uint32_t avail_out, + const uint8_t *next_in, + uint8_t *next_out + ) +{ + z_stream *stream = (z_stream*)data; + + if (!stream) + return; + + stream->avail_in = avail_in; + stream->avail_out = avail_out; + + stream->next_in = (uint8_t*)next_in; + stream->next_out = next_out; +} + +static uint32_t zlib_stream_get_avail_in(void *data) +{ + z_stream *stream = (z_stream*)data; + + if (!stream) + return 0; + + return stream->avail_in; +} + +static uint32_t zlib_stream_get_avail_out(void *data) +{ + z_stream *stream = (z_stream*)data; + + if (!stream) + return 0; + + return stream->avail_out; +} + +static uint64_t zlib_stream_get_total_out(void *data) +{ + z_stream *stream = (z_stream*)data; + + if (!stream) + return 0; + + return stream->total_out; +} + +static void zlib_stream_decrement_total_out(void *data, unsigned subtraction) +{ + z_stream *stream = (z_stream*)data; + + if (stream) + stream->total_out -= subtraction; +} + +static void zlib_stream_compress_free(void *data) +{ + z_stream *ret = (z_stream*)data; + if (ret) + deflateEnd(ret); +} + +static int zlib_stream_compress_data_to_file(void *data) +{ + int zstatus; + z_stream *stream = (z_stream*)data; + + if (!stream) + return -1; + + zstatus = deflate(stream, Z_FINISH); + + if (zstatus == Z_STREAM_END) + return 1; + + return 0; +} + +static bool zlib_stream_decompress_init(void *data) +{ + z_stream *stream = (z_stream*)data; + + if (!stream) + return false; + if (inflateInit(stream) != Z_OK) + return false; + return true; +} + +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; + + if (!(handle->stream = (z_stream*)zlib_stream_new())) + goto error; + + if (inflateInit2((z_streamp)handle->stream, -MAX_WBITS) != Z_OK) + goto error; + + handle->data = (uint8_t*)malloc(size); + + if (!handle->data) + goto error; + + zlib_stream_set(handle->stream, csize, size, + (const uint8_t*)cdata, handle->data); + + return true; + +error: + zlib_stream_free(handle->stream); + free(handle->stream); + if (handle->data) + free(handle->data); + + return false; +} + +static int zlib_stream_decompress_data_to_file_iterate(void *data) +{ + int zstatus; + z_stream *stream = (z_stream*)data; + + if (!stream) + return -1; + + zstatus = inflate(stream, Z_NO_FLUSH); + + if (zstatus == Z_STREAM_END) + return 1; + + if (zstatus != Z_OK && zstatus != Z_BUF_ERROR) + return -1; + + return 0; +} + +static void zlib_stream_compress_init(void *data, int level) +{ + z_stream *stream = (z_stream*)data; + + if (stream) + deflateInit(stream, level); +} + +static uint32_t zlib_stream_crc32_calculate(uint32_t crc, + const uint8_t *data, size_t length) +{ + return crc32(crc, data, length); +} + +const struct file_archive_file_backend zlib_backend = { + zlib_stream_new, + zlib_stream_free, + zlib_stream_set, + zlib_stream_get_avail_in, + zlib_stream_get_avail_out, + zlib_stream_get_total_out, + zlib_stream_decrement_total_out, + zlib_stream_decompress_init, + zlib_stream_decompress_data_to_file_init, + zlib_stream_decompress_data_to_file_iterate, + zlib_stream_compress_init, + zlib_stream_compress_free, + zlib_stream_compress_data_to_file, + zlib_stream_crc32_calculate, + "zlib" +}; diff --git a/desmume/src/libretro-common/include/compat/ifaddrs.h b/desmume/src/libretro-common/include/compat/ifaddrs.h index 2dc68487e..5e35077fa 100644 --- a/desmume/src/libretro-common/include/compat/ifaddrs.h +++ b/desmume/src/libretro-common/include/compat/ifaddrs.h @@ -1,53 +1,53 @@ -/* - * Copyright (c) 1995, 1999 - * Berkeley Software Design, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp - */ - -#ifndef _IFADDRS_H_ -#define _IFADDRS_H_ - -struct ifaddrs -{ - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - struct sockaddr *ifa_dstaddr; - void *ifa_data; -}; - -/* - * This may have been defined in . Note that if 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 - -extern int getifaddrs(struct ifaddrs **ifap); -extern void freeifaddrs(struct ifaddrs *ifa); - -#endif +/* + * 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 . Note that if 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 + +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); + +#endif diff --git a/desmume/src/libretro-common/include/file/archive_file.h b/desmume/src/libretro-common/include/file/archive_file.h index 1700718ac..280736435 100644 --- a/desmume/src/libretro-common/include/file/archive_file.h +++ b/desmume/src/libretro-common/include/file/archive_file.h @@ -1,138 +1,138 @@ -/* Copyright (C) 2010-2016 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 -#include - -#include - -enum file_archive_transfer_type -{ - ZLIB_TRANSFER_NONE = 0, - ZLIB_TRANSFER_INIT, - ZLIB_TRANSFER_ITERATE, - ZLIB_TRANSFER_DEINIT, - ZLIB_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; - -struct file_archive_file_backend -{ - void *(*stream_new)(void); - void (*stream_free)(void *); - void (*stream_set)(void *, uint32_t, uint32_t, - const uint8_t *, uint8_t *); - uint32_t (*stream_get_avail_in)(void*); - uint32_t (*stream_get_avail_out)(void*); - uint64_t (*stream_get_total_out)(void*); - void (*stream_decrement_total_out)(void *, unsigned); - bool (*stream_decompress_init)(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 *); - void (*stream_compress_init)(void *, int); - void (*stream_compress_free)(void *); - int (*stream_compress_data_to_file)(void *); - uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t); - const char *ident; -}; - -typedef struct file_archive_transfer -{ - void *handle; - const uint8_t *footer; - const uint8_t *directory; - const uint8_t *data; - int32_t zip_size; - enum file_archive_transfer_type type; - const struct file_archive_file_backend *backend; -} file_archive_transfer_t; - - -/* 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, void *userdata); - -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, - void *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_first_content_file: - * @zip_path : filename path to ZIP archive. - * @zip_path_size : size of ZIP archive. - * @valid_exts : valid extensions for a content file. - * @extraction_directory : the directory to extract temporary - * unzipped content to. - * - * Extract first content file from archive. - * - * Returns : true (1) on success, otherwise false (0). - **/ -bool file_archive_extract_first_content_file(char *zip_path, size_t zip_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, void *userdata); - -struct string_list *compressed_file_list_new(const char *filename, - const char* ext); - -void file_archive_deflate_init(void *data, int level); - -const struct file_archive_file_backend *file_archive_get_default_file_backend(void); - -extern const struct file_archive_file_backend zlib_backend; - -#endif - +/* Copyright (C) 2010-2016 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 +#include + +#include + +enum file_archive_transfer_type +{ + ZLIB_TRANSFER_NONE = 0, + ZLIB_TRANSFER_INIT, + ZLIB_TRANSFER_ITERATE, + ZLIB_TRANSFER_DEINIT, + ZLIB_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; + +struct file_archive_file_backend +{ + void *(*stream_new)(void); + void (*stream_free)(void *); + void (*stream_set)(void *, uint32_t, uint32_t, + const uint8_t *, uint8_t *); + uint32_t (*stream_get_avail_in)(void*); + uint32_t (*stream_get_avail_out)(void*); + uint64_t (*stream_get_total_out)(void*); + void (*stream_decrement_total_out)(void *, unsigned); + bool (*stream_decompress_init)(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 *); + void (*stream_compress_init)(void *, int); + void (*stream_compress_free)(void *); + int (*stream_compress_data_to_file)(void *); + uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t); + const char *ident; +}; + +typedef struct file_archive_transfer +{ + void *handle; + const uint8_t *footer; + const uint8_t *directory; + const uint8_t *data; + int32_t zip_size; + enum file_archive_transfer_type type; + const struct file_archive_file_backend *backend; +} file_archive_transfer_t; + + +/* 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, void *userdata); + +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, + void *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_first_content_file: + * @zip_path : filename path to ZIP archive. + * @zip_path_size : size of ZIP archive. + * @valid_exts : valid extensions for a content file. + * @extraction_directory : the directory to extract temporary + * unzipped content to. + * + * Extract first content file from archive. + * + * Returns : true (1) on success, otherwise false (0). + **/ +bool file_archive_extract_first_content_file(char *zip_path, size_t zip_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, void *userdata); + +struct string_list *compressed_file_list_new(const char *filename, + const char* ext); + +void file_archive_deflate_init(void *data, int level); + +const struct file_archive_file_backend *file_archive_get_default_file_backend(void); + +extern const struct file_archive_file_backend zlib_backend; + +#endif + diff --git a/desmume/src/libretro-common/include/lists/dir_list.h b/desmume/src/libretro-common/include/lists/dir_list.h index bfbda4dda..9b2a6fc9a 100644 --- a/desmume/src/libretro-common/include/lists/dir_list.h +++ b/desmume/src/libretro-common/include/lists/dir_list.h @@ -1,70 +1,70 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (dir_list.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __LIBRETRO_SDK_DIR_LIST_H -#define __LIBRETRO_SDK_DIR_LIST_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * dir_list_new: - * @dir : directory path. - * @ext : allowed extensions of file directory entries to include. - * @include_dirs : include directories as part of the finished directory listing? - * @include_compressed : include compressed files, even when not part of ext. - * - * Create a directory listing. - * - * Returns: pointer to a directory listing of type 'struct string_list *' on success, - * NULL in case of error. Has to be freed manually. - **/ -struct string_list *dir_list_new(const char *dir, const char *ext, - bool include_dirs, bool include_compressed); - -/** - * dir_list_sort: - * @list : pointer to the directory listing. - * @dir_first : move the directories in the listing to the top? - * - * Sorts a directory listing. - * - **/ -void dir_list_sort(struct string_list *list, bool dir_first); - -/** - * dir_list_free: - * @list : pointer to the directory listing - * - * Frees a directory listing. - * - **/ -void dir_list_free(struct string_list *list); - -#ifdef __cplusplus -} -#endif - -#endif +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (dir_list.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_DIR_LIST_H +#define __LIBRETRO_SDK_DIR_LIST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * dir_list_new: + * @dir : directory path. + * @ext : allowed extensions of file directory entries to include. + * @include_dirs : include directories as part of the finished directory listing? + * @include_compressed : include compressed files, even when not part of ext. + * + * Create a directory listing. + * + * Returns: pointer to a directory listing of type 'struct string_list *' on success, + * NULL in case of error. Has to be freed manually. + **/ +struct string_list *dir_list_new(const char *dir, const char *ext, + bool include_dirs, bool include_compressed); + +/** + * dir_list_sort: + * @list : pointer to the directory listing. + * @dir_first : move the directories in the listing to the top? + * + * Sorts a directory listing. + * + **/ +void dir_list_sort(struct string_list *list, bool dir_first); + +/** + * dir_list_free: + * @list : pointer to the directory listing + * + * Frees a directory listing. + * + **/ +void dir_list_free(struct string_list *list); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/desmume/src/libretro-common/include/lists/file_list.h b/desmume/src/libretro-common/include/lists/file_list.h index 74bf82272..860fd4e76 100644 --- a/desmume/src/libretro-common/include/lists/file_list.h +++ b/desmume/src/libretro-common/include/lists/file_list.h @@ -1,119 +1,119 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (file_list.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __LIBRETRO_SDK_FILE_LIST_H__ -#define __LIBRETRO_SDK_FILE_LIST_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#include - -struct item_file -{ - char *path; - char *label; - char *alt; - unsigned type; - size_t directory_ptr; - size_t entry_idx; - void *userdata; - void *actiondata; -}; - -typedef struct file_list -{ - struct item_file *list; - - size_t capacity; - size_t size; -} file_list_t; - - -void *file_list_get_userdata_at_offset(const file_list_t *list, - size_t index); - -void *file_list_get_actiondata_at_offset(const file_list_t *list, - size_t index); - -void file_list_free(file_list_t *list); - -bool file_list_push(file_list_t *userdata, const char *path, - const char *label, unsigned type, size_t current_directory_ptr, - size_t entry_index); - -void file_list_pop(file_list_t *list, size_t *directory_ptr); - -void file_list_clear(file_list_t *list); - -void file_list_copy(const file_list_t *src, file_list_t *dst); - -void file_list_get_last(const file_list_t *list, - const char **path, const char **label, - unsigned *type, size_t *entry_idx); - -void *file_list_get_last_actiondata(const file_list_t *list); - -size_t file_list_get_size(const file_list_t *list); - -size_t file_list_get_directory_ptr(const file_list_t *list); - -void file_list_get_at_offset(const file_list_t *list, size_t index, - const char **path, const char **label, - unsigned *type, size_t *entry_idx); - -void file_list_free_userdata(const file_list_t *list, size_t index); - -void file_list_free_actiondata(const file_list_t *list, size_t idx); - -void file_list_set_label_at_offset(file_list_t *list, size_t index, - const char *label); - -void file_list_get_label_at_offset(const file_list_t *list, size_t index, - const char **label); - -void file_list_set_alt_at_offset(file_list_t *list, size_t index, - const char *alt); - -void file_list_set_userdata(const file_list_t *list, size_t idx, void *ptr); - -void file_list_set_actiondata(const file_list_t *list, size_t idx, void *ptr); - -void file_list_get_alt_at_offset(const file_list_t *list, size_t index, - const char **alt); - -void file_list_sort_on_alt(file_list_t *list); - -void file_list_sort_on_type(file_list_t *list); - -bool file_list_search(const file_list_t *list, const char *needle, - size_t *index); - -#ifdef __cplusplus -} -#endif - -#endif +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_list.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_FILE_LIST_H__ +#define __LIBRETRO_SDK_FILE_LIST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +struct item_file +{ + char *path; + char *label; + char *alt; + unsigned type; + size_t directory_ptr; + size_t entry_idx; + void *userdata; + void *actiondata; +}; + +typedef struct file_list +{ + struct item_file *list; + + size_t capacity; + size_t size; +} file_list_t; + + +void *file_list_get_userdata_at_offset(const file_list_t *list, + size_t index); + +void *file_list_get_actiondata_at_offset(const file_list_t *list, + size_t index); + +void file_list_free(file_list_t *list); + +bool file_list_push(file_list_t *userdata, const char *path, + const char *label, unsigned type, size_t current_directory_ptr, + size_t entry_index); + +void file_list_pop(file_list_t *list, size_t *directory_ptr); + +void file_list_clear(file_list_t *list); + +void file_list_copy(const file_list_t *src, file_list_t *dst); + +void file_list_get_last(const file_list_t *list, + const char **path, const char **label, + unsigned *type, size_t *entry_idx); + +void *file_list_get_last_actiondata(const file_list_t *list); + +size_t file_list_get_size(const file_list_t *list); + +size_t file_list_get_directory_ptr(const file_list_t *list); + +void file_list_get_at_offset(const file_list_t *list, size_t index, + const char **path, const char **label, + unsigned *type, size_t *entry_idx); + +void file_list_free_userdata(const file_list_t *list, size_t index); + +void file_list_free_actiondata(const file_list_t *list, size_t idx); + +void file_list_set_label_at_offset(file_list_t *list, size_t index, + const char *label); + +void file_list_get_label_at_offset(const file_list_t *list, size_t index, + const char **label); + +void file_list_set_alt_at_offset(file_list_t *list, size_t index, + const char *alt); + +void file_list_set_userdata(const file_list_t *list, size_t idx, void *ptr); + +void file_list_set_actiondata(const file_list_t *list, size_t idx, void *ptr); + +void file_list_get_alt_at_offset(const file_list_t *list, size_t index, + const char **alt); + +void file_list_sort_on_alt(file_list_t *list); + +void file_list_sort_on_type(file_list_t *list); + +bool file_list_search(const file_list_t *list, const char *needle, + size_t *index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/desmume/src/libretro-common/include/lists/string_list.h b/desmume/src/libretro-common/include/lists/string_list.h index 4168116f7..70e84b999 100644 --- a/desmume/src/libretro-common/include/lists/string_list.h +++ b/desmume/src/libretro-common/include/lists/string_list.h @@ -1,148 +1,148 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (string_list.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __LIBRETRO_SDK_STRING_LIST_H -#define __LIBRETRO_SDK_STRING_LIST_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -union string_list_elem_attr -{ - bool b; - int i; - void *p; -}; - -struct string_list_elem -{ - char *data; - union string_list_elem_attr attr; -}; - -struct string_list -{ - struct string_list_elem *elems; - size_t size; - size_t cap; -}; - -/** - * string_list_find_elem: - * @list : pointer to string list - * @elem : element to find inside the string list. - * - * Searches for an element (@elem) inside the string list. - * - * Returns: true (1) if element could be found, otherwise false (0). - */ -int string_list_find_elem(const struct string_list *list, const char *elem); - -/** - * string_list_find_elem_prefix: - * @list : pointer to string list - * @prefix : prefix to append to @elem - * @elem : element to find inside the string list. - * - * Searches for an element (@elem) inside the string list. Will - * also search for the same element prefixed by @prefix. - * - * Returns: true (1) if element could be found, otherwise false (0). - */ -bool string_list_find_elem_prefix(const struct string_list *list, - const char *prefix, const char *elem); - -/** - * string_split: - * @str : string to turn into a string list - * @delim : delimiter character to use for splitting the string. - * - * Creates a new string list based on string @str, delimited by @delim. - * - * Returns: new string list if successful, otherwise NULL. - */ -struct string_list *string_split(const char *str, const char *delim); - -/** - * string_list_new: - * - * Creates a new string list. Has to be freed manually. - * - * Returns: new string list if successful, otherwise NULL. - */ -struct string_list *string_list_new(void); - -/** - * string_list_append: - * @list : pointer to string list - * @elem : element to add to the string list - * @attr : attributes of new element. - * - * Appends a new element to the string list. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -bool string_list_append(struct string_list *list, const char *elem, - union string_list_elem_attr attr); - -/** - * string_list_free - * @list : pointer to string list object - * - * Frees a string list. - */ -void string_list_free(struct string_list *list); - -/** - * string_list_join_concat: - * @buffer : buffer that @list will be joined to. - * @size : length of @buffer. - * @list : pointer to string list. - * @delim : delimiter character for @list. - * - * A string list will be joined/concatenated as a - * string to @buffer, delimited by @delim. - */ -void string_list_join_concat(char *buffer, size_t size, - const struct string_list *list, const char *sep); - -/** - * string_list_set: - * @list : pointer to string list - * @idx : index of element in string list - * @str : value for the element. - * - * Set value of element inside string list. - **/ -void string_list_set(struct string_list *list, unsigned idx, - const char *str); - -#ifdef __cplusplus -} -#endif - -#endif +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (string_list.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_STRING_LIST_H +#define __LIBRETRO_SDK_STRING_LIST_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +union string_list_elem_attr +{ + bool b; + int i; + void *p; +}; + +struct string_list_elem +{ + char *data; + union string_list_elem_attr attr; +}; + +struct string_list +{ + struct string_list_elem *elems; + size_t size; + size_t cap; +}; + +/** + * string_list_find_elem: + * @list : pointer to string list + * @elem : element to find inside the string list. + * + * Searches for an element (@elem) inside the string list. + * + * Returns: true (1) if element could be found, otherwise false (0). + */ +int string_list_find_elem(const struct string_list *list, const char *elem); + +/** + * string_list_find_elem_prefix: + * @list : pointer to string list + * @prefix : prefix to append to @elem + * @elem : element to find inside the string list. + * + * Searches for an element (@elem) inside the string list. Will + * also search for the same element prefixed by @prefix. + * + * Returns: true (1) if element could be found, otherwise false (0). + */ +bool string_list_find_elem_prefix(const struct string_list *list, + const char *prefix, const char *elem); + +/** + * string_split: + * @str : string to turn into a string list + * @delim : delimiter character to use for splitting the string. + * + * Creates a new string list based on string @str, delimited by @delim. + * + * Returns: new string list if successful, otherwise NULL. + */ +struct string_list *string_split(const char *str, const char *delim); + +/** + * string_list_new: + * + * Creates a new string list. Has to be freed manually. + * + * Returns: new string list if successful, otherwise NULL. + */ +struct string_list *string_list_new(void); + +/** + * string_list_append: + * @list : pointer to string list + * @elem : element to add to the string list + * @attr : attributes of new element. + * + * Appends a new element to the string list. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool string_list_append(struct string_list *list, const char *elem, + union string_list_elem_attr attr); + +/** + * string_list_free + * @list : pointer to string list object + * + * Frees a string list. + */ +void string_list_free(struct string_list *list); + +/** + * string_list_join_concat: + * @buffer : buffer that @list will be joined to. + * @size : length of @buffer. + * @list : pointer to string list. + * @delim : delimiter character for @list. + * + * A string list will be joined/concatenated as a + * string to @buffer, delimited by @delim. + */ +void string_list_join_concat(char *buffer, size_t size, + const struct string_list *list, const char *sep); + +/** + * string_list_set: + * @list : pointer to string list + * @idx : index of element in string list + * @str : value for the element. + * + * Set value of element inside string list. + **/ +void string_list_set(struct string_list *list, unsigned idx, + const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/desmume/src/libretro-common/include/net/net_ifinfo.h b/desmume/src/libretro-common/include/net/net_ifinfo.h index 982226f89..a32828a9f 100644 --- a/desmume/src/libretro-common/include/net/net_ifinfo.h +++ b/desmume/src/libretro-common/include/net/net_ifinfo.h @@ -1,49 +1,49 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (net_ifinfo.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _LIBRETRO_NET_IFINFO_H -#define _LIBRETRO_NET_IFINFO_H - -#include -#include - -#include - -struct net_ifinfo_entry -{ - char *name; - char *host; -}; - -struct net_ifinfo -{ - struct net_ifinfo_entry *entries; - size_t size; -}; - -typedef struct net_ifinfo net_ifinfo_t; - -void net_ifinfo_free(net_ifinfo_t *list); - -bool net_ifinfo_new(net_ifinfo_t *list); - -#endif +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (net_ifinfo.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_NET_IFINFO_H +#define _LIBRETRO_NET_IFINFO_H + +#include +#include + +#include + +struct net_ifinfo_entry +{ + char *name; + char *host; +}; + +struct net_ifinfo +{ + struct net_ifinfo_entry *entries; + size_t size; +}; + +typedef struct net_ifinfo net_ifinfo_t; + +void net_ifinfo_free(net_ifinfo_t *list); + +bool net_ifinfo_new(net_ifinfo_t *list); + +#endif diff --git a/desmume/src/libretro-common/include/queues/fifo_queue.h b/desmume/src/libretro-common/include/queues/fifo_queue.h index 5b4bb0166..76e6e9396 100644 --- a/desmume/src/libretro-common/include/queues/fifo_queue.h +++ b/desmume/src/libretro-common/include/queues/fifo_queue.h @@ -1,54 +1,54 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (fifo_queue.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __LIBRETRO_SDK_FIFO_BUFFER_H -#define __LIBRETRO_SDK_FIFO_BUFFER_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct fifo_buffer fifo_buffer_t; - -fifo_buffer_t *fifo_new(size_t size); - -void fifo_clear(fifo_buffer_t *buffer); - -void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size); - -void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size); - -void fifo_free(fifo_buffer_t *buffer); - -size_t fifo_read_avail(fifo_buffer_t *buffer); - -size_t fifo_write_avail(fifo_buffer_t *buffer); - -#ifdef __cplusplus -} -#endif - -#endif - +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (fifo_queue.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_FIFO_BUFFER_H +#define __LIBRETRO_SDK_FIFO_BUFFER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct fifo_buffer fifo_buffer_t; + +fifo_buffer_t *fifo_new(size_t size); + +void fifo_clear(fifo_buffer_t *buffer); + +void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size); + +void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size); + +void fifo_free(fifo_buffer_t *buffer); + +size_t fifo_read_avail(fifo_buffer_t *buffer); + +size_t fifo_write_avail(fifo_buffer_t *buffer); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/desmume/src/libretro-common/include/streams/file_stream.h b/desmume/src/libretro-common/include/streams/file_stream.h index de7a90fd7..86c866a93 100644 --- a/desmume/src/libretro-common/include/streams/file_stream.h +++ b/desmume/src/libretro-common/include/streams/file_stream.h @@ -1,75 +1,75 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (file_stream.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef __LIBRETRO_SDK_FILE_STREAM_H -#define __LIBRETRO_SDK_FILE_STREAM_H - -#include -#include - -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct RFILE RFILE; - -enum -{ - RFILE_MODE_READ = 0, - RFILE_MODE_WRITE, - RFILE_MODE_READ_WRITE, - - /* There is no garantee these requests will be attended. */ - RFILE_HINT_UNBUFFERED = 1<<8, - RFILE_HINT_MMAP = 1<<9 /* requires RFILE_MODE_READ */ -}; - -RFILE *retro_fopen(const char *path, unsigned mode, ssize_t len); - -ssize_t retro_fseek(RFILE *stream, ssize_t offset, int whence); - -ssize_t retro_fread(RFILE *stream, void *s, size_t len); - -ssize_t retro_fwrite(RFILE *stream, const void *s, size_t len); - -ssize_t retro_ftell(RFILE *stream); - -void retro_frewind(RFILE *stream); - -int retro_fclose(RFILE *stream); - -int retro_read_file(const char *path, void **buf, ssize_t *len); - -bool retro_write_file(const char *path, const void *data, ssize_t size); - -int retro_get_fd(RFILE *stream); - -#ifdef __cplusplus -} -#endif - -#endif +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_stream.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __LIBRETRO_SDK_FILE_STREAM_H +#define __LIBRETRO_SDK_FILE_STREAM_H + +#include +#include + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct RFILE RFILE; + +enum +{ + RFILE_MODE_READ = 0, + RFILE_MODE_WRITE, + RFILE_MODE_READ_WRITE, + + /* There is no garantee these requests will be attended. */ + RFILE_HINT_UNBUFFERED = 1<<8, + RFILE_HINT_MMAP = 1<<9 /* requires RFILE_MODE_READ */ +}; + +RFILE *retro_fopen(const char *path, unsigned mode, ssize_t len); + +ssize_t retro_fseek(RFILE *stream, ssize_t offset, int whence); + +ssize_t retro_fread(RFILE *stream, void *s, size_t len); + +ssize_t retro_fwrite(RFILE *stream, const void *s, size_t len); + +ssize_t retro_ftell(RFILE *stream); + +void retro_frewind(RFILE *stream); + +int retro_fclose(RFILE *stream); + +int retro_read_file(const char *path, void **buf, ssize_t *len); + +bool retro_write_file(const char *path, const void *data, ssize_t size); + +int retro_get_fd(RFILE *stream); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/desmume/src/libretro-common/include/streams/memory_stream.h b/desmume/src/libretro-common/include/streams/memory_stream.h index 94bbfc39e..ad08fc33a 100644 --- a/desmume/src/libretro-common/include/streams/memory_stream.h +++ b/desmume/src/libretro-common/include/streams/memory_stream.h @@ -1,51 +1,51 @@ -/* Copyright (C) 2010-2015 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (memory_stream.h). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _LIBRETRO_SDK_FILE_MEMORY_STREAM_H -#define _LIBRETRO_SDK_FILE_MEMORY_STREAM_H - -#include -#include - -typedef struct memstream memstream_t; - -memstream_t *memstream_open(void); - -void memstream_close(memstream_t * stream); - -size_t memstream_read(memstream_t * stream, void *data, size_t bytes); - -size_t memstream_write(memstream_t * stream, const void *data, size_t bytes); - -int memstream_getc(memstream_t * stream); - -char *memstream_gets(memstream_t * stream, char *buffer, size_t len); - -size_t memstream_pos(memstream_t * stream); - -int memstream_seek(memstream_t * stream, int offset, int whence); - -void memstream_set_buffer(uint8_t *buffer, size_t size); - -size_t memstream_get_last_size(void); - -#endif +/* Copyright (C) 2010-2015 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (memory_stream.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_SDK_FILE_MEMORY_STREAM_H +#define _LIBRETRO_SDK_FILE_MEMORY_STREAM_H + +#include +#include + +typedef struct memstream memstream_t; + +memstream_t *memstream_open(void); + +void memstream_close(memstream_t * stream); + +size_t memstream_read(memstream_t * stream, void *data, size_t bytes); + +size_t memstream_write(memstream_t * stream, const void *data, size_t bytes); + +int memstream_getc(memstream_t * stream); + +char *memstream_gets(memstream_t * stream, char *buffer, size_t len); + +size_t memstream_pos(memstream_t * stream); + +int memstream_seek(memstream_t * stream, int offset, int whence); + +void memstream_set_buffer(uint8_t *buffer, size_t size); + +size_t memstream_get_last_size(void); + +#endif diff --git a/desmume/src/libretro-common/lists/dir_list.c b/desmume/src/libretro-common/lists/dir_list.c index 8bcb3f3fb..b7144a368 100644 --- a/desmume/src/libretro-common/lists/dir_list.c +++ b/desmume/src/libretro-common/lists/dir_list.c @@ -1,214 +1,214 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (dir_list.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include -#include -#include - -#include -#include - -#include - -static int qstrcmp_plain(const void *a_, const void *b_) -{ - const struct string_list_elem *a = (const struct string_list_elem*)a_; - const struct string_list_elem *b = (const struct string_list_elem*)b_; - - return strcasecmp(a->data, b->data); -} - -static int qstrcmp_dir(const void *a_, const void *b_) -{ - const struct string_list_elem *a = (const struct string_list_elem*)a_; - const struct string_list_elem *b = (const struct string_list_elem*)b_; - int a_type = a->attr.i; - int b_type = b->attr.i; - - - /* Sort directories before files. */ - if (a_type != b_type) - return b_type - a_type; - return strcasecmp(a->data, b->data); -} - -/** - * dir_list_sort: - * @list : pointer to the directory listing. - * @dir_first : move the directories in the listing to the top? - * - * Sorts a directory listing. - * - **/ -void dir_list_sort(struct string_list *list, bool dir_first) -{ - if (list) - qsort(list->elems, list->size, sizeof(struct string_list_elem), - dir_first ? qstrcmp_dir : qstrcmp_plain); -} - -/** - * dir_list_free: - * @list : pointer to the directory listing - * - * Frees a directory listing. - * - **/ -void dir_list_free(struct string_list *list) -{ - string_list_free(list); -} - -/** - * parse_dir_entry: - * @name : name of the directory listing entry. - * @file_path : file path of the directory listing entry. - * @is_dir : is the directory listing a directory? - * @include_dirs : include directories as part of the finished directory listing? - * @include_compressed : Include compressed files, even if not part of ext_list. - * @list : pointer to directory listing. - * @ext_list : pointer to allowed file extensions listing. - * @file_ext : file extension of the directory listing entry. - * - * Parses a directory listing. - * - * Returns: zero on success, -1 on error, 1 if we should - * continue to the next entry in the directory listing. - **/ -static int parse_dir_entry(const char *name, char *file_path, - bool is_dir, bool include_dirs, bool include_compressed, - struct string_list *list, struct string_list *ext_list, - const char *file_ext) -{ - union string_list_elem_attr attr; - bool is_compressed_file = false; - bool supported_by_core = false; - - attr.i = RARCH_FILETYPE_UNSET; - - if (!is_dir) - { - is_compressed_file = path_is_compressed_file(file_path); - if (string_list_find_elem_prefix(ext_list, ".", file_ext)) - supported_by_core = true; - } - - if (!include_dirs && is_dir) - return 1; - - if (!strcmp(name, ".") || !strcmp(name, "..")) - return 1; - - if (!is_dir && ext_list && - ((!is_compressed_file && !supported_by_core) || - (!supported_by_core && !include_compressed))) - return 1; - - if (is_dir) - attr.i = RARCH_DIRECTORY; - if (is_compressed_file) - attr.i = RARCH_COMPRESSED_ARCHIVE; - /* The order of these ifs is important. - * If the file format is explicitly supported by the libretro-core, we - * need to immediately load it and not designate it as a compressed file. - * - * Example: .zip could be supported as a image by the core and as a - * compressed_file. In that case, we have to interpret it as a image. - * - * */ - if (supported_by_core) - attr.i = RARCH_PLAIN_FILE; - - if (!string_list_append(list, file_path, attr)) - return -1; - - return 0; -} - -/** - * dir_list_new: - * @dir : directory path. - * @ext : allowed extensions of file directory entries to include. - * @include_dirs : include directories as part of the finished directory listing? - * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc. - * - * Create a directory listing. - * - * Returns: pointer to a directory listing of type 'struct string_list *' on success, - * NULL in case of error. Has to be freed manually. - **/ -struct string_list *dir_list_new(const char *dir, - const char *ext, bool include_dirs, bool include_compressed) -{ - struct RDIR *entry = NULL; - struct string_list *ext_list = NULL; - struct string_list *list = NULL; - - if (!(list = string_list_new())) - return NULL; - - if (ext) - ext_list = string_split(ext, "|"); - - entry = retro_opendir(dir); - - if (!entry) - goto error; - - if (retro_dirent_error(entry)) - goto error; - - while (retro_readdir(entry)) - { - char file_path[PATH_MAX_LENGTH]; - bool is_dir; - int ret = 0; - const char *name = retro_dirent_get_name(entry); - const char *file_ext = path_get_extension(name); - - fill_pathname_join(file_path, dir, name, sizeof(file_path)); - is_dir = retro_dirent_is_dir(entry, file_path); - - ret = parse_dir_entry(name, file_path, is_dir, - include_dirs, include_compressed, list, ext_list, file_ext); - - if (ret == -1) - goto error; - - if (ret == 1) - continue; - } - - retro_closedir(entry); - - string_list_free(ext_list); - return list; - -error: - retro_closedir(entry); - - string_list_free(list); - string_list_free(ext_list); - return NULL; -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (dir_list.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include + +#include +#include + +#include + +static int qstrcmp_plain(const void *a_, const void *b_) +{ + const struct string_list_elem *a = (const struct string_list_elem*)a_; + const struct string_list_elem *b = (const struct string_list_elem*)b_; + + return strcasecmp(a->data, b->data); +} + +static int qstrcmp_dir(const void *a_, const void *b_) +{ + const struct string_list_elem *a = (const struct string_list_elem*)a_; + const struct string_list_elem *b = (const struct string_list_elem*)b_; + int a_type = a->attr.i; + int b_type = b->attr.i; + + + /* Sort directories before files. */ + if (a_type != b_type) + return b_type - a_type; + return strcasecmp(a->data, b->data); +} + +/** + * dir_list_sort: + * @list : pointer to the directory listing. + * @dir_first : move the directories in the listing to the top? + * + * Sorts a directory listing. + * + **/ +void dir_list_sort(struct string_list *list, bool dir_first) +{ + if (list) + qsort(list->elems, list->size, sizeof(struct string_list_elem), + dir_first ? qstrcmp_dir : qstrcmp_plain); +} + +/** + * dir_list_free: + * @list : pointer to the directory listing + * + * Frees a directory listing. + * + **/ +void dir_list_free(struct string_list *list) +{ + string_list_free(list); +} + +/** + * parse_dir_entry: + * @name : name of the directory listing entry. + * @file_path : file path of the directory listing entry. + * @is_dir : is the directory listing a directory? + * @include_dirs : include directories as part of the finished directory listing? + * @include_compressed : Include compressed files, even if not part of ext_list. + * @list : pointer to directory listing. + * @ext_list : pointer to allowed file extensions listing. + * @file_ext : file extension of the directory listing entry. + * + * Parses a directory listing. + * + * Returns: zero on success, -1 on error, 1 if we should + * continue to the next entry in the directory listing. + **/ +static int parse_dir_entry(const char *name, char *file_path, + bool is_dir, bool include_dirs, bool include_compressed, + struct string_list *list, struct string_list *ext_list, + const char *file_ext) +{ + union string_list_elem_attr attr; + bool is_compressed_file = false; + bool supported_by_core = false; + + attr.i = RARCH_FILETYPE_UNSET; + + if (!is_dir) + { + is_compressed_file = path_is_compressed_file(file_path); + if (string_list_find_elem_prefix(ext_list, ".", file_ext)) + supported_by_core = true; + } + + if (!include_dirs && is_dir) + return 1; + + if (!strcmp(name, ".") || !strcmp(name, "..")) + return 1; + + if (!is_dir && ext_list && + ((!is_compressed_file && !supported_by_core) || + (!supported_by_core && !include_compressed))) + return 1; + + if (is_dir) + attr.i = RARCH_DIRECTORY; + if (is_compressed_file) + attr.i = RARCH_COMPRESSED_ARCHIVE; + /* The order of these ifs is important. + * If the file format is explicitly supported by the libretro-core, we + * need to immediately load it and not designate it as a compressed file. + * + * Example: .zip could be supported as a image by the core and as a + * compressed_file. In that case, we have to interpret it as a image. + * + * */ + if (supported_by_core) + attr.i = RARCH_PLAIN_FILE; + + if (!string_list_append(list, file_path, attr)) + return -1; + + return 0; +} + +/** + * dir_list_new: + * @dir : directory path. + * @ext : allowed extensions of file directory entries to include. + * @include_dirs : include directories as part of the finished directory listing? + * @include_compressed : Only include files which match ext. Do not try to match compressed files, etc. + * + * Create a directory listing. + * + * Returns: pointer to a directory listing of type 'struct string_list *' on success, + * NULL in case of error. Has to be freed manually. + **/ +struct string_list *dir_list_new(const char *dir, + const char *ext, bool include_dirs, bool include_compressed) +{ + struct RDIR *entry = NULL; + struct string_list *ext_list = NULL; + struct string_list *list = NULL; + + if (!(list = string_list_new())) + return NULL; + + if (ext) + ext_list = string_split(ext, "|"); + + entry = retro_opendir(dir); + + if (!entry) + goto error; + + if (retro_dirent_error(entry)) + goto error; + + while (retro_readdir(entry)) + { + char file_path[PATH_MAX_LENGTH]; + bool is_dir; + int ret = 0; + const char *name = retro_dirent_get_name(entry); + const char *file_ext = path_get_extension(name); + + fill_pathname_join(file_path, dir, name, sizeof(file_path)); + is_dir = retro_dirent_is_dir(entry, file_path); + + ret = parse_dir_entry(name, file_path, is_dir, + include_dirs, include_compressed, list, ext_list, file_ext); + + if (ret == -1) + goto error; + + if (ret == 1) + continue; + } + + retro_closedir(entry); + + string_list_free(ext_list); + return list; + +error: + retro_closedir(entry); + + string_list_free(list); + string_list_free(ext_list); + return NULL; +} diff --git a/desmume/src/libretro-common/lists/file_list.c b/desmume/src/libretro-common/lists/file_list.c index 4a515f5cf..f2c98a8aa 100644 --- a/desmume/src/libretro-common/lists/file_list.c +++ b/desmume/src/libretro-common/lists/file_list.c @@ -1,428 +1,428 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (file_list.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include -#include - -/** - * file_list_capacity: - * @list : pointer to file list - * @cap : new capacity for file list. - * - * Change maximum capacity of file list's size. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -static bool file_list_capacity(file_list_t *list, size_t cap) -{ - struct item_file *new_data = NULL; - retro_assert(cap > list->size); - - new_data = (struct item_file*)realloc(list->list, - cap * sizeof(struct item_file)); - - if (!new_data) - return false; - - if (cap > list->capacity) - memset(&new_data[list->capacity], 0, - sizeof(*new_data) * (cap - list->capacity)); - - list->list = new_data; - list->capacity = cap; - - return true; -} - -bool file_list_push(file_list_t *list, - const char *path, const char *label, - unsigned type, size_t directory_ptr, - size_t entry_idx) -{ - if (list->size >= list->capacity && - !file_list_capacity(list, list->capacity * 2 + 1)) - return false; - - list->list[list->size].label = NULL; - list->list[list->size].path = NULL; - list->list[list->size].alt = NULL; - list->list[list->size].userdata = NULL; - list->list[list->size].actiondata = NULL; - list->list[list->size].type = type; - list->list[list->size].directory_ptr = directory_ptr; - list->list[list->size].entry_idx = entry_idx; - - if (label) - list->list[list->size].label = strdup(label); - if (path) - list->list[list->size].path = strdup(path); - - list->size++; - - return true; -} - -size_t file_list_get_size(const file_list_t *list) -{ - if (!list) - return 0; - return list->size; -} - -size_t file_list_get_directory_ptr(const file_list_t *list) -{ - size_t size = file_list_get_size(list); - return list->list[size].directory_ptr; -} - - -void file_list_pop(file_list_t *list, size_t *directory_ptr) -{ - if (!list) - return; - - if (list->size != 0) - { - --list->size; - if (list->list[list->size].path) - free(list->list[list->size].path); - list->list[list->size].path = NULL; - - if (list->list[list->size].label) - free(list->list[list->size].label); - list->list[list->size].label = NULL; - } - - if (directory_ptr) - *directory_ptr = list->list[list->size].directory_ptr; -} - -void file_list_free(file_list_t *list) -{ - size_t i; - - if (!list) - return; - - for (i = 0; i < list->size; i++) - { - file_list_free_userdata(list, i); - file_list_free_actiondata(list, i); - - if (list->list[i].path) - free(list->list[i].path); - list->list[i].path = NULL; - - if (list->list[i].label) - free(list->list[i].label); - list->list[i].label = NULL; - - if (list->list[i].alt) - free(list->list[i].alt); - list->list[i].alt = NULL; - } - if (list->list) - free(list->list); - list->list = NULL; - free(list); -} - -void file_list_clear(file_list_t *list) -{ - size_t i; - - if (!list) - return; - - for (i = 0; i < list->size; i++) - { - if (list->list[i].path) - free(list->list[i].path); - list->list[i].path = NULL; - - if (list->list[i].label) - free(list->list[i].label); - list->list[i].label = NULL; - - if (list->list[i].alt) - free(list->list[i].alt); - list->list[i].alt = NULL; - } - - list->size = 0; -} - -void file_list_copy(const file_list_t *src, file_list_t *dst) -{ - struct item_file *item; - - if (!src || !dst) - return; - - if (dst->list) - { - for (item = dst->list; item < &dst->list[dst->size]; ++item) - { - if (item->path) - free(item->path); - - if (item->label) - free(item->label); - - if (item->alt) - free(item->alt); - } - - free(dst->list); - } - - dst->size = 0; - dst->capacity = 0; - dst->list = (struct item_file*)malloc(src->size * sizeof(struct item_file)); - - if (!dst->list) - return; - - dst->size = dst->capacity = src->size; - - memcpy(dst->list, src->list, dst->size * sizeof(struct item_file)); - - for (item = dst->list; item < &dst->list[dst->size]; ++item) - { - if (item->path) - item->path = strdup(item->path); - - if (item->label) - item->label = strdup(item->label); - - if (item->alt) - item->alt = strdup(item->alt); - } -} - -void file_list_set_label_at_offset(file_list_t *list, size_t idx, - const char *label) -{ - if (!list) - return; - - if (list->list[idx].label) - free(list->list[idx].label); - list->list[idx].alt = NULL; - - if (label) - list->list[idx].label = strdup(label); -} - -void file_list_get_label_at_offset(const file_list_t *list, size_t idx, - const char **label) -{ - if (!label || !list) - return; - - *label = list->list[idx].path; - if (list->list[idx].label) - *label = list->list[idx].label; -} - -void file_list_set_alt_at_offset(file_list_t *list, size_t idx, - const char *alt) -{ - if (!list || !alt) - return; - - if (list->list[idx].alt) - free(list->list[idx].alt); - list->list[idx].alt = NULL; - - if (alt) - list->list[idx].alt = strdup(alt); -} - -void file_list_get_alt_at_offset(const file_list_t *list, size_t idx, - const char **alt) -{ - if (!list) - return; - - if (alt) - *alt = list->list[idx].alt ? - list->list[idx].alt : list->list[idx].path; -} - -static int file_list_alt_cmp(const void *a_, const void *b_) -{ - const struct item_file *a = (const struct item_file*)a_; - const struct item_file *b = (const struct item_file*)b_; - const char *cmp_a = a->alt ? a->alt : a->path; - const char *cmp_b = b->alt ? b->alt : b->path; - return strcasecmp(cmp_a, cmp_b); -} - -static int file_list_type_cmp(const void *a_, const void *b_) -{ - const struct item_file *a = (const struct item_file*)a_; - const struct item_file *b = (const struct item_file*)b_; - if (a->type < b->type) - return -1; - if (a->type == b->type) - return 0; - - return 1; -} - -void file_list_sort_on_alt(file_list_t *list) -{ - qsort(list->list, list->size, sizeof(list->list[0]), file_list_alt_cmp); -} - -void file_list_sort_on_type(file_list_t *list) -{ - qsort(list->list, list->size, sizeof(list->list[0]), file_list_type_cmp); -} - -void *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx) -{ - if (!list) - return NULL; - return list->list[idx].userdata; -} - -void file_list_set_userdata(const file_list_t *list, size_t idx, void *ptr) -{ - if (!list || !ptr) - return; - list->list[idx].userdata = ptr; -} - -void file_list_set_actiondata(const file_list_t *list, size_t idx, void *ptr) -{ - if (!list || !ptr) - return; - list->list[idx].actiondata = ptr; -} - -void *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx) -{ - if (!list) - return NULL; - return list->list[idx].actiondata; -} - -void file_list_free_actiondata(const file_list_t *list, size_t idx) -{ - if (!list) - return; - if (list->list[idx].actiondata) - free(list->list[idx].actiondata); - list->list[idx].actiondata = NULL; -} - -void file_list_free_userdata(const file_list_t *list, size_t idx) -{ - if (!list) - return; - if (list->list[idx].userdata) - free(list->list[idx].userdata); - list->list[idx].userdata = NULL; -} - -void *file_list_get_last_actiondata(const file_list_t *list) -{ - if (!list) - return NULL; - return list->list[list->size - 1].actiondata; -} - -void file_list_get_at_offset(const file_list_t *list, size_t idx, - const char **path, const char **label, unsigned *file_type, - size_t *entry_idx) -{ - if (!list) - return; - - if (path) - *path = list->list[idx].path; - if (label) - *label = list->list[idx].label; - if (file_type) - *file_type = list->list[idx].type; - if (entry_idx) - *entry_idx = list->list[idx].entry_idx; -} - -void file_list_get_last(const file_list_t *list, - const char **path, const char **label, - unsigned *file_type, size_t *entry_idx) -{ - if (!list) - return; - - if (list->size) - file_list_get_at_offset(list, list->size - 1, path, label, file_type, entry_idx); -} - -bool file_list_search(const file_list_t *list, const char *needle, size_t *idx) -{ - size_t i; - const char *alt; - bool ret = false; - - if (!list) - return false; - - for (i = 0; i < list->size; i++) - { - const char *str; - file_list_get_alt_at_offset(list, i, &alt); - if (!alt) - { - file_list_get_label_at_offset(list, i, &alt); - if (!alt) - continue; - } - - str = (const char *)strcasestr(alt, needle); - if (str == alt) - { - /* Found match with first chars, best possible match. */ - *idx = i; - ret = true; - break; - } - else if (str && !ret) - { - /* Found mid-string match, but try to find a match with - * first characters before we settle. */ - *idx = i; - ret = true; - } - } - - return ret; -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_list.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include + +/** + * file_list_capacity: + * @list : pointer to file list + * @cap : new capacity for file list. + * + * Change maximum capacity of file list's size. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +static bool file_list_capacity(file_list_t *list, size_t cap) +{ + struct item_file *new_data = NULL; + retro_assert(cap > list->size); + + new_data = (struct item_file*)realloc(list->list, + cap * sizeof(struct item_file)); + + if (!new_data) + return false; + + if (cap > list->capacity) + memset(&new_data[list->capacity], 0, + sizeof(*new_data) * (cap - list->capacity)); + + list->list = new_data; + list->capacity = cap; + + return true; +} + +bool file_list_push(file_list_t *list, + const char *path, const char *label, + unsigned type, size_t directory_ptr, + size_t entry_idx) +{ + if (list->size >= list->capacity && + !file_list_capacity(list, list->capacity * 2 + 1)) + return false; + + list->list[list->size].label = NULL; + list->list[list->size].path = NULL; + list->list[list->size].alt = NULL; + list->list[list->size].userdata = NULL; + list->list[list->size].actiondata = NULL; + list->list[list->size].type = type; + list->list[list->size].directory_ptr = directory_ptr; + list->list[list->size].entry_idx = entry_idx; + + if (label) + list->list[list->size].label = strdup(label); + if (path) + list->list[list->size].path = strdup(path); + + list->size++; + + return true; +} + +size_t file_list_get_size(const file_list_t *list) +{ + if (!list) + return 0; + return list->size; +} + +size_t file_list_get_directory_ptr(const file_list_t *list) +{ + size_t size = file_list_get_size(list); + return list->list[size].directory_ptr; +} + + +void file_list_pop(file_list_t *list, size_t *directory_ptr) +{ + if (!list) + return; + + if (list->size != 0) + { + --list->size; + if (list->list[list->size].path) + free(list->list[list->size].path); + list->list[list->size].path = NULL; + + if (list->list[list->size].label) + free(list->list[list->size].label); + list->list[list->size].label = NULL; + } + + if (directory_ptr) + *directory_ptr = list->list[list->size].directory_ptr; +} + +void file_list_free(file_list_t *list) +{ + size_t i; + + if (!list) + return; + + for (i = 0; i < list->size; i++) + { + file_list_free_userdata(list, i); + file_list_free_actiondata(list, i); + + if (list->list[i].path) + free(list->list[i].path); + list->list[i].path = NULL; + + if (list->list[i].label) + free(list->list[i].label); + list->list[i].label = NULL; + + if (list->list[i].alt) + free(list->list[i].alt); + list->list[i].alt = NULL; + } + if (list->list) + free(list->list); + list->list = NULL; + free(list); +} + +void file_list_clear(file_list_t *list) +{ + size_t i; + + if (!list) + return; + + for (i = 0; i < list->size; i++) + { + if (list->list[i].path) + free(list->list[i].path); + list->list[i].path = NULL; + + if (list->list[i].label) + free(list->list[i].label); + list->list[i].label = NULL; + + if (list->list[i].alt) + free(list->list[i].alt); + list->list[i].alt = NULL; + } + + list->size = 0; +} + +void file_list_copy(const file_list_t *src, file_list_t *dst) +{ + struct item_file *item; + + if (!src || !dst) + return; + + if (dst->list) + { + for (item = dst->list; item < &dst->list[dst->size]; ++item) + { + if (item->path) + free(item->path); + + if (item->label) + free(item->label); + + if (item->alt) + free(item->alt); + } + + free(dst->list); + } + + dst->size = 0; + dst->capacity = 0; + dst->list = (struct item_file*)malloc(src->size * sizeof(struct item_file)); + + if (!dst->list) + return; + + dst->size = dst->capacity = src->size; + + memcpy(dst->list, src->list, dst->size * sizeof(struct item_file)); + + for (item = dst->list; item < &dst->list[dst->size]; ++item) + { + if (item->path) + item->path = strdup(item->path); + + if (item->label) + item->label = strdup(item->label); + + if (item->alt) + item->alt = strdup(item->alt); + } +} + +void file_list_set_label_at_offset(file_list_t *list, size_t idx, + const char *label) +{ + if (!list) + return; + + if (list->list[idx].label) + free(list->list[idx].label); + list->list[idx].alt = NULL; + + if (label) + list->list[idx].label = strdup(label); +} + +void file_list_get_label_at_offset(const file_list_t *list, size_t idx, + const char **label) +{ + if (!label || !list) + return; + + *label = list->list[idx].path; + if (list->list[idx].label) + *label = list->list[idx].label; +} + +void file_list_set_alt_at_offset(file_list_t *list, size_t idx, + const char *alt) +{ + if (!list || !alt) + return; + + if (list->list[idx].alt) + free(list->list[idx].alt); + list->list[idx].alt = NULL; + + if (alt) + list->list[idx].alt = strdup(alt); +} + +void file_list_get_alt_at_offset(const file_list_t *list, size_t idx, + const char **alt) +{ + if (!list) + return; + + if (alt) + *alt = list->list[idx].alt ? + list->list[idx].alt : list->list[idx].path; +} + +static int file_list_alt_cmp(const void *a_, const void *b_) +{ + const struct item_file *a = (const struct item_file*)a_; + const struct item_file *b = (const struct item_file*)b_; + const char *cmp_a = a->alt ? a->alt : a->path; + const char *cmp_b = b->alt ? b->alt : b->path; + return strcasecmp(cmp_a, cmp_b); +} + +static int file_list_type_cmp(const void *a_, const void *b_) +{ + const struct item_file *a = (const struct item_file*)a_; + const struct item_file *b = (const struct item_file*)b_; + if (a->type < b->type) + return -1; + if (a->type == b->type) + return 0; + + return 1; +} + +void file_list_sort_on_alt(file_list_t *list) +{ + qsort(list->list, list->size, sizeof(list->list[0]), file_list_alt_cmp); +} + +void file_list_sort_on_type(file_list_t *list) +{ + qsort(list->list, list->size, sizeof(list->list[0]), file_list_type_cmp); +} + +void *file_list_get_userdata_at_offset(const file_list_t *list, size_t idx) +{ + if (!list) + return NULL; + return list->list[idx].userdata; +} + +void file_list_set_userdata(const file_list_t *list, size_t idx, void *ptr) +{ + if (!list || !ptr) + return; + list->list[idx].userdata = ptr; +} + +void file_list_set_actiondata(const file_list_t *list, size_t idx, void *ptr) +{ + if (!list || !ptr) + return; + list->list[idx].actiondata = ptr; +} + +void *file_list_get_actiondata_at_offset(const file_list_t *list, size_t idx) +{ + if (!list) + return NULL; + return list->list[idx].actiondata; +} + +void file_list_free_actiondata(const file_list_t *list, size_t idx) +{ + if (!list) + return; + if (list->list[idx].actiondata) + free(list->list[idx].actiondata); + list->list[idx].actiondata = NULL; +} + +void file_list_free_userdata(const file_list_t *list, size_t idx) +{ + if (!list) + return; + if (list->list[idx].userdata) + free(list->list[idx].userdata); + list->list[idx].userdata = NULL; +} + +void *file_list_get_last_actiondata(const file_list_t *list) +{ + if (!list) + return NULL; + return list->list[list->size - 1].actiondata; +} + +void file_list_get_at_offset(const file_list_t *list, size_t idx, + const char **path, const char **label, unsigned *file_type, + size_t *entry_idx) +{ + if (!list) + return; + + if (path) + *path = list->list[idx].path; + if (label) + *label = list->list[idx].label; + if (file_type) + *file_type = list->list[idx].type; + if (entry_idx) + *entry_idx = list->list[idx].entry_idx; +} + +void file_list_get_last(const file_list_t *list, + const char **path, const char **label, + unsigned *file_type, size_t *entry_idx) +{ + if (!list) + return; + + if (list->size) + file_list_get_at_offset(list, list->size - 1, path, label, file_type, entry_idx); +} + +bool file_list_search(const file_list_t *list, const char *needle, size_t *idx) +{ + size_t i; + const char *alt; + bool ret = false; + + if (!list) + return false; + + for (i = 0; i < list->size; i++) + { + const char *str; + file_list_get_alt_at_offset(list, i, &alt); + if (!alt) + { + file_list_get_label_at_offset(list, i, &alt); + if (!alt) + continue; + } + + str = (const char *)strcasestr(alt, needle); + if (str == alt) + { + /* Found match with first chars, best possible match. */ + *idx = i; + ret = true; + break; + } + else if (str && !ret) + { + /* Found mid-string match, but try to find a match with + * first characters before we settle. */ + *idx = i; + ret = true; + } + } + + return ret; +} diff --git a/desmume/src/libretro-common/lists/string_list.c b/desmume/src/libretro-common/lists/string_list.c index 3448053d6..b331df667 100644 --- a/desmume/src/libretro-common/lists/string_list.c +++ b/desmume/src/libretro-common/lists/string_list.c @@ -1,275 +1,275 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (string_list.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -/** - * string_list_free - * @list : pointer to string list object - * - * Frees a string list. - */ -void string_list_free(struct string_list *list) -{ - size_t i; - if (!list) - return; - - for (i = 0; i < list->size; i++) - free(list->elems[i].data); - free(list->elems); - free(list); -} - -/** - * string_list_capacity: - * @list : pointer to string list - * @cap : new capacity for string list. - * - * Change maximum capacity of string list's size. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -static bool string_list_capacity(struct string_list *list, size_t cap) -{ - struct string_list_elem *new_data = NULL; - retro_assert(cap > list->size); - - new_data = (struct string_list_elem*) - realloc(list->elems, cap * sizeof(*new_data)); - - if (!new_data) - return false; - - if (cap > list->cap) - memset(&new_data[list->cap], 0, sizeof(*new_data) * (cap - list->cap)); - - list->elems = new_data; - list->cap = cap; - return true; -} - -/** - * string_list_new: - * - * Creates a new string list. Has to be freed manually. - * - * Returns: new string list if successful, otherwise NULL. - */ -struct string_list *string_list_new(void) -{ - struct string_list *list = (struct string_list*) - calloc(1, sizeof(*list)); - - if (!list) - return NULL; - - if (!string_list_capacity(list, 32)) - { - string_list_free(list); - return NULL; - } - - return list; -} - -/** - * string_list_append: - * @list : pointer to string list - * @elem : element to add to the string list - * @attr : attributes of new element. - * - * Appends a new element to the string list. - * - * Returns: true (1) if successful, otherwise false (0). - **/ -bool string_list_append(struct string_list *list, const char *elem, - union string_list_elem_attr attr) -{ - char *data_dup = NULL; - - if (list->size >= list->cap && - !string_list_capacity(list, list->cap * 2)) - return false; - - data_dup = strdup(elem); - if (!data_dup) - return false; - - list->elems[list->size].data = data_dup; - list->elems[list->size].attr = attr; - - list->size++; - return true; -} - -/** - * string_list_set: - * @list : pointer to string list - * @idx : index of element in string list - * @str : value for the element. - * - * Set value of element inside string list. - **/ -void string_list_set(struct string_list *list, - unsigned idx, const char *str) -{ - free(list->elems[idx].data); - retro_assert(list->elems[idx].data = strdup(str)); -} - -/** - * string_list_join_concat: - * @buffer : buffer that @list will be joined to. - * @size : length of @buffer. - * @list : pointer to string list. - * @delim : delimiter character for @list. - * - * A string list will be joined/concatenated as a - * string to @buffer, delimited by @delim. - */ -void string_list_join_concat(char *buffer, size_t size, - const struct string_list *list, const char *delim) -{ - size_t i, len = strlen(buffer); - - retro_assert(len < size); - buffer += len; - size -= len; - - for (i = 0; i < list->size; i++) - { - strlcat(buffer, list->elems[i].data, size); - if ((i + 1) < list->size) - strlcat(buffer, delim, size); - } -} - -/** - * string_split: - * @str : string to turn into a string list - * @delim : delimiter character to use for splitting the string. - * - * Creates a new string list based on string @str, delimited by @delim. - * - * Returns: new string list if successful, otherwise NULL. - */ -struct string_list *string_split(const char *str, const char *delim) -{ - char *save = NULL; - char *copy = NULL; - const char *tmp = NULL; - struct string_list *list = string_list_new(); - - if (!list) - goto error; - - copy = strdup(str); - if (!copy) - goto error; - - tmp = strtok_r(copy, delim, &save); - while (tmp) - { - union string_list_elem_attr attr; - memset(&attr, 0, sizeof(attr)); - - if (!string_list_append(list, tmp, attr)) - goto error; - - tmp = strtok_r(NULL, delim, &save); - } - - free(copy); - return list; - -error: - string_list_free(list); - free(copy); - return NULL; -} - -/** - * string_list_find_elem: - * @list : pointer to string list - * @elem : element to find inside the string list. - * - * Searches for an element (@elem) inside the string list. - * - * Returns: true (1) if element could be found, otherwise false (0). - */ -int string_list_find_elem(const struct string_list *list, const char *elem) -{ - size_t i; - - if (!list) - return false; - - for (i = 0; i < list->size; i++) - { - if (strcasecmp(list->elems[i].data, elem) == 0) - return i+1; - } - - return false; -} - -/** - * string_list_find_elem_prefix: - * @list : pointer to string list - * @prefix : prefix to append to @elem - * @elem : element to find inside the string list. - * - * Searches for an element (@elem) inside the string list. Will - * also search for the same element prefixed by @prefix. - * - * Returns: true (1) if element could be found, otherwise false (0). - */ -bool string_list_find_elem_prefix(const struct string_list *list, - const char *prefix, const char *elem) -{ - size_t i; - char prefixed[PATH_MAX_LENGTH] = {0}; - - if (!list) - return false; - - strlcpy(prefixed, prefix, sizeof(prefixed)); - strlcat(prefixed, elem, sizeof(prefixed)); - - for (i = 0; i < list->size; i++) - { - if (strcasecmp(list->elems[i].data, elem) == 0 || - strcasecmp(list->elems[i].data, prefixed) == 0) - return true; - } - - return false; -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (string_list.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +/** + * string_list_free + * @list : pointer to string list object + * + * Frees a string list. + */ +void string_list_free(struct string_list *list) +{ + size_t i; + if (!list) + return; + + for (i = 0; i < list->size; i++) + free(list->elems[i].data); + free(list->elems); + free(list); +} + +/** + * string_list_capacity: + * @list : pointer to string list + * @cap : new capacity for string list. + * + * Change maximum capacity of string list's size. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +static bool string_list_capacity(struct string_list *list, size_t cap) +{ + struct string_list_elem *new_data = NULL; + retro_assert(cap > list->size); + + new_data = (struct string_list_elem*) + realloc(list->elems, cap * sizeof(*new_data)); + + if (!new_data) + return false; + + if (cap > list->cap) + memset(&new_data[list->cap], 0, sizeof(*new_data) * (cap - list->cap)); + + list->elems = new_data; + list->cap = cap; + return true; +} + +/** + * string_list_new: + * + * Creates a new string list. Has to be freed manually. + * + * Returns: new string list if successful, otherwise NULL. + */ +struct string_list *string_list_new(void) +{ + struct string_list *list = (struct string_list*) + calloc(1, sizeof(*list)); + + if (!list) + return NULL; + + if (!string_list_capacity(list, 32)) + { + string_list_free(list); + return NULL; + } + + return list; +} + +/** + * string_list_append: + * @list : pointer to string list + * @elem : element to add to the string list + * @attr : attributes of new element. + * + * Appends a new element to the string list. + * + * Returns: true (1) if successful, otherwise false (0). + **/ +bool string_list_append(struct string_list *list, const char *elem, + union string_list_elem_attr attr) +{ + char *data_dup = NULL; + + if (list->size >= list->cap && + !string_list_capacity(list, list->cap * 2)) + return false; + + data_dup = strdup(elem); + if (!data_dup) + return false; + + list->elems[list->size].data = data_dup; + list->elems[list->size].attr = attr; + + list->size++; + return true; +} + +/** + * string_list_set: + * @list : pointer to string list + * @idx : index of element in string list + * @str : value for the element. + * + * Set value of element inside string list. + **/ +void string_list_set(struct string_list *list, + unsigned idx, const char *str) +{ + free(list->elems[idx].data); + retro_assert(list->elems[idx].data = strdup(str)); +} + +/** + * string_list_join_concat: + * @buffer : buffer that @list will be joined to. + * @size : length of @buffer. + * @list : pointer to string list. + * @delim : delimiter character for @list. + * + * A string list will be joined/concatenated as a + * string to @buffer, delimited by @delim. + */ +void string_list_join_concat(char *buffer, size_t size, + const struct string_list *list, const char *delim) +{ + size_t i, len = strlen(buffer); + + retro_assert(len < size); + buffer += len; + size -= len; + + for (i = 0; i < list->size; i++) + { + strlcat(buffer, list->elems[i].data, size); + if ((i + 1) < list->size) + strlcat(buffer, delim, size); + } +} + +/** + * string_split: + * @str : string to turn into a string list + * @delim : delimiter character to use for splitting the string. + * + * Creates a new string list based on string @str, delimited by @delim. + * + * Returns: new string list if successful, otherwise NULL. + */ +struct string_list *string_split(const char *str, const char *delim) +{ + char *save = NULL; + char *copy = NULL; + const char *tmp = NULL; + struct string_list *list = string_list_new(); + + if (!list) + goto error; + + copy = strdup(str); + if (!copy) + goto error; + + tmp = strtok_r(copy, delim, &save); + while (tmp) + { + union string_list_elem_attr attr; + memset(&attr, 0, sizeof(attr)); + + if (!string_list_append(list, tmp, attr)) + goto error; + + tmp = strtok_r(NULL, delim, &save); + } + + free(copy); + return list; + +error: + string_list_free(list); + free(copy); + return NULL; +} + +/** + * string_list_find_elem: + * @list : pointer to string list + * @elem : element to find inside the string list. + * + * Searches for an element (@elem) inside the string list. + * + * Returns: true (1) if element could be found, otherwise false (0). + */ +int string_list_find_elem(const struct string_list *list, const char *elem) +{ + size_t i; + + if (!list) + return false; + + for (i = 0; i < list->size; i++) + { + if (strcasecmp(list->elems[i].data, elem) == 0) + return i+1; + } + + return false; +} + +/** + * string_list_find_elem_prefix: + * @list : pointer to string list + * @prefix : prefix to append to @elem + * @elem : element to find inside the string list. + * + * Searches for an element (@elem) inside the string list. Will + * also search for the same element prefixed by @prefix. + * + * Returns: true (1) if element could be found, otherwise false (0). + */ +bool string_list_find_elem_prefix(const struct string_list *list, + const char *prefix, const char *elem) +{ + size_t i; + char prefixed[PATH_MAX_LENGTH] = {0}; + + if (!list) + return false; + + strlcpy(prefixed, prefix, sizeof(prefixed)); + strlcat(prefixed, elem, sizeof(prefixed)); + + for (i = 0; i < list->size; i++) + { + if (strcasecmp(list->elems[i].data, elem) == 0 || + strcasecmp(list->elems[i].data, prefixed) == 0) + return true; + } + + return false; +} diff --git a/desmume/src/libretro-common/net/net_ifinfo.c b/desmume/src/libretro-common/net/net_ifinfo.c index 806032978..c2b91fd97 100644 --- a/desmume/src/libretro-common/net/net_ifinfo.c +++ b/desmume/src/libretro-common/net/net_ifinfo.c @@ -1,178 +1,178 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (compat_fnmatch.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include - -#if defined(_WIN32) && !defined(_XBOX) -#include -#include -#include -#else -#include -#include -#include - -#ifdef WANT_IFADDRS -#include -#else -#include -#endif -#endif - -#include - -void net_ifinfo_free(net_ifinfo_t *list) -{ - unsigned k; - - if (!list) - return; - - for (k = 0; k < list->size; k++) - { - struct net_ifinfo_entry *ptr = - (struct net_ifinfo_entry*)&list->entries[k]; - - if (!ptr) - continue; - - if (*ptr->name) - free(ptr->name); - if (*ptr->host) - free(ptr->host); - - ptr->name = NULL; - ptr->host = NULL; - } - free(list->entries); - free(list); -} - -bool net_ifinfo_new(net_ifinfo_t *list) -{ - unsigned k = 0; -#if defined(_WIN32) && !defined(_XBOX) - DWORD size; - PIP_ADAPTER_ADDRESSES adapter_addresses, aa; - PIP_ADAPTER_UNICAST_ADDRESS ua; - - DWORD rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &size); - - adapter_addresses = (PIP_ADAPTER_ADDRESSES)malloc(size); - - rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter_addresses, &size); - - if (rv != ERROR_SUCCESS) - goto error; - - for (aa = adapter_addresses; aa != NULL; aa = aa->Next) - { - char name[PATH_MAX_LENGTH]; - memset(name, 0, sizeof(name)); - - WideCharToMultiByte(CP_ACP, 0, aa->FriendlyName, wcslen(aa->FriendlyName), - name, PATH_MAX_LENGTH, NULL, NULL); - - for (ua = aa->FirstUnicastAddress; ua != NULL; ua = ua->Next) - { - char host[PATH_MAX_LENGTH]; - struct net_ifinfo_entry *ptr = (struct net_ifinfo_entry*) - realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); - - if (!ptr) - goto error; - - list->entries = ptr; - - memset(host, 0, sizeof(host)); - - getnameinfo(ua->Address.lpSockaddr, ua->Address.iSockaddrLength, - host, sizeof(host), NULL, NI_MAXSERV, NI_NUMERICHOST); - - list->entries[k].name = strdup(name); - list->entries[k].host = strdup(host); - list->size = k + 1; - - k++; - } - } - - free(adapter_addresses); -#else - struct ifaddrs *ifa = NULL; - struct ifaddrs *ifaddr = NULL; - - if (getifaddrs(&ifaddr) == -1) - goto error; - - if (!list) - goto error; - - for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) - { - char host[NI_MAXHOST]; - struct net_ifinfo_entry *ptr = NULL; - - if (!ifa->ifa_addr) - continue; - - if (ifa->ifa_addr->sa_family != AF_INET) - continue; - - if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), - host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) - goto error; - - ptr = (struct net_ifinfo_entry*) - realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); - - if (!ptr) - goto error; - - list->entries = ptr; - - list->entries[k].name = strdup(ifa->ifa_name); - list->entries[k].host = strdup(host); - list->size = k + 1; - - k++; - } - - freeifaddrs(ifaddr); -#endif - return true; - -error: -#ifdef _WIN32 - if (adapter_addresses) - free(adapter_addresses); -#else - freeifaddrs(ifaddr); -#endif - net_ifinfo_free(list); - - return false; -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (compat_fnmatch.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +#if defined(_WIN32) && !defined(_XBOX) +#include +#include +#include +#else +#include +#include +#include + +#ifdef WANT_IFADDRS +#include +#else +#include +#endif +#endif + +#include + +void net_ifinfo_free(net_ifinfo_t *list) +{ + unsigned k; + + if (!list) + return; + + for (k = 0; k < list->size; k++) + { + struct net_ifinfo_entry *ptr = + (struct net_ifinfo_entry*)&list->entries[k]; + + if (!ptr) + continue; + + if (*ptr->name) + free(ptr->name); + if (*ptr->host) + free(ptr->host); + + ptr->name = NULL; + ptr->host = NULL; + } + free(list->entries); + free(list); +} + +bool net_ifinfo_new(net_ifinfo_t *list) +{ + unsigned k = 0; +#if defined(_WIN32) && !defined(_XBOX) + DWORD size; + PIP_ADAPTER_ADDRESSES adapter_addresses, aa; + PIP_ADAPTER_UNICAST_ADDRESS ua; + + DWORD rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &size); + + adapter_addresses = (PIP_ADAPTER_ADDRESSES)malloc(size); + + rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter_addresses, &size); + + if (rv != ERROR_SUCCESS) + goto error; + + for (aa = adapter_addresses; aa != NULL; aa = aa->Next) + { + char name[PATH_MAX_LENGTH]; + memset(name, 0, sizeof(name)); + + WideCharToMultiByte(CP_ACP, 0, aa->FriendlyName, wcslen(aa->FriendlyName), + name, PATH_MAX_LENGTH, NULL, NULL); + + for (ua = aa->FirstUnicastAddress; ua != NULL; ua = ua->Next) + { + char host[PATH_MAX_LENGTH]; + struct net_ifinfo_entry *ptr = (struct net_ifinfo_entry*) + realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); + + if (!ptr) + goto error; + + list->entries = ptr; + + memset(host, 0, sizeof(host)); + + getnameinfo(ua->Address.lpSockaddr, ua->Address.iSockaddrLength, + host, sizeof(host), NULL, NI_MAXSERV, NI_NUMERICHOST); + + list->entries[k].name = strdup(name); + list->entries[k].host = strdup(host); + list->size = k + 1; + + k++; + } + } + + free(adapter_addresses); +#else + struct ifaddrs *ifa = NULL; + struct ifaddrs *ifaddr = NULL; + + if (getifaddrs(&ifaddr) == -1) + goto error; + + if (!list) + goto error; + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + char host[NI_MAXHOST]; + struct net_ifinfo_entry *ptr = NULL; + + if (!ifa->ifa_addr) + continue; + + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + + if (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) + goto error; + + ptr = (struct net_ifinfo_entry*) + realloc(list->entries, (k+1) * sizeof(struct net_ifinfo_entry)); + + if (!ptr) + goto error; + + list->entries = ptr; + + list->entries[k].name = strdup(ifa->ifa_name); + list->entries[k].host = strdup(host); + list->size = k + 1; + + k++; + } + + freeifaddrs(ifaddr); +#endif + return true; + +error: +#ifdef _WIN32 + if (adapter_addresses) + free(adapter_addresses); +#else + freeifaddrs(ifaddr); +#endif + net_ifinfo_free(list); + + return false; +} diff --git a/desmume/src/libretro-common/net/net_ifinfo_test.c b/desmume/src/libretro-common/net/net_ifinfo_test.c index cba7df3ab..b00da1b42 100644 --- a/desmume/src/libretro-common/net/net_ifinfo_test.c +++ b/desmume/src/libretro-common/net/net_ifinfo_test.c @@ -1,49 +1,49 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (compat_fnmatch.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include - -int main(int argc, const char *argv[]) -{ - unsigned k = 0; - net_ifinfo_t *list = - (net_ifinfo_t*)calloc(1, sizeof(*list)); - - if (!list) - return -1; - - if (!net_ifinfo_new(list)) - return -1; - - for (k = 0; k < list->size; k++) - { - printf("%s:%s\n", list->entries[k].name, list->entries[k].host); - } - - net_ifinfo_free(list); - - return 0; -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (compat_fnmatch.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +int main(int argc, const char *argv[]) +{ + unsigned k = 0; + net_ifinfo_t *list = + (net_ifinfo_t*)calloc(1, sizeof(*list)); + + if (!list) + return -1; + + if (!net_ifinfo_new(list)) + return -1; + + for (k = 0; k < list->size; k++) + { + printf("%s:%s\n", list->entries[k].name, list->entries[k].host); + } + + net_ifinfo_free(list); + + return 0; +} diff --git a/desmume/src/libretro-common/queues/fifo_queue.c b/desmume/src/libretro-common/queues/fifo_queue.c index e763cb69c..0407ded60 100644 --- a/desmume/src/libretro-common/queues/fifo_queue.c +++ b/desmume/src/libretro-common/queues/fifo_queue.c @@ -1,124 +1,124 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (fifo_queue.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include - -struct fifo_buffer -{ - uint8_t *buffer; - size_t size; - size_t first; - size_t end; -}; - -fifo_buffer_t *fifo_new(size_t size) -{ - fifo_buffer_t *buf = (fifo_buffer_t*)calloc(1, sizeof(*buf)); - - if (!buf) - return NULL; - - buf->buffer = (uint8_t*)calloc(1, size + 1); - if (!buf->buffer) - { - free(buf); - return NULL; - } - buf->size = size + 1; - - return buf; -} - -void fifo_clear(fifo_buffer_t *buffer) -{ - buffer->first = 0; - buffer->end = 0; -} - -void fifo_free(fifo_buffer_t *buffer) -{ - if (!buffer) - return; - - free(buffer->buffer); - free(buffer); -} - -size_t fifo_read_avail(fifo_buffer_t *buffer) -{ - size_t first = buffer->first; - size_t end = buffer->end; - - if (end < first) - end += buffer->size; - return end - first; -} - -size_t fifo_write_avail(fifo_buffer_t *buffer) -{ - size_t first = buffer->first; - size_t end = buffer->end; - - if (end < first) - end += buffer->size; - - return (buffer->size - 1) - (end - first); -} - -void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size) -{ - size_t first_write = size; - size_t rest_write = 0; - - if (buffer->end + size > buffer->size) - { - first_write = buffer->size - buffer->end; - rest_write = size - first_write; - } - - memcpy(buffer->buffer + buffer->end, in_buf, first_write); - memcpy(buffer->buffer, (const uint8_t*)in_buf + first_write, rest_write); - - buffer->end = (buffer->end + size) % buffer->size; -} - - -void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size) -{ - size_t first_read = size; - size_t rest_read = 0; - - if (buffer->first + size > buffer->size) - { - first_read = buffer->size - buffer->first; - rest_read = size - first_read; - } - - memcpy(in_buf, (const uint8_t*)buffer->buffer + buffer->first, first_read); - memcpy((uint8_t*)in_buf + first_read, buffer->buffer, rest_read); - - buffer->first = (buffer->first + size) % buffer->size; -} - +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (fifo_queue.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include + +struct fifo_buffer +{ + uint8_t *buffer; + size_t size; + size_t first; + size_t end; +}; + +fifo_buffer_t *fifo_new(size_t size) +{ + fifo_buffer_t *buf = (fifo_buffer_t*)calloc(1, sizeof(*buf)); + + if (!buf) + return NULL; + + buf->buffer = (uint8_t*)calloc(1, size + 1); + if (!buf->buffer) + { + free(buf); + return NULL; + } + buf->size = size + 1; + + return buf; +} + +void fifo_clear(fifo_buffer_t *buffer) +{ + buffer->first = 0; + buffer->end = 0; +} + +void fifo_free(fifo_buffer_t *buffer) +{ + if (!buffer) + return; + + free(buffer->buffer); + free(buffer); +} + +size_t fifo_read_avail(fifo_buffer_t *buffer) +{ + size_t first = buffer->first; + size_t end = buffer->end; + + if (end < first) + end += buffer->size; + return end - first; +} + +size_t fifo_write_avail(fifo_buffer_t *buffer) +{ + size_t first = buffer->first; + size_t end = buffer->end; + + if (end < first) + end += buffer->size; + + return (buffer->size - 1) - (end - first); +} + +void fifo_write(fifo_buffer_t *buffer, const void *in_buf, size_t size) +{ + size_t first_write = size; + size_t rest_write = 0; + + if (buffer->end + size > buffer->size) + { + first_write = buffer->size - buffer->end; + rest_write = size - first_write; + } + + memcpy(buffer->buffer + buffer->end, in_buf, first_write); + memcpy(buffer->buffer, (const uint8_t*)in_buf + first_write, rest_write); + + buffer->end = (buffer->end + size) % buffer->size; +} + + +void fifo_read(fifo_buffer_t *buffer, void *in_buf, size_t size) +{ + size_t first_read = size; + size_t rest_read = 0; + + if (buffer->first + size > buffer->size) + { + first_read = buffer->size - buffer->first; + rest_read = size - first_read; + } + + memcpy(in_buf, (const uint8_t*)buffer->buffer + buffer->first, first_read); + memcpy((uint8_t*)in_buf + first_read, buffer->buffer, rest_read); + + buffer->first = (buffer->first + size) % buffer->size; +} + diff --git a/desmume/src/libretro-common/streams/file_stream.c b/desmume/src/libretro-common/streams/file_stream.c index 41a6810f2..122a02051 100644 --- a/desmume/src/libretro-common/streams/file_stream.c +++ b/desmume/src/libretro-common/streams/file_stream.c @@ -1,536 +1,536 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (file_stream.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -#if defined(_WIN32) -# ifdef _MSC_VER -# define setmode _setmode -# endif -# ifdef _XBOX -# include -# define INVALID_FILE_ATTRIBUTES -1 -# else -# include -# include -# include -# include -# endif -#elif defined(VITA) -# include -# include - -#define PSP_O_RDONLY PSP2_O_RDONLY -#define PSP_O_RDWR PSP2_O_RDWR -#define PSP_O_CREAT PSP2_O_CREAT -#define PSP_O_WRONLY PSP2_O_WRONLY -#define PSP_O_TRUNC PSP2_O_TRUNC -#else -# if defined(PSP) -# include -# endif -# include -# include -# include -# include -#endif - -#ifdef __CELLOS_LV2__ -#include -#else -#include -#endif - -#include -#include - -#if 1 -#define HAVE_BUFFERED_IO 1 -#endif - -struct RFILE -{ - unsigned hints; -#if defined(PSP) || defined(VITA) - SceUID fd; -#elif defined(__CELLOS_LV2__) - int fd; -#else -#if defined(HAVE_BUFFERED_IO) - FILE *fp; -#endif -#if defined(HAVE_MMAP) - uint8_t *mapped; - uint64_t mappos; - uint64_t mapsize; -#endif - int fd; -#endif -}; - -int retro_get_fd(RFILE *stream) -{ - if (!stream) - return -1; -#if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) - return stream->fd; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - return fileno(stream->fp); -#endif - return stream->fd; -#endif -} - -RFILE *retro_fopen(const char *path, unsigned mode, ssize_t len) -{ - int flags = 0; - int mode_int = 0; - const char *mode_str = NULL; - RFILE *stream = (RFILE*)calloc(1, sizeof(*stream)); - - if (!stream) - return NULL; - - (void)mode_str; - (void)mode_int; - (void)flags; - - stream->hints = mode; - -#ifdef HAVE_MMAP - if (stream->hints & RFILE_HINT_MMAP && (stream->hints & 0xff) == RFILE_MODE_READ) - stream->hints |= RFILE_HINT_UNBUFFERED; - else -#endif - stream->hints &= ~RFILE_HINT_MMAP; - - switch (mode & 0xff) - { - case RFILE_MODE_READ: -#if defined(VITA) || defined(PSP) - mode_int = 0777; - flags = PSP_O_RDONLY; -#elif defined(__CELLOS_LV2__) - mode_int = 0777; - flags = CELL_FS_O_RDONLY; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - mode_str = "rb"; -#endif - /* No "else" here */ - flags = O_RDONLY; -#endif - break; - case RFILE_MODE_WRITE: -#if defined(VITA) || defined(PSP) - mode_int = 0777; - flags = PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC; -#elif defined(__CELLOS_LV2__) - mode_int = 0777; - flags = CELL_FS_O_CREAT | CELL_FS_O_WRONLY | CELL_FS_O_TRUNC; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - mode_str = "wb"; -#endif - else - { - flags = O_WRONLY | O_CREAT | O_TRUNC; -#ifndef _WIN32 - flags |= S_IRUSR | S_IWUSR; -#endif - } -#endif - break; - case RFILE_MODE_READ_WRITE: -#if defined(VITA) || defined(PSP) - mode_int = 0777; - flags = PSP_O_RDWR; -#elif defined(__CELLOS_LV2__) - mode_int = 0777; - flags = CELL_FS_O_RDWR; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - mode_str = "w+"; -#endif - else - { - flags = O_RDWR; -#ifdef _WIN32 - flags |= O_BINARY; -#endif - } -#endif - break; - } - -#if defined(VITA) || defined(PSP) - stream->fd = sceIoOpen(path, flags, mode_int); -#elif defined(__CELLOS_LV2__) - cellFsOpen(path, flags, &stream->fd, NULL, 0); -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - { - stream->fp = fopen(path, mode_str); - if (!stream->fp) - goto error; - } - else -#endif - { - stream->fd = open(path, flags); - if (stream->fd == -1) - goto error; -#ifdef HAVE_MMAP - if (stream->hints & RFILE_HINT_MMAP) - { - stream->mappos = 0; - stream->mapped = NULL; - stream->mapsize = retro_fseek(stream, 0, SEEK_END); - - if (stream->mapsize == (uint64_t)-1) - goto error; - - retro_frewind(stream); - - stream->mapped = (uint8_t*)mmap((void*)0, stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0); - - if (stream->mapped == MAP_FAILED) - stream->hints &= ~RFILE_HINT_MMAP; - } -#endif - } -#endif - -#if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) - if (stream->fd == -1) - goto error; -#endif - - return stream; - -error: - retro_fclose(stream); - return NULL; -} - -ssize_t retro_fseek(RFILE *stream, ssize_t offset, int whence) -{ - int ret = 0; - if (!stream) - return -1; - - (void)ret; - -#if defined(VITA) || defined(PSP) - ret = sceIoLseek(stream->fd, (SceOff)offset, whence); - if (ret == -1) - return -1; - return 0; -#elif defined(__CELLOS_LV2__) - uint64_t pos = 0; - if (cellFsLseek(stream->fd, offset, whence, &pos) != CELL_FS_SUCCEEDED) - return -1; - return 0; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - return fseek(stream->fp, (long)offset, whence); - else -#endif -#ifdef HAVE_MMAP - /* Need to check stream->mapped because this function is called in retro_fopen() */ - if (stream->mapped && stream->hints & RFILE_HINT_MMAP) - { - /* fseek() returns error on under/overflow but allows cursor > EOF for - read-only file descriptors. */ - switch (whence) - { - case SEEK_SET: - if (offset < 0) - return -1; - - stream->mappos = offset; - break; - - case SEEK_CUR: - if ((offset < 0 && stream->mappos + offset > stream->mappos) || - (offset > 0 && stream->mappos + offset < stream->mappos)) - return -1; - - stream->mappos += offset; - break; - - case SEEK_END: - if (stream->mapsize + offset < stream->mapsize) - return -1; - - stream->mappos = stream->mapsize + offset; - - break; - } - - return stream->mappos; - } - else -#endif - { - ret = lseek(stream->fd, offset, whence); - return ret < 0 ? -1 : ret; - } -#endif -} - -ssize_t retro_ftell(RFILE *stream) -{ - if (!stream) - return -1; -#if defined(VITA) || defined(PSP) - return sceIoLseek(stream->fd, 0, SEEK_CUR); -#elif defined(__CELLOS_LV2__) - uint64_t pos = 0; - if (cellFsLseek(stream->fd, 0, CELL_FS_SEEK_CUR, &pos) != CELL_FS_SUCCEEDED) - return -1; - return 0; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - return ftell(stream->fp); - else -#endif -#ifdef HAVE_MMAP - /* Need to check stream->mapped because this function is called in retro_fopen() */ - if (stream->mapped && stream->hints & RFILE_HINT_MMAP) - return stream->mappos; - else -#endif - return lseek(stream->fd, 0, SEEK_CUR); -#endif -} - -void retro_frewind(RFILE *stream) -{ - retro_fseek(stream, 0L, SEEK_SET); -} - -ssize_t retro_fread(RFILE *stream, void *s, size_t len) -{ - if (!stream || !s) - return -1; -#if defined(VITA) || defined(PSP) - return sceIoRead(stream->fd, s, len); -#elif defined(__CELLOS_LV2__) - uint64_t bytes_written; - if (cellFsRead(stream->fd, s, len, &bytes_written) != CELL_FS_SUCCEEDED) - return -1; - return bytes_written; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - return fread(s, 1, len, stream->fp); - else -#endif -#ifdef HAVE_MMAP - if (stream->hints & RFILE_HINT_MMAP) - { - if (stream->mappos > stream->mapsize) - return -1; - - if (stream->mappos + len > stream->mapsize) - len = stream->mapsize - stream->mappos; - - memcpy(s, &stream->mapped[stream->mappos], len); - stream->mappos += len; - - return len; - } - else -#endif - return read(stream->fd, s, len); -#endif -} - -ssize_t retro_fwrite(RFILE *stream, const void *s, size_t len) -{ - if (!stream) - return -1; -#if defined(VITA) || defined(PSP) - return sceIoWrite(stream->fd, s, len); -#elif defined(__CELLOS_LV2__) - uint64_t bytes_written; - if (cellFsWrite(stream->fd, s, len, &bytes_written) != CELL_FS_SUCCEEDED) - return -1; - return bytes_written; -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - return fwrite(s, 1, len, stream->fp); - else -#endif -#ifdef HAVE_MMAP - if (stream->hints & RFILE_HINT_MMAP) - return -1; - else -#endif - return write(stream->fd, s, len); -#endif -} - -int retro_fclose(RFILE *stream) -{ - if (!stream) - return -1; - -#if defined(VITA) || defined(PSP) - if (stream->fd > 0) - sceIoClose(stream->fd); -#elif defined(__CELLOS_LV2__) - if (stream->fd > 0) - cellFsClose(stream->fd); -#else -#if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) - { - if (stream->fp) - fclose(stream->fp); - } - else -#endif -#ifdef HAVE_MMAP - if (stream->hints & RFILE_HINT_MMAP) - munmap(stream->mapped, stream->mapsize); -#endif - - if (stream->fd > 0) - close(stream->fd); -#endif - free(stream); - - return 0; -} - -/** - * retro_read_file: - * @path : path to file. - * @buf : buffer to allocate and read the contents of the - * file into. Needs to be freed manually. - * - * Read the contents of a file into @buf. - * - * Returns: number of items read, -1 on error. - */ -int retro_read_file(const char *path, void **buf, ssize_t *len) -{ - ssize_t ret = 0; - ssize_t content_buf_size = 0; - void *content_buf = NULL; - RFILE *file = retro_fopen(path, RFILE_MODE_READ, -1); - - if (!file) - { -#if __STDC_VERSION__ >= 199901L - fprintf(stderr, "%s: Failed to open %s: %s\n", __FUNCTION__, path, strerror(errno)); -#else - fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); -#endif - goto error; - } - - if (retro_fseek(file, 0, SEEK_END) != 0) - goto error; - - content_buf_size = retro_ftell(file); - if (content_buf_size < 0) - goto error; - - retro_frewind(file); - - content_buf = malloc(content_buf_size + 1); - - if (!content_buf) - goto error; - - ret = retro_fread(file, content_buf, content_buf_size); - if (ret < 0) - { -#if __STDC_VERSION__ >= 199901L - fprintf(stderr, "%s: Failed to read %s: %s\n", __FUNCTION__, path, strerror(errno)); -#else - fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno)); -#endif - goto error; - } - - retro_fclose(file); - - *buf = content_buf; - - /* Allow for easy reading of strings to be safe. - * Will only work with sane character formatting (Unix). */ - ((char*)content_buf)[content_buf_size] = '\0'; - - if (len) - *len = ret; - - return 1; - -error: - if (file) - retro_fclose(file); - if (content_buf) - free(content_buf); - if (len) - *len = -1; - *buf = NULL; - return 0; -} - -/** - * retro_write_file: - * @path : path to file. - * @data : contents to write to the file. - * @size : size of the contents. - * - * Writes data to a file. - * - * Returns: true (1) on success, false (0) otherwise. - */ -bool retro_write_file(const char *path, const void *data, ssize_t size) -{ - ssize_t ret = 0; - RFILE *file = retro_fopen(path, RFILE_MODE_WRITE, -1); - if (!file) - return false; - - ret = retro_fwrite(file, data, size); - retro_fclose(file); - - return (ret == size); -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (file_stream.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#if defined(_WIN32) +# ifdef _MSC_VER +# define setmode _setmode +# endif +# ifdef _XBOX +# include +# define INVALID_FILE_ATTRIBUTES -1 +# else +# include +# include +# include +# include +# endif +#elif defined(VITA) +# include +# include + +#define PSP_O_RDONLY PSP2_O_RDONLY +#define PSP_O_RDWR PSP2_O_RDWR +#define PSP_O_CREAT PSP2_O_CREAT +#define PSP_O_WRONLY PSP2_O_WRONLY +#define PSP_O_TRUNC PSP2_O_TRUNC +#else +# if defined(PSP) +# include +# endif +# include +# include +# include +# include +#endif + +#ifdef __CELLOS_LV2__ +#include +#else +#include +#endif + +#include +#include + +#if 1 +#define HAVE_BUFFERED_IO 1 +#endif + +struct RFILE +{ + unsigned hints; +#if defined(PSP) || defined(VITA) + SceUID fd; +#elif defined(__CELLOS_LV2__) + int fd; +#else +#if defined(HAVE_BUFFERED_IO) + FILE *fp; +#endif +#if defined(HAVE_MMAP) + uint8_t *mapped; + uint64_t mappos; + uint64_t mapsize; +#endif + int fd; +#endif +}; + +int retro_get_fd(RFILE *stream) +{ + if (!stream) + return -1; +#if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) + return stream->fd; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return fileno(stream->fp); +#endif + return stream->fd; +#endif +} + +RFILE *retro_fopen(const char *path, unsigned mode, ssize_t len) +{ + int flags = 0; + int mode_int = 0; + const char *mode_str = NULL; + RFILE *stream = (RFILE*)calloc(1, sizeof(*stream)); + + if (!stream) + return NULL; + + (void)mode_str; + (void)mode_int; + (void)flags; + + stream->hints = mode; + +#ifdef HAVE_MMAP + if (stream->hints & RFILE_HINT_MMAP && (stream->hints & 0xff) == RFILE_MODE_READ) + stream->hints |= RFILE_HINT_UNBUFFERED; + else +#endif + stream->hints &= ~RFILE_HINT_MMAP; + + switch (mode & 0xff) + { + case RFILE_MODE_READ: +#if defined(VITA) || defined(PSP) + mode_int = 0777; + flags = PSP_O_RDONLY; +#elif defined(__CELLOS_LV2__) + mode_int = 0777; + flags = CELL_FS_O_RDONLY; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + mode_str = "rb"; +#endif + /* No "else" here */ + flags = O_RDONLY; +#endif + break; + case RFILE_MODE_WRITE: +#if defined(VITA) || defined(PSP) + mode_int = 0777; + flags = PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC; +#elif defined(__CELLOS_LV2__) + mode_int = 0777; + flags = CELL_FS_O_CREAT | CELL_FS_O_WRONLY | CELL_FS_O_TRUNC; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + mode_str = "wb"; +#endif + else + { + flags = O_WRONLY | O_CREAT | O_TRUNC; +#ifndef _WIN32 + flags |= S_IRUSR | S_IWUSR; +#endif + } +#endif + break; + case RFILE_MODE_READ_WRITE: +#if defined(VITA) || defined(PSP) + mode_int = 0777; + flags = PSP_O_RDWR; +#elif defined(__CELLOS_LV2__) + mode_int = 0777; + flags = CELL_FS_O_RDWR; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + mode_str = "w+"; +#endif + else + { + flags = O_RDWR; +#ifdef _WIN32 + flags |= O_BINARY; +#endif + } +#endif + break; + } + +#if defined(VITA) || defined(PSP) + stream->fd = sceIoOpen(path, flags, mode_int); +#elif defined(__CELLOS_LV2__) + cellFsOpen(path, flags, &stream->fd, NULL, 0); +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + { + stream->fp = fopen(path, mode_str); + if (!stream->fp) + goto error; + } + else +#endif + { + stream->fd = open(path, flags); + if (stream->fd == -1) + goto error; +#ifdef HAVE_MMAP + if (stream->hints & RFILE_HINT_MMAP) + { + stream->mappos = 0; + stream->mapped = NULL; + stream->mapsize = retro_fseek(stream, 0, SEEK_END); + + if (stream->mapsize == (uint64_t)-1) + goto error; + + retro_frewind(stream); + + stream->mapped = (uint8_t*)mmap((void*)0, stream->mapsize, PROT_READ, MAP_SHARED, stream->fd, 0); + + if (stream->mapped == MAP_FAILED) + stream->hints &= ~RFILE_HINT_MMAP; + } +#endif + } +#endif + +#if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) + if (stream->fd == -1) + goto error; +#endif + + return stream; + +error: + retro_fclose(stream); + return NULL; +} + +ssize_t retro_fseek(RFILE *stream, ssize_t offset, int whence) +{ + int ret = 0; + if (!stream) + return -1; + + (void)ret; + +#if defined(VITA) || defined(PSP) + ret = sceIoLseek(stream->fd, (SceOff)offset, whence); + if (ret == -1) + return -1; + return 0; +#elif defined(__CELLOS_LV2__) + uint64_t pos = 0; + if (cellFsLseek(stream->fd, offset, whence, &pos) != CELL_FS_SUCCEEDED) + return -1; + return 0; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return fseek(stream->fp, (long)offset, whence); + else +#endif +#ifdef HAVE_MMAP + /* Need to check stream->mapped because this function is called in retro_fopen() */ + if (stream->mapped && stream->hints & RFILE_HINT_MMAP) + { + /* fseek() returns error on under/overflow but allows cursor > EOF for + read-only file descriptors. */ + switch (whence) + { + case SEEK_SET: + if (offset < 0) + return -1; + + stream->mappos = offset; + break; + + case SEEK_CUR: + if ((offset < 0 && stream->mappos + offset > stream->mappos) || + (offset > 0 && stream->mappos + offset < stream->mappos)) + return -1; + + stream->mappos += offset; + break; + + case SEEK_END: + if (stream->mapsize + offset < stream->mapsize) + return -1; + + stream->mappos = stream->mapsize + offset; + + break; + } + + return stream->mappos; + } + else +#endif + { + ret = lseek(stream->fd, offset, whence); + return ret < 0 ? -1 : ret; + } +#endif +} + +ssize_t retro_ftell(RFILE *stream) +{ + if (!stream) + return -1; +#if defined(VITA) || defined(PSP) + return sceIoLseek(stream->fd, 0, SEEK_CUR); +#elif defined(__CELLOS_LV2__) + uint64_t pos = 0; + if (cellFsLseek(stream->fd, 0, CELL_FS_SEEK_CUR, &pos) != CELL_FS_SUCCEEDED) + return -1; + return 0; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return ftell(stream->fp); + else +#endif +#ifdef HAVE_MMAP + /* Need to check stream->mapped because this function is called in retro_fopen() */ + if (stream->mapped && stream->hints & RFILE_HINT_MMAP) + return stream->mappos; + else +#endif + return lseek(stream->fd, 0, SEEK_CUR); +#endif +} + +void retro_frewind(RFILE *stream) +{ + retro_fseek(stream, 0L, SEEK_SET); +} + +ssize_t retro_fread(RFILE *stream, void *s, size_t len) +{ + if (!stream || !s) + return -1; +#if defined(VITA) || defined(PSP) + return sceIoRead(stream->fd, s, len); +#elif defined(__CELLOS_LV2__) + uint64_t bytes_written; + if (cellFsRead(stream->fd, s, len, &bytes_written) != CELL_FS_SUCCEEDED) + return -1; + return bytes_written; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return fread(s, 1, len, stream->fp); + else +#endif +#ifdef HAVE_MMAP + if (stream->hints & RFILE_HINT_MMAP) + { + if (stream->mappos > stream->mapsize) + return -1; + + if (stream->mappos + len > stream->mapsize) + len = stream->mapsize - stream->mappos; + + memcpy(s, &stream->mapped[stream->mappos], len); + stream->mappos += len; + + return len; + } + else +#endif + return read(stream->fd, s, len); +#endif +} + +ssize_t retro_fwrite(RFILE *stream, const void *s, size_t len) +{ + if (!stream) + return -1; +#if defined(VITA) || defined(PSP) + return sceIoWrite(stream->fd, s, len); +#elif defined(__CELLOS_LV2__) + uint64_t bytes_written; + if (cellFsWrite(stream->fd, s, len, &bytes_written) != CELL_FS_SUCCEEDED) + return -1; + return bytes_written; +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + return fwrite(s, 1, len, stream->fp); + else +#endif +#ifdef HAVE_MMAP + if (stream->hints & RFILE_HINT_MMAP) + return -1; + else +#endif + return write(stream->fd, s, len); +#endif +} + +int retro_fclose(RFILE *stream) +{ + if (!stream) + return -1; + +#if defined(VITA) || defined(PSP) + if (stream->fd > 0) + sceIoClose(stream->fd); +#elif defined(__CELLOS_LV2__) + if (stream->fd > 0) + cellFsClose(stream->fd); +#else +#if defined(HAVE_BUFFERED_IO) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + { + if (stream->fp) + fclose(stream->fp); + } + else +#endif +#ifdef HAVE_MMAP + if (stream->hints & RFILE_HINT_MMAP) + munmap(stream->mapped, stream->mapsize); +#endif + + if (stream->fd > 0) + close(stream->fd); +#endif + free(stream); + + return 0; +} + +/** + * retro_read_file: + * @path : path to file. + * @buf : buffer to allocate and read the contents of the + * file into. Needs to be freed manually. + * + * Read the contents of a file into @buf. + * + * Returns: number of items read, -1 on error. + */ +int retro_read_file(const char *path, void **buf, ssize_t *len) +{ + ssize_t ret = 0; + ssize_t content_buf_size = 0; + void *content_buf = NULL; + RFILE *file = retro_fopen(path, RFILE_MODE_READ, -1); + + if (!file) + { +#if __STDC_VERSION__ >= 199901L + fprintf(stderr, "%s: Failed to open %s: %s\n", __FUNCTION__, path, strerror(errno)); +#else + fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); +#endif + goto error; + } + + if (retro_fseek(file, 0, SEEK_END) != 0) + goto error; + + content_buf_size = retro_ftell(file); + if (content_buf_size < 0) + goto error; + + retro_frewind(file); + + content_buf = malloc(content_buf_size + 1); + + if (!content_buf) + goto error; + + ret = retro_fread(file, content_buf, content_buf_size); + if (ret < 0) + { +#if __STDC_VERSION__ >= 199901L + fprintf(stderr, "%s: Failed to read %s: %s\n", __FUNCTION__, path, strerror(errno)); +#else + fprintf(stderr, "Failed to read %s: %s\n", path, strerror(errno)); +#endif + goto error; + } + + retro_fclose(file); + + *buf = content_buf; + + /* Allow for easy reading of strings to be safe. + * Will only work with sane character formatting (Unix). */ + ((char*)content_buf)[content_buf_size] = '\0'; + + if (len) + *len = ret; + + return 1; + +error: + if (file) + retro_fclose(file); + if (content_buf) + free(content_buf); + if (len) + *len = -1; + *buf = NULL; + return 0; +} + +/** + * retro_write_file: + * @path : path to file. + * @data : contents to write to the file. + * @size : size of the contents. + * + * Writes data to a file. + * + * Returns: true (1) on success, false (0) otherwise. + */ +bool retro_write_file(const char *path, const void *data, ssize_t size) +{ + ssize_t ret = 0; + RFILE *file = retro_fopen(path, RFILE_MODE_WRITE, -1); + if (!file) + return false; + + ret = retro_fwrite(file, data, size); + retro_fclose(file); + + return (ret == size); +} diff --git a/desmume/src/libretro-common/streams/memory_stream.c b/desmume/src/libretro-common/streams/memory_stream.c index 745ae7e08..c0c55df2a 100644 --- a/desmume/src/libretro-common/streams/memory_stream.c +++ b/desmume/src/libretro-common/streams/memory_stream.c @@ -1,142 +1,142 @@ -/* Copyright (C) 2010-2016 The RetroArch team - * - * --------------------------------------------------------------------------------------- - * The following license statement only applies to this file (memory_stream.c). - * --------------------------------------------------------------------------------------- - * - * Permission is hereby granted, free of charge, - * to any person obtaining a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include - -static uint8_t* g_buffer = NULL; -static size_t g_size = 0; -static size_t last_file_size = 0; - -struct memstream -{ - uint8_t *m_buf; - size_t m_size; - size_t m_ptr; -}; - -void memstream_set_buffer(uint8_t *buffer, size_t size) -{ - g_buffer = buffer; - g_size = size; -} - -size_t memstream_get_last_size(void) -{ - return last_file_size; -} - -static void memstream_init(memstream_t *stream, uint8_t *buffer, size_t max_size) -{ - stream->m_buf = buffer; - stream->m_size = max_size; - stream->m_ptr = 0; -} - -memstream_t *memstream_open(void) -{ - memstream_t *stream; - if (!g_buffer || !g_size) - return NULL; - - stream = (memstream_t*)calloc(1, sizeof(*stream)); - memstream_init(stream, g_buffer, g_size); - - g_buffer = NULL; - g_size = 0; - return stream; -} - -void memstream_close(memstream_t *stream) -{ - last_file_size = stream->m_ptr; - free(stream); -} - -size_t memstream_read(memstream_t *stream, void *data, size_t bytes) -{ - size_t avail = stream->m_size - stream->m_ptr; - if (bytes > avail) - bytes = avail; - - memcpy(data, stream->m_buf + stream->m_ptr, bytes); - stream->m_ptr += bytes; - return bytes; -} - -size_t memstream_write(memstream_t *stream, const void *data, size_t bytes) -{ - size_t avail = stream->m_size - stream->m_ptr; - if (bytes > avail) - bytes = avail; - - memcpy(stream->m_buf + stream->m_ptr, data, bytes); - stream->m_ptr += bytes; - return bytes; -} - -int memstream_seek(memstream_t *stream, int offset, int whence) -{ - size_t ptr; - - switch (whence) - { - case SEEK_SET: - ptr = offset; - break; - case SEEK_CUR: - ptr = stream->m_ptr + offset; - break; - case SEEK_END: - ptr = stream->m_size + offset; - break; - default: - return -1; - } - - if (ptr <= stream->m_size) - { - stream->m_ptr = ptr; - return 0; - } - return -1; -} - -size_t memstream_pos(memstream_t *stream) -{ - return stream->m_ptr; -} - -char *memstream_gets(memstream_t *stream, char *buffer, size_t len) -{ - return NULL; -} - -int memstream_getc(memstream_t *stream) -{ - if (stream->m_ptr >= stream->m_size) - return EOF; - return stream->m_buf[stream->m_ptr++]; -} +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (memory_stream.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include + +static uint8_t* g_buffer = NULL; +static size_t g_size = 0; +static size_t last_file_size = 0; + +struct memstream +{ + uint8_t *m_buf; + size_t m_size; + size_t m_ptr; +}; + +void memstream_set_buffer(uint8_t *buffer, size_t size) +{ + g_buffer = buffer; + g_size = size; +} + +size_t memstream_get_last_size(void) +{ + return last_file_size; +} + +static void memstream_init(memstream_t *stream, uint8_t *buffer, size_t max_size) +{ + stream->m_buf = buffer; + stream->m_size = max_size; + stream->m_ptr = 0; +} + +memstream_t *memstream_open(void) +{ + memstream_t *stream; + if (!g_buffer || !g_size) + return NULL; + + stream = (memstream_t*)calloc(1, sizeof(*stream)); + memstream_init(stream, g_buffer, g_size); + + g_buffer = NULL; + g_size = 0; + return stream; +} + +void memstream_close(memstream_t *stream) +{ + last_file_size = stream->m_ptr; + free(stream); +} + +size_t memstream_read(memstream_t *stream, void *data, size_t bytes) +{ + size_t avail = stream->m_size - stream->m_ptr; + if (bytes > avail) + bytes = avail; + + memcpy(data, stream->m_buf + stream->m_ptr, bytes); + stream->m_ptr += bytes; + return bytes; +} + +size_t memstream_write(memstream_t *stream, const void *data, size_t bytes) +{ + size_t avail = stream->m_size - stream->m_ptr; + if (bytes > avail) + bytes = avail; + + memcpy(stream->m_buf + stream->m_ptr, data, bytes); + stream->m_ptr += bytes; + return bytes; +} + +int memstream_seek(memstream_t *stream, int offset, int whence) +{ + size_t ptr; + + switch (whence) + { + case SEEK_SET: + ptr = offset; + break; + case SEEK_CUR: + ptr = stream->m_ptr + offset; + break; + case SEEK_END: + ptr = stream->m_size + offset; + break; + default: + return -1; + } + + if (ptr <= stream->m_size) + { + stream->m_ptr = ptr; + return 0; + } + return -1; +} + +size_t memstream_pos(memstream_t *stream) +{ + return stream->m_ptr; +} + +char *memstream_gets(memstream_t *stream, char *buffer, size_t len) +{ + return NULL; +} + +int memstream_getc(memstream_t *stream) +{ + if (stream->m_ptr >= stream->m_size) + return EOF; + return stream->m_buf[stream->m_ptr++]; +}