GHOST/Wayland: support URL decoding for file drag & drop
Paths that contained characters that needed escaping as URL's failed to import. Move URL decoding to a new file (GHOST_PathUtils), shared with X11 but maybe be useful for other platforms too.
This commit is contained in:
parent
727cc426bc
commit
a95103f6f4
Notes:
blender-bot
2023-02-14 07:18:54 +01:00
Referenced by commit c67d4117d4
, Fix broken build due to missing include.
Referenced by issue #99737, Drag and drop does not work with the wayland backend
|
@ -26,6 +26,7 @@ set(SRC
|
|||
intern/GHOST_ISystemPaths.cpp
|
||||
intern/GHOST_ModifierKeys.cpp
|
||||
intern/GHOST_Path-api.cpp
|
||||
intern/GHOST_PathUtils.cpp
|
||||
intern/GHOST_Rect.cpp
|
||||
intern/GHOST_System.cpp
|
||||
intern/GHOST_TimerManager.cpp
|
||||
|
@ -60,6 +61,7 @@ set(SRC
|
|||
intern/GHOST_EventTrackpad.h
|
||||
intern/GHOST_EventWheel.h
|
||||
intern/GHOST_ModifierKeys.h
|
||||
intern/GHOST_PathUtils.h
|
||||
intern/GHOST_System.h
|
||||
intern/GHOST_SystemPaths.h
|
||||
intern/GHOST_TimerManager.h
|
||||
|
|
|
@ -97,89 +97,10 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
|
|||
}
|
||||
}
|
||||
|
||||
/* Based on: https://stackoverflow.com/a/2766963/432509 */
|
||||
|
||||
using DecodeState_e = enum DecodeState_e {
|
||||
/** Searching for an ampersand to convert. */
|
||||
STATE_SEARCH = 0,
|
||||
/** Convert the two proceeding characters from hex. */
|
||||
STATE_CONVERTING
|
||||
};
|
||||
|
||||
void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int len = strlen(encodedIn);
|
||||
DecodeState_e state = STATE_SEARCH;
|
||||
int j;
|
||||
unsigned int asciiCharacter;
|
||||
char tempNumBuf[3] = {0};
|
||||
bool bothDigits = true;
|
||||
|
||||
memset(decodedOut, 0, bufferSize);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
switch (state) {
|
||||
case STATE_SEARCH:
|
||||
if (encodedIn[i] != '%') {
|
||||
strncat(decodedOut, &encodedIn[i], 1);
|
||||
assert((int)strlen(decodedOut) < bufferSize);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are now converting */
|
||||
state = STATE_CONVERTING;
|
||||
break;
|
||||
|
||||
case STATE_CONVERTING:
|
||||
bothDigits = true;
|
||||
|
||||
/* Create a buffer to hold the hex. For example, if %20, this
|
||||
* buffer would hold 20 (in ASCII) */
|
||||
memset(tempNumBuf, 0, sizeof(tempNumBuf));
|
||||
|
||||
/* Conversion complete (i.e. don't convert again next iter) */
|
||||
state = STATE_SEARCH;
|
||||
|
||||
strncpy(tempNumBuf, &encodedIn[i], 2);
|
||||
|
||||
/* Ensure both characters are hexadecimal */
|
||||
|
||||
for (j = 0; j < 2; ++j) {
|
||||
if (!isxdigit(tempNumBuf[j])) {
|
||||
bothDigits = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bothDigits) {
|
||||
break;
|
||||
}
|
||||
/* Convert two hexadecimal characters into one character */
|
||||
sscanf(tempNumBuf, "%x", &asciiCharacter);
|
||||
|
||||
/* Ensure we aren't going to overflow */
|
||||
assert((int)strlen(decodedOut) < bufferSize);
|
||||
|
||||
/* Concatenate this character onto the output */
|
||||
strncat(decodedOut, (char *)&asciiCharacter, 1);
|
||||
|
||||
/* Skip the next character */
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *GHOST_DropTargetX11::FileUrlDecode(char *fileUrl)
|
||||
{
|
||||
if (strncmp(fileUrl, "file://", 7) == 0) {
|
||||
/* assume one character of encoded URL can be expanded to 4 chars max */
|
||||
int decodedSize = 4 * strlen(fileUrl) + 1;
|
||||
char *decodedPath = (char *)malloc(decodedSize);
|
||||
|
||||
UrlDecode(decodedPath, decodedSize, fileUrl + 7);
|
||||
|
||||
return decodedPath;
|
||||
return GHOST_URL_decode_alloc(fileUrl + 7);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
|
@ -64,14 +64,6 @@ class GHOST_DropTargetX11 {
|
|||
*/
|
||||
void *getURIListGhostData(unsigned char *dropBuffer, int dropBufferSize);
|
||||
|
||||
/**
|
||||
* Decode URL (i.e. converts `file:///a%20b/test` to `file:///a b/test`)
|
||||
* \param decodedOut: - buffer for decoded URL.
|
||||
* \param bufferSize: - size of output buffer.
|
||||
* \param encodedIn: - input encoded buffer to be decoded.
|
||||
*/
|
||||
void UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn);
|
||||
|
||||
/**
|
||||
* Fully decode file URL (i.e. converts `file:///a%20b/test` to `/a b/test`)
|
||||
* \param fileUrl: - file path URL to be fully decoded.
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2010 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "GHOST_PathUtils.h"
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
/* Based on: https://stackoverflow.com/a/2766963/432509 */
|
||||
|
||||
using DecodeState_e = enum DecodeState_e {
|
||||
/** Searching for an ampersand to convert. */
|
||||
STATE_SEARCH = 0,
|
||||
/** Convert the two proceeding characters from hex. */
|
||||
STATE_CONVERTING
|
||||
};
|
||||
|
||||
void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src)
|
||||
{
|
||||
const unsigned int buf_src_len = strlen(buf_src);
|
||||
DecodeState_e state = STATE_SEARCH;
|
||||
unsigned int ascii_character;
|
||||
char temp_num_buf[3] = {0};
|
||||
|
||||
memset(buf_dst, 0, buf_dst_size);
|
||||
|
||||
for (unsigned int i = 0; i < buf_src_len; i++) {
|
||||
switch (state) {
|
||||
case STATE_SEARCH: {
|
||||
if (buf_src[i] != '%') {
|
||||
strncat(buf_dst, &buf_src[i], 1);
|
||||
assert((int)strlen(buf_dst) < buf_dst_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We are now converting. */
|
||||
state = STATE_CONVERTING;
|
||||
break;
|
||||
}
|
||||
case STATE_CONVERTING: {
|
||||
bool both_digits = true;
|
||||
|
||||
/* Create a buffer to hold the hex. For example, if `%20`,
|
||||
* this buffer would hold 20 (in ASCII). */
|
||||
memset(temp_num_buf, 0, sizeof(temp_num_buf));
|
||||
|
||||
/* Conversion complete (i.e. don't convert again next iteration). */
|
||||
state = STATE_SEARCH;
|
||||
|
||||
strncpy(temp_num_buf, &buf_src[i], 2);
|
||||
|
||||
/* Ensure both characters are hexadecimal. */
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (!isxdigit(temp_num_buf[j])) {
|
||||
both_digits = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!both_digits) {
|
||||
break;
|
||||
}
|
||||
/* Convert two hexadecimal characters into one character. */
|
||||
sscanf(temp_num_buf, "%x", &ascii_character);
|
||||
|
||||
/* Ensure we aren't going to overflow. */
|
||||
assert((int)strlen(buf_dst) < buf_dst_size);
|
||||
|
||||
/* Concatenate this character onto the output. */
|
||||
strncat(buf_dst, (char *)&ascii_character, 1);
|
||||
|
||||
/* Skip the next character. */
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *GHOST_URL_decode_alloc(const char *buf_src)
|
||||
{
|
||||
/* Assume one character of encoded URL can be expanded to 4 chars max. */
|
||||
const size_t decoded_size_max = 4 * strlen(buf_src) + 1;
|
||||
char *buf_dst = (char *)malloc(decoded_size_max);
|
||||
GHOST_URL_decode(buf_dst, decoded_size_max, buf_src);
|
||||
const size_t decoded_size = strlen(buf_dst) + 1;
|
||||
if (decoded_size != decoded_size_max) {
|
||||
char *buf_dst_trim = (char *)malloc(decoded_size);
|
||||
memcpy(buf_dst_trim, buf_dst, decoded_size);
|
||||
free(buf_dst);
|
||||
buf_dst = buf_dst_trim;
|
||||
}
|
||||
return buf_dst;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2010 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Decode URL (i.e. converts `file:///a%20b/test` to `file:///a b/test`)
|
||||
*
|
||||
* \param buf_dst: Buffer for decoded URL.
|
||||
* \param buf_dst_maxlen: Size of output buffer.
|
||||
* \param buf_src: Input encoded buffer to be decoded.
|
||||
*/
|
||||
void GHOST_URL_decode(char *buf_dst, int buf_dst_size, const char *buf_src);
|
||||
/**
|
||||
* A version of #GHOST_URL_decode that allocates the string & returns it.
|
||||
*
|
||||
* \param buf_src: Input encoded buffer to be decoded.
|
||||
* \return The decoded output buffer.
|
||||
*/
|
||||
char *GHOST_URL_decode_alloc(const char *buf_src);
|
|
@ -11,6 +11,7 @@
|
|||
#include "GHOST_EventDragnDrop.h"
|
||||
#include "GHOST_EventKey.h"
|
||||
#include "GHOST_EventWheel.h"
|
||||
#include "GHOST_PathUtils.h"
|
||||
#include "GHOST_TimerManager.h"
|
||||
#include "GHOST_WindowManager.h"
|
||||
#include "GHOST_utildefines.h"
|
||||
|
@ -1257,8 +1258,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
|
|||
flist->count = int(uris.size());
|
||||
flist->strings = static_cast<uint8_t **>(malloc(uris.size() * sizeof(uint8_t *)));
|
||||
for (size_t i = 0; i < uris.size(); i++) {
|
||||
flist->strings[i] = static_cast<uint8_t *>(malloc((uris[i].size() + 1) * sizeof(uint8_t)));
|
||||
memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
|
||||
flist->strings[i] = (uint8_t *)GHOST_URL_decode_alloc(uris[i].c_str());
|
||||
}
|
||||
|
||||
CLOG_INFO(LOG, 2, "drop_read_uris_fn file_count=%d", flist->count);
|
||||
|
|
Loading…
Reference in New Issue