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