1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
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 3 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 * Library 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
16 * <https://www.gnu.org/licenses/>.
17 */
18
19 #include "config.h"
20
21 #include <string.h>
22
23 #include <glib-object.h>
24
25 #include <libgimpcolor/gimpcolortypes.h>
26
27 #include "gimpwire.h"
28
29
30 typedef struct _GimpWireHandler GimpWireHandler;
31
32 struct _GimpWireHandler
33 {
34 guint32 type;
35 GimpWireReadFunc read_func;
36 GimpWireWriteFunc write_func;
37 GimpWireDestroyFunc destroy_func;
38 };
39
40
41 static GHashTable *wire_ht = NULL;
42 static GimpWireIOFunc wire_read_func = NULL;
43 static GimpWireIOFunc wire_write_func = NULL;
44 static GimpWireFlushFunc wire_flush_func = NULL;
45 static gboolean wire_error_val = FALSE;
46
47
48 static void gimp_wire_init (void);
49
50
51 void
gimp_wire_register(guint32 type,GimpWireReadFunc read_func,GimpWireWriteFunc write_func,GimpWireDestroyFunc destroy_func)52 gimp_wire_register (guint32 type,
53 GimpWireReadFunc read_func,
54 GimpWireWriteFunc write_func,
55 GimpWireDestroyFunc destroy_func)
56 {
57 GimpWireHandler *handler;
58
59 if (! wire_ht)
60 gimp_wire_init ();
61
62 handler = g_hash_table_lookup (wire_ht, &type);
63
64 if (! handler)
65 handler = g_slice_new0 (GimpWireHandler);
66
67 handler->type = type;
68 handler->read_func = read_func;
69 handler->write_func = write_func;
70 handler->destroy_func = destroy_func;
71
72 g_hash_table_insert (wire_ht, &handler->type, handler);
73 }
74
75 void
gimp_wire_set_reader(GimpWireIOFunc read_func)76 gimp_wire_set_reader (GimpWireIOFunc read_func)
77 {
78 wire_read_func = read_func;
79 }
80
81 void
gimp_wire_set_writer(GimpWireIOFunc write_func)82 gimp_wire_set_writer (GimpWireIOFunc write_func)
83 {
84 wire_write_func = write_func;
85 }
86
87 void
gimp_wire_set_flusher(GimpWireFlushFunc flush_func)88 gimp_wire_set_flusher (GimpWireFlushFunc flush_func)
89 {
90 wire_flush_func = flush_func;
91 }
92
93 gboolean
gimp_wire_read(GIOChannel * channel,guint8 * buf,gsize count,gpointer user_data)94 gimp_wire_read (GIOChannel *channel,
95 guint8 *buf,
96 gsize count,
97 gpointer user_data)
98 {
99 if (wire_read_func)
100 {
101 if (!(* wire_read_func) (channel, buf, count, user_data))
102 {
103 /* Gives a confusing error message most of the time, disable:
104 g_warning ("%s: gimp_wire_read: error", g_get_prgname ());
105 */
106 wire_error_val = TRUE;
107 return FALSE;
108 }
109 }
110 else
111 {
112 GIOStatus status;
113 GError *error = NULL;
114 gsize bytes;
115
116 while (count > 0)
117 {
118 do
119 {
120 bytes = 0;
121 status = g_io_channel_read_chars (channel,
122 (gchar *) buf, count,
123 &bytes,
124 &error);
125 }
126 while (G_UNLIKELY (status == G_IO_STATUS_AGAIN));
127
128 if (G_UNLIKELY (status != G_IO_STATUS_NORMAL))
129 {
130 if (error)
131 {
132 g_warning ("%s: gimp_wire_read(): error: %s",
133 g_get_prgname (), error->message);
134 g_error_free (error);
135 }
136 else
137 {
138 g_warning ("%s: gimp_wire_read(): error",
139 g_get_prgname ());
140 }
141
142 wire_error_val = TRUE;
143 return FALSE;
144 }
145
146 if (G_UNLIKELY (bytes == 0))
147 {
148 g_warning ("%s: gimp_wire_read(): unexpected EOF",
149 g_get_prgname ());
150 wire_error_val = TRUE;
151 return FALSE;
152 }
153
154 count -= bytes;
155 buf += bytes;
156 }
157 }
158
159 return TRUE;
160 }
161
162 gboolean
gimp_wire_write(GIOChannel * channel,const guint8 * buf,gsize count,gpointer user_data)163 gimp_wire_write (GIOChannel *channel,
164 const guint8 *buf,
165 gsize count,
166 gpointer user_data)
167 {
168 if (wire_write_func)
169 {
170 if (!(* wire_write_func) (channel, (guint8 *) buf, count, user_data))
171 {
172 g_warning ("%s: gimp_wire_write: error", g_get_prgname ());
173 wire_error_val = TRUE;
174 return FALSE;
175 }
176 }
177 else
178 {
179 GIOStatus status;
180 GError *error = NULL;
181 gsize bytes;
182
183 while (count > 0)
184 {
185 do
186 {
187 bytes = 0;
188 status = g_io_channel_write_chars (channel,
189 (const gchar *) buf, count,
190 &bytes,
191 &error);
192 }
193 while (G_UNLIKELY (status == G_IO_STATUS_AGAIN));
194
195 if (G_UNLIKELY (status != G_IO_STATUS_NORMAL))
196 {
197 if (error)
198 {
199 g_warning ("%s: gimp_wire_write(): error: %s",
200 g_get_prgname (), error->message);
201 g_error_free (error);
202 }
203 else
204 {
205 g_warning ("%s: gimp_wire_write(): error",
206 g_get_prgname ());
207 }
208
209 wire_error_val = TRUE;
210 return FALSE;
211 }
212
213 count -= bytes;
214 buf += bytes;
215 }
216 }
217
218 return TRUE;
219 }
220
221 gboolean
gimp_wire_flush(GIOChannel * channel,gpointer user_data)222 gimp_wire_flush (GIOChannel *channel,
223 gpointer user_data)
224 {
225 if (wire_flush_func)
226 return (* wire_flush_func) (channel, user_data);
227
228 return FALSE;
229 }
230
231 gboolean
gimp_wire_error(void)232 gimp_wire_error (void)
233 {
234 return wire_error_val;
235 }
236
237 void
gimp_wire_clear_error(void)238 gimp_wire_clear_error (void)
239 {
240 wire_error_val = FALSE;
241 }
242
243 gboolean
gimp_wire_read_msg(GIOChannel * channel,GimpWireMessage * msg,gpointer user_data)244 gimp_wire_read_msg (GIOChannel *channel,
245 GimpWireMessage *msg,
246 gpointer user_data)
247 {
248 GimpWireHandler *handler;
249
250 if (G_UNLIKELY (! wire_ht))
251 g_error ("gimp_wire_read_msg: the wire protocol has not been initialized");
252
253 if (wire_error_val)
254 return !wire_error_val;
255
256 if (! _gimp_wire_read_int32 (channel, &msg->type, 1, user_data))
257 return FALSE;
258
259 handler = g_hash_table_lookup (wire_ht, &msg->type);
260
261 if (G_UNLIKELY (! handler))
262 g_error ("gimp_wire_read_msg: could not find handler for message: %d",
263 msg->type);
264
265 (* handler->read_func) (channel, msg, user_data);
266
267 return !wire_error_val;
268 }
269
270 gboolean
gimp_wire_write_msg(GIOChannel * channel,GimpWireMessage * msg,gpointer user_data)271 gimp_wire_write_msg (GIOChannel *channel,
272 GimpWireMessage *msg,
273 gpointer user_data)
274 {
275 GimpWireHandler *handler;
276
277 if (G_UNLIKELY (! wire_ht))
278 g_error ("gimp_wire_write_msg: the wire protocol has not been initialized");
279
280 if (wire_error_val)
281 return !wire_error_val;
282
283 handler = g_hash_table_lookup (wire_ht, &msg->type);
284
285 if (G_UNLIKELY (! handler))
286 g_error ("gimp_wire_write_msg: could not find handler for message: %d",
287 msg->type);
288
289 if (! _gimp_wire_write_int32 (channel, &msg->type, 1, user_data))
290 return FALSE;
291
292 (* handler->write_func) (channel, msg, user_data);
293
294 return !wire_error_val;
295 }
296
297 void
gimp_wire_destroy(GimpWireMessage * msg)298 gimp_wire_destroy (GimpWireMessage *msg)
299 {
300 GimpWireHandler *handler;
301
302 if (G_UNLIKELY (! wire_ht))
303 g_error ("gimp_wire_destroy: the wire protocol has not been initialized");
304
305 handler = g_hash_table_lookup (wire_ht, &msg->type);
306
307 if (G_UNLIKELY (! handler))
308 g_error ("gimp_wire_destroy: could not find handler for message: %d\n",
309 msg->type);
310
311 (* handler->destroy_func) (msg);
312 }
313
314 gboolean
_gimp_wire_read_int64(GIOChannel * channel,guint64 * data,gint count,gpointer user_data)315 _gimp_wire_read_int64 (GIOChannel *channel,
316 guint64 *data,
317 gint count,
318 gpointer user_data)
319 {
320 g_return_val_if_fail (count >= 0, FALSE);
321
322 if (count > 0)
323 {
324 if (! _gimp_wire_read_int8 (channel,
325 (guint8 *) data, count * 8, user_data))
326 return FALSE;
327
328 while (count--)
329 {
330 *data = GUINT64_FROM_BE (*data);
331 data++;
332 }
333 }
334
335 return TRUE;
336 }
337
338 gboolean
_gimp_wire_read_int32(GIOChannel * channel,guint32 * data,gint count,gpointer user_data)339 _gimp_wire_read_int32 (GIOChannel *channel,
340 guint32 *data,
341 gint count,
342 gpointer user_data)
343 {
344 g_return_val_if_fail (count >= 0, FALSE);
345
346 if (count > 0)
347 {
348 if (! _gimp_wire_read_int8 (channel,
349 (guint8 *) data, count * 4, user_data))
350 return FALSE;
351
352 while (count--)
353 {
354 *data = g_ntohl (*data);
355 data++;
356 }
357 }
358
359 return TRUE;
360 }
361
362 gboolean
_gimp_wire_read_int16(GIOChannel * channel,guint16 * data,gint count,gpointer user_data)363 _gimp_wire_read_int16 (GIOChannel *channel,
364 guint16 *data,
365 gint count,
366 gpointer user_data)
367 {
368 g_return_val_if_fail (count >= 0, FALSE);
369
370 if (count > 0)
371 {
372 if (! _gimp_wire_read_int8 (channel,
373 (guint8 *) data, count * 2, user_data))
374 return FALSE;
375
376 while (count--)
377 {
378 *data = g_ntohs (*data);
379 data++;
380 }
381 }
382
383 return TRUE;
384 }
385
386 gboolean
_gimp_wire_read_int8(GIOChannel * channel,guint8 * data,gint count,gpointer user_data)387 _gimp_wire_read_int8 (GIOChannel *channel,
388 guint8 *data,
389 gint count,
390 gpointer user_data)
391 {
392 g_return_val_if_fail (count >= 0, FALSE);
393
394 return gimp_wire_read (channel, data, count, user_data);
395 }
396
397 gboolean
_gimp_wire_read_double(GIOChannel * channel,gdouble * data,gint count,gpointer user_data)398 _gimp_wire_read_double (GIOChannel *channel,
399 gdouble *data,
400 gint count,
401 gpointer user_data)
402 {
403 gdouble *t;
404 guint8 tmp[8];
405 gint i;
406
407 g_return_val_if_fail (count >= 0, FALSE);
408
409 t = (gdouble *) tmp;
410
411 for (i = 0; i < count; i++)
412 {
413 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
414 gint j;
415 #endif
416
417 if (! _gimp_wire_read_int8 (channel, tmp, 8, user_data))
418 return FALSE;
419
420 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
421 for (j = 0; j < 4; j++)
422 {
423 guint8 swap;
424
425 swap = tmp[j];
426 tmp[j] = tmp[7 - j];
427 tmp[7 - j] = swap;
428 }
429 #endif
430
431 data[i] = *t;
432 }
433
434 return TRUE;
435 }
436
437 gboolean
_gimp_wire_read_string(GIOChannel * channel,gchar ** data,gint count,gpointer user_data)438 _gimp_wire_read_string (GIOChannel *channel,
439 gchar **data,
440 gint count,
441 gpointer user_data)
442 {
443 gint i;
444
445 g_return_val_if_fail (count >= 0, FALSE);
446
447 for (i = 0; i < count; i++)
448 {
449 guint32 tmp;
450
451 if (! _gimp_wire_read_int32 (channel, &tmp, 1, user_data))
452 return FALSE;
453
454 if (tmp > 0)
455 {
456 data[i] = g_try_new (gchar, tmp);
457
458 if (! data[i])
459 {
460 g_printerr ("%s: failed to allocate %u bytes\n", G_STRFUNC, tmp);
461 return FALSE;
462 }
463
464 if (! _gimp_wire_read_int8 (channel,
465 (guint8 *) data[i], tmp, user_data))
466 {
467 g_free (data[i]);
468 return FALSE;
469 }
470
471 /* make sure that the string is NULL-terminated */
472 data[i][tmp - 1] = '\0';
473 }
474 else
475 {
476 data[i] = NULL;
477 }
478 }
479
480 return TRUE;
481 }
482
483 gboolean
_gimp_wire_read_color(GIOChannel * channel,GimpRGB * data,gint count,gpointer user_data)484 _gimp_wire_read_color (GIOChannel *channel,
485 GimpRGB *data,
486 gint count,
487 gpointer user_data)
488 {
489 g_return_val_if_fail (count >= 0, FALSE);
490
491 return _gimp_wire_read_double (channel,
492 (gdouble *) data, 4 * count, user_data);
493 }
494
495 gboolean
_gimp_wire_write_int64(GIOChannel * channel,const guint64 * data,gint count,gpointer user_data)496 _gimp_wire_write_int64 (GIOChannel *channel,
497 const guint64 *data,
498 gint count,
499 gpointer user_data)
500 {
501 g_return_val_if_fail (count >= 0, FALSE);
502
503 if (count > 0)
504 {
505 gint i;
506
507 for (i = 0; i < count; i++)
508 {
509 guint64 tmp = GUINT64_TO_BE (data[i]);
510
511 if (! _gimp_wire_write_int8 (channel,
512 (const guint8 *) &tmp, 8, user_data))
513 return FALSE;
514 }
515 }
516
517 return TRUE;
518 }
519
520 gboolean
_gimp_wire_write_int32(GIOChannel * channel,const guint32 * data,gint count,gpointer user_data)521 _gimp_wire_write_int32 (GIOChannel *channel,
522 const guint32 *data,
523 gint count,
524 gpointer user_data)
525 {
526 g_return_val_if_fail (count >= 0, FALSE);
527
528 if (count > 0)
529 {
530 gint i;
531
532 for (i = 0; i < count; i++)
533 {
534 guint32 tmp = g_htonl (data[i]);
535
536 if (! _gimp_wire_write_int8 (channel,
537 (const guint8 *) &tmp, 4, user_data))
538 return FALSE;
539 }
540 }
541
542 return TRUE;
543 }
544
545 gboolean
_gimp_wire_write_int16(GIOChannel * channel,const guint16 * data,gint count,gpointer user_data)546 _gimp_wire_write_int16 (GIOChannel *channel,
547 const guint16 *data,
548 gint count,
549 gpointer user_data)
550 {
551 g_return_val_if_fail (count >= 0, FALSE);
552
553 if (count > 0)
554 {
555 gint i;
556
557 for (i = 0; i < count; i++)
558 {
559 guint16 tmp = g_htons (data[i]);
560
561 if (! _gimp_wire_write_int8 (channel,
562 (const guint8 *) &tmp, 2, user_data))
563 return FALSE;
564 }
565 }
566
567 return TRUE;
568 }
569
570 gboolean
_gimp_wire_write_int8(GIOChannel * channel,const guint8 * data,gint count,gpointer user_data)571 _gimp_wire_write_int8 (GIOChannel *channel,
572 const guint8 *data,
573 gint count,
574 gpointer user_data)
575 {
576 g_return_val_if_fail (count >= 0, FALSE);
577
578 return gimp_wire_write (channel, data, count, user_data);
579 }
580
581 gboolean
_gimp_wire_write_double(GIOChannel * channel,const gdouble * data,gint count,gpointer user_data)582 _gimp_wire_write_double (GIOChannel *channel,
583 const gdouble *data,
584 gint count,
585 gpointer user_data)
586 {
587 gdouble *t;
588 guint8 tmp[8];
589 gint i;
590 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
591 gint j;
592 #endif
593
594 g_return_val_if_fail (count >= 0, FALSE);
595
596 t = (gdouble *) tmp;
597
598 for (i = 0; i < count; i++)
599 {
600 *t = data[i];
601
602 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
603 for (j = 0; j < 4; j++)
604 {
605 guint8 swap;
606
607 swap = tmp[j];
608 tmp[j] = tmp[7 - j];
609 tmp[7 - j] = swap;
610 }
611 #endif
612
613 if (! _gimp_wire_write_int8 (channel, tmp, 8, user_data))
614 return FALSE;
615
616 #if 0
617 {
618 gint k;
619
620 g_print ("Wire representation of %f:\t", data[i]);
621
622 for (k = 0; k < 8; k++)
623 g_print ("%02x ", tmp[k]);
624
625 g_print ("\n");
626 }
627 #endif
628 }
629
630 return TRUE;
631 }
632
633 gboolean
_gimp_wire_write_string(GIOChannel * channel,gchar ** data,gint count,gpointer user_data)634 _gimp_wire_write_string (GIOChannel *channel,
635 gchar **data,
636 gint count,
637 gpointer user_data)
638 {
639 gint i;
640
641 g_return_val_if_fail (count >= 0, FALSE);
642
643 for (i = 0; i < count; i++)
644 {
645 guint32 tmp;
646
647 if (data[i])
648 tmp = strlen (data[i]) + 1;
649 else
650 tmp = 0;
651
652 if (! _gimp_wire_write_int32 (channel, &tmp, 1, user_data))
653 return FALSE;
654
655 if (tmp > 0)
656 if (! _gimp_wire_write_int8 (channel,
657 (const guint8 *) data[i], tmp, user_data))
658 return FALSE;
659 }
660
661 return TRUE;
662 }
663
664 gboolean
_gimp_wire_write_color(GIOChannel * channel,const GimpRGB * data,gint count,gpointer user_data)665 _gimp_wire_write_color (GIOChannel *channel,
666 const GimpRGB *data,
667 gint count,
668 gpointer user_data)
669 {
670 g_return_val_if_fail (count >= 0, FALSE);
671
672 return _gimp_wire_write_double (channel,
673 (gdouble *) data, 4 * count, user_data);
674 }
675
676 static guint
gimp_wire_hash(const guint32 * key)677 gimp_wire_hash (const guint32 *key)
678 {
679 return *key;
680 }
681
682 static gboolean
gimp_wire_compare(const guint32 * a,const guint32 * b)683 gimp_wire_compare (const guint32 *a,
684 const guint32 *b)
685 {
686 return (*a == *b);
687 }
688
689 static void
gimp_wire_init(void)690 gimp_wire_init (void)
691 {
692 if (! wire_ht)
693 wire_ht = g_hash_table_new ((GHashFunc) gimp_wire_hash,
694 (GCompareFunc) gimp_wire_compare);
695 }
696