1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * gimpparasite.c
5  * Copyright (C) 1998 Jay Cox <jaycox@gimp.org>
6  *
7  * This library is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 3 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <stdio.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #include <string.h>
29 
30 #include <glib-object.h>
31 
32 #ifdef G_OS_WIN32
33 #include <process.h>                /* For _getpid() */
34 #endif
35 
36 #include "gimpbasetypes.h"
37 
38 #include "gimpparasite.h"
39 
40 
41 /**
42  * SECTION: gimpparasite
43  * @title: GimpParasite
44  * @short_description: Arbitrary pieces of data which can be attached
45  *                     to various GIMP objects.
46  * @see_also: gimp_image_parasite_attach(),
47  *            gimp_drawable_parasite_attach(), gimp_parasite_attach()
48  *            and their related functions.
49  *
50  * Arbitrary pieces of data which can be attached to various GIMP objects.
51  **/
52 
53 
54 /*
55  * GIMP_TYPE_PARASITE
56  */
57 
58 GType
gimp_parasite_get_type(void)59 gimp_parasite_get_type (void)
60 {
61   static GType type = 0;
62 
63   if (! type)
64     type = g_boxed_type_register_static ("GimpParasite",
65                                          (GBoxedCopyFunc) gimp_parasite_copy,
66                                          (GBoxedFreeFunc) gimp_parasite_free);
67 
68   return type;
69 }
70 
71 
72 /*
73  * GIMP_TYPE_PARAM_PARASITE
74  */
75 
76 #define GIMP_PARAM_SPEC_PARASITE(pspec)    (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_PARASITE, GimpParamSpecParasite))
77 
78 typedef struct _GimpParamSpecParasite GimpParamSpecParasite;
79 
80 struct _GimpParamSpecParasite
81 {
82   GParamSpecBoxed parent_instance;
83 };
84 
85 static void       gimp_param_parasite_class_init  (GParamSpecClass *class);
86 static void       gimp_param_parasite_init        (GParamSpec      *pspec);
87 static gboolean   gimp_param_parasite_validate    (GParamSpec      *pspec,
88                                                    GValue          *value);
89 static gint       gimp_param_parasite_values_cmp  (GParamSpec      *pspec,
90                                                    const GValue    *value1,
91                                                    const GValue    *value2);
92 
93 GType
gimp_param_parasite_get_type(void)94 gimp_param_parasite_get_type (void)
95 {
96   static GType type = 0;
97 
98   if (! type)
99     {
100       const GTypeInfo type_info =
101       {
102         sizeof (GParamSpecClass),
103         NULL, NULL,
104         (GClassInitFunc) gimp_param_parasite_class_init,
105         NULL, NULL,
106         sizeof (GimpParamSpecParasite),
107         0,
108         (GInstanceInitFunc) gimp_param_parasite_init
109       };
110 
111       type = g_type_register_static (G_TYPE_PARAM_BOXED,
112                                      "GimpParamParasite",
113                                      &type_info, 0);
114     }
115 
116   return type;
117 }
118 
119 static void
gimp_param_parasite_class_init(GParamSpecClass * class)120 gimp_param_parasite_class_init (GParamSpecClass *class)
121 {
122   class->value_type     = GIMP_TYPE_PARASITE;
123   class->value_validate = gimp_param_parasite_validate;
124   class->values_cmp     = gimp_param_parasite_values_cmp;
125 }
126 
127 static void
gimp_param_parasite_init(GParamSpec * pspec)128 gimp_param_parasite_init (GParamSpec *pspec)
129 {
130 }
131 
132 static gboolean
gimp_param_parasite_validate(GParamSpec * pspec,GValue * value)133 gimp_param_parasite_validate (GParamSpec *pspec,
134                               GValue     *value)
135 {
136   GimpParasite *parasite = value->data[0].v_pointer;
137 
138   if (! parasite)
139     {
140       return TRUE;
141     }
142   else if (parasite->name == NULL                          ||
143            *parasite->name == '\0'                         ||
144            ! g_utf8_validate (parasite->name, -1, NULL)    ||
145            (parasite->size == 0 && parasite->data != NULL) ||
146            (parasite->size >  0 && parasite->data == NULL))
147     {
148       g_value_set_boxed (value, NULL);
149       return TRUE;
150     }
151 
152   return FALSE;
153 }
154 
155 static gint
gimp_param_parasite_values_cmp(GParamSpec * pspec,const GValue * value1,const GValue * value2)156 gimp_param_parasite_values_cmp (GParamSpec   *pspec,
157                                 const GValue *value1,
158                                 const GValue *value2)
159 {
160   GimpParasite *parasite1 = value1->data[0].v_pointer;
161   GimpParasite *parasite2 = value2->data[0].v_pointer;
162 
163   /*  try to return at least *something*, it's useless anyway...  */
164 
165   if (! parasite1)
166     return parasite2 != NULL ? -1 : 0;
167   else if (! parasite2)
168     return parasite1 != NULL;
169   else
170     return gimp_parasite_compare (parasite1, parasite2);
171 }
172 
173 GParamSpec *
gimp_param_spec_parasite(const gchar * name,const gchar * nick,const gchar * blurb,GParamFlags flags)174 gimp_param_spec_parasite (const gchar *name,
175                           const gchar *nick,
176                           const gchar *blurb,
177                           GParamFlags  flags)
178 {
179   GimpParamSpecParasite *parasite_spec;
180 
181   parasite_spec = g_param_spec_internal (GIMP_TYPE_PARAM_PARASITE,
182                                          name, nick, blurb, flags);
183 
184   return G_PARAM_SPEC (parasite_spec);
185 }
186 
187 
188 #ifdef DEBUG
189 static void
gimp_parasite_print(GimpParasite * parasite)190 gimp_parasite_print (GimpParasite *parasite)
191 {
192   if (parasite == NULL)
193     {
194       g_print ("pid %d: attempt to print a null parasite\n", getpid ());
195       return;
196     }
197 
198   g_print ("pid %d: parasite: %p\n", getpid (), parasite);
199 
200   if (parasite->name)
201     g_print ("\tname: %s\n", parasite->name);
202   else
203     g_print ("\tname: NULL\n");
204 
205   g_print ("\tflags: %d\n", parasite->flags);
206   g_print ("\tsize: %d\n", parasite->size);
207   if (parasite->size > 0)
208     g_print ("\tdata: %p\n", parasite->data);
209 }
210 #endif
211 
212 GimpParasite *
gimp_parasite_new(const gchar * name,guint32 flags,guint32 size,gconstpointer data)213 gimp_parasite_new (const gchar    *name,
214                    guint32         flags,
215                    guint32         size,
216                    gconstpointer   data)
217 {
218   GimpParasite *parasite;
219 
220   if (! (name && *name))
221     return NULL;
222 
223   parasite = g_slice_new (GimpParasite);
224   parasite->name  = g_strdup (name);
225   parasite->flags = (flags & 0xFF);
226   parasite->size  = size;
227 
228   if (size)
229     parasite->data = g_memdup (data, size);
230   else
231     parasite->data = NULL;
232 
233   return parasite;
234 }
235 
236 void
gimp_parasite_free(GimpParasite * parasite)237 gimp_parasite_free (GimpParasite *parasite)
238 {
239   if (parasite == NULL)
240     return;
241 
242   if (parasite->name)
243     g_free (parasite->name);
244 
245   if (parasite->data)
246     g_free (parasite->data);
247 
248   g_slice_free (GimpParasite, parasite);
249 }
250 
251 gboolean
gimp_parasite_is_type(const GimpParasite * parasite,const gchar * name)252 gimp_parasite_is_type (const GimpParasite *parasite,
253                        const gchar        *name)
254 {
255   if (!parasite || !parasite->name)
256     return FALSE;
257 
258   return (strcmp (parasite->name, name) == 0);
259 }
260 
261 GimpParasite *
gimp_parasite_copy(const GimpParasite * parasite)262 gimp_parasite_copy (const GimpParasite *parasite)
263 {
264   if (parasite == NULL)
265     return NULL;
266 
267   return gimp_parasite_new (parasite->name, parasite->flags,
268                             parasite->size, parasite->data);
269 }
270 
271 gboolean
gimp_parasite_compare(const GimpParasite * a,const GimpParasite * b)272 gimp_parasite_compare (const GimpParasite *a,
273                        const GimpParasite *b)
274 {
275   if (a && b &&
276       a->name && b->name &&
277       strcmp (a->name, b->name) == 0 &&
278       a->flags == b->flags &&
279       a->size == b->size)
280     {
281       if (a->data == NULL && b->data == NULL)
282         return TRUE;
283       else if (a->data && b->data && memcmp (a->data, b->data, a->size) == 0)
284         return TRUE;
285     }
286 
287   return FALSE;
288 }
289 
290 gulong
gimp_parasite_flags(const GimpParasite * parasite)291 gimp_parasite_flags (const GimpParasite *parasite)
292 {
293   if (parasite == NULL)
294     return 0;
295 
296   return parasite->flags;
297 }
298 
299 gboolean
gimp_parasite_is_persistent(const GimpParasite * parasite)300 gimp_parasite_is_persistent (const GimpParasite *parasite)
301 {
302   if (parasite == NULL)
303     return FALSE;
304 
305   return (parasite->flags & GIMP_PARASITE_PERSISTENT);
306 }
307 
308 gboolean
gimp_parasite_is_undoable(const GimpParasite * parasite)309 gimp_parasite_is_undoable (const GimpParasite *parasite)
310 {
311   if (parasite == NULL)
312     return FALSE;
313 
314   return (parasite->flags & GIMP_PARASITE_UNDOABLE);
315 }
316 
317 gboolean
gimp_parasite_has_flag(const GimpParasite * parasite,gulong flag)318 gimp_parasite_has_flag (const GimpParasite *parasite,
319                         gulong              flag)
320 {
321   if (parasite == NULL)
322     return FALSE;
323 
324   return (parasite->flags & flag);
325 }
326 
327 const gchar *
gimp_parasite_name(const GimpParasite * parasite)328 gimp_parasite_name (const GimpParasite *parasite)
329 {
330   if (parasite)
331     return parasite->name;
332 
333   return NULL;
334 }
335 
336 gconstpointer
gimp_parasite_data(const GimpParasite * parasite)337 gimp_parasite_data (const GimpParasite *parasite)
338 {
339   if (parasite)
340     return parasite->data;
341 
342   return NULL;
343 }
344 
345 glong
gimp_parasite_data_size(const GimpParasite * parasite)346 gimp_parasite_data_size (const GimpParasite *parasite)
347 {
348   if (parasite)
349     return parasite->size;
350 
351   return 0;
352 }
353