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>
7 * gstregistrybinary.c: GstRegistryBinary object, support routines
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * - keep registry binary blob and reference strings
27 * - don't free/unmmap contents when leaving gst_registry_binary_read_cache()
28 * - free at gst_deinit() / _priv_gst_registry_cleanup() ?
30 * - GST_PLUGIN_FLAG_CONST
31 * - GstPluginFeature, GstIndexFactory, GstElementFactory
32 * - needs Flags (GST_PLUGIN_FEATURE_FLAG_CONST)
33 * - can we turn loaded into flag?
34 * - why do we collect a list of binary chunks and not write immediately
35 * - because we need to process subchunks, before we can set e.g. nr_of_items
37 * - need more robustness
38 * - don't parse beyond mem-block size
52 #if defined (_MSC_VER) && _MSC_VER >= 1400
56 #include <gst/gst_private.h>
57 #include <gst/gstconfig.h>
58 #include <gst/gstelement.h>
59 #include <gst/gsttypefind.h>
60 #include <gst/gsttypefindfactory.h>
61 #include <gst/gsturi.h>
62 #include <gst/gstinfo.h>
63 #include <gst/gstenumtypes.h>
64 #include <gst/gstpadtemplate.h>
66 #include <gst/gstregistrybinary.h>
68 #include <glib/gstdio.h> /* for g_stat(), g_mapped_file(), ... */
70 #include "glib-compat-private.h"
73 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
77 #define unpack_element(_inptr, _outptr, _element) \
78 _outptr = (_element *) _inptr; \
79 _inptr += sizeof (_element)
81 #define unpack_const_string(_inptr, _outptr) \
82 _outptr = g_intern_string ((const gchar *)_inptr); \
83 _inptr += strlen(_outptr) + 1
85 #define unpack_string(_inptr, _outptr) \
86 _outptr = g_strdup ((gchar *)_inptr); \
87 _inptr += strlen(_outptr) + 1
89 #define ALIGNMENT (sizeof (void *))
90 #define alignment(_address) (gsize)_address%ALIGNMENT
91 #define align(_ptr) _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
94 /* CRC32 calculation */
96 /* The crc32() function is copyrighted and licensed as specified below.
97 * This only applies to this single function:
99 crc32.c -- compute the CRC-32 of a data stream
100 Copyright (C) 1995-1998 Mark Adler
102 This software is provided 'as-is', without any express or implied
103 warranty. In no event will the authors be held liable for any damages
104 arising from the use of this software.
106 Permission is granted to anyone to use this software for any purpose,
107 including commercial applications, and to alter it and redistribute it
108 freely, subject to the following restrictions:
110 1. The origin of this software must not be misrepresented; you must not
111 claim that you wrote the original software. If you use this software
112 in a product, an acknowledgment in the product documentation would be
113 appreciated but is not required.
114 2. Altered source versions must be plainly marked as such, and must not be
115 misrepresented as being the original software.
116 3. This notice may not be removed or altered from any source distribution.
118 Jean-loup Gailly Mark Adler
119 jloup@gzip.org madler@alumni.caltech.edu
122 /* Changes for gstreamer:
123 * - Changed to use GLib data types
124 * - Change function name to _gst_crc32
125 * - Return the old CRC instead of 0 when len or buf are 0/NULL
128 /* ========================================================================
129 * Table of CRC-32's of all single-byte values (made by make_crc_table)
131 static const guint32 crc_table[256] = {
132 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
133 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
134 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
135 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
136 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
137 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
138 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
139 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
140 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
141 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
142 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
143 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
144 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
145 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
146 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
147 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
148 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
149 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
150 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
151 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
152 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
153 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
154 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
155 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
156 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
157 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
158 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
159 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
160 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
161 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
162 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
163 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
164 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
165 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
166 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
167 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
168 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
169 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
170 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
171 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
172 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
173 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
174 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
175 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
176 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
177 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
178 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
179 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
180 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
181 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
182 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
186 /* ========================================================================= */
187 #define DO1(buf) crc = crc_table[((gint)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
188 #define DO2(buf) DO1(buf); DO1(buf);
189 #define DO4(buf) DO2(buf); DO2(buf);
190 #define DO8(buf) DO4(buf); DO4(buf);
192 /* ========================================================================= */
194 _gst_crc32 (guint32 crc, const gchar * buf, guint len)
196 if (buf == NULL || len == 0)
199 crc = crc ^ 0xffffffffL;
208 return crc ^ 0xffffffffL;
216 /* Registry saving */
219 * gst_registry_binary_write:
221 * Write from a memory location to the registry cache file
223 * Returns: %TRUE for success
225 inline static gboolean
226 gst_registry_binary_write (GstRegistry * registry, const void *mem,
227 const gssize size, unsigned long *file_position, gboolean align,
230 gchar padder[ALIGNMENT] = { 0, };
233 /* Padding to insert the struct that requiere word alignment */
234 if ((align) && (alignment (*file_position) != 0)) {
235 padsize = ALIGNMENT - alignment (*file_position);
236 if (write (registry->cache_file, padder, padsize) != padsize) {
237 GST_ERROR ("Failed to write binary registry padder");
241 *crc32 = _gst_crc32 (*crc32, padder, padsize);
242 *file_position = *file_position + padsize;
245 if (write (registry->cache_file, mem, size) != size) {
246 GST_ERROR ("Failed to write binary registry element");
250 *crc32 = _gst_crc32 (*crc32, mem, size);
252 *file_position = *file_position + size;
258 * gst_registry_binary_initialize_magic:
260 * Initialize the GstBinaryRegistryMagic, setting both our magic number and
261 * gstreamer major/minor version
263 inline static gboolean
264 gst_registry_binary_initialize_magic (GstBinaryRegistryMagic * m)
266 memset (m, 0, sizeof (GstBinaryRegistryMagic));
268 if (!strncpy (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
269 GST_MAGIC_BINARY_REGISTRY_LEN)
270 || !strncpy (m->version, GST_MAGIC_BINARY_VERSION_STR,
271 GST_MAGIC_BINARY_VERSION_LEN)) {
272 GST_ERROR ("Failed to write magic to the registry magic structure");
283 * gst_registry_binary_save_const_string:
285 * Store a const string in a binary chunk.
287 * Returns: %TRUE for success
289 inline static gboolean
290 gst_registry_binary_save_const_string (GList ** list, const gchar * str)
292 GstBinaryChunk *chunk;
294 chunk = g_malloc (sizeof (GstBinaryChunk));
295 chunk->data = (gpointer) str;
296 chunk->size = strlen ((gchar *) chunk->data) + 1;
297 chunk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
298 chunk->align = FALSE;
299 *list = g_list_prepend (*list, chunk);
304 * gst_registry_binary_save_string:
306 * Store a string in a binary chunk.
308 * Returns: %TRUE for success
310 inline static gboolean
311 gst_registry_binary_save_string (GList ** list, gchar * str)
313 GstBinaryChunk *chunk;
315 chunk = g_malloc (sizeof (GstBinaryChunk));
317 chunk->size = strlen ((gchar *) chunk->data) + 1;
318 chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
319 chunk->align = FALSE;
320 *list = g_list_prepend (*list, chunk);
326 * gst_registry_binary_save_data:
328 * Store some data in a binary chunk.
330 * Returns: the initialized chunk
332 inline static GstBinaryChunk *
333 gst_registry_binary_make_data (gpointer data, gulong size)
335 GstBinaryChunk *chunk;
337 chunk = g_malloc (sizeof (GstBinaryChunk));
340 chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
347 * gst_registry_binary_save_pad_template:
349 * Store pad_templates in binary chunks.
351 * Returns: %TRUE for success
354 gst_registry_binary_save_pad_template (GList ** list,
355 GstStaticPadTemplate * template)
357 GstBinaryPadTemplate *pt;
360 pt = g_malloc (sizeof (GstBinaryPadTemplate));
361 chk = gst_registry_binary_make_data (pt, sizeof (GstBinaryPadTemplate));
363 pt->presence = template->presence;
364 pt->direction = template->direction;
366 /* pack pad template strings */
367 gst_registry_binary_save_const_string (list,
368 (gchar *) (template->static_caps.string));
369 gst_registry_binary_save_const_string (list, template->name_template);
371 *list = g_list_prepend (*list, chk);
378 * gst_registry_binary_save_feature:
380 * Store features in binary chunks.
382 * Returns: %TRUE for success
385 gst_registry_binary_save_feature (GList ** list, GstPluginFeature * feature)
387 const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
388 GstBinaryPluginFeature *pf = NULL;
389 GstBinaryChunk *chk = NULL;
393 GST_ERROR ("NULL feature type_name, aborting.");
397 if (GST_IS_ELEMENT_FACTORY (feature)) {
398 GstBinaryElementFactory *ef;
399 GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
401 ef = g_malloc (sizeof (GstBinaryElementFactory));
402 chk = gst_registry_binary_make_data (ef, sizeof (GstBinaryElementFactory));
403 ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
404 pf = (GstBinaryPluginFeature *) ef;
406 /* save interfaces */
407 for (walk = factory->interfaces; walk;
408 walk = g_list_next (walk), ef->ninterfaces++) {
409 gst_registry_binary_save_const_string (list, (gchar *) walk->data);
411 GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
413 if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
414 if (factory->uri_protocols && *factory->uri_protocols) {
415 GstBinaryChunk *subchk;
419 gst_registry_binary_make_data (&factory->uri_type,
420 sizeof (factory->uri_type));
421 subchk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
423 protocol = factory->uri_protocols;
425 gst_registry_binary_save_const_string (list, *protocol++);
428 *list = g_list_prepend (*list, subchk);
429 GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
431 g_warning ("GStreamer feature '%s' is URI handler but does not provide"
432 " any protocols it can handle", feature->name);
436 /* save pad-templates */
437 for (walk = factory->staticpadtemplates; walk;
438 walk = g_list_next (walk), ef->npadtemplates++) {
439 GstStaticPadTemplate *template = walk->data;
441 if (!gst_registry_binary_save_pad_template (list, template)) {
442 GST_ERROR ("Can't fill pad template, aborting.");
447 /* pack element factory strings */
448 gst_registry_binary_save_const_string (list, factory->details.author);
449 gst_registry_binary_save_const_string (list, factory->details.description);
450 gst_registry_binary_save_const_string (list, factory->details.klass);
451 gst_registry_binary_save_const_string (list, factory->details.longname);
452 } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
453 GstBinaryTypeFindFactory *tff;
454 GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
457 /* we copy the caps here so we can simplify them before saving. This is a lot
458 * faster when loading them later on */
459 GstCaps *copy = gst_caps_copy (factory->caps);
461 tff = g_malloc (sizeof (GstBinaryTypeFindFactory));
463 gst_registry_binary_make_data (tff, sizeof (GstBinaryTypeFindFactory));
464 tff->nextensions = 0;
465 pf = (GstBinaryPluginFeature *) tff;
467 /* save extensions */
468 if (factory->extensions) {
469 while (factory->extensions[tff->nextensions]) {
470 gst_registry_binary_save_const_string (list,
471 factory->extensions[tff->nextensions++]);
475 gst_caps_do_simplify (copy);
476 str = gst_caps_to_string (copy);
477 gst_caps_unref (copy);
478 gst_registry_binary_save_string (list, str);
480 #ifndef GST_DISABLE_INDEX
481 else if (GST_IS_INDEX_FACTORY (feature)) {
482 GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
484 pf = g_malloc (sizeof (GstBinaryPluginFeature));
485 chk = gst_registry_binary_make_data (pf, sizeof (GstBinaryPluginFeature));
486 pf->rank = feature->rank;
488 /* pack element factory strings */
489 gst_registry_binary_save_const_string (list, factory->longdesc);
493 GST_WARNING ("unhandled feature type '%s'", type_name);
497 pf->rank = feature->rank;
498 *list = g_list_prepend (*list, chk);
500 /* pack plugin feature strings */
501 gst_registry_binary_save_const_string (list, feature->name);
502 gst_registry_binary_save_const_string (list, (gchar *) type_name);
516 * gst_registry_binary_save_plugin:
518 * Adapt a GstPlugin to our GstBinaryPluginElement structure, and write it to
522 gst_registry_binary_save_plugin (GList ** list, GstRegistry * registry,
525 GstBinaryPluginElement *pe;
527 GList *plugin_features = NULL;
530 pe = g_malloc (sizeof (GstBinaryPluginElement));
531 chk = gst_registry_binary_make_data (pe, sizeof (GstBinaryPluginElement));
533 pe->file_size = plugin->file_size;
534 pe->file_mtime = plugin->file_mtime;
537 /* pack plugin features */
539 gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
540 for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
541 GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
543 if (!gst_registry_binary_save_feature (list, feature)) {
544 GST_ERROR ("Can't fill plugin feature, aborting.");
548 GST_DEBUG ("Save plugin '%s' with %d features", plugin->desc.name,
551 gst_plugin_feature_list_free (plugin_features);
553 /* pack plugin element strings */
554 gst_registry_binary_save_const_string (list, plugin->desc.origin);
555 gst_registry_binary_save_const_string (list, plugin->desc.package);
556 gst_registry_binary_save_const_string (list, plugin->desc.source);
557 gst_registry_binary_save_const_string (list, plugin->desc.license);
558 gst_registry_binary_save_const_string (list, plugin->desc.version);
559 gst_registry_binary_save_const_string (list, plugin->filename);
560 gst_registry_binary_save_const_string (list, plugin->desc.description);
561 gst_registry_binary_save_const_string (list, plugin->desc.name);
563 *list = g_list_prepend (*list, chk);
565 GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
571 gst_plugin_feature_list_free (plugin_features);
579 * gst_registry_binary_write_cache:
580 * @registry: a #GstRegistry
581 * @location: a filename
583 * Write the @registry to a cache to file at given @location.
585 * Returns: %TRUE on success.
588 gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
592 GstBinaryRegistryMagic magic;
593 GList *to_write = NULL;
594 unsigned long file_position = 0;
596 GST_INFO ("Building binary registry cache image");
598 g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
599 tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
600 registry->cache_file = g_mkstemp (tmp_location);
601 if (registry->cache_file == -1) {
604 /* oops, I bet the directory doesn't exist */
605 dir = g_path_get_dirname (location);
606 g_mkdir_with_parents (dir, 0777);
609 /* the previous g_mkstemp call overwrote the XXXXXX placeholder ... */
610 g_free (tmp_location);
611 tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
612 registry->cache_file = g_mkstemp (tmp_location);
614 if (registry->cache_file == -1) {
615 GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno));
616 g_free (tmp_location);
621 if (!gst_registry_binary_initialize_magic (&magic))
624 /* iterate trough the list of plugins and fit them into binary structures */
625 for (walk = registry->plugins; walk; walk = g_list_next (walk)) {
626 GstPlugin *plugin = GST_PLUGIN (walk->data);
628 if (!plugin->filename)
631 if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
635 ret = g_stat (plugin->filename, &statbuf);
636 if ((ret = g_stat (plugin->filename, &statbuf)) < 0 ||
637 plugin->file_mtime != statbuf.st_mtime ||
638 plugin->file_size != statbuf.st_size)
642 if (!gst_registry_binary_save_plugin (&to_write, registry, plugin)) {
643 GST_ERROR ("Can't write binary plugin information for \"%s\"",
648 GST_INFO ("Writing binary registry cache");
651 if (write (registry->cache_file, &magic,
652 sizeof (GstBinaryRegistryMagic)) != sizeof (GstBinaryRegistryMagic)) {
653 GST_ERROR ("Failed to write binary registry magic");
656 file_position += sizeof (GstBinaryRegistryMagic);
658 /* write out data chunks */
659 for (walk = to_write; walk; walk = g_list_next (walk)) {
660 GstBinaryChunk *cur = walk->data;
662 if (!gst_registry_binary_write (registry, cur->data, cur->size,
663 &file_position, cur->align, &magic.crc32)) {
664 if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
670 if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
675 g_list_free (to_write);
677 if (lseek (registry->cache_file, 0, SEEK_SET) != 0) {
678 GST_ERROR ("Seeking to rewrite the binary registry CRC32 failed");
680 if (write (registry->cache_file, &magic,
681 sizeof (GstBinaryRegistryMagic)) != sizeof (GstBinaryRegistryMagic))
682 GST_ERROR ("Failed to rewrite binary registry magic");
685 if (close (registry->cache_file) < 0)
688 if (g_file_test (tmp_location, G_FILE_TEST_EXISTS)) {
692 if (g_rename (tmp_location, location) < 0)
695 /* FIXME: shouldn't we return FALSE here? */
698 g_free (tmp_location);
699 GST_INFO ("Wrote binary registry cache");
705 for (walk = to_write; walk; walk = g_list_next (walk)) {
706 GstBinaryChunk *cur = walk->data;
708 if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
712 g_list_free (to_write);
717 (void) close (registry->cache_file);
722 g_remove (tmp_location);
723 g_free (tmp_location);
728 GST_ERROR ("close() failed: %s", g_strerror (errno));
729 goto fail_after_close;
733 GST_ERROR ("g_rename() failed: %s", g_strerror (errno));
734 goto fail_after_close;
739 /* Registry loading */
742 * gst_registry_binary_check_magic:
744 * Check GstBinaryRegistryMagic validity.
745 * Return < 0 if something is wrong, -2 means
746 * that just the version of the registry is out of
747 * date, -1 is a general failure.
750 gst_registry_binary_check_magic (gchar ** in, gsize size)
752 GstBinaryRegistryMagic *m;
756 GST_DEBUG ("Reading/casting for GstBinaryRegistryMagic at address %p", *in);
757 unpack_element (*in, m, GstBinaryRegistryMagic);
759 if (m == NULL || m->magic == NULL || m->version == NULL) {
760 GST_WARNING ("Binary registry magic structure is broken");
763 if (strncmp (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
764 GST_MAGIC_BINARY_REGISTRY_LEN) != 0) {
766 ("Binary registry magic is different : %02x%02x%02x%02x != %02x%02x%02x%02x",
767 GST_MAGIC_BINARY_REGISTRY_STR[0] & 0xff,
768 GST_MAGIC_BINARY_REGISTRY_STR[1] & 0xff,
769 GST_MAGIC_BINARY_REGISTRY_STR[2] & 0xff,
770 GST_MAGIC_BINARY_REGISTRY_STR[3] & 0xff, m->magic[0] & 0xff,
771 m->magic[1] & 0xff, m->magic[2] & 0xff, m->magic[3] & 0xff);
774 if (strncmp (m->version, GST_MAGIC_BINARY_VERSION_STR,
775 GST_MAGIC_BINARY_VERSION_LEN)) {
776 GST_WARNING ("Binary registry magic version is different : %s != %s",
777 GST_MAGIC_BINARY_VERSION_STR, m->version);
781 crc32 = _gst_crc32 (crc32, *in, size - sizeof (GstBinaryRegistryMagic));
782 if (crc32 != m->crc32) {
783 GST_WARNING ("Binary registry CRC32 different: 0x%x != 0x%x\n", crc32,
793 * gst_registry_binary_load_pad_template:
795 * Make a new GstStaticPadTemplate from current GstBinaryPadTemplate structure
797 * Returns: new GstStaticPadTemplate
800 gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in)
802 GstBinaryPadTemplate *pt;
803 GstStaticPadTemplate *template;
806 GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in);
807 unpack_element (*in, pt, GstBinaryPadTemplate);
809 template = g_new0 (GstStaticPadTemplate, 1);
810 template->presence = pt->presence;
811 template->direction = pt->direction;
813 /* unpack pad template strings */
814 unpack_const_string (*in, template->name_template);
815 unpack_string (*in, template->static_caps.string);
817 __gst_element_factory_add_static_pad_template (factory, template);
818 GST_DEBUG ("Added pad_template %s", template->name_template);
825 * gst_registry_binary_load_feature:
827 * Make a new GstPluginFeature from current binary plugin feature structure
829 * Returns: new GstPluginFeature
832 gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
833 const gchar * plugin_name)
835 GstBinaryPluginFeature *pf = NULL;
836 GstPluginFeature *feature;
837 gchar *type_name = NULL, *str;
841 /* unpack plugin feature strings */
842 unpack_string (*in, type_name);
844 if (!type_name || !*(type_name)) {
845 GST_ERROR ("No feature type name");
849 GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
851 if (!(type = g_type_from_name (type_name))) {
852 GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
856 if ((feature = g_object_new (type, NULL)) == NULL) {
857 GST_ERROR ("Can't create feature from type");
861 if (!GST_IS_PLUGIN_FEATURE (feature)) {
862 GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
866 /* unpack more plugin feature strings */
867 unpack_string (*in, feature->name);
869 if (GST_IS_ELEMENT_FACTORY (feature)) {
870 GstBinaryElementFactory *ef;
871 GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
874 GST_LOG ("Reading/casting for GstBinaryElementFactory at address %p", *in);
875 unpack_element (*in, ef, GstBinaryElementFactory);
876 pf = (GstBinaryPluginFeature *) ef;
878 /* unpack element factory strings */
879 unpack_string (*in, factory->details.longname);
880 unpack_string (*in, factory->details.klass);
881 unpack_string (*in, factory->details.description);
882 unpack_string (*in, factory->details.author);
883 GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
884 factory->details.longname, ef->npadtemplates);
886 /* load pad templates */
887 for (i = 0; i < ef->npadtemplates; i++) {
888 if (!gst_registry_binary_load_pad_template (factory, in)) {
889 GST_ERROR ("Error while loading binary pad template");
895 if (ef->nuriprotocols) {
896 GST_DEBUG ("Reading %d UriTypes at address %p", ef->nuriprotocols, *in);
899 factory->uri_type = *((guint *) * in);
900 *in += sizeof (factory->uri_type);
901 //unpack_element(*in, &factory->uri_type, factory->uri_type);
903 factory->uri_protocols = g_new0 (gchar *, ef->nuriprotocols + 1);
904 for (i = 0; i < ef->nuriprotocols; i++) {
905 unpack_string (*in, str);
906 factory->uri_protocols[i] = str;
909 /* load interfaces */
910 GST_DEBUG ("Reading %d Interfaces at address %p", ef->ninterfaces, *in);
911 for (i = 0; i < ef->ninterfaces; i++) {
912 unpack_string (*in, str);
913 __gst_element_factory_add_interface (factory, str);
916 } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
917 GstBinaryTypeFindFactory *tff;
918 GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
921 GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
922 unpack_element (*in, tff, GstBinaryTypeFindFactory);
923 pf = (GstBinaryPluginFeature *) tff;
926 unpack_string (*in, str);
927 factory->caps = gst_caps_from_string (str);
929 /* load extensions */
930 if (tff->nextensions) {
931 GST_DEBUG ("Reading %d Typefind extensions at address %p",
932 tff->nextensions, *in);
933 factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
934 for (i = 0; i < tff->nextensions; i++) {
935 unpack_string (*in, str);
936 factory->extensions[i] = str;
940 #ifndef GST_DISABLE_INDEX
941 else if (GST_IS_INDEX_FACTORY (feature)) {
942 GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
945 GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
946 unpack_element (*in, pf, GstBinaryPluginFeature);
948 /* unpack index factory strings */
949 unpack_string (*in, factory->longdesc);
953 feature->rank = pf->rank;
955 /* should already be the interned string, but better make sure */
956 feature->plugin_name = g_intern_string (plugin_name);
958 gst_registry_add_feature (registry, feature);
959 GST_DEBUG ("Added feature %s", feature->name);
967 if (GST_IS_OBJECT (feature))
968 gst_object_unref (feature);
970 g_object_unref (feature);
976 * gst_registry_binary_load_plugin:
978 * Make a new GstPlugin from current GstBinaryPluginElement structure
979 * and save it to the GstRegistry. Return an offset to the next
980 * GstBinaryPluginElement structure.
983 gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
985 GstBinaryPluginElement *pe;
986 GstPlugin *plugin = NULL;
990 GST_LOG ("Reading/casting for GstBinaryPluginElement at address %p", *in);
991 unpack_element (*in, pe, GstBinaryPluginElement);
993 if (pe->nfeatures < 0) {
994 GST_ERROR ("The number of feature structure is not valid !");
998 if (pe->file_mtime < 0 || pe->file_size < 0) {
999 GST_ERROR ("Plugin time or file size is not valid !");
1003 plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
1005 /* TODO: also set GST_PLUGIN_FLAG_CONST */
1006 plugin->flags |= GST_PLUGIN_FLAG_CACHED;
1007 plugin->file_mtime = pe->file_mtime;
1008 plugin->file_size = pe->file_size;
1010 /* unpack plugin element strings */
1011 unpack_const_string (*in, plugin->desc.name);
1012 unpack_string (*in, plugin->desc.description);
1013 unpack_string (*in, plugin->filename);
1014 unpack_const_string (*in, plugin->desc.version);
1015 unpack_const_string (*in, plugin->desc.license);
1016 unpack_const_string (*in, plugin->desc.source);
1017 unpack_const_string (*in, plugin->desc.package);
1018 unpack_const_string (*in, plugin->desc.origin);
1019 GST_LOG ("read strings for '%s'", plugin->desc.name);
1021 plugin->basename = g_path_get_basename (plugin->filename);
1023 /* Takes ownership of plugin */
1024 gst_registry_add_plugin (registry, plugin);
1025 GST_INFO ("Added plugin '%s' plugin with %d features from binary registry",
1026 plugin->desc.name, pe->nfeatures);
1027 for (i = 0; i < pe->nfeatures; i++) {
1028 if (!gst_registry_binary_load_feature (registry, in, plugin->desc.name)) {
1029 GST_ERROR ("Error while loading binary feature");
1043 * gst_registry_binary_read_cache:
1044 * @registry: a #GstRegistry
1045 * @location: a filename
1047 * Read the contents of the binary cache file at @location into @registry.
1049 * Returns: %TRUE on success.
1052 gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
1054 GMappedFile *mapped = NULL;
1055 GTimer *timer = NULL;
1056 gchar *contents = NULL;
1061 gboolean res = FALSE;
1062 gint check_magic_result;
1064 /* make sure these types exist */
1065 GST_TYPE_ELEMENT_FACTORY;
1066 GST_TYPE_TYPE_FIND_FACTORY;
1067 #ifndef GST_DISABLE_INDEX
1068 GST_TYPE_INDEX_FACTORY;
1071 timer = g_timer_new ();
1073 mapped = g_mapped_file_new (location, FALSE, &err);
1075 GST_INFO ("Unable to mmap file %s : %s", location, err->message);
1079 g_file_get_contents (location, &contents, &size, &err);
1081 GST_INFO ("Unable to read file %s : %s", location, err->message);
1082 g_timer_destroy (timer);
1087 if ((contents = g_mapped_file_get_contents (mapped)) == NULL) {
1088 GST_ERROR ("Can't load file %s : %s", location, g_strerror (errno));
1091 /* check length for header */
1092 size = g_mapped_file_get_length (mapped);
1094 /* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */
1096 GST_DEBUG ("File data at address %p", in);
1097 if (size < sizeof (GstBinaryRegistryMagic)) {
1098 GST_ERROR ("No or broken registry header");
1101 /* check if header is valid */
1102 if ((check_magic_result = gst_registry_binary_check_magic (&in, size)) < 0) {
1104 if (check_magic_result == -1)
1106 ("Binary registry type not recognized (invalid magic) for file at %s",
1111 /* check if there are plugins in the file */
1113 if (!(((gsize) in + sizeof (GstBinaryPluginElement)) <
1114 (gsize) contents + size)) {
1115 GST_INFO ("No binary plugins structure to read");
1116 /* empty file, this is not an error */
1119 ((gsize) in + sizeof (GstBinaryPluginElement)) <
1120 (gsize) contents + size;) {
1121 GST_DEBUG ("reading binary registry %" G_GSIZE_FORMAT "(%x)/%"
1122 G_GSIZE_FORMAT, (gsize) in - (gsize) contents,
1123 (guint) ((gsize) in - (gsize) contents), size);
1124 if (!gst_registry_binary_load_plugin (registry, &in)) {
1125 GST_ERROR ("Problem while reading binary registry");
1131 g_timer_stop (timer);
1132 seconds = g_timer_elapsed (timer, NULL);
1134 GST_INFO ("loaded %s in %lf seconds", location, seconds);
1137 /* TODO: once we re-use the pointers to registry contents return here */
1140 g_timer_destroy (timer);
1142 g_mapped_file_free (mapped);
1150 /* FIXME 0.11: these are here for backwards compatibility */
1153 gst_registry_xml_read_cache (GstRegistry * registry, const char *location)
1159 gst_registry_xml_write_cache (GstRegistry * registry, const char *location)