Mercurial > repos > blastem
comparison util.c @ 1692:5dacaef602a7 segacd
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 05 Jan 2019 00:58:08 -0800 |
parents | c362f2c7766a |
children | ba3fb7a3be6b |
comparison
equal
deleted
inserted
replaced
1504:95b3a1a8b26c | 1692:5dacaef602a7 |
---|---|
202 size--; | 202 size--; |
203 } | 203 } |
204 *(output++) = 0; | 204 *(output++) = 0; |
205 } | 205 } |
206 | 206 |
207 char *utf16be_to_utf8(uint8_t *buf, uint32_t max_size) | |
208 { | |
209 uint8_t *cur = buf; | |
210 uint32_t converted_size = 0; | |
211 for (uint32_t i = 0; i < max_size; i++, cur+=2) | |
212 { | |
213 uint16_t code = *cur << 16 | cur[1]; | |
214 if (!code) { | |
215 break; | |
216 } | |
217 if (code < 0x80) { | |
218 converted_size++; | |
219 } else if (code < 0x800) { | |
220 converted_size += 2; | |
221 } else { | |
222 //TODO: Deal with surrogate pairs | |
223 converted_size += 3; | |
224 } | |
225 } | |
226 char *out = malloc(converted_size + 1); | |
227 char *cur_out = out; | |
228 cur = buf; | |
229 for (uint32_t i = 0; i < max_size; i++, cur+=2) | |
230 { | |
231 uint16_t code = *cur << 16 | cur[1]; | |
232 if (!code) { | |
233 break; | |
234 } | |
235 if (code < 0x80) { | |
236 *(cur_out++) = code; | |
237 } else if (code < 0x800) { | |
238 *(cur_out++) = 0xC0 | code >> 6; | |
239 *(cur_out++) = 0x80 | (code & 0x3F); | |
240 } else { | |
241 //TODO: Deal with surrogate pairs | |
242 *(cur_out++) = 0xF0 | code >> 12; | |
243 *(cur_out++) = 0x80 | (code >> 6 & 0x3F); | |
244 *(cur_out++) = 0x80 | (code & 0x3F); | |
245 } | |
246 } | |
247 *cur_out = 0; | |
248 return out; | |
249 } | |
250 | |
251 int utf8_codepoint(const char **text) | |
252 { | |
253 uint8_t initial = **text; | |
254 (*text)++; | |
255 if (initial < 0x80) { | |
256 return initial; | |
257 } | |
258 int base = 0; | |
259 uint8_t extended_bytes = 0; | |
260 if ((initial & 0xE0) == 0xC0) { | |
261 base = 0x80; | |
262 initial &= 0x1F; | |
263 extended_bytes = 1; | |
264 } else if ((initial & 0xF0) == 0xE0) { | |
265 base = 0x800; | |
266 initial &= 0xF; | |
267 extended_bytes = 2; | |
268 } else if ((initial & 0xF8) == 0xF0) { | |
269 base = 0x10000; | |
270 initial &= 0x7; | |
271 extended_bytes = 3; | |
272 } | |
273 int value = initial; | |
274 for (uint8_t i = 0; i < extended_bytes; i++) | |
275 { | |
276 if ((**text & 0xC0) != 0x80) { | |
277 return -1; | |
278 } | |
279 value = value << 6; | |
280 value |= (**text) & 0x3F; | |
281 (*text)++; | |
282 } | |
283 return value + base; | |
284 } | |
285 | |
207 char is_path_sep(char c) | 286 char is_path_sep(char c) |
208 { | 287 { |
209 #ifdef _WIN32 | 288 #ifdef _WIN32 |
210 if (c == '\\') { | 289 if (c == '\\') { |
211 return 1; | 290 return 1; |
222 } | 301 } |
223 #endif | 302 #endif |
224 return is_path_sep(path[0]); | 303 return is_path_sep(path[0]); |
225 } | 304 } |
226 | 305 |
227 char * basename_no_extension(char *path) | 306 char * basename_no_extension(const char *path) |
228 { | 307 { |
229 char *lastdot = NULL; | 308 const char *lastdot = NULL; |
230 char *lastslash = NULL; | 309 const char *lastslash = NULL; |
231 char *cur; | 310 const char *cur; |
232 for (cur = path; *cur; cur++) | 311 for (cur = path; *cur; cur++) |
233 { | 312 { |
234 if (*cur == '.') { | 313 if (*cur == '.') { |
235 lastdot = cur; | 314 lastdot = cur; |
236 } else if (is_path_sep(*cur)) { | 315 } else if (is_path_sep(*cur)) { |
248 barename[lastdot-lastslash] = 0; | 327 barename[lastdot-lastslash] = 0; |
249 | 328 |
250 return barename; | 329 return barename; |
251 } | 330 } |
252 | 331 |
253 char *path_extension(char *path) | 332 char *path_extension(char const *path) |
254 { | 333 { |
255 char *lastdot = NULL; | 334 char const *lastdot = NULL; |
256 char *lastslash = NULL; | 335 char const *lastslash = NULL; |
257 char *cur; | 336 char const *cur; |
258 for (cur = path; *cur; cur++) | 337 for (cur = path; *cur; cur++) |
259 { | 338 { |
260 if (*cur == '.') { | 339 if (*cur == '.') { |
261 lastdot = cur; | 340 lastdot = cur; |
262 } else if (is_path_sep(*cur)) { | 341 } else if (is_path_sep(*cur)) { |
268 return NULL; | 347 return NULL; |
269 } | 348 } |
270 return strdup(lastdot+1); | 349 return strdup(lastdot+1); |
271 } | 350 } |
272 | 351 |
273 char * path_dirname(char *path) | 352 uint8_t path_matches_extensions(char *path, char **ext_list, uint32_t num_exts) |
274 { | 353 { |
275 char *lastslash = NULL; | 354 char *ext = path_extension(path); |
276 char *cur; | 355 if (!ext) { |
356 return 0; | |
357 } | |
358 uint32_t extidx; | |
359 for (extidx = 0; extidx < num_exts; extidx++) | |
360 { | |
361 if (!strcasecmp(ext, ext_list[extidx])) { | |
362 free(ext); | |
363 return 1; | |
364 } | |
365 } | |
366 free(ext); | |
367 return 0; | |
368 } | |
369 | |
370 char * path_dirname(const char *path) | |
371 { | |
372 const char *lastslash = NULL; | |
373 const char *cur; | |
277 for (cur = path; *cur; cur++) | 374 for (cur = path; *cur; cur++) |
278 { | 375 { |
279 if (is_path_sep(*cur)) { | 376 if (is_path_sep(*cur)) { |
280 lastslash = cur; | 377 lastslash = cur; |
281 } | 378 } |
438 return path; | 535 return path; |
439 } | 536 } |
440 | 537 |
441 dir_entry *get_dir_list(char *path, size_t *numret) | 538 dir_entry *get_dir_list(char *path, size_t *numret) |
442 { | 539 { |
443 HANDLE dir; | 540 dir_entry *ret; |
444 WIN32_FIND_DATA file; | 541 if (path[0] == PATH_SEP[0] && !path[1]) { |
445 char *pattern = alloc_concat(path, "/*.*"); | 542 int drives = GetLogicalDrives(); |
446 dir = FindFirstFile(pattern, &file); | 543 size_t count = 0; |
447 free(pattern); | 544 for (int i = 0; i < 26; i++) |
448 if (dir == INVALID_HANDLE_VALUE) { | 545 { |
546 if (drives & (1 << i)) { | |
547 count++; | |
548 } | |
549 } | |
550 ret = calloc(count, sizeof(dir_entry)); | |
551 dir_entry *cur = ret; | |
552 for (int i = 0; i < 26; i++) | |
553 { | |
554 if (drives & (1 << i)) { | |
555 cur->name = malloc(4); | |
556 cur->name[0] = 'A' + i; | |
557 cur->name[1] = ':'; | |
558 cur->name[2] = PATH_SEP[0]; | |
559 cur->name[3] = 0; | |
560 cur->is_dir = 1; | |
561 cur++; | |
562 } | |
563 } | |
449 if (numret) { | 564 if (numret) { |
450 *numret = 0; | 565 *numret = count; |
451 } | 566 } |
452 return NULL; | 567 } else { |
453 } | 568 HANDLE dir; |
454 | 569 WIN32_FIND_DATA file; |
455 size_t storage = 64; | 570 char *pattern = alloc_concat(path, "/*.*"); |
456 dir_entry *ret = malloc(sizeof(dir_entry) * storage); | 571 dir = FindFirstFile(pattern, &file); |
457 size_t pos = 0; | 572 free(pattern); |
458 | 573 if (dir == INVALID_HANDLE_VALUE) { |
459 do { | 574 if (numret) { |
460 if (pos == storage) { | 575 *numret = 0; |
461 storage = storage * 2; | 576 } |
462 ret = realloc(ret, sizeof(dir_entry) * storage); | 577 return NULL; |
463 } | 578 } |
464 ret[pos].name = strdup(file.cFileName); | 579 |
465 ret[pos++].is_dir = (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | 580 size_t storage = 64; |
466 } while (FindNextFile(dir, &file)); | 581 ret = malloc(sizeof(dir_entry) * storage); |
467 | 582 size_t pos = 0; |
468 FindClose(dir); | 583 |
469 if (numret) { | 584 if (path[1] == ':' && (!path[2] || (path[2] == PATH_SEP[0] && !path[3]))) { |
470 *numret = pos; | 585 //we are in the root of a drive, add a virtual .. entry |
586 //for navigating to the virtual root directory | |
587 ret[pos].name = strdup(".."); | |
588 ret[pos++].is_dir = 1; | |
589 } | |
590 | |
591 do { | |
592 if (pos == storage) { | |
593 storage = storage * 2; | |
594 ret = realloc(ret, sizeof(dir_entry) * storage); | |
595 } | |
596 ret[pos].name = strdup(file.cFileName); | |
597 ret[pos++].is_dir = (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
598 } while (FindNextFile(dir, &file)); | |
599 | |
600 FindClose(dir); | |
601 if (numret) { | |
602 *numret = pos; | |
603 } | |
471 } | 604 } |
472 return ret; | 605 return ret; |
473 } | 606 } |
474 | 607 |
475 time_t get_modification_time(char *path) | 608 time_t get_modification_time(char *path) |
487 //adjust for difference between Windows and Unix Epoch | 620 //adjust for difference between Windows and Unix Epoch |
488 wintime -= 11644473600LL; | 621 wintime -= 11644473600LL; |
489 return (time_t)wintime; | 622 return (time_t)wintime; |
490 } | 623 } |
491 | 624 |
492 int ensure_dir_exists(char *path) | 625 int ensure_dir_exists(const char *path) |
493 { | 626 { |
494 if (CreateDirectory(path, NULL)) { | 627 if (CreateDirectory(path, NULL)) { |
495 return 1; | 628 return 1; |
496 } | 629 } |
497 if (GetLastError() == ERROR_ALREADY_EXISTS) { | 630 if (GetLastError() == ERROR_ALREADY_EXISTS) { |
624 ret[pos++].is_dir = entry->d_type == DT_DIR; | 757 ret[pos++].is_dir = entry->d_type == DT_DIR; |
625 } | 758 } |
626 if (numret) { | 759 if (numret) { |
627 *numret = pos; | 760 *numret = pos; |
628 } | 761 } |
762 closedir(d); | |
629 return ret; | 763 return ret; |
630 } | 764 } |
631 | 765 |
632 time_t get_modification_time(char *path) | 766 time_t get_modification_time(char *path) |
633 { | 767 { |
641 //Android's Bionic doesn't support the new style so we'll use the old one instead | 775 //Android's Bionic doesn't support the new style so we'll use the old one instead |
642 return st.st_mtime; | 776 return st.st_mtime; |
643 #endif | 777 #endif |
644 } | 778 } |
645 | 779 |
646 int ensure_dir_exists(char *path) | 780 int ensure_dir_exists(const char *path) |
647 { | 781 { |
648 struct stat st; | 782 struct stat st; |
649 if (stat(path, &st)) { | 783 if (stat(path, &st)) { |
650 if (errno == ENOENT) { | 784 if (errno == ENOENT) { |
651 char *parent = strdup(path); | 785 char *parent = strdup(path); |
678 free(list[i].name); | 812 free(list[i].name); |
679 } | 813 } |
680 free(list); | 814 free(list); |
681 } | 815 } |
682 | 816 |
817 static int sort_dir_alpha(const void *a, const void *b) | |
818 { | |
819 const dir_entry *da, *db; | |
820 da = a; | |
821 db = b; | |
822 if (da->is_dir != db->is_dir) { | |
823 return db->is_dir - da->is_dir; | |
824 } | |
825 return strcasecmp(((dir_entry *)a)->name, ((dir_entry *)b)->name); | |
826 } | |
827 | |
828 void sort_dir_list(dir_entry *list, size_t num_entries) | |
829 { | |
830 qsort(list, num_entries, sizeof(dir_entry), sort_dir_alpha); | |
831 } | |
832 | |
683 #ifdef __ANDROID__ | 833 #ifdef __ANDROID__ |
684 | 834 |
685 #include <SDL.h> | 835 #include <SDL.h> |
686 char *read_bundled_file(char *name, uint32_t *sizeret) | 836 char *read_bundled_file(char *name, uint32_t *sizeret) |
687 { | 837 { |
757 ret = NULL; | 907 ret = NULL; |
758 } | 908 } |
759 } else { | 909 } else { |
760 ret = NULL; | 910 ret = NULL; |
761 } | 911 } |
912 fclose(f); | |
762 return ret; | 913 return ret; |
763 } | 914 } |
764 | 915 |
765 | 916 |
766 #ifdef _WIN32 | 917 #ifdef _WIN32 |
774 return NULL; | 925 return NULL; |
775 } | 926 } |
776 | 927 |
777 char const *get_config_dir() | 928 char const *get_config_dir() |
778 { | 929 { |
779 return get_userdata_dir(); | 930 static char* confdir; |
931 if (!confdir) { | |
932 char const *base = get_userdata_dir(); | |
933 if (base) { | |
934 confdir = alloc_concat(base, PATH_SEP "blastem"); | |
935 } | |
936 } | |
937 return confdir; | |
780 } | 938 } |
781 #define CONFIG_PREFIX "" | 939 #define CONFIG_PREFIX "" |
782 #define SAVE_PREFIX "" | 940 #define SAVE_PREFIX "" |
783 | 941 |
784 #else | 942 #else |