Add restarting of the plugin loader and blacklisting of broken files
[platform/upstream/gstreamer.git] / gst / gstregistrychunks.c
1 /* GStreamer
2  * Copyright (C) 2006 Josep Torra <josep@fluendo.com>
3  *               2006 Mathieu Garcia <matthieu@fluendo.com>
4  *               2006,2007 Stefan Kost <ensonic@users.sf.net>
5  *               2008 Sebastian Dröge <slomo@circular-chaos.org>
6  *               2008 Jan Schmidt <jan.schmidt@sun.com>
7  *
8  * gstregistrychunks.c: GstRegistryChunk helper for serialising/deserialising
9  * plugin entries and features.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #  include "config.h"
29 #endif
30
31 #include <gst/gst_private.h>
32 #include <gst/gstconfig.h>
33 #include <gst/gstelement.h>
34 #include <gst/gsttypefind.h>
35 #include <gst/gsttypefindfactory.h>
36 #include <gst/gsturi.h>
37 #include <gst/gstinfo.h>
38 #include <gst/gstenumtypes.h>
39 #include <gst/gstpadtemplate.h>
40
41 #include <gst/gstregistrychunks.h>
42
43 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
44
45 /* count string length, but return -1 if we hit the eof */
46 static gint
47 _strnlen (const gchar * str, gint maxlen)
48 {
49   gint len = 0;
50
51   if (G_UNLIKELY (len == maxlen))
52     return -1;
53
54   while (*str++ != '\0') {
55     len++;
56     if (G_UNLIKELY (len == maxlen))
57       return -1;
58   }
59   return len;
60 }
61
62 /* Macros */
63 #define unpack_element(inptr, outptr, element, endptr, error_label) G_STMT_START{ \
64   if (inptr + sizeof(element) >= endptr) \
65     goto error_label; \
66   outptr = (element *) inptr; \
67   inptr += sizeof (element); \
68 }G_STMT_END
69
70 #define unpack_const_string(inptr, outptr, endptr, error_label) G_STMT_START{\
71   gint _len = _strnlen (inptr, (endptr-inptr)); \
72   if (_len == -1) \
73     goto error_label; \
74   outptr = g_intern_string ((const gchar *)inptr); \
75   inptr += _len + 1; \
76 }G_STMT_END
77
78 #define unpack_string(inptr, outptr, endptr, error_label)  G_STMT_START{\
79   gint _len = _strnlen (inptr, (endptr-inptr)); \
80   if (_len == -1) \
81     goto error_label; \
82   outptr = g_memdup ((gconstpointer)inptr, _len + 1); \
83   inptr += _len + 1; \
84 }G_STMT_END
85
86 #define ALIGNMENT            (sizeof (void *))
87 #define alignment(_address)  (gsize)_address%ALIGNMENT
88 #define align(_ptr)          _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
89
90 /*
91  * gst_registry_chunks_save_const_string:
92  *
93  * Store a const string in a binary chunk.
94  *
95  * Returns: %TRUE for success
96  */
97 inline static gboolean
98 gst_registry_chunks_save_const_string (GList ** list, const gchar * str)
99 {
100   GstRegistryChunk *chunk;
101
102   if (G_UNLIKELY (str == NULL)) {
103     GST_ERROR ("unexpected NULL string in plugin or plugin feature data");
104     str = "";
105   }
106
107   chunk = g_malloc (sizeof (GstRegistryChunk));
108   chunk->data = (gpointer) str;
109   chunk->size = strlen ((gchar *) chunk->data) + 1;
110   chunk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
111   chunk->align = FALSE;
112   *list = g_list_prepend (*list, chunk);
113   return TRUE;
114 }
115
116 /*
117  * gst_registry_chunks_save_string:
118  *
119  * Store a string in a binary chunk.
120  *
121  * Returns: %TRUE for success
122  */
123 inline static gboolean
124 gst_registry_chunks_save_string (GList ** list, gchar * str)
125 {
126   GstRegistryChunk *chunk;
127
128   chunk = g_malloc (sizeof (GstRegistryChunk));
129   chunk->data = str;
130   chunk->size = strlen ((gchar *) chunk->data) + 1;
131   chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
132   chunk->align = FALSE;
133   *list = g_list_prepend (*list, chunk);
134   return TRUE;
135 }
136
137 /*
138  * gst_registry_chunks_save_data:
139  *
140  * Store some data in a binary chunk.
141  *
142  * Returns: the initialized chunk
143  */
144 inline static GstRegistryChunk *
145 gst_registry_chunks_make_data (gpointer data, gulong size)
146 {
147   GstRegistryChunk *chunk;
148
149   chunk = g_malloc (sizeof (GstRegistryChunk));
150   chunk->data = data;
151   chunk->size = size;
152   chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
153   chunk->align = TRUE;
154   return chunk;
155 }
156
157
158 /*
159  * gst_registry_chunks_save_pad_template:
160  *
161  * Store pad_templates in binary chunks.
162  *
163  * Returns: %TRUE for success
164  */
165 static gboolean
166 gst_registry_chunks_save_pad_template (GList ** list,
167     GstStaticPadTemplate * template)
168 {
169   GstRegistryChunkPadTemplate *pt;
170   GstRegistryChunk *chk;
171
172   pt = g_malloc0 (sizeof (GstRegistryChunkPadTemplate));
173   chk =
174       gst_registry_chunks_make_data (pt, sizeof (GstRegistryChunkPadTemplate));
175
176   pt->presence = template->presence;
177   pt->direction = template->direction;
178
179   /* pack pad template strings */
180   gst_registry_chunks_save_const_string (list,
181       (gchar *) (template->static_caps.string));
182   gst_registry_chunks_save_const_string (list, template->name_template);
183
184   *list = g_list_prepend (*list, chk);
185
186   return TRUE;
187 }
188
189 /*
190  * gst_registry_chunks_save_feature:
191  *
192  * Store features in binary chunks.
193  *
194  * Returns: %TRUE for success
195  */
196 static gboolean
197 gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
198 {
199   const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
200   GstRegistryChunkPluginFeature *pf = NULL;
201   GstRegistryChunk *chk = NULL;
202   GList *walk;
203
204   if (!type_name) {
205     GST_ERROR ("NULL feature type_name, aborting.");
206     return FALSE;
207   }
208
209   if (GST_IS_ELEMENT_FACTORY (feature)) {
210     GstRegistryChunkElementFactory *ef;
211     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
212
213     ef = g_malloc0 (sizeof (GstRegistryChunkElementFactory));
214     chk =
215         gst_registry_chunks_make_data (ef,
216         sizeof (GstRegistryChunkElementFactory));
217     ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
218     pf = (GstRegistryChunkPluginFeature *) ef;
219
220     /* save interfaces */
221     for (walk = factory->interfaces; walk;
222         walk = g_list_next (walk), ef->ninterfaces++) {
223       gst_registry_chunks_save_const_string (list, (gchar *) walk->data);
224     }
225     GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
226     /* save uritypes */
227     if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
228       if (factory->uri_protocols && *factory->uri_protocols) {
229         GstRegistryChunk *subchk;
230         gchar **protocol;
231
232         subchk =
233             gst_registry_chunks_make_data (&factory->uri_type,
234             sizeof (factory->uri_type));
235         subchk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
236
237         protocol = factory->uri_protocols;
238         while (*protocol) {
239           gst_registry_chunks_save_const_string (list, *protocol++);
240           ef->nuriprotocols++;
241         }
242         *list = g_list_prepend (*list, subchk);
243         GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
244       } else {
245         g_warning ("GStreamer feature '%s' is URI handler but does not provide"
246             " any protocols it can handle", feature->name);
247       }
248     }
249
250     /* save pad-templates */
251     for (walk = factory->staticpadtemplates; walk;
252         walk = g_list_next (walk), ef->npadtemplates++) {
253       GstStaticPadTemplate *template = walk->data;
254
255       if (!gst_registry_chunks_save_pad_template (list, template)) {
256         GST_ERROR ("Can't fill pad template, aborting.");
257         goto fail;
258       }
259     }
260
261     /* pack element factory strings */
262     gst_registry_chunks_save_const_string (list, factory->details.author);
263     gst_registry_chunks_save_const_string (list, factory->details.description);
264     gst_registry_chunks_save_const_string (list, factory->details.klass);
265     gst_registry_chunks_save_const_string (list, factory->details.longname);
266   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
267     GstRegistryChunkTypeFindFactory *tff;
268     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
269     gchar *str;
270
271     tff = g_malloc0 (sizeof (GstRegistryChunkTypeFindFactory));
272     chk =
273         gst_registry_chunks_make_data (tff,
274         sizeof (GstRegistryChunkTypeFindFactory));
275     tff->nextensions = 0;
276     pf = (GstRegistryChunkPluginFeature *) tff;
277
278     /* save extensions */
279     if (factory->extensions) {
280       while (factory->extensions[tff->nextensions]) {
281         gst_registry_chunks_save_const_string (list,
282             factory->extensions[tff->nextensions++]);
283       }
284     }
285     /* save caps */
286     if (factory->caps) {
287       /* we copy the caps here so we can simplify them before saving. This
288        * is a lot faster when loading them later on */
289       GstCaps *copy = gst_caps_copy (factory->caps);
290
291       gst_caps_do_simplify (copy);
292       str = gst_caps_to_string (copy);
293       gst_caps_unref (copy);
294       gst_registry_chunks_save_string (list, str);
295     } else {
296       gst_registry_chunks_save_const_string (list, "");
297     }
298   } else if (GST_IS_INDEX_FACTORY (feature)) {
299     GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
300
301     pf = g_malloc0 (sizeof (GstRegistryChunkPluginFeature));
302     chk =
303         gst_registry_chunks_make_data (pf,
304         sizeof (GstRegistryChunkPluginFeature));
305     pf->rank = feature->rank;
306
307     /* pack element factory strings */
308     gst_registry_chunks_save_const_string (list, factory->longdesc);
309   } else {
310     GST_WARNING ("unhandled feature type '%s'", type_name);
311   }
312
313   if (pf) {
314     pf->rank = feature->rank;
315     *list = g_list_prepend (*list, chk);
316
317     /* pack plugin feature strings */
318     gst_registry_chunks_save_const_string (list, feature->name);
319     gst_registry_chunks_save_const_string (list, (gchar *) type_name);
320
321     return TRUE;
322   }
323
324   /* Errors */
325 fail:
326   g_free (chk);
327   g_free (pf);
328   return FALSE;
329 }
330
331 static gboolean
332 gst_registry_chunks_save_plugin_dep (GList ** list, GstPluginDep * dep)
333 {
334   GstRegistryChunkDep *ed;
335   GstRegistryChunk *chk;
336   gchar **s;
337
338   ed = g_new0 (GstRegistryChunkDep, 1);
339   chk = gst_registry_chunks_make_data (ed, sizeof (GstRegistryChunkDep));
340
341   ed->flags = dep->flags;
342   ed->n_env_vars = 0;
343   ed->n_paths = 0;
344   ed->n_names = 0;
345
346   ed->env_hash = dep->env_hash;
347   ed->stat_hash = dep->stat_hash;
348
349   for (s = dep->env_vars; s != NULL && *s != NULL; ++s, ++ed->n_env_vars)
350     gst_registry_chunks_save_string (list, g_strdup (*s));
351
352   for (s = dep->paths; s != NULL && *s != NULL; ++s, ++ed->n_paths)
353     gst_registry_chunks_save_string (list, g_strdup (*s));
354
355   for (s = dep->names; s != NULL && *s != NULL; ++s, ++ed->n_names)
356     gst_registry_chunks_save_string (list, g_strdup (*s));
357
358   *list = g_list_prepend (*list, chk);
359
360   GST_LOG ("Saved external plugin dependency");
361   return TRUE;
362 }
363
364 /*
365  * _priv_gst_registry_chunks_save_plugin:
366  *
367  * Adapt a GstPlugin to our GstRegistryChunkPluginElement structure, and
368  * prepend it as a GstRegistryChunk in the provided list.
369  *
370  */
371 gboolean
372 _priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
373     GstPlugin * plugin)
374 {
375   GstRegistryChunkPluginElement *pe;
376   GstRegistryChunk *chk;
377   GList *plugin_features = NULL;
378   GList *walk;
379
380   pe = g_malloc0 (sizeof (GstRegistryChunkPluginElement));
381   chk =
382       gst_registry_chunks_make_data (pe,
383       sizeof (GstRegistryChunkPluginElement));
384
385   pe->file_size = plugin->file_size;
386   pe->file_mtime = plugin->file_mtime;
387   pe->nfeatures = 0;
388   pe->n_deps = 0;
389
390   /* pack external deps */
391   for (walk = plugin->priv->deps; walk != NULL; walk = walk->next) {
392     if (!gst_registry_chunks_save_plugin_dep (list, walk->data)) {
393       GST_ERROR ("Could not save external plugin dependency, aborting.");
394       goto fail;
395     }
396     ++pe->n_deps;
397   }
398
399   /* pack plugin features */
400   plugin_features =
401       gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
402   for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
403     GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
404
405     if (!gst_registry_chunks_save_feature (list, feature)) {
406       GST_ERROR ("Can't fill plugin feature, aborting.");
407       goto fail;
408     }
409   }
410
411   gst_plugin_feature_list_free (plugin_features);
412
413   /* pack cache data */
414   if (plugin->priv->cache_data) {
415     gchar *cache_str = gst_structure_to_string (plugin->priv->cache_data);
416     gst_registry_chunks_save_string (list, cache_str);
417   } else {
418     gst_registry_chunks_save_const_string (list, "");
419   }
420
421   /* pack plugin element strings */
422   gst_registry_chunks_save_const_string (list, plugin->desc.origin);
423   gst_registry_chunks_save_const_string (list, plugin->desc.package);
424   gst_registry_chunks_save_const_string (list, plugin->desc.source);
425   gst_registry_chunks_save_const_string (list, plugin->desc.license);
426   gst_registry_chunks_save_const_string (list, plugin->desc.version);
427   gst_registry_chunks_save_const_string (list, plugin->filename);
428   gst_registry_chunks_save_const_string (list, plugin->desc.description);
429   gst_registry_chunks_save_const_string (list, plugin->desc.name);
430
431   *list = g_list_prepend (*list, chk);
432
433   GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
434       plugin->desc.name);
435   return TRUE;
436
437   /* Errors */
438 fail:
439   gst_plugin_feature_list_free (plugin_features);
440   g_free (chk);
441   g_free (pe);
442   return FALSE;
443 }
444
445 /*
446  * gst_registry_chunks_load_pad_template:
447  *
448  * Make a new GstStaticPadTemplate from current GstRegistryChunkPadTemplate
449  * structure.
450  *
451  * Returns: new GstStaticPadTemplate
452  */
453 static gboolean
454 gst_registry_chunks_load_pad_template (GstElementFactory * factory, gchar ** in,
455     gchar * end)
456 {
457   GstRegistryChunkPadTemplate *pt;
458   GstStaticPadTemplate *template = NULL;
459
460   align (*in);
461   GST_DEBUG ("Reading/casting for GstRegistryChunkPadTemplate at address %p",
462       *in);
463   unpack_element (*in, pt, GstRegistryChunkPadTemplate, end, fail);
464
465   template = g_new0 (GstStaticPadTemplate, 1);
466   template->presence = pt->presence;
467   template->direction = pt->direction;
468
469   /* unpack pad template strings */
470   unpack_const_string (*in, template->name_template, end, fail);
471   unpack_string (*in, template->static_caps.string, end, fail);
472
473   __gst_element_factory_add_static_pad_template (factory, template);
474   GST_DEBUG ("Added pad_template %s", template->name_template);
475
476   return TRUE;
477 fail:
478   GST_INFO ("Reading pad template failed");
479   g_free (template);
480   return FALSE;
481 }
482
483 /*
484  * gst_registry_chunks_load_feature:
485  *
486  * Make a new GstPluginFeature from current binary plugin feature structure
487  *
488  * Returns: new GstPluginFeature
489  */
490 static gboolean
491 gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
492     gchar * end, const gchar * plugin_name)
493 {
494   GstRegistryChunkPluginFeature *pf = NULL;
495   GstPluginFeature *feature = NULL;
496   gchar *type_name = NULL, *str;
497   GType type;
498   guint i;
499
500   /* unpack plugin feature strings */
501   unpack_string (*in, type_name, end, fail);
502
503   if (G_UNLIKELY (!type_name)) {
504     GST_ERROR ("No feature type name");
505     return FALSE;
506   }
507
508   GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
509
510   if (G_UNLIKELY (!(type = g_type_from_name (type_name)))) {
511     GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
512         plugin_name);
513     g_free (type_name);
514     return FALSE;
515   }
516   if (G_UNLIKELY ((feature = g_object_new (type, NULL)) == NULL)) {
517     GST_ERROR ("Can't create feature from type");
518     g_free (type_name);
519     return FALSE;
520   }
521
522   if (G_UNLIKELY (!GST_IS_PLUGIN_FEATURE (feature))) {
523     GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
524     goto fail;
525   }
526
527   /* unpack more plugin feature strings */
528   unpack_string (*in, feature->name, end, fail);
529
530   if (GST_IS_ELEMENT_FACTORY (feature)) {
531     GstRegistryChunkElementFactory *ef;
532     guint n;
533     GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (feature);
534
535     align (*in);
536     GST_LOG ("Reading/casting for GstRegistryChunkElementFactory at address %p",
537         *in);
538     unpack_element (*in, ef, GstRegistryChunkElementFactory, end, fail);
539     pf = (GstRegistryChunkPluginFeature *) ef;
540
541     /* unpack element factory strings */
542     unpack_string (*in, factory->details.longname, end, fail);
543     unpack_string (*in, factory->details.klass, end, fail);
544     unpack_string (*in, factory->details.description, end, fail);
545     unpack_string (*in, factory->details.author, end, fail);
546     n = ef->npadtemplates;
547     GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
548         factory->details.longname, n);
549
550     /* load pad templates */
551     for (i = 0; i < n; i++) {
552       if (G_UNLIKELY (!gst_registry_chunks_load_pad_template (factory, in,
553                   end))) {
554         GST_ERROR ("Error while loading binary pad template");
555         goto fail;
556       }
557     }
558
559     /* load uritypes */
560     if (G_UNLIKELY ((n = ef->nuriprotocols))) {
561       GST_DEBUG ("Reading %d UriTypes at address %p", n, *in);
562
563       align (*in);
564       factory->uri_type = *((guint *) * in);
565       *in += sizeof (factory->uri_type);
566       /*unpack_element(*in, &factory->uri_type, factory->uri_type, end, fail); */
567
568       factory->uri_protocols = g_new0 (gchar *, n + 1);
569       for (i = 0; i < n; i++) {
570         unpack_string (*in, str, end, fail);
571         factory->uri_protocols[i] = str;
572       }
573     }
574     /* load interfaces */
575     if (G_UNLIKELY ((n = ef->ninterfaces))) {
576       GST_DEBUG ("Reading %d Interfaces at address %p", n, *in);
577       for (i = 0; i < n; i++) {
578         unpack_string (*in, str, end, fail);
579         __gst_element_factory_add_interface (factory, str);
580         g_free (str);
581       }
582     }
583   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
584     GstRegistryChunkTypeFindFactory *tff;
585     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
586
587     align (*in);
588     GST_DEBUG
589         ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
590         *in);
591     unpack_element (*in, tff, GstRegistryChunkTypeFindFactory, end, fail);
592     pf = (GstRegistryChunkPluginFeature *) tff;
593
594     /* load caps */
595     unpack_string (*in, str, end, fail);
596     factory->caps = (str && *str) ? gst_caps_from_string (str) : NULL;
597     g_free (str);
598     /* load extensions */
599     if (tff->nextensions) {
600       GST_DEBUG ("Reading %d Typefind extensions at address %p",
601           tff->nextensions, *in);
602       factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
603       for (i = 0; i < tff->nextensions; i++) {
604         unpack_string (*in, str, end, fail);
605         factory->extensions[i] = str;
606       }
607     }
608   } else if (GST_IS_INDEX_FACTORY (feature)) {
609     GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
610
611     align (*in);
612     GST_DEBUG
613         ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
614         *in);
615     unpack_element (*in, pf, GstRegistryChunkPluginFeature, end, fail);
616
617     /* unpack index factory strings */
618     unpack_string (*in, factory->longdesc, end, fail);
619   } else {
620     GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
621     goto fail;
622   }
623
624   feature->rank = pf->rank;
625
626   /* should already be the interned string, but better make sure */
627   feature->plugin_name = g_intern_string (plugin_name);
628
629   gst_registry_add_feature (registry, feature);
630   GST_DEBUG ("Added feature %s", feature->name);
631
632   g_free (type_name);
633   return TRUE;
634
635   /* Errors */
636 fail:
637   GST_INFO ("Reading plugin feature failed");
638   g_free (type_name);
639   if (feature) {
640     if (GST_IS_OBJECT (feature))
641       gst_object_unref (feature);
642     else
643       g_object_unref (feature);
644   }
645   return FALSE;
646 }
647
648 static gchar **
649 gst_registry_chunks_load_plugin_dep_strv (gchar ** in, gchar * end, guint n)
650 {
651   gchar **arr;
652
653   if (n == 0)
654     return NULL;
655
656   arr = g_new0 (gchar *, n + 1);
657   while (n > 0) {
658     unpack_string (*in, arr[n - 1], end, fail);
659     --n;
660   }
661   return arr;
662 fail:
663   GST_INFO ("Reading plugin dependency strings failed");
664   return NULL;
665 }
666
667 static gboolean
668 gst_registry_chunks_load_plugin_dep (GstPlugin * plugin, gchar ** in,
669     gchar * end)
670 {
671   GstPluginDep *dep;
672   GstRegistryChunkDep *d;
673   gchar **s;
674
675   align (*in);
676   GST_LOG_OBJECT (plugin, "Unpacking GstRegistryChunkDep from %p", *in);
677   unpack_element (*in, d, GstRegistryChunkDep, end, fail);
678
679   dep = g_new0 (GstPluginDep, 1);
680
681   dep->env_hash = d->env_hash;
682   dep->stat_hash = d->stat_hash;
683
684   dep->flags = d->flags;
685
686   dep->names = gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_names);
687   dep->paths = gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_paths);
688   dep->env_vars =
689       gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_env_vars);
690
691   plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
692
693   GST_DEBUG_OBJECT (plugin, "Loaded external plugin dependency from registry: "
694       "env_hash: %08x, stat_hash: %08x", dep->env_hash, dep->stat_hash);
695   for (s = dep->env_vars; s != NULL && *s != NULL; ++s)
696     GST_LOG_OBJECT (plugin, " evar: %s", *s);
697   for (s = dep->paths; s != NULL && *s != NULL; ++s)
698     GST_LOG_OBJECT (plugin, " path: %s", *s);
699   for (s = dep->names; s != NULL && *s != NULL; ++s)
700     GST_LOG_OBJECT (plugin, " name: %s", *s);
701
702   return TRUE;
703 fail:
704   GST_INFO ("Reading plugin dependency failed");
705   return FALSE;
706 }
707
708
709 /*
710  * _priv_gst_registry_chunks_load_plugin:
711  *
712  * Make a new GstPlugin from current GstRegistryChunkPluginElement structure
713  * and add it to the GstRegistry. Return an offset to the next
714  * GstRegistryChunkPluginElement structure.
715  */
716 gboolean
717 _priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
718     gchar * end, GstPlugin ** out_plugin)
719 {
720   GstRegistryChunkPluginElement *pe;
721   GstPlugin *plugin = NULL;
722   gchar *cache_str = NULL;
723   guint i, n;
724
725   align (*in);
726   GST_LOG ("Reading/casting for GstRegistryChunkPluginElement at address %p",
727       *in);
728   unpack_element (*in, pe, GstRegistryChunkPluginElement, end, fail);
729
730   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
731
732   /* TODO: also set GST_PLUGIN_FLAG_CONST */
733   plugin->flags |= GST_PLUGIN_FLAG_CACHED;
734   plugin->file_mtime = pe->file_mtime;
735   plugin->file_size = pe->file_size;
736
737   /* unpack plugin element strings */
738   unpack_const_string (*in, plugin->desc.name, end, fail);
739   unpack_string (*in, plugin->desc.description, end, fail);
740   unpack_string (*in, plugin->filename, end, fail);
741   unpack_const_string (*in, plugin->desc.version, end, fail);
742   unpack_const_string (*in, plugin->desc.license, end, fail);
743   unpack_const_string (*in, plugin->desc.source, end, fail);
744   unpack_const_string (*in, plugin->desc.package, end, fail);
745   unpack_const_string (*in, plugin->desc.origin, end, fail);
746   GST_LOG ("read strings for name='%s'", plugin->desc.name);
747   GST_LOG ("  desc.description='%s'", plugin->desc.description);
748   GST_LOG ("  filename='%s'", plugin->filename);
749   GST_LOG ("  desc.version='%s'", plugin->desc.version);
750   GST_LOG ("  desc.license='%s'", plugin->desc.license);
751   GST_LOG ("  desc.source='%s'", plugin->desc.source);
752   GST_LOG ("  desc.package='%s'", plugin->desc.package);
753   GST_LOG ("  desc.origin='%s'", plugin->desc.origin);
754
755   /* unpack cache data */
756   unpack_string (*in, cache_str, end, fail);
757   if (*cache_str) {
758     plugin->priv->cache_data = gst_structure_from_string (cache_str, NULL);
759   }
760   g_free (cache_str);
761
762   /* If the license string is 'BLACKLIST', mark this as a blacklisted
763    * plugin */
764   if (strcmp (plugin->desc.license, "BLACKLIST") == 0)
765     plugin->flags |= GST_PLUGIN_FLAG_BLACKLISTED;
766
767   plugin->basename = g_path_get_basename (plugin->filename);
768
769   /* Takes ownership of plugin */
770   gst_registry_add_plugin (registry, plugin);
771   n = pe->nfeatures;
772   GST_DEBUG ("Added plugin '%s' plugin with %d features from binary registry",
773       plugin->desc.name, n);
774
775   /* Load plugin features */
776   for (i = 0; i < n; i++) {
777     if (G_UNLIKELY (!gst_registry_chunks_load_feature (registry, in, end,
778                 plugin->desc.name))) {
779       GST_ERROR ("Error while loading binary feature");
780       gst_registry_remove_plugin (registry, plugin);
781       goto fail;
782     }
783   }
784
785   /* Load external plugin dependencies */
786   for (i = 0; i < pe->n_deps; ++i) {
787     if (G_UNLIKELY (!gst_registry_chunks_load_plugin_dep (plugin, in, end))) {
788       GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency");
789       gst_registry_remove_plugin (registry, plugin);
790       goto fail;
791     }
792   }
793
794   if (out_plugin)
795     *out_plugin = plugin;
796
797   return TRUE;
798
799   /* Errors */
800 fail:
801   GST_INFO ("Reading plugin failed");
802   return FALSE;
803 }