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