VirtualBox

source: vbox/trunk/src/VBox/GuestHost/common/mime-type-converter.cpp@ 103795

Last change on this file since 103795 was 101674, checked in by vboxsync, 13 months ago

GuestHost: Shared Clipboard and DnD: Add common code for mime-types conversion, bugref:10194.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/** @file
2 * Common code for mime-type data conversion.
3 *
4 * This code supposed to be shared between Shared Clipboard and
5 * Drag-And-Drop services. The main purpose is to convert data into and
6 * from VirtualBox internal representation and host/guest specific format.
7 */
8
9/*
10 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31#include <iprt/string.h>
32#include <iprt/utf16.h>
33#include <iprt/mem.h>
34#include <iprt/log.h>
35
36#include <VBox/GuestHost/mime-type-converter.h>
37
38#define VBOX_WAYLAND_MIME_TYPE_NAME_MAX (32)
39
40/* Declaration of mime-type conversion helper function. */
41typedef DECLCALLBACKTYPE(int, FNVBFMTCONVERTOR, (void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut));
42typedef FNVBFMTCONVERTOR *PFNVBFMTCONVERTOR;
43
44/**
45 * A helper function that converts UTF-8 string into UTF-16.
46 *
47 * @returns IPRT status code.
48 * @param pvBufIn Input buffer which contains UTF-8 data.
49 * @param cbBufIn Size of input buffer in bytes.
50 * @param ppvBufOut Newly allocated output buffer which will contain UTF-16 data (must be freed by caller).
51 * @param pcbBufOut Size of output buffer.
52 */
53static DECLCALLBACK(int) vbConvertUtf8ToUtf16(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
54{
55 int rc;
56 size_t cwDst;
57 void *pvDst = NULL;
58
59 rc = RTStrValidateEncodingEx((char *)pvBufIn, cbBufIn, 0);
60 if (RT_SUCCESS(rc))
61 {
62 rc = ShClConvUtf8LFToUtf16CRLF((const char *)pvBufIn, cbBufIn, (PRTUTF16 *)&pvDst, &cwDst);
63 if (RT_SUCCESS(rc))
64 {
65 *ppvBufOut = pvDst;
66 *pcbBufOut = cwDst * sizeof(RTUTF16);
67 }
68 else
69 LogRel(("Data Converter: unable to convert input UTF8 string into VBox format, rc=%Rrc\n", rc));
70 }
71 else
72 LogRel(("Data Converter: unable to validate input UTF8 string, rc=%Rrc\n", rc));
73
74 return rc;
75}
76
77/**
78 * A helper function that converts UTF-16 string into UTF-8.
79 *
80 * @returns IPRT status code.
81 * @param pvBufIn Input buffer which contains UTF-16 data.
82 * @param cbBufIn Size of input buffer in bytes.
83 * @param ppvBufOut Newly allocated output buffer which will contain UTF-8 data (must be freed by caller).
84 * @param pcbBufOut Size of output buffer.
85 */
86static DECLCALLBACK(int) vbConvertUtf16ToUtf8(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
87{
88 int rc;
89
90 rc = RTUtf16ValidateEncodingEx((PCRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16),
91 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
92 if (RT_SUCCESS(rc))
93 {
94 size_t chDst = 0;
95 rc = ShClUtf16LenUtf8((PCRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16), &chDst);
96 if (RT_SUCCESS(rc))
97 {
98 /* Add space for '\0'. */
99 chDst++;
100
101 char *pszDst = (char *)RTMemAllocZ(chDst);
102 if (pszDst)
103 {
104 size_t cbActual = 0;
105 rc = ShClConvUtf16CRLFToUtf8LF((PCRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16), pszDst, chDst, &cbActual);
106 if (RT_SUCCESS(rc))
107 {
108 *pcbBufOut = cbActual;
109 *ppvBufOut = pszDst;
110 }
111 }
112 else
113 {
114 LogRel(("Data Converter: unable to allocate memory for UTF16 string conversion, rc=%Rrc\n", rc));
115 rc = VERR_NO_MEMORY;
116 }
117 }
118 }
119
120 return rc;
121}
122
123/**
124 * A helper function that converts Latin-1 string into UTF-16.
125 *
126 * @returns IPRT status code.
127 * @param pvBufIn Input buffer which contains Latin-1 data.
128 * @param cbBufIn Size of input buffer in bytes.
129 * @param ppvBufOut Newly allocated output buffer which will contain UTF-16 data (must be freed by caller).
130 * @param pcbBufOut Size of output buffer.
131 */
132static DECLCALLBACK(int) vbConvertLatin1ToUtf16(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
133{
134 int rc;
135 size_t cwDst;
136 void *pvDst = NULL;
137
138 rc = ShClConvLatin1LFToUtf16CRLF((char *)pvBufIn, cbBufIn, (PRTUTF16 *)&pvDst, &cwDst);
139 if (RT_SUCCESS(rc))
140 {
141 *ppvBufOut = pvDst;
142 *pcbBufOut = cwDst * sizeof(RTUTF16);
143 }
144 else
145 LogRel(("Data Converter: unable to convert input Latin1 string into VBox format, rc=%Rrc\n", rc));
146
147 return rc;
148}
149
150/**
151 * A helper function that converts UTF-16 string into Latin-1.
152 *
153 * @returns IPRT status code.
154 * @param pvBufIn Input buffer which contains UTF-16 data.
155 * @param cbBufIn Size of input buffer in bytes.
156 * @param ppvBufOut Newly allocated output buffer which will contain Latin-1 data (must be freed by caller).
157 * @param pcbBufOut Size of output buffer.
158 */
159static DECLCALLBACK(int) vbConvertUtf16ToLatin1(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
160{
161 int rc;
162
163 /* Make RTUtf16ToLatin1ExTag() to allocate output buffer. */
164 *ppvBufOut = NULL;
165
166 rc = RTUtf16ValidateEncodingEx((PCRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16),
167 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
168 if (RT_SUCCESS(rc))
169 rc = RTUtf16ToLatin1ExTag(
170 (PCRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16), (char **)ppvBufOut, cbBufIn, pcbBufOut, RTSTR_TAG);
171
172 return rc;
173}
174
175/**
176 * A helper function that converts HTML data into internal VBox representation (UTF-8).
177 *
178 * @returns IPRT status code.
179 * @param pvBufIn Input buffer which contains HTML data.
180 * @param cbBufIn Size of input buffer in bytes.
181 * @param ppvBufOut Newly allocated output buffer which will contain UTF-8 data (must be freed by caller).
182 * @param pcbBufOut Size of output buffer.
183 */
184static DECLCALLBACK(int) vbConvertHtmlToVBox(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
185{
186 int rc = VERR_PARSE_ERROR;
187 void *pvDst = NULL;
188 size_t cbDst = 0;
189
190 /* From X11 counterpart: */
191
192 /*
193 * The common VBox HTML encoding will be - UTF-8
194 * because it more general for HTML formats then UTF-16
195 * X11 clipboard returns UTF-16, so before sending it we should
196 * convert it to UTF-8.
197 *
198 * Some applications sends data in UTF-16, some in UTF-8,
199 * without indication it in MIME.
200 *
201 * In case of UTF-16, at least [Open|Libre] Office adds an byte order mark (0xfeff)
202 * at the start of the clipboard data.
203 */
204
205 if ( cbBufIn >= (int)sizeof(RTUTF16)
206 && *(PRTUTF16)pvBufIn == VBOX_SHCL_UTF16LEMARKER)
207 {
208 /* Input buffer is expected to be UTF-16 encoded. */
209 LogRel(("Data Converter: unable to convert UTF-16 encoded HTML data into VBox format\n"));
210
211 rc = RTUtf16ValidateEncodingEx((PCRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16),
212 RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED | RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
213 if (RT_SUCCESS(rc))
214 {
215 rc = ShClConvUtf16ToUtf8HTML((PRTUTF16)pvBufIn, cbBufIn / sizeof(RTUTF16), (char**)&pvDst, &cbDst);
216 if (RT_SUCCESS(rc))
217 {
218 *ppvBufOut = pvDst;
219 *pcbBufOut = cbDst;
220 }
221 else
222 LogRel(("Data Converter: unable to convert input UTF16 string into VBox format, rc=%Rrc\n", rc));
223 }
224 else
225 LogRel(("Data Converter: unable to validate input UTF8 string, rc=%Rrc\n", rc));
226 }
227 else
228 {
229 LogRel(("Data Converter: converting UTF-8 encoded HTML data into VBox format\n"));
230
231 /* Input buffer is expected to be UTF-8 encoded. */
232 rc = RTStrValidateEncodingEx((char *)pvBufIn, cbBufIn, 0);
233 if (RT_SUCCESS(rc))
234 {
235 pvDst = RTMemAllocZ(cbBufIn + 1 /* '\0' */);
236 if (pvDst)
237 {
238 memcpy(pvDst, pvBufIn, cbBufIn);
239 *ppvBufOut = pvDst;
240 *pcbBufOut = cbBufIn + 1 /* '\0' */;
241 }
242 else
243 rc = VERR_NO_MEMORY;
244 }
245 }
246
247 return rc;
248}
249
250/**
251 * A helper function that validates HTML data in UTF-8 format and passes out a duplicated buffer.
252 *
253 * This function supposed to convert HTML data from internal VBox representation (UTF-8)
254 * into what will be accepted by X11/Wayland clients. However, since we paste HTML content
255 * in UTF-8 representation, there is nothing to do with conversion. We only validate buffer here.
256 *
257 * @returns IPRT status code.
258 * @param pvBufIn Input buffer which contains HTML data.
259 * @param cbBufIn Size of input buffer in bytes.
260 * @param ppvBufOut Newly allocated output buffer which will contain UTF-8 data (must be freed by caller).
261 * @param pcbBufOut Size of output buffer.
262 */
263static DECLCALLBACK(int) vbConvertVBoxToHtml(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
264{
265 int rc;
266
267 rc = RTStrValidateEncodingEx((char *)pvBufIn, cbBufIn, 0);
268 if (RT_SUCCESS(rc))
269 {
270 void *pvBuf = RTMemAllocZ(cbBufIn);
271 if (pvBuf)
272 {
273 memcpy(pvBuf, pvBufIn, cbBufIn);
274 *ppvBufOut = pvBuf;
275 *pcbBufOut = cbBufIn;
276 }
277 else
278 rc = VERR_NO_MEMORY;
279 }
280
281 return rc;
282}
283
284/**
285 * A helper function that converts BMP image data into internal VBox representation.
286 *
287 * @returns IPRT status code.
288 * @param pvBufIn Input buffer which contains BMP image data.
289 * @param cbBufIn Size of input buffer in bytes.
290 * @param ppvBufOut Newly allocated output buffer which will contain image data (must be freed by caller).
291 * @param pcbBufOut Size of output buffer.
292 */
293static DECLCALLBACK(int) vbConvertBmpToVBox(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
294{
295 int rc;
296 const void *pvBufOutTmp = NULL;
297 size_t cbBufOutTmp = 0;
298
299 rc = ShClBmpGetDib(pvBufIn, cbBufIn, &pvBufOutTmp, &cbBufOutTmp);
300 if (RT_SUCCESS(rc))
301 {
302 void *pvBuf = RTMemAllocZ(cbBufOutTmp);
303 if (pvBuf)
304 {
305 memcpy(pvBuf, pvBufOutTmp, cbBufOutTmp);
306 *ppvBufOut = pvBuf;
307 *pcbBufOut = cbBufOutTmp;
308 }
309 else
310 rc = VERR_NO_MEMORY;
311 }
312 else
313 LogRel(("Data Converter: unable to convert image data (%u bytes) into BMP format, rc=%Rrc\n", cbBufIn, rc));
314
315 return rc;
316}
317
318/**
319 * A helper function that converts image data from internal VBox representation into BMP.
320 *
321 * @returns IPRT status code.
322 * @param pvBufIn Input buffer which contains image data in VBox format.
323 * @param cbBufIn Size of input buffer in bytes.
324 * @param ppvBufOut Newly allocated output buffer which will contain BMP image data (must be freed by caller).
325 * @param pcbBufOut Size of output buffer.
326 */
327static DECLCALLBACK(int) vbConvertVBoxToBmp(void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
328{
329 return ShClDibToBmp(pvBufIn, cbBufIn, ppvBufOut, pcbBufOut);
330}
331
332/* This table represents mime-types cache and contains its
333 * content converted into VirtualBox internal representation. */
334static struct VBCONVERTERFMTTABLE
335{
336 /** Content mime-type as reported by X11/Wayland. */
337 const char * pcszMimeType;
338 /** VBox content type representation. */
339 const SHCLFORMAT uFmtVBox;
340 /** Pointer to a function which converts data into internal
341 * VirtualBox representation. */
342 const PFNVBFMTCONVERTOR pfnConvertToVbox;
343 /** Pointer to a function which converts data from internal
344 * VirtualBox representation into X11/Wayland format. */
345 const PFNVBFMTCONVERTOR pfnConvertToNative;
346 /** A buffer which contains mime-type data cache in VirtualBox
347 * internal representation. */
348 void * pvBuf;
349 /** Size of cached data. */
350 size_t cbBuf;
351} g_aConverterFormats[] =
352{
353 { "INVALID", VBOX_SHCL_FMT_NONE, NULL, NULL, NULL, 0, },
354
355 { "UTF8_STRING", VBOX_SHCL_FMT_UNICODETEXT, vbConvertUtf8ToUtf16, vbConvertUtf16ToUtf8, NULL, 0, },
356 { "text/plain;charset=UTF-8", VBOX_SHCL_FMT_UNICODETEXT, vbConvertUtf8ToUtf16, vbConvertUtf16ToUtf8, NULL, 0, },
357 { "text/plain;charset=utf-8", VBOX_SHCL_FMT_UNICODETEXT, vbConvertUtf8ToUtf16, vbConvertUtf16ToUtf8, NULL, 0, },
358 { "STRING", VBOX_SHCL_FMT_UNICODETEXT, vbConvertLatin1ToUtf16, vbConvertUtf16ToLatin1, NULL, 0, },
359 { "TEXT", VBOX_SHCL_FMT_UNICODETEXT, vbConvertLatin1ToUtf16, vbConvertUtf16ToLatin1, NULL, 0, },
360 { "text/plain", VBOX_SHCL_FMT_UNICODETEXT, vbConvertLatin1ToUtf16, vbConvertUtf16ToLatin1, NULL, 0, },
361
362 { "text/html", VBOX_SHCL_FMT_HTML, vbConvertHtmlToVBox, vbConvertVBoxToHtml, NULL, 0, },
363 { "text/html;charset=utf-8", VBOX_SHCL_FMT_HTML, vbConvertHtmlToVBox, vbConvertVBoxToHtml, NULL, 0, },
364 { "application/x-moz-nativehtml", VBOX_SHCL_FMT_HTML, vbConvertHtmlToVBox, vbConvertVBoxToHtml, NULL, 0, },
365
366 { "image/bmp", VBOX_SHCL_FMT_BITMAP, vbConvertBmpToVBox, vbConvertVBoxToBmp, NULL, 0, },
367 { "image/x-bmp", VBOX_SHCL_FMT_BITMAP, vbConvertBmpToVBox, vbConvertVBoxToBmp, NULL, 0, },
368 { "image/x-MS-bmp", VBOX_SHCL_FMT_BITMAP, vbConvertBmpToVBox, vbConvertVBoxToBmp, NULL, 0, },
369};
370
371
372RTDECL(void) VBoxMimeConvEnumerateMimeById(const SHCLFORMAT uFmtVBox, PFNVBFMTCONVMIMEBYID pfnCb, void *pvData)
373{
374 for (unsigned i = 0; i < RT_ELEMENTS(g_aConverterFormats); i++)
375 if (uFmtVBox & g_aConverterFormats[i].uFmtVBox)
376 pfnCb(g_aConverterFormats[i].pcszMimeType, pvData);
377}
378
379RTDECL(const char *) VBoxMimeConvGetMimeById(const SHCLFORMAT uFmtVBox)
380{
381 for (unsigned i = 0; i < RT_ELEMENTS(g_aConverterFormats); i++)
382 if (uFmtVBox & g_aConverterFormats[i].uFmtVBox)
383 return g_aConverterFormats[i].pcszMimeType;
384
385 return NULL;
386}
387
388RTDECL(SHCLFORMAT) VBoxMimeConvGetIdByMime(const char *pcszMimeType)
389{
390 for (unsigned i = 0; i < RT_ELEMENTS(g_aConverterFormats); i++)
391 if (RTStrNCmp(g_aConverterFormats[i].pcszMimeType, pcszMimeType, VBOX_WAYLAND_MIME_TYPE_NAME_MAX) == 0)
392 return g_aConverterFormats[i].uFmtVBox;
393
394 return VBOX_SHCL_FMT_NONE;
395}
396
397RTDECL(int) VBoxMimeConvVBoxToNative(const char *pcszMimeType, void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
398{
399 for (unsigned i = 0; i < RT_ELEMENTS(g_aConverterFormats); i++)
400 if (RTStrNCmp(g_aConverterFormats[i].pcszMimeType, pcszMimeType, VBOX_WAYLAND_MIME_TYPE_NAME_MAX) == 0)
401 return g_aConverterFormats[i].pfnConvertToNative(pvBufIn, cbBufIn, ppvBufOut, pcbBufOut);
402
403 return VERR_NOT_FOUND;
404}
405
406RTDECL(int) VBoxMimeConvNativeToVBox(const char *pcszMimeType, void *pvBufIn, int cbBufIn, void **ppvBufOut, size_t *pcbBufOut)
407{
408 for (unsigned i = 0; i < RT_ELEMENTS(g_aConverterFormats); i++)
409 if (RTStrNCmp(g_aConverterFormats[i].pcszMimeType, pcszMimeType, VBOX_WAYLAND_MIME_TYPE_NAME_MAX) == 0)
410 return g_aConverterFormats[i].pfnConvertToVbox(pvBufIn, cbBufIn, ppvBufOut, pcbBufOut);
411
412 return VERR_NOT_FOUND;
413}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette