gstpad: Fix non-serialized sticky event push
[platform/upstream/gstreamer.git] / subprojects / gstreamer / 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., 51 Franklin St, Fifth Floor,
24  * Boston, MA 02110-1301, 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/gsttracerfactory.h>
35 #include <gst/gsttypefind.h>
36 #include <gst/gsttypefindfactory.h>
37 #include <gst/gstdeviceproviderfactory.h>
38 #include <gst/gstdynamictypefactory.h>
39 #include <gst/gsturi.h>
40 #include <gst/gstinfo.h>
41 #include <gst/gstenumtypes.h>
42 #include <gst/gstpadtemplate.h>
43 #include "glib-compat-private.h"
44
45 #include <gst/gstregistrychunks.h>
46
47 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
48
49 /* count string length, but return -1 if we hit the eof */
50 #ifdef HAVE_STRNLEN
51 static inline gint
52 _strnlen (const gchar * str, gint maxlen)
53 {
54   gint len = strnlen (str, maxlen);
55
56   if (G_UNLIKELY (len == maxlen))
57     return -1;
58   return len;
59 }
60 #else
61 static inline gint
62 _strnlen (const gchar * str, gint maxlen)
63 {
64   gint len = 0;
65
66   while (G_LIKELY (len < maxlen)) {
67     if (G_UNLIKELY (str[len] == '\0'))
68       return len;
69     len++;
70   }
71   return -1;
72 }
73 #endif
74
75 /* Macros */
76 #define unpack_element(inptr, outptr, element, endptr, error_label) G_STMT_START{ \
77   if (inptr + sizeof(element) > endptr) { \
78     GST_ERROR ("Failed reading element " G_STRINGIFY (element)  \
79         ". Have %d bytes need %" G_GSIZE_FORMAT, \
80         (int) (endptr - inptr), sizeof(element)); \
81     goto error_label; \
82   } \
83   outptr = (element *) inptr; \
84   inptr += sizeof (element); \
85 }G_STMT_END
86
87 #define unpack_const_string(inptr, outptr, endptr, error_label) G_STMT_START{\
88   gint _len = _strnlen (inptr, (endptr-inptr)); \
89   if (_len == -1) \
90     goto error_label; \
91   outptr = g_intern_string ((const gchar *)inptr); \
92   inptr += _len + 1; \
93 }G_STMT_END
94
95 #define unpack_string(inptr, outptr, endptr, error_label)  G_STMT_START{\
96   gint _len = _strnlen (inptr, (endptr-inptr)); \
97   if (_len == -1) \
98     goto error_label; \
99   outptr = g_memdup2 ((gconstpointer)inptr, _len + 1); \
100   inptr += _len + 1; \
101 }G_STMT_END
102
103 #define unpack_string_nocopy(inptr, outptr, endptr, error_label)  G_STMT_START{\
104   gint _len = _strnlen (inptr, (endptr-inptr)); \
105   if (_len == -1) \
106     goto error_label; \
107   outptr = (const gchar *)inptr; \
108   inptr += _len + 1; \
109 }G_STMT_END
110
111 #define ALIGNMENT            (sizeof (void *))
112 #define alignment(_address)  (gsize)_address%ALIGNMENT
113 #define align(_ptr)          _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
114
115 void
116 _priv_gst_registry_chunk_free (GstRegistryChunk * chunk)
117 {
118   if (!(chunk->flags & GST_REGISTRY_CHUNK_FLAG_CONST)) {
119     if ((chunk->flags & GST_REGISTRY_CHUNK_FLAG_MALLOC))
120       g_free (chunk->data);
121     else
122       g_slice_free1 (chunk->size, chunk->data);
123   }
124   g_slice_free (GstRegistryChunk, chunk);
125 }
126
127 /*
128  * gst_registry_chunks_save_const_string:
129  *
130  * Store a const string in a binary chunk.
131  *
132  * Returns: %TRUE for success
133  */
134 inline static gboolean
135 gst_registry_chunks_save_const_string (GList ** list, const gchar * str)
136 {
137   GstRegistryChunk *chunk;
138
139   if (G_UNLIKELY (str == NULL)) {
140     GST_ERROR ("unexpected NULL string in plugin or plugin feature data");
141     str = "";
142   }
143
144   chunk = g_slice_new (GstRegistryChunk);
145   chunk->data = (gpointer) str;
146   chunk->size = strlen ((gchar *) chunk->data) + 1;
147   chunk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
148   chunk->align = FALSE;
149   *list = g_list_prepend (*list, chunk);
150   return TRUE;
151 }
152
153 /*
154  * gst_registry_chunks_save_string:
155  *
156  * Store a string in a binary chunk.
157  *
158  * Returns: %TRUE for success
159  */
160 inline static gboolean
161 gst_registry_chunks_save_string (GList ** list, gchar * str)
162 {
163   GstRegistryChunk *chunk;
164
165   chunk = g_slice_new (GstRegistryChunk);
166   chunk->data = str;
167   chunk->size = strlen ((gchar *) chunk->data) + 1;
168   chunk->flags = GST_REGISTRY_CHUNK_FLAG_MALLOC;
169   chunk->align = FALSE;
170   *list = g_list_prepend (*list, chunk);
171   return TRUE;
172 }
173
174 /*
175  * gst_registry_chunks_save_data:
176  *
177  * Store some data in a binary chunk.
178  *
179  * Returns: the initialized chunk
180  */
181 inline static GstRegistryChunk *
182 gst_registry_chunks_make_data (gpointer data, gulong size)
183 {
184   GstRegistryChunk *chunk;
185
186   chunk = g_slice_new (GstRegistryChunk);
187   chunk->data = data;
188   chunk->size = size;
189   chunk->flags = GST_REGISTRY_CHUNK_FLAG_NONE;
190   chunk->align = TRUE;
191   return chunk;
192 }
193
194
195 /*
196  * gst_registry_chunks_save_pad_template:
197  *
198  * Store pad_templates in binary chunks.
199  *
200  * Returns: %TRUE for success
201  */
202 static gboolean
203 gst_registry_chunks_save_pad_template (GList ** list,
204     GstStaticPadTemplate * template)
205 {
206   GstRegistryChunkPadTemplate *pt;
207   GstRegistryChunk *chk;
208
209   pt = g_slice_new (GstRegistryChunkPadTemplate);
210   chk =
211       gst_registry_chunks_make_data (pt, sizeof (GstRegistryChunkPadTemplate));
212
213   pt->presence = template->presence;
214   pt->direction = template->direction;
215
216   /* pack pad template strings */
217   gst_registry_chunks_save_const_string (list,
218       (gchar *) (template->static_caps.string));
219   gst_registry_chunks_save_const_string (list, template->name_template);
220
221   *list = g_list_prepend (*list, chk);
222
223   return TRUE;
224 }
225
226 /*
227  * gst_registry_chunks_save_feature:
228  *
229  * Store features in binary chunks.
230  *
231  * Returns: %TRUE for success
232  */
233 static gboolean
234 gst_registry_chunks_save_feature (GList ** list, GstPluginFeature * feature)
235 {
236   const gchar *type_name = G_OBJECT_TYPE_NAME (feature);
237   GstRegistryChunkPluginFeature *pf = NULL;
238   GstRegistryChunk *chk = NULL;
239   GList *walk;
240   gsize pf_size = 0;
241
242   if (!type_name) {
243     GST_ERROR ("NULL feature type_name, aborting.");
244     return FALSE;
245   }
246
247   if (GST_IS_ELEMENT_FACTORY (feature)) {
248     GstRegistryChunkElementFactory *ef;
249     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
250
251     /* Initialize with zeroes because of struct padding and
252      * valgrind complaining about copying uninitialized memory
253      */
254     ef = g_slice_new0 (GstRegistryChunkElementFactory);
255     pf_size = sizeof (GstRegistryChunkElementFactory);
256     chk = gst_registry_chunks_make_data (ef, pf_size);
257     ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
258     pf = (GstRegistryChunkPluginFeature *) ef;
259
260     /* save interfaces */
261     for (walk = factory->interfaces; walk;
262         walk = g_list_next (walk), ef->ninterfaces++) {
263       gst_registry_chunks_save_const_string (list, (gchar *) walk->data);
264     }
265     GST_DEBUG_OBJECT (feature, "saved %d interfaces %d pad templates",
266         ef->ninterfaces, ef->npadtemplates);
267
268     /* save uritypes */
269     if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
270       if (factory->uri_protocols && *factory->uri_protocols) {
271         GstRegistryChunk *subchk;
272         gchar **protocol;
273
274         subchk =
275             gst_registry_chunks_make_data (&factory->uri_type,
276             sizeof (factory->uri_type));
277         subchk->flags = GST_REGISTRY_CHUNK_FLAG_CONST;
278
279         protocol = factory->uri_protocols;
280         while (*protocol) {
281           gst_registry_chunks_save_const_string (list, *protocol++);
282           ef->nuriprotocols++;
283         }
284         *list = g_list_prepend (*list, subchk);
285         GST_DEBUG_OBJECT (feature, "Saved %d UriTypes", ef->nuriprotocols);
286       } else {
287         g_warning ("GStreamer feature '%s' is URI handler but does not provide"
288             " any protocols it can handle", GST_OBJECT_NAME (feature));
289       }
290     }
291
292     /* save pad-templates */
293     for (walk = factory->staticpadtemplates; walk;
294         walk = g_list_next (walk), ef->npadtemplates++) {
295       GstStaticPadTemplate *template = walk->data;
296
297       if (!gst_registry_chunks_save_pad_template (list, template)) {
298         GST_ERROR_OBJECT (feature, "Can't fill pad template, aborting.");
299         goto fail;
300       }
301     }
302
303     /* pack element metadata strings */
304     gst_registry_chunks_save_string (list,
305         gst_structure_to_string (factory->metadata));
306   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
307     GstRegistryChunkTypeFindFactory *tff;
308     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
309     gchar *str;
310
311     /* Initialize with zeroes because of struct padding and
312      * valgrind complaining about copying uninitialized memory
313      */
314     tff = g_slice_new0 (GstRegistryChunkTypeFindFactory);
315     pf_size = sizeof (GstRegistryChunkTypeFindFactory);
316     chk = gst_registry_chunks_make_data (tff, pf_size);
317     tff->nextensions = 0;
318     pf = (GstRegistryChunkPluginFeature *) tff;
319
320     /* save extensions */
321     if (factory->extensions) {
322       while (factory->extensions[tff->nextensions]) {
323         gst_registry_chunks_save_const_string (list,
324             factory->extensions[tff->nextensions++]);
325       }
326     }
327     GST_DEBUG_OBJECT (feature, "saved %d extensions", tff->nextensions);
328     /* save caps */
329     if (factory->caps) {
330       GstCaps *fcaps = gst_caps_ref (factory->caps);
331       /* we simplify the caps before saving. This is a lot faster
332        * when loading them later on */
333       fcaps = gst_caps_simplify (fcaps);
334       str = gst_caps_to_string (fcaps);
335       gst_caps_unref (fcaps);
336
337       gst_registry_chunks_save_string (list, str);
338     } else {
339       gst_registry_chunks_save_const_string (list, "");
340     }
341   } else if (GST_IS_DEVICE_PROVIDER_FACTORY (feature)) {
342     GstRegistryChunkDeviceProviderFactory *tff;
343     GstDeviceProviderFactory *factory = GST_DEVICE_PROVIDER_FACTORY (feature);
344
345     /* Initialize with zeroes because of struct padding and
346      * valgrind complaining about copying uninitialized memory
347      */
348     tff = g_slice_new0 (GstRegistryChunkDeviceProviderFactory);
349     chk =
350         gst_registry_chunks_make_data (tff,
351         sizeof (GstRegistryChunkDeviceProviderFactory));
352     pf = (GstRegistryChunkPluginFeature *) tff;
353
354
355     /* pack element metadata strings */
356     gst_registry_chunks_save_string (list,
357         gst_structure_to_string (factory->metadata));
358   } else if (GST_IS_TRACER_FACTORY (feature)) {
359     /* Initialize with zeroes because of struct padding and
360      * valgrind complaining about copying uninitialized memory
361      */
362     pf = g_slice_new0 (GstRegistryChunkPluginFeature);
363     pf_size = sizeof (GstRegistryChunkPluginFeature);
364     chk = gst_registry_chunks_make_data (pf, pf_size);
365   } else if (GST_IS_DYNAMIC_TYPE_FACTORY (feature)) {
366     GstRegistryChunkDynamicTypeFactory *tmp;
367
368     tmp = g_slice_new0 (GstRegistryChunkDynamicTypeFactory);
369     chk =
370         gst_registry_chunks_make_data (tmp,
371         sizeof (GstRegistryChunkDynamicTypeFactory));
372     pf = (GstRegistryChunkPluginFeature *) tmp;
373   } else {
374     GST_WARNING_OBJECT (feature, "unhandled feature type '%s'", type_name);
375   }
376
377   if (pf) {
378     pf->rank = feature->rank;
379     *list = g_list_prepend (*list, chk);
380
381     /* pack plugin feature strings */
382     gst_registry_chunks_save_const_string (list, GST_OBJECT_NAME (feature));
383     gst_registry_chunks_save_const_string (list, (gchar *) type_name);
384
385     return TRUE;
386   }
387
388   /* Errors */
389 fail:
390   g_slice_free (GstRegistryChunk, chk);
391   g_slice_free1 (pf_size, pf);
392   return FALSE;
393 }
394
395 static gboolean
396 gst_registry_chunks_save_plugin_dep (GList ** list, GstPluginDep * dep)
397 {
398   GstRegistryChunkDep *ed;
399   GstRegistryChunk *chk;
400   gchar **s;
401
402   ed = g_slice_new (GstRegistryChunkDep);
403   chk = gst_registry_chunks_make_data (ed, sizeof (GstRegistryChunkDep));
404
405   ed->flags = dep->flags;
406   ed->n_env_vars = 0;
407   ed->n_paths = 0;
408   ed->n_names = 0;
409
410   ed->env_hash = dep->env_hash;
411   ed->stat_hash = dep->stat_hash;
412
413   for (s = dep->env_vars; s != NULL && *s != NULL; ++s, ++ed->n_env_vars)
414     gst_registry_chunks_save_string (list, g_strdup (*s));
415
416   for (s = dep->paths; s != NULL && *s != NULL; ++s, ++ed->n_paths)
417     gst_registry_chunks_save_string (list, g_strdup (*s));
418
419   for (s = dep->names; s != NULL && *s != NULL; ++s, ++ed->n_names)
420     gst_registry_chunks_save_string (list, g_strdup (*s));
421
422   *list = g_list_prepend (*list, chk);
423
424   GST_LOG ("Saved external plugin dependency");
425   return TRUE;
426 }
427
428 /*
429  * _priv_gst_registry_chunks_save_plugin:
430  *
431  * Adapt a GstPlugin to our GstRegistryChunkPluginElement structure, and
432  * prepend it as a GstRegistryChunk in the provided list.
433  *
434  */
435 gboolean
436 _priv_gst_registry_chunks_save_plugin (GList ** list, GstRegistry * registry,
437     GstPlugin * plugin)
438 {
439   GstRegistryChunkPluginElement *pe;
440   GstRegistryChunk *chk;
441   GList *plugin_features = NULL;
442   GList *walk;
443
444   pe = g_slice_new (GstRegistryChunkPluginElement);
445   chk =
446       gst_registry_chunks_make_data (pe,
447       sizeof (GstRegistryChunkPluginElement));
448
449   pe->file_size = plugin->file_size;
450   pe->file_mtime = plugin->file_mtime;
451   pe->nfeatures = 0;
452   pe->n_deps = 0;
453
454   /* pack external deps */
455   for (walk = plugin->priv->deps; walk != NULL; walk = walk->next) {
456     if (!gst_registry_chunks_save_plugin_dep (list, walk->data)) {
457       GST_ERROR ("Could not save external plugin dependency, aborting.");
458       goto fail;
459     }
460     ++pe->n_deps;
461   }
462
463   /* pack plugin features */
464   plugin_features = _priv_plugin_get_features (registry, plugin);
465   for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
466     GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
467
468     if (!gst_registry_chunks_save_feature (list, feature)) {
469       GST_ERROR ("Can't fill plugin feature, aborting.");
470       goto fail;
471     }
472   }
473
474   gst_plugin_feature_list_free (plugin_features);
475
476   /* pack cache data */
477   if (plugin->priv->cache_data) {
478     gchar *cache_str = gst_structure_to_string (plugin->priv->cache_data);
479     gst_registry_chunks_save_string (list, cache_str);
480   } else {
481     gst_registry_chunks_save_const_string (list, "");
482   }
483
484   /* pack plugin element strings */
485   gst_registry_chunks_save_const_string (list,
486       (plugin->desc.release_datetime) ? plugin->desc.release_datetime : "");
487   gst_registry_chunks_save_const_string (list, plugin->desc.origin);
488   gst_registry_chunks_save_const_string (list, plugin->desc.package);
489   gst_registry_chunks_save_const_string (list, plugin->desc.source);
490   gst_registry_chunks_save_const_string (list, plugin->desc.license);
491   gst_registry_chunks_save_const_string (list, plugin->desc.version);
492   gst_registry_chunks_save_const_string (list, plugin->filename);
493   gst_registry_chunks_save_const_string (list, plugin->desc.description);
494   gst_registry_chunks_save_const_string (list, plugin->desc.name);
495
496   *list = g_list_prepend (*list, chk);
497
498   GST_DEBUG ("Found %d features in plugin %p (%s)", pe->nfeatures,
499       plugin, plugin->desc.name);
500   return TRUE;
501
502   /* Errors */
503 fail:
504   gst_plugin_feature_list_free (plugin_features);
505   g_slice_free (GstRegistryChunk, chk);
506   g_slice_free (GstRegistryChunkPluginElement, pe);
507   return FALSE;
508 }
509
510 /*
511  * gst_registry_chunks_load_pad_template:
512  *
513  * Make a new GstStaticPadTemplate from current GstRegistryChunkPadTemplate
514  * structure.
515  *
516  * Returns: new GstStaticPadTemplate
517  */
518 static gboolean
519 gst_registry_chunks_load_pad_template (GstElementFactory * factory, gchar ** in,
520     gchar * end)
521 {
522   GstRegistryChunkPadTemplate *pt;
523   GstStaticPadTemplate *template = NULL;
524
525   align (*in);
526   GST_DEBUG ("Reading/casting for GstRegistryChunkPadTemplate at address %p",
527       *in);
528   unpack_element (*in, pt, GstRegistryChunkPadTemplate, end, fail);
529
530   template = g_slice_new (GstStaticPadTemplate);
531   template->presence = pt->presence;
532   template->direction = (GstPadDirection) pt->direction;
533   template->static_caps.caps = NULL;
534
535   /* unpack pad template strings */
536   unpack_const_string (*in, template->name_template, end, fail);
537   unpack_const_string (*in, template->static_caps.string, end, fail);
538
539   __gst_element_factory_add_static_pad_template (factory, template);
540   GST_DEBUG ("Added pad_template %s", template->name_template);
541
542   return TRUE;
543 fail:
544   GST_INFO ("Reading pad template failed");
545   if (template)
546     g_slice_free (GstStaticPadTemplate, template);
547   return FALSE;
548 }
549
550 /*
551  * gst_registry_chunks_load_feature:
552  *
553  * Make a new GstPluginFeature from current binary plugin feature structure
554  *
555  * Returns: new GstPluginFeature
556  */
557 static gboolean
558 gst_registry_chunks_load_feature (GstRegistry * registry, gchar ** in,
559     gchar * end, GstPlugin * plugin)
560 {
561   GstRegistryChunkPluginFeature *pf = NULL;
562   GstPluginFeature *feature = NULL;
563   const gchar *const_str, *type_name;
564   const gchar *feature_name;
565   const gchar *plugin_name;
566   gchar *str;
567   GType type;
568   guint i;
569
570   plugin_name = plugin->desc.name;
571
572   /* unpack plugin feature strings */
573   unpack_string_nocopy (*in, type_name, end, fail);
574
575   if (G_UNLIKELY (!type_name)) {
576     GST_ERROR ("No feature type name");
577     return FALSE;
578   }
579
580   /* unpack more plugin feature strings */
581   unpack_string_nocopy (*in, feature_name, end, fail);
582
583   GST_DEBUG ("Plugin '%s' feature '%s' typename : '%s'", plugin_name,
584       feature_name, type_name);
585
586   if (G_UNLIKELY (!(type = g_type_from_name (type_name)))) {
587     GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
588         plugin_name);
589     return FALSE;
590   }
591   if (G_UNLIKELY ((feature =
592               g_object_new (type, "name", feature_name, NULL)) == NULL)) {
593     GST_ERROR ("Can't create feature from type");
594     return FALSE;
595   }
596
597   if (G_UNLIKELY (!GST_IS_PLUGIN_FEATURE (feature))) {
598     GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
599     goto fail;
600   }
601
602   if (GST_IS_ELEMENT_FACTORY (feature)) {
603     GstRegistryChunkElementFactory *ef;
604     guint n;
605     GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (feature);
606     gchar *str;
607     const gchar *meta_data_str;
608
609     align (*in);
610     GST_LOG ("Reading/casting for GstRegistryChunkElementFactory at address %p",
611         *in);
612     unpack_element (*in, ef, GstRegistryChunkElementFactory, end, fail);
613     pf = (GstRegistryChunkPluginFeature *) ef;
614
615     /* unpack element factory strings */
616     unpack_string_nocopy (*in, meta_data_str, end, fail);
617     if (meta_data_str && *meta_data_str) {
618       factory->metadata = gst_structure_from_string (meta_data_str, NULL);
619       if (!factory->metadata) {
620         GST_ERROR
621             ("Error when trying to deserialize structure for metadata '%s'",
622             meta_data_str);
623         goto fail;
624       }
625     }
626     n = ef->npadtemplates;
627     GST_DEBUG ("Element factory : npadtemplates=%d", n);
628
629     /* load pad templates */
630     for (i = 0; i < n; i++) {
631       if (G_UNLIKELY (!gst_registry_chunks_load_pad_template (factory, in,
632                   end))) {
633         GST_ERROR ("Error while loading binary pad template");
634         goto fail;
635       }
636     }
637
638     /* load uritypes */
639     if (G_UNLIKELY ((n = ef->nuriprotocols))) {
640       GST_DEBUG ("Reading %d UriTypes at address %p", n, *in);
641
642       align (*in);
643       factory->uri_type = *((guint *) * in);
644       *in += sizeof (factory->uri_type);
645       /*unpack_element(*in, &factory->uri_type, factory->uri_type, end, fail); */
646
647       factory->uri_protocols = g_new0 (gchar *, n + 1);
648       for (i = 0; i < n; i++) {
649         unpack_string (*in, str, end, fail);
650         factory->uri_protocols[i] = str;
651       }
652     }
653     /* load interfaces */
654     if (G_UNLIKELY ((n = ef->ninterfaces))) {
655       GST_DEBUG ("Reading %d Interfaces at address %p", n, *in);
656       for (i = 0; i < n; i++) {
657         unpack_string_nocopy (*in, const_str, end, fail);
658         __gst_element_factory_add_interface (factory, const_str);
659       }
660     }
661   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
662     GstRegistryChunkTypeFindFactory *tff;
663     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
664
665     align (*in);
666     GST_DEBUG
667         ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
668         *in);
669     unpack_element (*in, tff, GstRegistryChunkTypeFindFactory, end, fail);
670     pf = (GstRegistryChunkPluginFeature *) tff;
671
672     /* load typefinder caps */
673     unpack_string_nocopy (*in, const_str, end, fail);
674     if (const_str != NULL && *const_str != '\0')
675       factory->caps = gst_caps_from_string (const_str);
676     else
677       factory->caps = NULL;
678
679     /* load extensions */
680     if (tff->nextensions) {
681       GST_DEBUG ("Reading %d Typefind extensions at address %p",
682           tff->nextensions, *in);
683       factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
684       /* unpack in reverse order to maintain the correct order */
685       for (i = tff->nextensions; i > 0; i--) {
686         unpack_string (*in, str, end, fail);
687         factory->extensions[i - 1] = str;
688       }
689     }
690   } else if (GST_IS_DEVICE_PROVIDER_FACTORY (feature)) {
691     GstRegistryChunkDeviceProviderFactory *dmf;
692     GstDeviceProviderFactory *factory = GST_DEVICE_PROVIDER_FACTORY (feature);
693     const gchar *meta_data_str;
694
695     align (*in);
696     GST_DEBUG
697         ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
698         *in);
699
700     unpack_element (*in, dmf, GstRegistryChunkDeviceProviderFactory, end, fail);
701
702     pf = (GstRegistryChunkPluginFeature *) dmf;
703
704     /* unpack element factory strings */
705     unpack_string_nocopy (*in, meta_data_str, end, fail);
706     if (meta_data_str && *meta_data_str) {
707       factory->metadata = gst_structure_from_string (meta_data_str, NULL);
708       if (!factory->metadata) {
709         GST_ERROR
710             ("Error when trying to deserialize structure for metadata '%s'",
711             meta_data_str);
712         goto fail;
713       }
714     }
715   } else if (GST_IS_TRACER_FACTORY (feature)) {
716     align (*in);
717     GST_DEBUG
718         ("Reading/casting for GstRegistryChunkPluginFeature at address %p",
719         *in);
720     unpack_element (*in, pf, GstRegistryChunkPluginFeature, end, fail);
721   } else if (GST_IS_DYNAMIC_TYPE_FACTORY (feature)) {
722     GstRegistryChunkDynamicTypeFactory *tmp;
723
724     align (*in);
725     unpack_element (*in, tmp, GstRegistryChunkDynamicTypeFactory, end, fail);
726
727     pf = (GstRegistryChunkPluginFeature *) tmp;
728   } else {
729     GST_WARNING ("unhandled factory type : %s", G_OBJECT_TYPE_NAME (feature));
730     goto fail;
731   }
732
733   feature->rank = pf->rank;
734
735   feature->plugin_name = plugin_name;
736   feature->plugin = plugin;
737   g_object_add_weak_pointer ((GObject *) plugin,
738       (gpointer *) & feature->plugin);
739
740   gst_registry_add_feature (registry, feature);
741   GST_DEBUG ("Added feature %s, plugin %p %s", GST_OBJECT_NAME (feature),
742       plugin, plugin_name);
743
744   return TRUE;
745
746   /* Errors */
747 fail:
748   GST_INFO ("Reading plugin feature failed");
749   if (feature) {
750     gst_object_unref (feature);
751   }
752   return FALSE;
753 }
754
755 static gchar **
756 gst_registry_chunks_load_plugin_dep_strv (gchar ** in, gchar * end, guint n)
757 {
758   gchar **arr;
759
760   if (n == 0)
761     return NULL;
762
763   arr = g_new0 (gchar *, n + 1);
764   while (n > 0) {
765     unpack_string (*in, arr[n - 1], end, fail);
766     --n;
767   }
768   return arr;
769 fail:
770   GST_INFO ("Reading plugin dependency strings failed");
771   g_strfreev (arr);
772   return NULL;
773 }
774
775 static gboolean
776 gst_registry_chunks_load_plugin_dep (GstPlugin * plugin, gchar ** in,
777     gchar * end)
778 {
779   GstPluginDep *dep;
780   GstRegistryChunkDep *d;
781   gchar **s;
782
783   align (*in);
784   GST_LOG_OBJECT (plugin, "Unpacking GstRegistryChunkDep from %p", *in);
785   unpack_element (*in, d, GstRegistryChunkDep, end, fail);
786
787   dep = g_slice_new (GstPluginDep);
788
789   dep->env_hash = d->env_hash;
790   dep->stat_hash = d->stat_hash;
791
792   dep->flags = (GstPluginDependencyFlags) d->flags;
793
794   dep->names = gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_names);
795   dep->paths = gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_paths);
796   dep->env_vars =
797       gst_registry_chunks_load_plugin_dep_strv (in, end, d->n_env_vars);
798
799   plugin->priv->deps = g_list_append (plugin->priv->deps, dep);
800
801   GST_DEBUG_OBJECT (plugin, "Loaded external plugin dependency from registry: "
802       "env_hash: %08x, stat_hash: %08x", dep->env_hash, dep->stat_hash);
803   for (s = dep->env_vars; s != NULL && *s != NULL; ++s)
804     GST_LOG_OBJECT (plugin, " evar: %s", *s);
805   for (s = dep->paths; s != NULL && *s != NULL; ++s)
806     GST_LOG_OBJECT (plugin, " path: %s", *s);
807   for (s = dep->names; s != NULL && *s != NULL; ++s)
808     GST_LOG_OBJECT (plugin, " name: %s", *s);
809
810   return TRUE;
811 fail:
812   GST_INFO ("Reading plugin dependency failed");
813   return FALSE;
814 }
815
816
817 /*
818  * _priv_gst_registry_chunks_load_plugin:
819  *
820  * Make a new GstPlugin from current GstRegistryChunkPluginElement structure
821  * and add it to the GstRegistry. Return an offset to the next
822  * GstRegistryChunkPluginElement structure.
823  */
824 gboolean
825 _priv_gst_registry_chunks_load_plugin (GstRegistry * registry, gchar ** in,
826     gchar * end, GstPlugin ** out_plugin)
827 {
828 #ifndef GST_DISABLE_GST_DEBUG
829   gchar *start = *in;
830 #endif
831   GstRegistryChunkPluginElement *pe;
832   const gchar *cache_str = NULL;
833   GstPlugin *plugin = NULL;
834   guint i, n;
835
836   align (*in);
837   GST_LOG ("Reading/casting for GstRegistryChunkPluginElement at address %p",
838       *in);
839   unpack_element (*in, pe, GstRegistryChunkPluginElement, end, fail);
840
841   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
842
843   /* TODO: also set GST_PLUGIN_FLAG_CONST */
844   GST_OBJECT_FLAG_SET (plugin, GST_PLUGIN_FLAG_CACHED);
845   plugin->file_mtime = pe->file_mtime;
846   plugin->file_size = pe->file_size;
847
848   /* unpack plugin element strings */
849   unpack_const_string (*in, plugin->desc.name, end, fail);
850   unpack_const_string (*in, plugin->desc.description, end, fail);
851   unpack_string (*in, plugin->filename, end, fail);
852   unpack_const_string (*in, plugin->desc.version, end, fail);
853   unpack_const_string (*in, plugin->desc.license, end, fail);
854   unpack_const_string (*in, plugin->desc.source, end, fail);
855   unpack_const_string (*in, plugin->desc.package, end, fail);
856   unpack_const_string (*in, plugin->desc.origin, end, fail);
857   unpack_const_string (*in, plugin->desc.release_datetime, end, fail);
858
859   GST_LOG ("read strings for name='%s'", plugin->desc.name);
860   GST_LOG ("  desc.description='%s'", plugin->desc.description);
861   GST_LOG ("  filename='%s'", plugin->filename);
862   GST_LOG ("  desc.version='%s'", plugin->desc.version);
863   GST_LOG ("  desc.license='%s'", plugin->desc.license);
864   GST_LOG ("  desc.source='%s'", plugin->desc.source);
865   GST_LOG ("  desc.package='%s'", plugin->desc.package);
866   GST_LOG ("  desc.origin='%s'", plugin->desc.origin);
867   GST_LOG ("  desc.datetime=%s", plugin->desc.release_datetime);
868
869   if (plugin->desc.release_datetime[0] == '\0')
870     plugin->desc.release_datetime = NULL;
871
872   /* unpack cache data */
873   unpack_string_nocopy (*in, cache_str, end, fail);
874   if (cache_str != NULL && *cache_str != '\0')
875     plugin->priv->cache_data = gst_structure_from_string (cache_str, NULL);
876
877   /* If the license string is 'BLACKLIST', mark this as a blacklisted
878    * plugin */
879   if (strcmp (plugin->desc.license, "BLACKLIST") == 0)
880     GST_OBJECT_FLAG_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED);
881
882   plugin->basename = g_path_get_basename (plugin->filename);
883
884   /* Takes ownership of plugin */
885   gst_registry_add_plugin (registry, plugin);
886   n = pe->nfeatures;
887   GST_DEBUG ("Added plugin '%s' plugin with %d features from binary registry",
888       plugin->desc.name, n);
889
890   /* Load plugin features */
891   for (i = 0; i < n; i++) {
892     if (G_UNLIKELY (!gst_registry_chunks_load_feature (registry, in, end,
893                 plugin))) {
894       GST_ERROR ("Error while loading binary feature for plugin '%s'",
895           GST_STR_NULL (plugin->desc.name));
896       gst_registry_remove_plugin (registry, plugin);
897       goto fail;
898     }
899   }
900
901   /* Load external plugin dependencies */
902   for (i = 0; i < pe->n_deps; ++i) {
903     if (G_UNLIKELY (!gst_registry_chunks_load_plugin_dep (plugin, in, end))) {
904       GST_ERROR_OBJECT (plugin, "Could not read external plugin dependency "
905           "for plugin '%s'", GST_STR_NULL (plugin->desc.name));
906       gst_registry_remove_plugin (registry, plugin);
907       goto fail;
908     }
909   }
910
911   if (out_plugin)
912     *out_plugin = plugin;
913
914   return TRUE;
915
916   /* Errors */
917 fail:
918   GST_INFO ("Reading plugin failed after %u bytes", (guint) (end - start));
919   return FALSE;
920 }
921
922 void
923 _priv_gst_registry_chunks_save_global_header (GList ** list,
924     GstRegistry * registry, guint32 filter_env_hash)
925 {
926   GstRegistryChunkGlobalHeader *hdr;
927   GstRegistryChunk *chk;
928
929   hdr = g_slice_new (GstRegistryChunkGlobalHeader);
930   chk = gst_registry_chunks_make_data (hdr,
931       sizeof (GstRegistryChunkGlobalHeader));
932
933   hdr->filter_env_hash = filter_env_hash;
934
935   *list = g_list_prepend (*list, chk);
936
937   GST_LOG ("Saved global header (filter_env_hash=0x%08x)", filter_env_hash);
938 }
939
940 gboolean
941 _priv_gst_registry_chunks_load_global_header (GstRegistry * registry,
942     gchar ** in, gchar * end, guint32 * filter_env_hash)
943 {
944   GstRegistryChunkGlobalHeader *hdr;
945
946   align (*in);
947   GST_LOG ("Reading/casting for GstRegistryChunkGlobalHeader at %p", *in);
948   unpack_element (*in, hdr, GstRegistryChunkGlobalHeader, end, fail);
949   *filter_env_hash = hdr->filter_env_hash;
950   return TRUE;
951
952   /* Errors */
953 fail:
954   GST_WARNING ("Reading global header failed");
955   return FALSE;
956 }