wayland: Convert URI to local path for DropFile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index dfa62ec..bf2aeea 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -1312,36 +1312,145 @@ data_device_handle_motion(void *data, struct wl_data_device *wl_data_device,
{
}
+/* Decodes URI escape sequences in string buf of len bytes
+ (excluding the terminating NULL byte) in-place. Since
+ URI-encoded characters take three times the space of
+ normal characters, this should not be an issue.
+
+ Returns the number of decoded bytes that wound up in
+ the buffer, excluding the terminating NULL byte.
+
+ The buffer is guaranteed to be NULL-terminated but
+ may contain embedded NULL bytes.
+
+ On error, -1 is returned.
+
+ FIXME: This was shamelessly copied from SDL_x11events.c
+ */
+static int Wayland_URIDecode(char *buf, int len) {
+ int ri, wi, di;
+ char decode = '\0';
+ if (buf == NULL || len < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (len == 0) {
+ len = SDL_strlen(buf);
+ }
+ for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) {
+ if (di == 0) {
+ /* start decoding */
+ if (buf[ri] == '%') {
+ decode = '\0';
+ di += 1;
+ continue;
+ }
+ /* normal write */
+ buf[wi] = buf[ri];
+ wi += 1;
+ continue;
+ } else if (di == 1 || di == 2) {
+ char off = '\0';
+ char isa = buf[ri] >= 'a' && buf[ri] <= 'f';
+ char isA = buf[ri] >= 'A' && buf[ri] <= 'F';
+ char isn = buf[ri] >= '0' && buf[ri] <= '9';
+ if (!(isa || isA || isn)) {
+ /* not a hexadecimal */
+ int sri;
+ for (sri = ri - di; sri <= ri; sri += 1) {
+ buf[wi] = buf[sri];
+ wi += 1;
+ }
+ di = 0;
+ continue;
+ }
+ /* itsy bitsy magicsy */
+ if (isn) {
+ off = 0 - '0';
+ } else if (isa) {
+ off = 10 - 'a';
+ } else if (isA) {
+ off = 10 - 'A';
+ }
+ decode |= (buf[ri] + off) << (2 - di) * 4;
+ if (di == 2) {
+ buf[wi] = decode;
+ wi += 1;
+ di = 0;
+ } else {
+ di += 1;
+ }
+ continue;
+ }
+ }
+ buf[wi] = '\0';
+ return wi;
+}
+
+/* Convert URI to local filename
+ return filename if possible, else NULL
+
+ FIXME: This was shamelessly copied from SDL_x11events.c
+*/
+static char* Wayland_URIToLocal(char* uri) {
+ char *file = NULL;
+ SDL_bool local;
+
+ if (SDL_memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */
+ else if (SDL_strstr(uri,":/") != NULL) return file; /* wrong scheme */
+
+ local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/');
+
+ /* got a hostname? */
+ if (!local && uri[0] == '/' && uri[2] != '/') {
+ char* hostname_end = SDL_strchr(uri+1, '/');
+ if (hostname_end != NULL) {
+ char hostname[ 257 ];
+ if (gethostname(hostname, 255) == 0) {
+ hostname[ 256 ] = '\0';
+ if (SDL_memcmp(uri+1, hostname, hostname_end - (uri+1)) == 0) {
+ uri = hostname_end + 1;
+ local = SDL_TRUE;
+ }
+ }
+ }
+ }
+ if (local) {
+ file = uri;
+ /* Convert URI escape sequences to real characters */
+ Wayland_URIDecode(file, 0);
+ if (uri[1] == '/') {
+ file++;
+ } else {
+ file--;
+ }
+ }
+ return file;
+}
+
static void
data_device_handle_drop(void *data, struct wl_data_device *wl_data_device)
{
SDL_WaylandDataDevice *data_device = data;
- void *buffer = NULL;
- size_t length = 0;
-
- const char *current_uri = NULL;
- const char *last_char = NULL;
- char *current_char = NULL;
if (data_device->drag_offer != NULL) {
/* TODO: SDL Support more mime types */
- buffer = Wayland_data_offer_receive(data_device->drag_offer,
- &length, FILE_MIME, SDL_FALSE);
-
- /* uri-list */
- current_uri = (const char *)buffer;
- last_char = (const char *)buffer + length;
- for (current_char = buffer; current_char < last_char; ++current_char) {
- if (*current_char == '\n' || *current_char == 0) {
- if (*current_uri != 0 && *current_uri != '#') {
- *current_char = 0;
- SDL_SendDropFile(NULL, current_uri);
+ size_t length;
+ void *buffer = Wayland_data_offer_receive(data_device->drag_offer,
+ &length, FILE_MIME, SDL_FALSE);
+ if (buffer) {
+ char *saveptr = NULL;
+ char *token = SDL_strtokr((char *) buffer, "\r\n", &saveptr);
+ while (token != NULL) {
+ char *fn = Wayland_URIToLocal(token);
+ if (fn) {
+ SDL_SendDropFile(NULL, fn); /* FIXME: Window? */
}
- current_uri = (const char *)current_char + 1;
+ token = SDL_strtokr(NULL, "\r\n", &saveptr);
}
+ SDL_SendDropComplete(NULL); /* FIXME: Window? */
+ SDL_free(buffer);
}
-
- SDL_free(buffer);
}
}