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