Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / main / util.c
diff --git a/source/mupen64plus-core/src/main/util.c b/source/mupen64plus-core/src/main/util.c
new file mode 100644 (file)
index 0000000..b92c762
--- /dev/null
@@ -0,0 +1,404 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *   Mupen64plus - util.c                                                  *
+ *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
+ *   Copyright (C) 2012 CasualJames                                        *
+ *   Copyright (C) 2002 Hacktarux                                          *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/**
+ * Provides common utilities to the rest of the code:
+ *  -String functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "rom.h"
+#include "util.h"
+#include "osal/files.h"
+#include "osal/preproc.h"
+
+/**********************
+     File utilities
+ **********************/
+
+file_status_t read_from_file(const char *filename, void *data, size_t size)
+{
+    FILE *f = fopen(filename, "rb");
+    if (f == NULL)
+    {
+        return file_open_error;
+    }
+
+    if (fread(data, 1, size, f) != size)
+    {
+        fclose(f);
+        return file_read_error;
+    }
+
+    fclose(f);
+    return file_ok;
+}
+
+file_status_t write_to_file(const char *filename, const void *data, size_t size)
+{
+    FILE *f = fopen(filename, "wb");
+    if (f == NULL)
+    {
+        return file_open_error;
+    }
+
+    if (fwrite(data, 1, size, f) != size)
+    {
+        fclose(f);
+        return file_read_error;
+    }
+
+    fclose(f);
+    return file_ok;
+}
+
+/**********************
+   Byte swap utilities
+ **********************/
+void swap_buffer(void *buffer, size_t length, size_t count)
+{
+    size_t i;
+    if (length == 2)
+    {
+        unsigned short *pun = (unsigned short *)buffer;
+        for (i = 0; i < count; i++)
+            pun[i] = m64p_swap16(pun[i]);
+    }
+    else if (length == 4)
+    {
+        unsigned int *pun = (unsigned int *)buffer;
+        for (i = 0; i < count; i++)
+            pun[i] = m64p_swap32(pun[i]);
+    }
+    else if (length == 8)
+    {
+        unsigned long long *pun = (unsigned long long *)buffer;
+        for (i = 0; i < count; i++)
+            pun[i] = m64p_swap64(pun[i]);
+    }
+}
+
+void to_little_endian_buffer(void *buffer, size_t length, size_t count)
+{
+    #ifdef M64P_BIG_ENDIAN
+    swap_buffer(buffer, length, count);
+    #endif
+}
+
+void to_big_endian_buffer(void *buffer, size_t length, size_t count)
+{
+    #ifndef M64P_BIG_ENDIAN
+    swap_buffer(buffer, length, count);
+    #endif
+}
+
+/**********************
+     GUI utilities
+ **********************/
+void countrycodestring(unsigned short countrycode, char *string)
+{
+    switch (countrycode)
+    {
+    case 0:    /* Demo */
+        strcpy(string, "Demo");
+        break;
+
+    case '7':  /* Beta */
+        strcpy(string, "Beta");
+        break;
+
+    case 0x41: /* Japan / USA */
+        strcpy(string, "USA/Japan");
+        break;
+
+    case 0x44: /* Germany */
+        strcpy(string, "Germany");
+        break;
+
+    case 0x45: /* USA */
+        strcpy(string, "USA");
+        break;
+
+    case 0x46: /* France */
+        strcpy(string, "France");
+        break;
+
+    case 'I':  /* Italy */
+        strcpy(string, "Italy");
+        break;
+
+    case 0x4A: /* Japan */
+        strcpy(string, "Japan");
+        break;
+
+    case 'S':  /* Spain */
+        strcpy(string, "Spain");
+        break;
+
+    case 0x55: case 0x59:  /* Australia */
+        sprintf(string, "Australia (0x%02X)", countrycode);
+        break;
+
+    case 0x50: case 0x58: case 0x20:
+    case 0x21: case 0x38: case 0x70:
+        sprintf(string, "Europe (0x%02X)", countrycode);
+        break;
+
+    default:
+        sprintf(string, "Unknown (0x%02X)", countrycode);
+        break;
+    }
+}
+
+void imagestring(unsigned char imagetype, char *string)
+{
+    switch (imagetype)
+    {
+    case Z64IMAGE:
+        strcpy(string, ".z64 (native)");
+        break;
+    case V64IMAGE:
+        strcpy(string, ".v64 (byteswapped)");
+        break;
+    case N64IMAGE:
+        strcpy(string, ".n64 (wordswapped)");
+        break;
+    default:
+        string[0] = '\0';
+    }
+}
+
+/**********************
+     Path utilities
+ **********************/
+
+/* Looks for an instance of ANY of the characters in 'needles' in 'haystack',
+ * starting from the end of 'haystack'. Returns a pointer to the last position
+ * of some character on 'needles' on 'haystack'. If not found, returns NULL.
+ */
+static const char* strpbrk_reverse(const char* needles, const char* haystack)
+{
+    size_t stringlength = strlen(haystack), counter;
+
+    for (counter = stringlength; counter > 0; --counter)
+    {
+        if (strchr(needles, haystack[counter-1]))
+            break;
+    }
+
+    if (counter == 0)
+        return NULL;
+
+    return haystack + counter - 1;
+}
+
+const char* namefrompath(const char* path)
+{
+    const char* last_separator_ptr = strpbrk_reverse(OSAL_DIR_SEPARATORS, path);
+    
+    if (last_separator_ptr != NULL)
+        return last_separator_ptr + 1;
+    else
+        return path;
+}
+
+static int is_path_separator(char c)
+{
+    return strchr(OSAL_DIR_SEPARATORS, c) != NULL;
+}
+
+char* combinepath(const char* first, const char *second)
+{
+    size_t len_first = strlen(first), off_second = 0;
+
+    if (first == NULL || second == NULL)
+        return NULL;
+
+    while (is_path_separator(first[len_first-1]))
+        len_first--;
+
+    while (is_path_separator(second[off_second]))
+        off_second++;
+
+    return formatstr("%.*s%c%s", (int) len_first, first, OSAL_DIR_SEPARATORS[0], second + off_second);
+}
+
+/**********************
+    String utilities
+ **********************/
+char *trim(char *str)
+{
+    char *start = str, *end = str + strlen(str);
+
+    while (start < end && isspace(*start))
+        start++;
+
+    while (end > start && isspace(*(end-1)))
+        end--;
+
+    memmove(str, start, end - start);
+    str[end - start] = '\0';
+
+    return str;
+}
+
+int string_to_int(const char *str, int *result)
+{
+    char *endptr;
+    long int n;
+    if (*str == '\0' || isspace(*str))
+        return 0;
+    errno = 0;
+    n = strtol(str, &endptr, 10);
+    if (*endptr != '\0' || errno != 0 || n < INT_MIN || n > INT_MAX)
+        return 0;
+    *result = (int)n;
+    return 1;
+}
+
+static unsigned char char2hex(char c)
+{
+    c = tolower(c);
+    if(c >= '0' && c <= '9')
+        return c - '0';
+    else if(c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    else
+        return 0xFF;
+}
+
+int parse_hex(const char *str, unsigned char *output, size_t output_size)
+{
+    size_t i, j;
+    for (i = 0; i < output_size; i++)
+    {
+        output[i] = 0;
+        for (j = 0; j < 2; j++)
+        {
+            unsigned char h = char2hex(*str++);
+            if (h == 0xFF)
+                return 0;
+
+            output[i] = (output[i] << 4) | h;
+        }
+    }
+
+    if (*str != '\0')
+        return 0;
+
+    return 1;
+}
+
+char *formatstr(const char *fmt, ...)
+{
+       int size = 128, ret;
+       char *str = (char *)malloc(size), *newstr;
+       va_list args;
+
+       /* There are two implementations of vsnprintf we have to deal with:
+        * C99 version: Returns the number of characters which would have been written
+        *              if the buffer had been large enough, and -1 on failure.
+        * Windows version: Returns the number of characters actually written,
+        *                  and -1 on failure or truncation.
+        * NOTE: An implementation equivalent to the Windows one appears in glibc <2.1.
+        */
+       while (str != NULL)
+       {
+               va_start(args, fmt);
+               ret = vsnprintf(str, size, fmt, args);
+               va_end(args);
+
+               // Successful result?
+               if (ret >= 0 && ret < size)
+                       return str;
+
+               // Increment the capacity of the buffer
+               if (ret >= size)
+                       size = ret + 1; // C99 version: We got the needed buffer size
+               else
+                       size *= 2; // Windows version: Keep guessing
+
+               newstr = (char *)realloc(str, size);
+               if (newstr == NULL)
+                       free(str);
+               str = newstr;
+       }
+
+       return NULL;
+}
+
+ini_line ini_parse_line(char **lineptr)
+{
+    char *line = *lineptr, *endline = strchr(*lineptr, '\n'), *equal;
+    ini_line l;
+
+    // Null terminate the current line and point to the next line
+    if (endline != NULL)
+        *endline = '\0';
+    *lineptr = line + strlen(line) + 1;
+
+    // Parse the line contents
+    trim(line);
+
+    if (line[0] == '#' || line[0] == ';')
+    {
+        line++;
+
+        l.type = INI_COMMENT;
+        l.name = NULL;
+        l.value = trim(line);
+    }
+    else if (line[0] == '[' && line[strlen(line)-1] == ']')
+    {
+        line[strlen(line)-1] = '\0';
+        line++;
+
+        l.type = INI_SECTION;
+        l.name = trim(line);
+        l.value = NULL;
+    }
+    else if ((equal = strchr(line, '=')) != NULL)
+    {
+        char *name = line, *value = equal + 1;
+        *equal = '\0';
+
+        l.type = INI_PROPERTY;
+        l.name = trim(name);
+        l.value = trim(value);
+    }
+    else
+    {
+        l.type = (*line == '\0') ? INI_BLANK : INI_TRASH;
+        l.name = NULL;
+        l.value = NULL;
+    }
+
+    return l;
+}