1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <gegl.h>
25 
26 #include "libgimpbase/gimpbase.h"
27 
28 #include "pdb-types.h"
29 
30 #include "core/gimpparamspecs-desc.h"
31 
32 #include "gimppdb.h"
33 #include "gimppdb-query.h"
34 #include "gimppdberror.h"
35 #include "gimp-pdb-compat.h"
36 #include "gimpprocedure.h"
37 
38 #include "gimp-intl.h"
39 
40 
41 #define PDB_REGEX_FLAGS    (G_REGEX_CASELESS | G_REGEX_OPTIMIZE)
42 
43 #define COMPAT_BLURB       "This procedure is deprecated! Use '%s' instead."
44 
45 
46 typedef struct _PDBDump PDBDump;
47 
48 struct _PDBDump
49 {
50   GimpPDB       *pdb;
51   GOutputStream *output;
52   GError        *error;
53 
54   gboolean       dumping_compat;
55 };
56 
57 typedef struct _PDBQuery PDBQuery;
58 
59 struct _PDBQuery
60 {
61   GimpPDB  *pdb;
62 
63   GRegex   *name_regex;
64   GRegex   *blurb_regex;
65   GRegex   *help_regex;
66   GRegex   *author_regex;
67   GRegex   *copyright_regex;
68   GRegex   *date_regex;
69   GRegex   *proc_type_regex;
70 
71   gchar   **list_of_procs;
72   gint      num_procs;
73   gboolean  querying_compat;
74 };
75 
76 typedef struct _PDBStrings PDBStrings;
77 
78 struct _PDBStrings
79 {
80   gboolean  compat;
81 
82   gchar    *blurb;
83   gchar    *help;
84   gchar    *author;
85   gchar    *copyright;
86   gchar    *date;
87 };
88 
89 
90 /*  local function prototypes  */
91 
92 static void   gimp_pdb_query_entry  (gpointer       key,
93                                      gpointer       value,
94                                      gpointer       user_data);
95 static void   gimp_pdb_print_entry  (gpointer       key,
96                                      gpointer       value,
97                                      gpointer       user_data);
98 static void   gimp_pdb_get_strings  (PDBStrings    *strings,
99                                      GimpProcedure *procedure,
100                                      gboolean       compat);
101 static void   gimp_pdb_free_strings (PDBStrings    *strings);
102 
103 
104 /*  public functions  */
105 
106 gboolean
gimp_pdb_dump(GimpPDB * pdb,GFile * file,GError ** error)107 gimp_pdb_dump (GimpPDB  *pdb,
108                GFile    *file,
109                GError  **error)
110 {
111   PDBDump pdb_dump = { 0, };
112 
113   g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE);
114   g_return_val_if_fail (G_IS_FILE (file), FALSE);
115   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
116 
117   pdb_dump.pdb    = pdb;
118   pdb_dump.output = G_OUTPUT_STREAM (g_file_replace (file,
119                                                      NULL, FALSE,
120                                                      G_FILE_CREATE_NONE,
121                                                      NULL, error));
122   if (! pdb_dump.output)
123     return FALSE;
124 
125   pdb_dump.dumping_compat = FALSE;
126 
127   g_hash_table_foreach (pdb->procedures,
128                         gimp_pdb_print_entry,
129                         &pdb_dump);
130 
131   pdb_dump.dumping_compat = TRUE;
132 
133   g_hash_table_foreach (pdb->compat_proc_names,
134                         gimp_pdb_print_entry,
135                         &pdb_dump);
136 
137   if (pdb_dump.error)
138     {
139       GCancellable *cancellable = g_cancellable_new ();
140 
141       g_set_error (error, pdb_dump.error->domain, pdb_dump.error->code,
142                    _("Writing PDB file '%s' failed: %s"),
143                    gimp_file_get_utf8_name (file), pdb_dump.error->message);
144       g_clear_error (&pdb_dump.error);
145 
146       /* Cancel the overwrite initiated by g_file_replace(). */
147       g_cancellable_cancel (cancellable);
148       g_output_stream_close (pdb_dump.output, cancellable, NULL);
149       g_object_unref (cancellable);
150       g_object_unref (pdb_dump.output);
151 
152       return FALSE;
153     }
154 
155   g_object_unref (pdb_dump.output);
156 
157   return TRUE;
158 }
159 
160 gboolean
gimp_pdb_query(GimpPDB * pdb,const gchar * name,const gchar * blurb,const gchar * help,const gchar * author,const gchar * copyright,const gchar * date,const gchar * proc_type,gint * num_procs,gchar *** procs,GError ** error)161 gimp_pdb_query (GimpPDB       *pdb,
162                 const gchar   *name,
163                 const gchar   *blurb,
164                 const gchar   *help,
165                 const gchar   *author,
166                 const gchar   *copyright,
167                 const gchar   *date,
168                 const gchar   *proc_type,
169                 gint          *num_procs,
170                 gchar       ***procs,
171                 GError       **error)
172 {
173   PDBQuery pdb_query = { 0, };
174   gboolean success   = FALSE;
175 
176   g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE);
177   g_return_val_if_fail (name != NULL, FALSE);
178   g_return_val_if_fail (blurb != NULL, FALSE);
179   g_return_val_if_fail (help != NULL, FALSE);
180   g_return_val_if_fail (author != NULL, FALSE);
181   g_return_val_if_fail (copyright != NULL, FALSE);
182   g_return_val_if_fail (date != NULL, FALSE);
183   g_return_val_if_fail (proc_type != NULL, FALSE);
184   g_return_val_if_fail (num_procs != NULL, FALSE);
185   g_return_val_if_fail (procs != NULL, FALSE);
186   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
187 
188   *num_procs = 0;
189   *procs     = NULL;
190 
191   pdb_query.name_regex = g_regex_new (name, PDB_REGEX_FLAGS, 0, error);
192   if (! pdb_query.name_regex)
193     goto cleanup;
194 
195   pdb_query.blurb_regex = g_regex_new (blurb, PDB_REGEX_FLAGS, 0, error);
196   if (! pdb_query.blurb_regex)
197     goto cleanup;
198 
199   pdb_query.help_regex = g_regex_new (help, PDB_REGEX_FLAGS, 0, error);
200   if (! pdb_query.help_regex)
201     goto cleanup;
202 
203   pdb_query.author_regex = g_regex_new (author, PDB_REGEX_FLAGS, 0, error);
204   if (! pdb_query.author_regex)
205     goto cleanup;
206 
207   pdb_query.copyright_regex = g_regex_new (copyright, PDB_REGEX_FLAGS, 0, error);
208   if (! pdb_query.copyright_regex)
209     goto cleanup;
210 
211   pdb_query.date_regex = g_regex_new (date, PDB_REGEX_FLAGS, 0, error);
212   if (! pdb_query.date_regex)
213     goto cleanup;
214 
215   pdb_query.proc_type_regex = g_regex_new (proc_type, PDB_REGEX_FLAGS, 0, error);
216   if (! pdb_query.proc_type_regex)
217     goto cleanup;
218 
219   success = TRUE;
220 
221   pdb_query.pdb             = pdb;
222   pdb_query.list_of_procs   = NULL;
223   pdb_query.num_procs       = 0;
224   pdb_query.querying_compat = FALSE;
225 
226   g_hash_table_foreach (pdb->procedures,
227                         gimp_pdb_query_entry, &pdb_query);
228 
229   pdb_query.querying_compat = TRUE;
230 
231   g_hash_table_foreach (pdb->compat_proc_names,
232                         gimp_pdb_query_entry, &pdb_query);
233 
234  cleanup:
235 
236   if (pdb_query.proc_type_regex)
237     g_regex_unref (pdb_query.proc_type_regex);
238 
239   if (pdb_query.date_regex)
240     g_regex_unref (pdb_query.date_regex);
241 
242   if (pdb_query.copyright_regex)
243     g_regex_unref (pdb_query.copyright_regex);
244 
245   if (pdb_query.author_regex)
246     g_regex_unref (pdb_query.author_regex);
247 
248   if (pdb_query.help_regex)
249     g_regex_unref (pdb_query.help_regex);
250 
251   if (pdb_query.blurb_regex)
252     g_regex_unref (pdb_query.blurb_regex);
253 
254   if (pdb_query.name_regex)
255     g_regex_unref (pdb_query.name_regex);
256 
257   if (success)
258     {
259       *num_procs = pdb_query.num_procs;
260       *procs     = pdb_query.list_of_procs;
261     }
262 
263   return success;
264 }
265 
266 gboolean
gimp_pdb_proc_info(GimpPDB * pdb,const gchar * proc_name,gchar ** blurb,gchar ** help,gchar ** author,gchar ** copyright,gchar ** date,GimpPDBProcType * proc_type,gint * num_args,gint * num_values,GError ** error)267 gimp_pdb_proc_info (GimpPDB          *pdb,
268                     const gchar      *proc_name,
269                     gchar           **blurb,
270                     gchar           **help,
271                     gchar           **author,
272                     gchar           **copyright,
273                     gchar           **date,
274                     GimpPDBProcType  *proc_type,
275                     gint             *num_args,
276                     gint             *num_values,
277                     GError          **error)
278 {
279   GimpProcedure *procedure;
280   PDBStrings     strings;
281 
282   g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE);
283   g_return_val_if_fail (proc_name != NULL, FALSE);
284   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
285 
286   procedure = gimp_pdb_lookup_procedure (pdb, proc_name);
287 
288   if (procedure)
289     {
290       gimp_pdb_get_strings (&strings, procedure, FALSE);
291     }
292   else
293     {
294       const gchar *compat_name;
295 
296       compat_name = gimp_pdb_lookup_compat_proc_name (pdb, proc_name);
297 
298       if (compat_name)
299         {
300           procedure = gimp_pdb_lookup_procedure (pdb, compat_name);
301 
302           if (procedure)
303             gimp_pdb_get_strings (&strings, procedure, TRUE);
304         }
305     }
306 
307   if (procedure)
308     {
309       *blurb      = strings.compat ? strings.blurb : g_strdup (strings.blurb);
310       *help       = strings.compat ? strings.help : g_strdup (strings.help);
311       *author     = strings.compat ? strings.author : g_strdup (strings.author);
312       *copyright  = strings.compat ? strings.copyright : g_strdup (strings.copyright);
313       *date       = strings.compat ? strings.date : g_strdup (strings.date);
314       *proc_type  = procedure->proc_type;
315       *num_args   = procedure->num_args;
316       *num_values = procedure->num_values;
317 
318       return TRUE;
319     }
320 
321   g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
322                _("Procedure '%s' not found"), proc_name);
323 
324   return FALSE;
325 }
326 
327 
328 /*  private functions  */
329 
330 static gboolean
match_string(GRegex * regex,const gchar * string)331 match_string (GRegex      *regex,
332               const gchar *string)
333 {
334   if (! string)
335     string = "";
336 
337   return g_regex_match (regex, string, 0, NULL);
338 }
339 
340 static void
gimp_pdb_query_entry(gpointer key,gpointer value,gpointer user_data)341 gimp_pdb_query_entry (gpointer key,
342                       gpointer value,
343                       gpointer user_data)
344 {
345   PDBQuery      *pdb_query = user_data;
346   GList         *list;
347   GimpProcedure *procedure;
348   const gchar   *proc_name;
349   PDBStrings     strings;
350   GEnumClass    *enum_class;
351   GimpEnumDesc  *type_desc;
352 
353   proc_name = key;
354 
355   if (pdb_query->querying_compat)
356     list = g_hash_table_lookup (pdb_query->pdb->procedures, value);
357   else
358     list = value;
359 
360   if (! list)
361     return;
362 
363   procedure = list->data;
364 
365   gimp_pdb_get_strings (&strings, procedure, pdb_query->querying_compat);
366 
367   enum_class = g_type_class_ref (GIMP_TYPE_PDB_PROC_TYPE);
368   type_desc = gimp_enum_get_desc (enum_class, procedure->proc_type);
369   g_type_class_unref  (enum_class);
370 
371   if (match_string (pdb_query->name_regex,      proc_name)         &&
372       match_string (pdb_query->blurb_regex,     strings.blurb)     &&
373       match_string (pdb_query->help_regex,      strings.help)      &&
374       match_string (pdb_query->author_regex,    strings.author)    &&
375       match_string (pdb_query->copyright_regex, strings.copyright) &&
376       match_string (pdb_query->date_regex,      strings.date)      &&
377       match_string (pdb_query->proc_type_regex, type_desc->value_desc))
378     {
379       pdb_query->num_procs++;
380       pdb_query->list_of_procs = g_renew (gchar *, pdb_query->list_of_procs,
381                                           pdb_query->num_procs);
382       pdb_query->list_of_procs[pdb_query->num_procs - 1] = g_strdup (proc_name);
383     }
384 
385   gimp_pdb_free_strings (&strings);
386 }
387 
388 /* #define DEBUG_OUTPUT 1 */
389 
390 static void
output_string(GString * dest,const gchar * string)391 output_string (GString     *dest,
392                const gchar *string)
393 {
394 #ifndef DEBUG_OUTPUT
395   g_string_append_printf (dest, "\"");
396 #endif
397 
398   if (string)
399     while (*string)
400       {
401         switch (*string)
402           {
403           case '\\' : g_string_append_printf (dest, "\\\\"); break;
404           case '\"' : g_string_append_printf (dest, "\\\""); break;
405           case '{'  : g_string_append_printf (dest, "@{");   break;
406           case '@'  : g_string_append_printf (dest, "@@");   break;
407           case '}'  : g_string_append_printf (dest, "@}");   break;
408 
409           default:
410             g_string_append_printf (dest, "%c", *string);
411           }
412         string++;
413       }
414 
415 #ifndef DEBUG_OUTPUT
416   g_string_append_printf (dest, "\"\n");
417 #endif
418 }
419 
420 static void
gimp_pdb_print_entry(gpointer key,gpointer value,gpointer user_data)421 gimp_pdb_print_entry (gpointer key,
422                       gpointer value,
423                       gpointer user_data)
424 {
425   PDBDump       *pdb_dump = user_data;
426   GOutputStream *output   = pdb_dump->output;
427   const gchar   *proc_name;
428   GList         *list;
429   GEnumClass    *arg_class;
430   GEnumClass    *proc_class;
431   GString       *buf;
432   GString       *string;
433   gint           num = 0;
434 
435   if (pdb_dump->error)
436     return;
437 
438   proc_name = key;
439 
440   if (pdb_dump->dumping_compat)
441     list = g_hash_table_lookup (pdb_dump->pdb->procedures, value);
442   else
443     list = value;
444 
445   arg_class  = g_type_class_ref (GIMP_TYPE_PDB_ARG_TYPE);
446   proc_class = g_type_class_ref (GIMP_TYPE_PDB_PROC_TYPE);
447 
448   buf    = g_string_new (NULL);
449   string = g_string_new (NULL);
450 
451   for (; list; list = list->next)
452     {
453       GimpProcedure *procedure = list->data;
454       PDBStrings     strings;
455       GEnumValue    *arg_value;
456       GimpEnumDesc  *type_desc;
457       gint           i;
458 
459       num++;
460 
461       gimp_pdb_get_strings (&strings, procedure, pdb_dump->dumping_compat);
462 
463 #ifdef DEBUG_OUTPUT
464       g_string_append_printf (string, "(");
465 #else
466       g_string_append_printf (string, "(register-procedure ");
467 #endif
468 
469       if (num != 1)
470         {
471           g_string_printf (buf, "%s <%d>", proc_name, num);
472           output_string (string, buf->str);
473         }
474       else
475         {
476           output_string (string, proc_name);
477         }
478 
479       type_desc = gimp_enum_get_desc (proc_class, procedure->proc_type);
480 
481 #ifdef DEBUG_OUTPUT
482 
483       g_string_append_printf (string, " (");
484 
485       for (i = 0; i < procedure->num_args; i++)
486         {
487           GParamSpec     *pspec = procedure->args[i];
488           GimpPDBArgType  arg_type;
489 
490           arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
491 
492           arg_value = g_enum_get_value (arg_class, arg_type);
493 
494           if (i > 0)
495             g_string_append_printf (string, " ");
496 
497           output_string (string, arg_value->value_name);
498         }
499 
500       g_string_append_printf (string, ") (");
501 
502       for (i = 0; i < procedure->num_values; i++)
503         {
504           GParamSpec     *pspec = procedure->values[i];
505           GimpPDBArgType  arg_type;
506 
507           arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
508 
509           arg_value = g_enum_get_value (arg_class, arg_type);
510 
511           if (i > 0)
512             g_string_append_printf (string, " ");
513 
514           output_string (string, arg_value->value_name);
515         }
516 
517       g_string_append_printf (string, "))\n");
518 
519 #else /* ! DEBUG_OUTPUT */
520 
521       g_string_append_printf (string, "  ");
522       output_string (string, strings.blurb);
523 
524       g_string_append_printf (string, "  ");
525       output_string (string, strings.help);
526 
527       g_string_append_printf (string, "  ");
528       output_string (string, strings.author);
529 
530       g_string_append_printf (string, "  ");
531       output_string (string, strings.copyright);
532 
533       g_string_append_printf (string, "  ");
534       output_string (string, strings.date);
535 
536       g_string_append_printf (string, "  ");
537       output_string (string, type_desc->value_desc);
538 
539       g_string_append_printf (string, "  (");
540 
541       for (i = 0; i < procedure->num_args; i++)
542         {
543           GParamSpec     *pspec = procedure->args[i];
544           GimpPDBArgType  arg_type;
545           gchar          *desc  = gimp_param_spec_get_desc (pspec);
546 
547           g_string_append_printf (string, "\n    (\n");
548 
549           arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
550 
551           arg_value = g_enum_get_value (arg_class, arg_type);
552 
553           g_string_append_printf (string, "      ");
554           output_string (string, g_param_spec_get_name (pspec));
555 
556           g_string_append_printf (string, "      ");
557           output_string (string, arg_value->value_name);
558 
559           g_string_append_printf (string, "      ");
560           output_string (string, desc);
561 
562           g_free (desc);
563 
564           g_string_append_printf (string, "    )");
565         }
566 
567       g_string_append_printf (string, "\n  )\n");
568 
569       g_string_append_printf (string, "  (");
570 
571       for (i = 0; i < procedure->num_values; i++)
572         {
573           GParamSpec     *pspec = procedure->values[i];
574           GimpPDBArgType  arg_type;
575           gchar          *desc  = gimp_param_spec_get_desc (pspec);
576 
577           g_string_append_printf (string, "\n    (\n");
578 
579           arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
580 
581           arg_value = g_enum_get_value (arg_class, arg_type);
582 
583           g_string_append_printf (string, "      ");
584           output_string (string, g_param_spec_get_name (pspec));
585 
586           g_string_append_printf (string, "      ");
587           output_string (string, arg_value->value_name);
588 
589           g_string_append_printf (string, "      ");
590           output_string (string, desc);
591 
592           g_free (desc);
593 
594           g_string_append_printf (string, "    )");
595         }
596 
597       g_string_append_printf (string, "\n  )");
598       g_string_append_printf (string, "\n)\n");
599 
600 #endif /* DEBUG_OUTPUT */
601 
602       gimp_pdb_free_strings (&strings);
603     }
604 
605   g_output_stream_write_all (output, string->str, string->len,
606                              NULL, NULL, &pdb_dump->error);
607 
608   g_string_free (string, TRUE);
609   g_string_free (buf, TRUE);
610 
611   g_type_class_unref (arg_class);
612   g_type_class_unref (proc_class);
613 }
614 
615 static void
gimp_pdb_get_strings(PDBStrings * strings,GimpProcedure * procedure,gboolean compat)616 gimp_pdb_get_strings (PDBStrings    *strings,
617                       GimpProcedure *procedure,
618                       gboolean       compat)
619 {
620   strings->compat = compat;
621 
622   if (compat)
623     {
624       strings->blurb     = g_strdup_printf (COMPAT_BLURB,
625                                             gimp_object_get_name (procedure));
626       strings->help      = g_strdup (strings->blurb);
627       strings->author    = NULL;
628       strings->copyright = NULL;
629       strings->date      = NULL;
630     }
631   else
632     {
633       strings->blurb     = procedure->blurb;
634       strings->help      = procedure->help;
635       strings->author    = procedure->author;
636       strings->copyright = procedure->copyright;
637       strings->date      = procedure->date;
638     }
639 }
640 
641 static void
gimp_pdb_free_strings(PDBStrings * strings)642 gimp_pdb_free_strings (PDBStrings *strings)
643 {
644   if (strings->compat)
645     {
646       g_free (strings->blurb);
647       g_free (strings->help);
648     }
649 }
650