Bug Summary

File:cdk/x11/cdkselection-x11.c
Warning:line 478, column 22
Out of bound memory access (accessed memory precedes memory block)

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cdkselection-x11.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/cdk/x11 -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -D G_LOG_DOMAIN="Cdk" -D G_LOG_USE_STRUCTURED=1 -D CDK_COMPILATION -I ../.. -I ../../cdk -I ../../cdk -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/cdk/x11 -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170037-43636-1 -x c cdkselection-x11.c
1/* CDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the CTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the CTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * CTK+ at ftp://ftp.ctk.org/pub/ctk/.
23 */
24
25#include "config.h"
26
27#include "cdkselection.h"
28#include "cdkproperty.h"
29#include "cdkprivate.h"
30#include "cdkprivate-x11.h"
31#include "cdkdisplay-x11.h"
32
33#include <X11/Xlib.h>
34#include <X11/Xatom.h>
35#include <string.h>
36
37
38typedef struct _OwnerInfo OwnerInfo;
39
40struct _OwnerInfo
41{
42 CdkAtom selection;
43 CdkWindow *owner;
44 gulong serial;
45};
46
47static GSList *owner_list;
48
49/* When a window is destroyed we check if it is the owner
50 * of any selections. This is somewhat inefficient, but
51 * owner_list is typically short, and it is a low memory,
52 * low code solution
53 */
54void
55_cdk_x11_selection_window_destroyed (CdkWindow *window)
56{
57 GSList *tmp_list = owner_list;
58 while (tmp_list)
59 {
60 OwnerInfo *info = tmp_list->data;
61 tmp_list = tmp_list->next;
62
63 if (info->owner == window)
64 {
65 owner_list = g_slist_remove (owner_list, info);
66 g_free (info);
67 }
68 }
69}
70
71/* We only pass through those SelectionClear events that actually
72 * reflect changes to the selection owner that we didn’t make ourself.
73 */
74gboolean
75_cdk_x11_selection_filter_clear_event (XSelectionClearEvent *event)
76{
77 GSList *tmp_list = owner_list;
78 CdkDisplay *display = cdk_x11_lookup_xdisplay (event->display);
79
80 while (tmp_list)
81 {
82 OwnerInfo *info = tmp_list->data;
83
84 if (cdk_window_get_display (info->owner) == display &&
85 info->selection == cdk_x11_xatom_to_atom_for_display (display, event->selection))
86 {
87 if ((CDK_WINDOW_XID (info->owner)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((info->owner)), ((cdk_window_get_type (
)))))))->impl)), ((cdk_window_impl_x11_get_type ()))))))->
xid)
== event->window &&
88 event->serial >= info->serial))
89 {
90 owner_list = g_slist_remove (owner_list, info);
91 g_free (info);
92 return TRUE(!(0));
93 }
94 else
95 return FALSE(0);
96 }
97 tmp_list = tmp_list->next;
98 }
99
100 return FALSE(0);
101}
102
103gboolean
104_cdk_x11_display_set_selection_owner (CdkDisplay *display,
105 CdkWindow *owner,
106 CdkAtom selection,
107 guint32 time,
108 gboolean send_event G_GNUC_UNUSED__attribute__ ((__unused__)))
109{
110 Display *xdisplay;
111 Window xwindow;
112 Atom xselection;
113 GSList *tmp_list;
114 OwnerInfo *info;
115
116 if (cdk_display_is_closed (display))
117 return FALSE(0);
118
119 if (owner)
120 {
121 if (CDK_WINDOW_DESTROYED (owner)(((CdkWindow *)(owner))->destroyed) || !CDK_WINDOW_IS_X11 (owner)((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*)
(((owner)->impl)); GType __t = ((cdk_window_impl_x11_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))
)
122 return FALSE(0);
123
124 cdk_window_ensure_native (owner);
125 xdisplay = CDK_WINDOW_XDISPLAY (owner)(((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance
*) (((cdk_window_get_screen (owner)))), ((cdk_x11_screen_get_type
()))))))->xdisplay)
;
126 xwindow = CDK_WINDOW_XID (owner)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((owner)), ((cdk_window_get_type ()))))))->
impl)), ((cdk_window_impl_x11_get_type ()))))))->xid)
;
127 }
128 else
129 {
130 xdisplay = CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay
)
;
131 xwindow = None0L;
132 }
133
134 xselection = cdk_x11_atom_to_xatom_for_display (display, selection);
135
136 tmp_list = owner_list;
137 while (tmp_list)
138 {
139 info = tmp_list->data;
140 if (info->selection == selection)
141 {
142 owner_list = g_slist_remove (owner_list, info);
143 g_free (info);
144 break;
145 }
146 tmp_list = tmp_list->next;
147 }
148
149 if (owner)
150 {
151 info = g_new (OwnerInfo, 1)((OwnerInfo *) g_malloc_n ((1), sizeof (OwnerInfo)));
152 info->owner = owner;
153 info->serial = NextRequest (CDK_WINDOW_XDISPLAY (owner))(((_XPrivDisplay)((((((CdkX11Screen*) (void *) g_type_check_instance_cast
((GTypeInstance*) (((cdk_window_get_screen (owner)))), ((cdk_x11_screen_get_type
()))))))->xdisplay)))->request + 1)
;
154 info->selection = selection;
155
156 owner_list = g_slist_prepend (owner_list, info);
157 }
158
159 XSetSelectionOwner (xdisplay, xselection, xwindow, time);
160
161 return (XGetSelectionOwner (xdisplay, xselection) == xwindow);
162}
163
164CdkWindow *
165_cdk_x11_display_get_selection_owner (CdkDisplay *display,
166 CdkAtom selection)
167{
168 Window xwindow;
169
170 if (cdk_display_is_closed (display))
171 return NULL((void*)0);
172
173 xwindow = XGetSelectionOwner (CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay
)
,
174 cdk_x11_atom_to_xatom_for_display (display,
175 selection));
176 if (xwindow == None0L)
177 return NULL((void*)0);
178
179 return cdk_x11_window_lookup_for_display (display, xwindow);
180}
181
182void
183_cdk_x11_display_convert_selection (CdkDisplay *display,
184 CdkWindow *requestor,
185 CdkAtom selection,
186 CdkAtom target,
187 guint32 time)
188{
189 g_return_if_fail (selection != CDK_NONE)do { if ((selection != ((CdkAtom)((gpointer) (gulong) (0)))))
{ } else { g_return_if_fail_warning ("Cdk", ((const char*) (
__func__)), "selection != CDK_NONE"); return; } } while (0)
;
190
191 if (CDK_WINDOW_DESTROYED (requestor)(((CdkWindow *)(requestor))->destroyed) || !CDK_WINDOW_IS_X11 (requestor)((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*)
(((requestor)->impl)); GType __t = ((cdk_window_impl_x11_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))
)
192 return;
193
194 cdk_window_ensure_native (requestor);
195
196 XConvertSelection (CDK_WINDOW_XDISPLAY (requestor)(((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance
*) (((cdk_window_get_screen (requestor)))), ((cdk_x11_screen_get_type
()))))))->xdisplay)
,
197 cdk_x11_atom_to_xatom_for_display (display, selection),
198 cdk_x11_atom_to_xatom_for_display (display, target),
199 cdk_x11_get_xatom_by_name_for_display (display, "CDK_SELECTION"),
200 CDK_WINDOW_XID (requestor)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((requestor)), ((cdk_window_get_type ())))
)))->impl)), ((cdk_window_impl_x11_get_type ()))))))->xid
)
, time);
201}
202
203gint
204_cdk_x11_display_get_selection_property (CdkDisplay *display,
205 CdkWindow *requestor,
206 guchar **data,
207 CdkAtom *ret_type,
208 gint *ret_format)
209{
210 gulong nitems;
211 gulong nbytes;
212 gulong length = 0;
213 Atom prop_type;
214 gint prop_format;
215 guchar *t = NULL((void*)0);
216
217 if (CDK_WINDOW_DESTROYED (requestor)(((CdkWindow *)(requestor))->destroyed) || !CDK_WINDOW_IS_X11 (requestor)((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*)
(((requestor)->impl)); GType __t = ((cdk_window_impl_x11_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; })))))
)
218 goto err;
219
220 t = NULL((void*)0);
221
222 /* We can't delete the selection here, because it might be the INCR
223 protocol, in which case the client has to make sure they'll be
224 notified of PropertyChange events _before_ the property is deleted.
225 Otherwise there's no guarantee we'll win the race ... */
226 if (XGetWindowProperty (CDK_WINDOW_XDISPLAY (requestor)(((((CdkX11Screen*) (void *) g_type_check_instance_cast ((GTypeInstance
*) (((cdk_window_get_screen (requestor)))), ((cdk_x11_screen_get_type
()))))))->xdisplay)
,
227 CDK_WINDOW_XID (requestor)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((requestor)), ((cdk_window_get_type ())))
)))->impl)), ((cdk_window_impl_x11_get_type ()))))))->xid
)
,
228 cdk_x11_get_xatom_by_name_for_display (display, "CDK_SELECTION"),
229 0, 0x1FFFFFFF /* MAXINT32 / 4 */, False0,
230 AnyPropertyType0L, &prop_type, &prop_format,
231 &nitems, &nbytes, &t) != Success0)
232 goto err;
233
234 if (prop_type != None0L)
235 {
236 if (ret_type)
237 *ret_type = cdk_x11_xatom_to_atom_for_display (display, prop_type);
238 if (ret_format)
239 *ret_format = prop_format;
240
241 if (prop_type == XA_ATOM((Atom) 4) ||
242 prop_type == cdk_x11_get_xatom_by_name_for_display (display, "ATOM_PAIR"))
243 {
244 Atom* atoms = (Atom*) t;
245 CdkAtom* atoms_dest;
246 gint num_atom, i;
247
248 if (prop_format != 32)
249 goto err;
250
251 num_atom = nitems;
252 length = sizeof (CdkAtom) * num_atom + 1;
253
254 if (data)
255 {
256 *data = g_malloc (length);
257 (*data)[length - 1] = '\0';
258 atoms_dest = (CdkAtom *)(*data);
259
260 for (i=0; i < num_atom; i++)
261 atoms_dest[i] = cdk_x11_xatom_to_atom_for_display (display, atoms[i]);
262 }
263 }
264 else
265 {
266 switch (prop_format)
267 {
268 case 8:
269 length = nitems;
270 break;
271 case 16:
272 length = sizeof(short) * nitems;
273 break;
274 case 32:
275 length = sizeof(long) * nitems;
276 break;
277 default:
278 g_assert_not_reached ()do { g_assertion_message_expr ("Cdk", "cdkselection-x11.c", 278
, ((const char*) (__func__)), ((void*)0)); } while (0)
;
279 break;
280 }
281
282 /* Add on an extra byte to handle null termination. X guarantees
283 that t will be 1 longer than nitems and null terminated */
284 length += 1;
285
286 if (data)
287 *data = g_memdup2 (t, length);
288 }
289
290 if (t)
291 XFree (t);
292
293 return length - 1;
294 }
295
296 err:
297 if (ret_type)
298 *ret_type = CDK_NONE((CdkAtom)((gpointer) (gulong) (0)));
299 if (ret_format)
300 *ret_format = 0;
301 if (data)
302 *data = NULL((void*)0);
303
304 return 0;
305}
306
307void
308_cdk_x11_display_send_selection_notify (CdkDisplay *display,
309 CdkWindow *requestor,
310 CdkAtom selection,
311 CdkAtom target,
312 CdkAtom property,
313 guint32 time)
314{
315 XSelectionEvent xevent;
316
317 xevent.type = SelectionNotify31;
318 xevent.serial = 0;
319 xevent.send_event = True1;
320 xevent.requestor = CDK_WINDOW_XID (requestor)(((((CdkWindowImplX11*) (void *) g_type_check_instance_cast (
(GTypeInstance*) ((((((CdkWindow*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((requestor)), ((cdk_window_get_type ())))
)))->impl)), ((cdk_window_impl_x11_get_type ()))))))->xid
)
;
321 xevent.selection = cdk_x11_atom_to_xatom_for_display (display, selection);
322 xevent.target = cdk_x11_atom_to_xatom_for_display (display, target);
323 if (property == CDK_NONE((CdkAtom)((gpointer) (gulong) (0))))
324 xevent.property = None0L;
325 else
326 xevent.property = cdk_x11_atom_to_xatom_for_display (display, property);
327 xevent.time = time;
328
329 _cdk_x11_display_send_xevent (display, xevent.requestor, False0, NoEventMask0L, (XEvent*) & xevent);
330}
331
332/**
333 * cdk_x11_display_text_property_to_text_list:
334 * @display: (type CdkX11Display): The #CdkDisplay where the encoding is defined
335 * @encoding: an atom representing the encoding. The most
336 * common values for this are STRING, or COMPOUND_TEXT.
337 * This is value used as the type for the property
338 * @format: the format of the property
339 * @text: The text data
340 * @length: The number of items to transform
341 * @list: location to store an array of strings in
342 * the encoding of the current locale. This array should be
343 * freed using cdk_free_text_list().
344 *
345 * Convert a text string from the encoding as it is stored
346 * in a property into an array of strings in the encoding of
347 * the current locale. (The elements of the array represent the
348 * nul-separated elements of the original text string.)
349 *
350 * Returns: the number of strings stored in list, or 0,
351 * if the conversion failed
352 *
353 * Since: 2.24
354 */
355gint
356cdk_x11_display_text_property_to_text_list (CdkDisplay *display,
357 CdkAtom encoding,
358 gint format,
359 const guchar *text,
360 gint length,
361 gchar ***list)
362{
363 XTextProperty property;
364 gint count = 0;
365 gint res;
366 gchar **local_list;
367 g_return_val_if_fail (CDK_IS_DISPLAY (display), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((display)); GType __t = ((cdk_display_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__
)), "CDK_IS_DISPLAY (display)"); return (0); } } while (0)
;
368
369 if (list)
370 *list = NULL((void*)0);
371
372 if (cdk_display_is_closed (display))
373 return 0;
374
375 property.value = (guchar *)text;
376 property.encoding = cdk_x11_atom_to_xatom_for_display (display, encoding);
377 property.format = format;
378 property.nitems = length;
379 res = XmbTextPropertyToTextList (CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay
)
, &property,
380 &local_list, &count);
381 if (res == XNoMemory-1 || res == XLocaleNotSupported-2 || res == XConverterNotFound-3)
382 return 0;
383 else
384 {
385 if (list)
386 *list = local_list;
387 else
388 XFreeStringList (local_list);
389
390 return count;
391 }
392}
393
394/**
395 * cdk_x11_free_text_list:
396 * @list: the value stored in the @list parameter by
397 * a call to cdk_x11_display_text_property_to_text_list().
398 *
399 * Frees the array of strings created by
400 * cdk_x11_display_text_property_to_text_list().
401 *
402 * Since: 2.24
403 */
404void
405cdk_x11_free_text_list (gchar **list)
406{
407 g_return_if_fail (list != NULL)do { if ((list != ((void*)0))) { } else { g_return_if_fail_warning
("Cdk", ((const char*) (__func__)), "list != NULL"); return;
} } while (0)
;
408
409 XFreeStringList (list);
410}
411
412static gint
413make_list (const gchar *text,
414 gint length,
415 gboolean latin1,
416 gchar ***list)
417{
418 GSList *strings = NULL((void*)0);
419 gint n_strings = 0;
420 gint i;
421 const gchar *p = text;
422 const gchar *q;
423 GSList *tmp_list;
424 GError *error = NULL((void*)0);
425
426 while (p < text + length)
4
Assuming the condition is true
5
Loop condition is true. Entering loop body
11
Assuming the condition is false
12
Loop condition is false. Execution continues on line 467
427 {
428 gchar *str;
429
430 q = p;
431 while (*q && q < text + length)
6
Assuming the condition is false
432 q++;
433
434 if (latin1
6.1
'latin1' is 1
)
7
Taking true branch
435 {
436 str = g_convert (p, q - p,
437 "UTF-8", "ISO-8859-1",
438 NULL((void*)0), NULL((void*)0), &error);
439
440 if (!str)
8
Assuming 'str' is non-null
9
Taking false branch
441 {
442 g_warning ("Error converting selection from STRING: %s",
443 error->message);
444 g_error_free (error);
445 }
446 }
447 else
448 {
449 str = g_strndup (p, q - p);
450 if (!g_utf8_validate (str, -1, NULL((void*)0)))
451 {
452 g_warning ("Error converting selection from UTF8_STRING");
453 g_free (str);
454 str = NULL((void*)0);
455 }
456 }
457
458 if (str
9.1
'str' is non-null
)
10
Taking true branch
459 {
460 strings = g_slist_prepend (strings, str);
461 n_strings++;
462 }
463
464 p = q + 1;
465 }
466
467 if (list)
13
Assuming 'list' is non-null
14
Taking true branch
468 {
469 *list = g_new (gchar *, n_strings + 1)((gchar * *) g_malloc_n ((n_strings + 1), sizeof (gchar *)));
470 (*list)[n_strings] = NULL((void*)0);
471 }
472
473 i = n_strings;
474 tmp_list = strings;
475 while (tmp_list)
15
Loop condition is true. Entering loop body
17
Loop condition is true. Entering loop body
476 {
477 if (list
15.1
'list' is non-null
17.1
'list' is non-null
)
16
Taking true branch
18
Taking true branch
478 (*list)[--i] = tmp_list->data;
19
Out of bound memory access (accessed memory precedes memory block)
479 else
480 g_free (tmp_list->data);
481
482 tmp_list = tmp_list->next;
483 }
484
485 g_slist_free (strings);
486
487 return n_strings;
488}
489
490gint
491_cdk_x11_display_text_property_to_utf8_list (CdkDisplay *display,
492 CdkAtom encoding,
493 gint format,
494 const guchar *text,
495 gint length,
496 gchar ***list)
497{
498 if (encoding == CDK_TARGET_STRING((CdkAtom)((gpointer) (gulong) (31))))
1
Assuming 'encoding' is equal to CDK_TARGET_STRING
2
Taking true branch
499 {
500 return make_list ((gchar *)text, length, TRUE(!(0)), list);
3
Calling 'make_list'
501 }
502 else if (encoding == cdk_atom_intern_static_string ("UTF8_STRING"))
503 {
504 return make_list ((gchar *)text, length, FALSE(0), list);
505 }
506 else
507 {
508 gchar **local_list;
509 gint local_count;
510 gint i;
511 const gchar *charset = NULL((void*)0);
512 gboolean need_conversion = !g_get_charset (&charset);
513 gint count = 0;
514 GError *error = NULL((void*)0);
515
516 /* Probably COMPOUND text, we fall back to Xlib routines
517 */
518 local_count = cdk_x11_display_text_property_to_text_list (display,
519 encoding,
520 format,
521 text,
522 length,
523 &local_list);
524 if (list)
525 *list = g_new (gchar *, local_count + 1)((gchar * *) g_malloc_n ((local_count + 1), sizeof (gchar *))
)
;
526
527 for (i=0; i<local_count; i++)
528 {
529 /* list contains stuff in our default encoding
530 */
531 if (need_conversion)
532 {
533 gchar *utf = g_convert (local_list[i], -1,
534 "UTF-8", charset,
535 NULL((void*)0), NULL((void*)0), &error);
536 if (utf)
537 {
538 if (list)
539 (*list)[count++] = utf;
540 else
541 g_free (utf);
542 }
543 else
544 {
545 g_warning ("Error converting to UTF-8 from '%s': %s",
546 charset, error->message);
547 g_error_free (error);
548 error = NULL((void*)0);
549 }
550 }
551 else
552 {
553 if (list)
554 {
555 if (g_utf8_validate (local_list[i], -1, NULL((void*)0)))
556 (*list)[count++] = g_strdup (local_list[i])g_strdup_inline (local_list[i]);
557 else
558 g_warning ("Error converting selection");
559 }
560 }
561 }
562
563 if (local_count)
564 cdk_x11_free_text_list (local_list);
565
566 if (list)
567 (*list)[count] = NULL((void*)0);
568
569 return count;
570 }
571}
572
573/**
574 * cdk_x11_display_string_to_compound_text:
575 * @display: (type CdkX11Display): the #CdkDisplay where the encoding is defined
576 * @str: a nul-terminated string
577 * @encoding: (out) (transfer none): location to store the encoding atom
578 * (to be used as the type for the property)
579 * @format: (out): location to store the format of the property
580 * @ctext: (out) (array length=length): location to store newly
581 * allocated data for the property
582 * @length: the length of @ctext, in bytes
583 *
584 * Convert a string from the encoding of the current
585 * locale into a form suitable for storing in a window property.
586 *
587 * Returns: 0 upon success, non-zero upon failure
588 *
589 * Since: 2.24
590 */
591gint
592cdk_x11_display_string_to_compound_text (CdkDisplay *display,
593 const gchar *str,
594 CdkAtom *encoding,
595 gint *format,
596 guchar **ctext,
597 gint *length)
598{
599 gint res;
600 XTextProperty property;
601
602 g_return_val_if_fail (CDK_IS_DISPLAY (display), 0)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((display)); GType __t = ((cdk_display_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__
)), "CDK_IS_DISPLAY (display)"); return (0); } } while (0)
;
603
604 if (cdk_display_is_closed (display))
605 res = XLocaleNotSupported-2;
606 else
607 res = XmbTextListToTextProperty (CDK_DISPLAY_XDISPLAY (display)(((((CdkX11Display*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((display)), ((cdk_x11_display_get_type()))))))->xdisplay
)
,
608 (char **)&str, 1, XCompoundTextStyle,
609 &property);
610 if (res != Success0)
611 {
612 property.encoding = None0L;
613 property.format = None0L;
614 property.value = NULL((void*)0);
615 property.nitems = 0;
616 }
617
618 if (encoding)
619 *encoding = cdk_x11_xatom_to_atom_for_display (display, property.encoding);
620 if (format)
621 *format = property.format;
622 if (ctext)
623 *ctext = property.value;
624 if (length)
625 *length = property.nitems;
626
627 return res;
628}
629
630/* The specifications for COMPOUND_TEXT and STRING specify that C0 and
631 * C1 are not allowed except for \n and \t, however the X conversions
632 * routines for COMPOUND_TEXT only enforce this in one direction,
633 * causing cut-and-paste of \r and \r\n separated text to fail.
634 * This routine strips out all non-allowed C0 and C1 characters
635 * from the input string and also canonicalizes \r, and \r\n to \n
636 */
637static gchar *
638sanitize_utf8 (const gchar *src,
639 gboolean return_latin1)
640{
641 gint len = strlen (src);
642 GString *result = g_string_sized_new (len);
643 const gchar *p = src;
644
645 while (*p)
646 {
647 if (*p == '\r')
648 {
649 p++;
650 if (*p == '\n')
651 p++;
652
653 g_string_append_c (result, '\n')g_string_append_c_inline (result, '\n');
654 }
655 else
656 {
657 gunichar ch = g_utf8_get_char (p);
658
659 if (!((ch < 0x20 && ch != '\t' && ch != '\n') || (ch >= 0x7f && ch < 0xa0)))
660 {
661 if (return_latin1)
662 {
663 if (ch <= 0xff)
664 g_string_append_c (result, ch)g_string_append_c_inline (result, ch);
665 else
666 g_string_append_printf (result,
667 ch < 0x10000 ? "\\u%04x" : "\\U%08x",
668 ch);
669 }
670 else
671 {
672 char buf[7];
673 gint buflen;
674
675 buflen = g_unichar_to_utf8 (ch, buf);
676 g_string_append_len (result, buf, buflen)g_string_append_len_inline (result, buf, buflen);
677 }
678 }
679
680 p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]);
681 }
682 }
683
684 return g_string_free (result, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((result
), ((0))) : g_string_free_and_steal (result)) : (g_string_free
) ((result), ((0))))
;
685}
686
687gchar *
688_cdk_x11_display_utf8_to_string_target (CdkDisplay *display G_GNUC_UNUSED__attribute__ ((__unused__)),
689 const gchar *str)
690{
691 return sanitize_utf8 (str, TRUE(!(0)));
692}
693
694/**
695 * cdk_x11_display_utf8_to_compound_text:
696 * @display: (type CdkX11Display): a #CdkDisplay
697 * @str: a UTF-8 string
698 * @encoding: (out): location to store resulting encoding
699 * @format: (out): location to store format of the result
700 * @ctext: (out) (array length=length): location to store the data of the result
701 * @length: location to store the length of the data
702 * stored in @ctext
703 *
704 * Converts from UTF-8 to compound text.
705 *
706 * Returns: %TRUE if the conversion succeeded,
707 * otherwise %FALSE
708 *
709 * Since: 2.24
710 */
711gboolean
712cdk_x11_display_utf8_to_compound_text (CdkDisplay *display,
713 const gchar *str,
714 CdkAtom *encoding,
715 gint *format,
716 guchar **ctext,
717 gint *length)
718{
719 gboolean need_conversion;
720 const gchar *charset;
721 gchar *locale_str, *tmp_str;
722 GError *error = NULL((void*)0);
723 gboolean result;
724
725 g_return_val_if_fail (str != NULL, FALSE)do { if ((str != ((void*)0))) { } else { g_return_if_fail_warning
("Cdk", ((const char*) (__func__)), "str != NULL"); return (
(0)); } } while (0)
;
726 g_return_val_if_fail (CDK_IS_DISPLAY (display), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((display)); GType __t = ((cdk_display_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Cdk", ((const char*) (__func__
)), "CDK_IS_DISPLAY (display)"); return ((0)); } } while (0)
;
727
728 need_conversion = !g_get_charset (&charset);
729
730 tmp_str = sanitize_utf8 (str, FALSE(0));
731
732 if (need_conversion)
733 {
734 locale_str = g_convert (tmp_str, -1,
735 charset, "UTF-8",
736 NULL((void*)0), NULL((void*)0), &error);
737 g_free (tmp_str);
738
739 if (!locale_str)
740 {
741 if (!g_error_matches (error, G_CONVERT_ERRORg_convert_error_quark(), G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
742 {
743 g_warning ("Error converting from UTF-8 to '%s': %s",
744 charset, error->message);
745 }
746 g_error_free (error);
747
748 if (encoding)
749 *encoding = None0L;
750 if (format)
751 *format = None0L;
752 if (ctext)
753 *ctext = NULL((void*)0);
754 if (length)
755 *length = 0;
756
757 return FALSE(0);
758 }
759 }
760 else
761 locale_str = tmp_str;
762
763 result = cdk_x11_display_string_to_compound_text (display, locale_str,
764 encoding, format,
765 ctext, length);
766 result = (result == Success0? TRUE(!(0)) : FALSE(0));
767
768 g_free (locale_str);
769
770 return result;
771}
772
773/**
774 * cdk_x11_free_compound_text:
775 * @ctext: The pointer stored in @ctext from a call to
776 * cdk_x11_display_string_to_compound_text().
777 *
778 * Frees the data returned from cdk_x11_display_string_to_compound_text().
779 *
780 * Since: 2.24
781 */
782void
783cdk_x11_free_compound_text (guchar *ctext)
784{
785 if (ctext)
786 XFree (ctext);
787}