diff options
author | Campbell Barton <campbell@blender.org> | 2022-08-04 15:33:23 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-08-04 15:33:23 +0300 |
commit | a95103f6f4abda2be9020f13df1256bf0f62c255 (patch) | |
tree | 56239f477fd583771e1bb339b48f43eb67868775 /intern | |
parent | 727cc426bc723c8757941ce9bf23745ee5f6ab9d (diff) |
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.
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/CMakeLists.txt | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_DropTargetX11.cpp | 81 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_DropTargetX11.h | 8 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_PathUtils.cpp | 101 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_PathUtils.h | 24 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWayland.cpp | 4 |
6 files changed, 130 insertions, 90 deletions
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index cf0d4b1e35d..0ac3a234946 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -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 diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp index 252a8bfd095..b4cb088cbeb 100644 --- a/intern/ghost/intern/GHOST_DropTargetX11.cpp +++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp @@ -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; diff --git a/intern/ghost/intern/GHOST_DropTargetX11.h b/intern/ghost/intern/GHOST_DropTargetX11.h index f0ef27697e1..db73ddff70f 100644 --- a/intern/ghost/intern/GHOST_DropTargetX11.h +++ b/intern/ghost/intern/GHOST_DropTargetX11.h @@ -65,14 +65,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. * \return decoded file path (result should be free-d). diff --git a/intern/ghost/intern/GHOST_PathUtils.cpp b/intern/ghost/intern/GHOST_PathUtils.cpp new file mode 100644 index 00000000000..3b57480039a --- /dev/null +++ b/intern/ghost/intern/GHOST_PathUtils.cpp @@ -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; +} diff --git a/intern/ghost/intern/GHOST_PathUtils.h b/intern/ghost/intern/GHOST_PathUtils.h new file mode 100644 index 00000000000..26a31d1f5c6 --- /dev/null +++ b/intern/ghost/intern/GHOST_PathUtils.h @@ -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); diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp index 7da8d56ed0d..e6366d25788 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cpp +++ b/intern/ghost/intern/GHOST_SystemWayland.cpp @@ -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); |