Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / src / main / util.c
CommitLineData
451ab91e 1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - util.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2012 CasualJames *
5 * Copyright (C) 2002 Hacktarux *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
21 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22
23/**
24 * Provides common utilities to the rest of the code:
25 * -String functions
26 */
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <ctype.h>
32#include <string.h>
33#include <stdarg.h>
34#include <errno.h>
35#include <limits.h>
36
37#include "rom.h"
38#include "util.h"
39#include "osal/files.h"
40#include "osal/preproc.h"
41
42/**********************
43 File utilities
44 **********************/
45
46file_status_t read_from_file(const char *filename, void *data, size_t size)
47{
48 FILE *f = fopen(filename, "rb");
49 if (f == NULL)
50 {
51 return file_open_error;
52 }
53
54 if (fread(data, 1, size, f) != size)
55 {
56 fclose(f);
57 return file_read_error;
58 }
59
60 fclose(f);
61 return file_ok;
62}
63
64file_status_t write_to_file(const char *filename, const void *data, size_t size)
65{
66 FILE *f = fopen(filename, "wb");
67 if (f == NULL)
68 {
69 return file_open_error;
70 }
71
72 if (fwrite(data, 1, size, f) != size)
73 {
74 fclose(f);
75 return file_read_error;
76 }
77
78 fclose(f);
79 return file_ok;
80}
81
82/**********************
83 Byte swap utilities
84 **********************/
85void swap_buffer(void *buffer, size_t length, size_t count)
86{
87 size_t i;
88 if (length == 2)
89 {
90 unsigned short *pun = (unsigned short *)buffer;
91 for (i = 0; i < count; i++)
92 pun[i] = m64p_swap16(pun[i]);
93 }
94 else if (length == 4)
95 {
96 unsigned int *pun = (unsigned int *)buffer;
97 for (i = 0; i < count; i++)
98 pun[i] = m64p_swap32(pun[i]);
99 }
100 else if (length == 8)
101 {
102 unsigned long long *pun = (unsigned long long *)buffer;
103 for (i = 0; i < count; i++)
104 pun[i] = m64p_swap64(pun[i]);
105 }
106}
107
108void to_little_endian_buffer(void *buffer, size_t length, size_t count)
109{
110 #ifdef M64P_BIG_ENDIAN
111 swap_buffer(buffer, length, count);
112 #endif
113}
114
115void to_big_endian_buffer(void *buffer, size_t length, size_t count)
116{
117 #ifndef M64P_BIG_ENDIAN
118 swap_buffer(buffer, length, count);
119 #endif
120}
121
122/**********************
123 GUI utilities
124 **********************/
125void countrycodestring(unsigned short countrycode, char *string)
126{
127 switch (countrycode)
128 {
129 case 0: /* Demo */
130 strcpy(string, "Demo");
131 break;
132
133 case '7': /* Beta */
134 strcpy(string, "Beta");
135 break;
136
137 case 0x41: /* Japan / USA */
138 strcpy(string, "USA/Japan");
139 break;
140
141 case 0x44: /* Germany */
142 strcpy(string, "Germany");
143 break;
144
145 case 0x45: /* USA */
146 strcpy(string, "USA");
147 break;
148
149 case 0x46: /* France */
150 strcpy(string, "France");
151 break;
152
153 case 'I': /* Italy */
154 strcpy(string, "Italy");
155 break;
156
157 case 0x4A: /* Japan */
158 strcpy(string, "Japan");
159 break;
160
161 case 'S': /* Spain */
162 strcpy(string, "Spain");
163 break;
164
165 case 0x55: case 0x59: /* Australia */
166 sprintf(string, "Australia (0x%02X)", countrycode);
167 break;
168
169 case 0x50: case 0x58: case 0x20:
170 case 0x21: case 0x38: case 0x70:
171 sprintf(string, "Europe (0x%02X)", countrycode);
172 break;
173
174 default:
175 sprintf(string, "Unknown (0x%02X)", countrycode);
176 break;
177 }
178}
179
180void imagestring(unsigned char imagetype, char *string)
181{
182 switch (imagetype)
183 {
184 case Z64IMAGE:
185 strcpy(string, ".z64 (native)");
186 break;
187 case V64IMAGE:
188 strcpy(string, ".v64 (byteswapped)");
189 break;
190 case N64IMAGE:
191 strcpy(string, ".n64 (wordswapped)");
192 break;
193 default:
194 string[0] = '\0';
195 }
196}
197
198/**********************
199 Path utilities
200 **********************/
201
202/* Looks for an instance of ANY of the characters in 'needles' in 'haystack',
203 * starting from the end of 'haystack'. Returns a pointer to the last position
204 * of some character on 'needles' on 'haystack'. If not found, returns NULL.
205 */
206static const char* strpbrk_reverse(const char* needles, const char* haystack)
207{
208 size_t stringlength = strlen(haystack), counter;
209
210 for (counter = stringlength; counter > 0; --counter)
211 {
212 if (strchr(needles, haystack[counter-1]))
213 break;
214 }
215
216 if (counter == 0)
217 return NULL;
218
219 return haystack + counter - 1;
220}
221
222const char* namefrompath(const char* path)
223{
224 const char* last_separator_ptr = strpbrk_reverse(OSAL_DIR_SEPARATORS, path);
225
226 if (last_separator_ptr != NULL)
227 return last_separator_ptr + 1;
228 else
229 return path;
230}
231
232static int is_path_separator(char c)
233{
234 return strchr(OSAL_DIR_SEPARATORS, c) != NULL;
235}
236
237char* combinepath(const char* first, const char *second)
238{
239 size_t len_first = strlen(first), off_second = 0;
240
241 if (first == NULL || second == NULL)
242 return NULL;
243
244 while (is_path_separator(first[len_first-1]))
245 len_first--;
246
247 while (is_path_separator(second[off_second]))
248 off_second++;
249
250 return formatstr("%.*s%c%s", (int) len_first, first, OSAL_DIR_SEPARATORS[0], second + off_second);
251}
252
253/**********************
254 String utilities
255 **********************/
256char *trim(char *str)
257{
258 char *start = str, *end = str + strlen(str);
259
260 while (start < end && isspace(*start))
261 start++;
262
263 while (end > start && isspace(*(end-1)))
264 end--;
265
266 memmove(str, start, end - start);
267 str[end - start] = '\0';
268
269 return str;
270}
271
272int string_to_int(const char *str, int *result)
273{
274 char *endptr;
275 long int n;
276 if (*str == '\0' || isspace(*str))
277 return 0;
278 errno = 0;
279 n = strtol(str, &endptr, 10);
280 if (*endptr != '\0' || errno != 0 || n < INT_MIN || n > INT_MAX)
281 return 0;
282 *result = (int)n;
283 return 1;
284}
285
286static unsigned char char2hex(char c)
287{
288 c = tolower(c);
289 if(c >= '0' && c <= '9')
290 return c - '0';
291 else if(c >= 'a' && c <= 'f')
292 return c - 'a' + 10;
293 else
294 return 0xFF;
295}
296
297int parse_hex(const char *str, unsigned char *output, size_t output_size)
298{
299 size_t i, j;
300 for (i = 0; i < output_size; i++)
301 {
302 output[i] = 0;
303 for (j = 0; j < 2; j++)
304 {
305 unsigned char h = char2hex(*str++);
306 if (h == 0xFF)
307 return 0;
308
309 output[i] = (output[i] << 4) | h;
310 }
311 }
312
313 if (*str != '\0')
314 return 0;
315
316 return 1;
317}
318
319char *formatstr(const char *fmt, ...)
320{
321 int size = 128, ret;
322 char *str = (char *)malloc(size), *newstr;
323 va_list args;
324
325 /* There are two implementations of vsnprintf we have to deal with:
326 * C99 version: Returns the number of characters which would have been written
327 * if the buffer had been large enough, and -1 on failure.
328 * Windows version: Returns the number of characters actually written,
329 * and -1 on failure or truncation.
330 * NOTE: An implementation equivalent to the Windows one appears in glibc <2.1.
331 */
332 while (str != NULL)
333 {
334 va_start(args, fmt);
335 ret = vsnprintf(str, size, fmt, args);
336 va_end(args);
337
338 // Successful result?
339 if (ret >= 0 && ret < size)
340 return str;
341
342 // Increment the capacity of the buffer
343 if (ret >= size)
344 size = ret + 1; // C99 version: We got the needed buffer size
345 else
346 size *= 2; // Windows version: Keep guessing
347
348 newstr = (char *)realloc(str, size);
349 if (newstr == NULL)
350 free(str);
351 str = newstr;
352 }
353
354 return NULL;
355}
356
357ini_line ini_parse_line(char **lineptr)
358{
359 char *line = *lineptr, *endline = strchr(*lineptr, '\n'), *equal;
360 ini_line l;
361
362 // Null terminate the current line and point to the next line
363 if (endline != NULL)
364 *endline = '\0';
365 *lineptr = line + strlen(line) + 1;
366
367 // Parse the line contents
368 trim(line);
369
370 if (line[0] == '#' || line[0] == ';')
371 {
372 line++;
373
374 l.type = INI_COMMENT;
375 l.name = NULL;
376 l.value = trim(line);
377 }
378 else if (line[0] == '[' && line[strlen(line)-1] == ']')
379 {
380 line[strlen(line)-1] = '\0';
381 line++;
382
383 l.type = INI_SECTION;
384 l.name = trim(line);
385 l.value = NULL;
386 }
387 else if ((equal = strchr(line, '=')) != NULL)
388 {
389 char *name = line, *value = equal + 1;
390 *equal = '\0';
391
392 l.type = INI_PROPERTY;
393 l.name = trim(name);
394 l.value = trim(value);
395 }
396 else
397 {
398 l.type = (*line == '\0') ? INI_BLANK : INI_TRASH;
399 l.name = NULL;
400 l.value = NULL;
401 }
402
403 return l;
404}