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