diff 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
line wrap: on
line diff
--- a/util.c	Tue Dec 19 00:49:13 2017 -0800
+++ b/util.c	Sat Jan 05 00:58:08 2019 -0800
@@ -204,6 +204,85 @@
 	*(output++) = 0;
 }
 
+char *utf16be_to_utf8(uint8_t *buf, uint32_t max_size)
+{
+	uint8_t *cur = buf;
+	uint32_t converted_size = 0;
+	for (uint32_t i = 0; i < max_size; i++, cur+=2)
+	{
+		uint16_t code = *cur << 16 | cur[1];
+		if (!code) {
+			break;
+		}
+		if (code < 0x80) {
+			converted_size++;
+		} else if (code < 0x800) {
+			converted_size += 2;
+		} else {
+			//TODO: Deal with surrogate pairs
+			converted_size += 3;
+		}
+	}
+	char *out = malloc(converted_size + 1);
+	char *cur_out = out;
+	cur = buf;
+	for (uint32_t i = 0; i < max_size; i++, cur+=2)
+	{
+		uint16_t code = *cur << 16 | cur[1];
+		if (!code) {
+			break;
+		}
+		if (code < 0x80) {
+			*(cur_out++) = code;
+		} else if (code < 0x800) {
+			*(cur_out++) = 0xC0 | code >> 6;
+			*(cur_out++) = 0x80 | (code & 0x3F);
+		} else {
+			//TODO: Deal with surrogate pairs
+			*(cur_out++) = 0xF0 | code >> 12;
+			*(cur_out++) = 0x80 | (code >> 6 & 0x3F);
+			*(cur_out++) = 0x80 | (code & 0x3F);
+		}
+	}
+	*cur_out = 0;
+	return out;
+}
+
+int utf8_codepoint(const char **text)
+{
+	uint8_t initial = **text;
+	(*text)++;
+	if (initial < 0x80) {
+		return initial;
+	}
+	int base = 0;
+	uint8_t extended_bytes = 0;
+	if ((initial & 0xE0) == 0xC0) {
+		base = 0x80;
+		initial &= 0x1F;
+		extended_bytes = 1;
+	} else if ((initial & 0xF0) == 0xE0) {
+		base = 0x800;
+		initial &= 0xF;
+		extended_bytes = 2;
+	} else if ((initial & 0xF8) == 0xF0) {
+		base = 0x10000;
+		initial &= 0x7;
+		extended_bytes = 3;
+	}
+	int value = initial;
+	for (uint8_t i = 0; i < extended_bytes; i++)
+	{
+		if ((**text & 0xC0) != 0x80) {
+			return -1;
+		}
+		value = value << 6;
+		value |= (**text) & 0x3F;
+		(*text)++;
+	}
+	return value + base;
+}
+
 char is_path_sep(char c)
 {
 #ifdef _WIN32
@@ -224,11 +303,11 @@
 	return is_path_sep(path[0]);
 }
 
-char * basename_no_extension(char *path)
+char * basename_no_extension(const char *path)
 {
-	char *lastdot = NULL;
-	char *lastslash = NULL;
-	char *cur;
+	const char *lastdot = NULL;
+	const char *lastslash = NULL;
+	const char *cur;
 	for (cur = path; *cur; cur++)
 	{
 		if (*cur == '.') {
@@ -250,11 +329,11 @@
 	return barename;
 }
 
-char *path_extension(char *path)
+char *path_extension(char const *path)
 {
-	char *lastdot = NULL;
-	char *lastslash = NULL;
-	char *cur;
+	char const *lastdot = NULL;
+	char const *lastslash = NULL;
+	char const *cur;
 	for (cur = path; *cur; cur++)
 	{
 		if (*cur == '.') {
@@ -270,10 +349,28 @@
 	return strdup(lastdot+1);
 }
 
-char * path_dirname(char *path)
+uint8_t path_matches_extensions(char *path, char **ext_list, uint32_t num_exts)
 {
-	char *lastslash = NULL;
-	char *cur;
+	char *ext = path_extension(path);
+	if (!ext) {
+		return 0;
+	}
+	uint32_t extidx;
+	for (extidx = 0; extidx < num_exts; extidx++)
+	{
+		if (!strcasecmp(ext, ext_list[extidx])) {
+			free(ext);
+			return 1;
+		}
+	}
+	free(ext);
+	return 0;
+}
+
+char * path_dirname(const char *path)
+{
+	const char *lastslash = NULL;
+	const char *cur;
 	for (cur = path; *cur; cur++)
 	{
 		if (is_path_sep(*cur)) {
@@ -440,34 +537,70 @@
 
 dir_entry *get_dir_list(char *path, size_t *numret)
 {
-	HANDLE dir;
-	WIN32_FIND_DATA file;
-	char *pattern = alloc_concat(path, "/*.*");
-	dir = FindFirstFile(pattern, &file);
-	free(pattern);
-	if (dir == INVALID_HANDLE_VALUE) {
+	dir_entry *ret;
+	if (path[0] == PATH_SEP[0] && !path[1]) {
+		int drives = GetLogicalDrives();
+		size_t count = 0;
+		for (int i = 0; i < 26; i++)
+		{
+			if (drives & (1 << i)) {
+				count++;
+			}
+		}
+		ret = calloc(count, sizeof(dir_entry));
+		dir_entry *cur = ret;
+		for (int i = 0; i < 26; i++)
+		{
+			if (drives & (1 << i)) {
+				cur->name = malloc(4);
+				cur->name[0] = 'A' + i;
+				cur->name[1] = ':';
+				cur->name[2] = PATH_SEP[0];
+				cur->name[3] = 0;
+				cur->is_dir = 1;
+				cur++;
+			}
+		}
 		if (numret) {
-			*numret = 0;
+			*numret = count;
 		}
-		return NULL;
-	}
-	
-	size_t storage = 64;
-	dir_entry *ret = malloc(sizeof(dir_entry) * storage);
-	size_t pos = 0;
-	
-	do {
-		if (pos == storage) {
-			storage = storage * 2;
-			ret = realloc(ret, sizeof(dir_entry) * storage);
+	} else {
+		HANDLE dir;
+		WIN32_FIND_DATA file;
+		char *pattern = alloc_concat(path, "/*.*");
+		dir = FindFirstFile(pattern, &file);
+		free(pattern);
+		if (dir == INVALID_HANDLE_VALUE) {
+			if (numret) {
+				*numret = 0;
+			}
+			return NULL;
 		}
-		ret[pos].name = strdup(file.cFileName);
-		ret[pos++].is_dir = (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
-	} while (FindNextFile(dir, &file));
-	
-	FindClose(dir);
-	if (numret) {
-		*numret = pos;
+		
+		size_t storage = 64;
+		ret = malloc(sizeof(dir_entry) * storage);
+		size_t pos = 0;
+		
+		if (path[1] == ':' && (!path[2] || (path[2] == PATH_SEP[0] && !path[3]))) {
+			//we are in the root of a drive, add a virtual .. entry
+			//for navigating to the virtual root directory
+			ret[pos].name = strdup("..");
+			ret[pos++].is_dir = 1;
+		}
+		
+		do {
+			if (pos == storage) {
+				storage = storage * 2;
+				ret = realloc(ret, sizeof(dir_entry) * storage);
+			}
+			ret[pos].name = strdup(file.cFileName);
+			ret[pos++].is_dir = (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+		} while (FindNextFile(dir, &file));
+		
+		FindClose(dir);
+		if (numret) {
+			*numret = pos;
+		}
 	}
 	return ret;
 }
@@ -489,7 +622,7 @@
 	return (time_t)wintime;
 }
 
-int ensure_dir_exists(char *path)
+int ensure_dir_exists(const char *path)
 {
 	if (CreateDirectory(path, NULL)) {
 		return 1;
@@ -626,6 +759,7 @@
 	if (numret) {
 		*numret = pos;
 	}
+	closedir(d);
 	return ret;
 }
 
@@ -643,7 +777,7 @@
 #endif
 }
 
-int ensure_dir_exists(char *path)
+int ensure_dir_exists(const char *path)
 {
 	struct stat st;
 	if (stat(path, &st)) {
@@ -680,6 +814,22 @@
 	free(list);
 }
 
+static int sort_dir_alpha(const void *a, const void *b)
+{
+	const dir_entry *da, *db;
+	da = a;
+	db = b;
+	if (da->is_dir != db->is_dir) {
+		return db->is_dir - da->is_dir;
+	}
+	return strcasecmp(((dir_entry *)a)->name, ((dir_entry *)b)->name);
+}
+
+void sort_dir_list(dir_entry *list, size_t num_entries)
+{
+	qsort(list, num_entries, sizeof(dir_entry), sort_dir_alpha);
+}
+
 #ifdef __ANDROID__
 
 #include <SDL.h>
@@ -759,6 +909,7 @@
 	} else {
 		ret = NULL;
 	}
+	fclose(f);
 	return ret;
 }
 
@@ -776,7 +927,14 @@
 
 char const *get_config_dir()
 {
-	return get_userdata_dir();
+	static char* confdir;
+	if (!confdir) {
+		char const *base = get_userdata_dir();
+		if (base) {	
+			confdir = alloc_concat(base,  PATH_SEP "blastem");
+		}
+	}
+	return confdir;
 }
 #define CONFIG_PREFIX ""
 #define SAVE_PREFIX ""