gstreamer_core/gst/gstregistrybinary.c
changeset 0 0e761a78d257
child 7 567bb019e3e3
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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  *
       
     6  * gstregistrybinary.c: GstRegistryBinary object, support routines
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public
       
    19  * License along with this library; if not, write to the
       
    20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    21  * Boston, MA 02111-1307, USA.
       
    22  */
       
    23 
       
    24 /* FIXME:
       
    25  * - Add random key to libgstreamer during build and only accept registry,
       
    26  *   if key matches (or is the version check enough)
       
    27  * - keep registry binary blob and reference strings
       
    28  *   - don't free/unmmap contents when leaving gst_registry_binary_read_cache()
       
    29  *     - free at gst_deinit() / _priv_gst_registry_cleanup() ?
       
    30  *   - GstPlugin:
       
    31  *     - GST_PLUGIN_FLAG_CONST
       
    32  *   -GstPluginFeature, GstIndexFactory, GstElementFactory
       
    33  *     - needs Flags (GST_PLUGIN_FEATURE_FLAG_CONST)
       
    34  *     - can we turn loaded into flag?
       
    35  * - why do we collect a list of binary chunks and not write immediately
       
    36  *   - because we need to process subchunks, before we can set e.g. nr_of_items
       
    37  *     in parent chunk
       
    38  * - need more robustness
       
    39  *   - don't parse beyond mem-block size
       
    40  *   - include md5-sum ?
       
    41  */
       
    42 
       
    43 #ifdef HAVE_CONFIG_H
       
    44 #  include "config.h"
       
    45 #endif
       
    46 
       
    47 #ifdef HAVE_UNISTD_H
       
    48 #include <unistd.h>
       
    49 #endif
       
    50 
       
    51 #include <errno.h>
       
    52 #include <stdio.h>
       
    53 
       
    54 #if defined (_MSC_VER) && _MSC_VER >= 1400
       
    55 #include <io.h>
       
    56 #endif
       
    57 
       
    58 #include <gst/gst_private.h>
       
    59 #include <gst/gstconfig.h>
       
    60 #include <gst/gstelement.h>
       
    61 #include <gst/gsttypefind.h>
       
    62 #include <gst/gsttypefindfactory.h>
       
    63 #include <gst/gsturi.h>
       
    64 #include <gst/gstinfo.h>
       
    65 #include <gst/gstenumtypes.h>
       
    66 #include <gst/gstpadtemplate.h>
       
    67 
       
    68 #include <gst/gstregistrybinary.h>
       
    69 
       
    70 #include <glib/gstdio.h>        /* for g_stat(), g_mapped_file(), ... */
       
    71 
       
    72 #include "glib-compat-private.h"
       
    73 
       
    74 
       
    75 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
       
    76 
       
    77 /* macros */
       
    78 
       
    79 #define unpack_element(_inptr, _outptr, _element)  \
       
    80   _outptr = (_element *)_inptr; \
       
    81   _inptr += sizeof (_element)
       
    82 
       
    83 #define unpack_const_string(_inptr, _outptr) \
       
    84   _outptr = g_intern_string ((const gchar *)_inptr); \
       
    85   _inptr += strlen(_outptr) + 1
       
    86 
       
    87 #define unpack_string(_inptr, _outptr)  \
       
    88   _outptr = g_strdup ((gchar *)_inptr); \
       
    89   _inptr += strlen(_outptr) + 1
       
    90 
       
    91 #if !GST_HAVE_UNALIGNED_ACCESS
       
    92 #  define alignment32(_address)  (gsize)_address%4
       
    93 #  define align32(_ptr)          _ptr += (( alignment32(_ptr) == 0) ? 0 : 4-alignment32(_ptr))
       
    94 #else
       
    95 #  define alignment32(_address)  0
       
    96 #  define align32(_ptr)          do {} while(0)
       
    97 #endif
       
    98 
       
    99 
       
   100 /* Registry saving */
       
   101 
       
   102 /*
       
   103  * gst_registry_binary_write:
       
   104  *
       
   105  * Write from a memory location to the registry cache file
       
   106  *
       
   107  * Returns: %TRUE for success
       
   108  */
       
   109 inline static gboolean
       
   110 gst_registry_binary_write (GstRegistry * registry, const void *mem,
       
   111     const gssize size, unsigned long *file_position, gboolean align)
       
   112 {
       
   113 #if !GST_HAVE_UNALIGNED_ACCESS
       
   114   gchar padder[] = { 0, 0, 0, 0 };
       
   115   int padsize = 0;
       
   116 
       
   117   /* Padding to insert the struct that requiere word alignment */
       
   118   if ((align) && (alignment32 (*file_position) != 0)) {
       
   119     padsize = 4 - alignment32 (*file_position);
       
   120     if (write (registry->cache_file, padder, padsize) != padsize) {
       
   121       GST_ERROR ("Failed to write binary registry padder");
       
   122       return FALSE;
       
   123     }
       
   124     *file_position = *file_position + padsize;
       
   125   }
       
   126 #endif
       
   127 
       
   128   if (write (registry->cache_file, mem, size) != size) {
       
   129     GST_ERROR ("Failed to write binary registry element");
       
   130     return FALSE;
       
   131   }
       
   132   *file_position = *file_position + size;
       
   133   return TRUE;
       
   134 }
       
   135 
       
   136 
       
   137 /*
       
   138  * gst_registry_binary_initialize_magic:
       
   139  *
       
   140  * Initialize the GstBinaryRegistryMagic, setting both our magic number and
       
   141  * gstreamer major/minor version
       
   142  */
       
   143 inline static gboolean
       
   144 gst_registry_binary_initialize_magic (GstBinaryRegistryMagic * m)
       
   145 {
       
   146   if (!strncpy (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
       
   147           GST_MAGIC_BINARY_REGISTRY_LEN)
       
   148       || !strncpy (m->version, GST_MAJORMINOR, GST_MAGIC_BINARY_VERSION_LEN)) {
       
   149     GST_ERROR ("Failed to write magic to the registry magic structure");
       
   150     return FALSE;
       
   151   }
       
   152   return TRUE;
       
   153 }
       
   154 
       
   155 
       
   156 /*
       
   157  * gst_registry_binary_save_const_string:
       
   158  *
       
   159  * Store a const string in a binary chunk.
       
   160  *
       
   161  * Returns: %TRUE for success
       
   162  */
       
   163 inline static gboolean
       
   164 gst_registry_binary_save_const_string (GList ** list, const gchar * str)
       
   165 {
       
   166   GstBinaryChunk *chunk;
       
   167 
       
   168   chunk = g_malloc (sizeof (GstBinaryChunk));
       
   169   chunk->data = (gpointer) str;
       
   170   chunk->size = strlen ((gchar *) chunk->data) + 1;
       
   171   chunk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
       
   172   chunk->align = FALSE;
       
   173   *list = g_list_prepend (*list, chunk);
       
   174   return TRUE;
       
   175 }
       
   176 
       
   177 /*
       
   178  * gst_registry_binary_save_string:
       
   179  *
       
   180  * Store a string in a binary chunk.
       
   181  *
       
   182  * Returns: %TRUE for success
       
   183  */
       
   184 inline static gboolean
       
   185 gst_registry_binary_save_string (GList ** list, gchar * str)
       
   186 {
       
   187   GstBinaryChunk *chunk;
       
   188 
       
   189   chunk = g_malloc (sizeof (GstBinaryChunk));
       
   190   chunk->data = str;
       
   191   chunk->size = strlen ((gchar *) chunk->data) + 1;
       
   192   chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
       
   193   chunk->align = FALSE;
       
   194   *list = g_list_prepend (*list, chunk);
       
   195   return TRUE;
       
   196 }
       
   197 
       
   198 
       
   199 /*
       
   200  * gst_registry_binary_save_data:
       
   201  *
       
   202  * Store some data in a binary chunk.
       
   203  *
       
   204  * Returns: the initialized chunk
       
   205  */
       
   206 inline static GstBinaryChunk *
       
   207 gst_registry_binary_make_data (gpointer data, gulong size)
       
   208 {
       
   209   GstBinaryChunk *chunk;
       
   210 
       
   211   chunk = g_malloc (sizeof (GstBinaryChunk));
       
   212   chunk->data = data;
       
   213   chunk->size = size;
       
   214   chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
       
   215   chunk->align = TRUE;
       
   216   return chunk;
       
   217 }
       
   218 
       
   219 
       
   220 /*
       
   221  * gst_registry_binary_save_pad_template:
       
   222  *
       
   223  * Store pad_templates in binary chunks.
       
   224  *
       
   225  * Returns: %TRUE for success
       
   226  */
       
   227 static gboolean
       
   228 gst_registry_binary_save_pad_template (GList ** list,
       
   229     GstStaticPadTemplate * template)
       
   230 {
       
   231   GstBinaryPadTemplate *pt;
       
   232   GstBinaryChunk *chk;
       
   233 
       
   234   pt = g_malloc (sizeof (GstBinaryPadTemplate));
       
   235   chk = gst_registry_binary_make_data (pt, sizeof (GstBinaryPadTemplate));
       
   236 
       
   237   pt->presence = template->presence;
       
   238   pt->direction = template->direction;
       
   239 
       
   240   /* pack pad template strings */
       
   241   gst_registry_binary_save_const_string (list,
       
   242       (gchar *) (template->static_caps.string));
       
   243   gst_registry_binary_save_const_string (list, template->name_template);
       
   244 
       
   245   *list = g_list_prepend (*list, chk);
       
   246 
       
   247   return TRUE;
       
   248 }
       
   249 
       
   250 
       
   251 /*
       
   252  * gst_registry_binary_save_feature:
       
   253  *
       
   254  * Store features in binary chunks.
       
   255  *
       
   256  * Returns: %TRUE for success
       
   257  */
       
   258 static gboolean
       
   259 gst_registry_binary_save_feature (GList ** list, GstPluginFeature * feature)
       
   260 {
       
   261   const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
       
   262   GstBinaryPluginFeature *pf = NULL;
       
   263   GstBinaryChunk *chk = NULL;
       
   264   GList *walk;
       
   265 
       
   266   if (!type_name) {
       
   267     GST_ERROR ("NULL feature type_name, aborting.");
       
   268     return FALSE;
       
   269   }
       
   270 
       
   271   if (GST_IS_ELEMENT_FACTORY (feature)) {
       
   272     GstBinaryElementFactory *ef;
       
   273     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
       
   274 
       
   275     ef = g_malloc (sizeof (GstBinaryElementFactory));
       
   276     chk = gst_registry_binary_make_data (ef, sizeof (GstBinaryElementFactory));
       
   277     ef->npadtemplates = ef->ninterfaces = ef->nuriprotocols = 0;
       
   278     pf = (GstBinaryPluginFeature *) ef;
       
   279 
       
   280     /* save interfaces */
       
   281     for (walk = factory->interfaces; walk;
       
   282         walk = g_list_next (walk), ef->ninterfaces++) {
       
   283       gst_registry_binary_save_const_string (list, (gchar *) walk->data);
       
   284     }
       
   285     GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
       
   286     /* save uritypes */
       
   287     if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
       
   288       if (factory->uri_protocols) {
       
   289         GstBinaryChunk *subchk;
       
   290         gchar **protocol;
       
   291 
       
   292         subchk =
       
   293             gst_registry_binary_make_data (&factory->uri_type,
       
   294             sizeof (factory->uri_type));
       
   295         subchk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
       
   296 
       
   297         protocol = factory->uri_protocols;
       
   298         while (*protocol) {
       
   299           gst_registry_binary_save_const_string (list, *protocol++);
       
   300           ef->nuriprotocols++;
       
   301         }
       
   302         *list = g_list_prepend (*list, subchk);
       
   303         GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
       
   304       } else {
       
   305         g_warning ("GStreamer feature '%s' is URI handler but does not provide"
       
   306             " any protocols it can handle", feature->name);
       
   307       }
       
   308     }
       
   309 
       
   310     /* save pad-templates */
       
   311     for (walk = factory->staticpadtemplates; walk;
       
   312         walk = g_list_next (walk), ef->npadtemplates++) {
       
   313       GstStaticPadTemplate *template = walk->data;
       
   314 
       
   315       if (!gst_registry_binary_save_pad_template (list, template)) {
       
   316         GST_ERROR ("Can't fill pad template, aborting.");
       
   317         goto fail;
       
   318       }
       
   319     }
       
   320 
       
   321     /* pack element factory strings */
       
   322     gst_registry_binary_save_const_string (list, factory->details.author);
       
   323     gst_registry_binary_save_const_string (list, factory->details.description);
       
   324     gst_registry_binary_save_const_string (list, factory->details.klass);
       
   325     gst_registry_binary_save_const_string (list, factory->details.longname);
       
   326   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
       
   327     GstBinaryTypeFindFactory *tff;
       
   328     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
       
   329     gchar *str;
       
   330 
       
   331     /* we copy the caps here so we can simplify them before saving. This is a lot
       
   332      * faster when loading them later on */
       
   333     GstCaps *copy = gst_caps_copy (factory->caps);
       
   334 
       
   335     tff = g_malloc (sizeof (GstBinaryTypeFindFactory));
       
   336     chk =
       
   337         gst_registry_binary_make_data (tff, sizeof (GstBinaryTypeFindFactory));
       
   338     tff->nextensions = 0;
       
   339     pf = (GstBinaryPluginFeature *) tff;
       
   340 
       
   341     /* save extensions */
       
   342     if (factory->extensions) {
       
   343       while (factory->extensions[tff->nextensions]) {
       
   344         gst_registry_binary_save_const_string (list,
       
   345             factory->extensions[tff->nextensions++]);
       
   346       }
       
   347     }
       
   348     /* save caps */
       
   349     gst_caps_do_simplify (copy);
       
   350     str = gst_caps_to_string (copy);
       
   351     gst_caps_unref (copy);
       
   352     gst_registry_binary_save_string (list, str);
       
   353   }
       
   354 #ifndef GST_DISABLE_INDEX
       
   355   else if (GST_IS_INDEX_FACTORY (feature)) {
       
   356     GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
       
   357 
       
   358     pf = g_malloc (sizeof (GstBinaryPluginFeature));
       
   359     chk = gst_registry_binary_make_data (pf, sizeof (GstBinaryPluginFeature));
       
   360     pf->rank = feature->rank;
       
   361 
       
   362     /* pack element factory strings */
       
   363     gst_registry_binary_save_const_string (list, factory->longdesc);
       
   364   }
       
   365 #endif
       
   366   else {
       
   367     GST_WARNING ("unhandled feature type '%s'", type_name);
       
   368   }
       
   369 
       
   370   if (pf) {
       
   371     pf->rank = feature->rank;
       
   372     *list = g_list_prepend (*list, chk);
       
   373 
       
   374     /* pack plugin feature strings */
       
   375     gst_registry_binary_save_const_string (list, feature->name);
       
   376     gst_registry_binary_save_const_string (list, (gchar *) type_name);
       
   377 
       
   378     return TRUE;
       
   379   }
       
   380 
       
   381   /* Errors */
       
   382 fail:
       
   383   g_free (chk);
       
   384   g_free (pf);
       
   385   return FALSE;
       
   386 }
       
   387 
       
   388 
       
   389 /*
       
   390  * gst_registry_binary_save_plugin:
       
   391  *
       
   392  * Adapt a GstPlugin to our GstBinaryPluginElement structure, and write it to
       
   393  * the registry file.
       
   394  */
       
   395 static gboolean
       
   396 gst_registry_binary_save_plugin (GList ** list, GstRegistry * registry,
       
   397     GstPlugin * plugin)
       
   398 {
       
   399   GstBinaryPluginElement *pe;
       
   400   GstBinaryChunk *chk;
       
   401   GList *plugin_features = NULL;
       
   402   GList *walk;
       
   403 
       
   404   pe = g_malloc (sizeof (GstBinaryPluginElement));
       
   405   chk = gst_registry_binary_make_data (pe, sizeof (GstBinaryPluginElement));
       
   406 
       
   407   pe->file_size = plugin->file_size;
       
   408   pe->file_mtime = plugin->file_mtime;
       
   409   pe->nfeatures = 0;
       
   410 
       
   411   /* pack plugin features */
       
   412   plugin_features =
       
   413       gst_registry_get_feature_list_by_plugin (registry, plugin->desc.name);
       
   414   for (walk = plugin_features; walk; walk = g_list_next (walk), pe->nfeatures++) {
       
   415     GstPluginFeature *feature = GST_PLUGIN_FEATURE (walk->data);
       
   416 
       
   417     if (!gst_registry_binary_save_feature (list, feature)) {
       
   418       GST_ERROR ("Can't fill plugin feature, aborting.");
       
   419       goto fail;
       
   420     }
       
   421   }
       
   422   GST_DEBUG ("Save plugin '%s' with %d features", plugin->desc.name,
       
   423       pe->nfeatures);
       
   424 
       
   425   gst_plugin_feature_list_free (plugin_features);
       
   426 
       
   427   /* pack plugin element strings */
       
   428   gst_registry_binary_save_const_string (list, plugin->desc.origin);
       
   429   gst_registry_binary_save_const_string (list, plugin->desc.package);
       
   430   gst_registry_binary_save_const_string (list, plugin->desc.source);
       
   431   gst_registry_binary_save_const_string (list, plugin->desc.license);
       
   432   gst_registry_binary_save_const_string (list, plugin->desc.version);
       
   433   gst_registry_binary_save_const_string (list, plugin->filename);
       
   434   gst_registry_binary_save_const_string (list, plugin->desc.description);
       
   435   gst_registry_binary_save_const_string (list, plugin->desc.name);
       
   436 
       
   437   *list = g_list_prepend (*list, chk);
       
   438 
       
   439   GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
       
   440       plugin->desc.name);
       
   441   return TRUE;
       
   442 
       
   443   /* Errors */
       
   444 fail:
       
   445   gst_plugin_feature_list_free (plugin_features);
       
   446   g_free (chk);
       
   447   g_free (pe);
       
   448   return FALSE;
       
   449 }
       
   450 
       
   451 
       
   452 /**
       
   453  * gst_registry_binary_write_cache:
       
   454  * @registry: a #GstRegistry
       
   455  * @location: a filename
       
   456  *
       
   457  * Write the @registry to a cache to file at given @location.
       
   458  * 
       
   459  * Returns: %TRUE on success.
       
   460  */
       
   461 #ifdef __SYMBIAN32__
       
   462 EXPORT_C
       
   463 #endif
       
   464 
       
   465 gboolean
       
   466 gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
       
   467 {
       
   468   GList *walk;
       
   469   gchar *tmp_location;
       
   470   GstBinaryRegistryMagic *magic;
       
   471   GstBinaryChunk *magic_chunk;
       
   472   GList *to_write = NULL;
       
   473   unsigned long file_position = 0;
       
   474 
       
   475   GST_INFO ("Building binary registry cache image");
       
   476 
       
   477   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
       
   478   tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
       
   479   registry->cache_file = g_mkstemp (tmp_location);
       
   480   if (registry->cache_file == -1) {
       
   481     gchar *dir;
       
   482 
       
   483     /* oops, I bet the directory doesn't exist */
       
   484     dir = g_path_get_dirname (location);
       
   485     g_mkdir_with_parents (dir, 0777);
       
   486     g_free (dir);
       
   487 
       
   488     /* the previous g_mkstemp call overwrote the XXXXXX placeholder ... */
       
   489     g_free (tmp_location);
       
   490     tmp_location = g_strconcat (location, ".tmpXXXXXX", NULL);
       
   491     registry->cache_file = g_mkstemp (tmp_location);
       
   492 
       
   493     if (registry->cache_file == -1) {
       
   494       GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno));
       
   495       g_free (tmp_location);
       
   496       return FALSE;
       
   497     }
       
   498   }
       
   499 
       
   500   magic = g_malloc (sizeof (GstBinaryRegistryMagic));
       
   501   if (!gst_registry_binary_initialize_magic (magic))
       
   502     goto fail;
       
   503 
       
   504   magic_chunk = g_malloc (sizeof (GstBinaryChunk));
       
   505   magic_chunk->data = magic;
       
   506   magic_chunk->size = sizeof (GstBinaryRegistryMagic);
       
   507   magic_chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
       
   508   magic_chunk->align = TRUE;
       
   509 
       
   510   /* iterate trough the list of plugins and fit them into binary structures */
       
   511   for (walk = registry->plugins; walk; walk = g_list_next (walk)) {
       
   512     GstPlugin *plugin = GST_PLUGIN (walk->data);
       
   513 
       
   514     if (!plugin->filename)
       
   515       continue;
       
   516 
       
   517     if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
       
   518       int ret;
       
   519       struct stat statbuf;
       
   520 
       
   521       ret = g_stat (plugin->filename, &statbuf);
       
   522       if ((ret = g_stat (plugin->filename, &statbuf)) < 0 ||
       
   523           plugin->file_mtime != statbuf.st_mtime ||
       
   524           plugin->file_size != statbuf.st_size)
       
   525         continue;
       
   526     }
       
   527 
       
   528     if (!gst_registry_binary_save_plugin (&to_write, registry, plugin)) {
       
   529       GST_ERROR ("Can't write binary plugin information for \"%s\"",
       
   530           plugin->filename);
       
   531     }
       
   532   }
       
   533   to_write = g_list_prepend (to_write, magic_chunk);
       
   534 
       
   535   GST_INFO ("Writing binary registry cache");
       
   536 
       
   537   /* write out data chunks */
       
   538   for (walk = to_write; walk; walk = g_list_next (walk)) {
       
   539     GstBinaryChunk *cur = walk->data;
       
   540 
       
   541     if (!gst_registry_binary_write (registry, cur->data, cur->size,
       
   542             &file_position, cur->align)) {
       
   543       if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
       
   544         g_free (cur->data);
       
   545       g_free (cur);
       
   546       g_list_free (to_write);
       
   547       goto fail;
       
   548     }
       
   549     if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
       
   550       g_free (cur->data);
       
   551     g_free (cur);
       
   552   }
       
   553   g_list_free (to_write);
       
   554 
       
   555   if (close (registry->cache_file) < 0)
       
   556     goto close_failed;
       
   557 
       
   558   if (g_file_test (tmp_location, G_FILE_TEST_EXISTS)) {
       
   559 #ifdef WIN32
       
   560     g_remove (location);
       
   561 #endif
       
   562     if (g_rename (tmp_location, location) < 0)
       
   563       goto rename_failed;
       
   564   } else {
       
   565     /* FIXME: shouldn't we return FALSE here? */
       
   566   }
       
   567 
       
   568   g_free (tmp_location);
       
   569   GST_INFO ("Wrote binary registry cache");
       
   570   return TRUE;
       
   571 
       
   572   /* Errors */
       
   573 fail:
       
   574   {
       
   575     (void) close (registry->cache_file);
       
   576     /* fall through */
       
   577   }
       
   578 fail_after_close:
       
   579   {
       
   580     g_remove (tmp_location);
       
   581     g_free (tmp_location);
       
   582     return FALSE;
       
   583   }
       
   584 close_failed:
       
   585   {
       
   586     GST_ERROR ("close() failed: %s", g_strerror (errno));
       
   587     goto fail_after_close;
       
   588   }
       
   589 rename_failed:
       
   590   {
       
   591     GST_ERROR ("g_rename() failed: %s", g_strerror (errno));
       
   592     goto fail_after_close;
       
   593   }
       
   594 }
       
   595 
       
   596 
       
   597 /* Registry loading */
       
   598 
       
   599 /*
       
   600  * gst_registry_binary_check_magic:
       
   601  *
       
   602  * Check GstBinaryRegistryMagic validity.
       
   603  * Return FALSE if something is wrong
       
   604  */
       
   605 static gboolean
       
   606 gst_registry_binary_check_magic (gchar ** in)
       
   607 {
       
   608   GstBinaryRegistryMagic *m;
       
   609 
       
   610   align32 (*in);
       
   611   GST_DEBUG ("Reading/casting for GstBinaryRegistryMagic at address %p", *in);
       
   612   unpack_element (*in, m, GstBinaryRegistryMagic);
       
   613 
       
   614   if (m == NULL || m->magic == NULL || m->version == NULL) {
       
   615     GST_WARNING ("Binary registry magic structure is broken");
       
   616     return FALSE;
       
   617   }
       
   618   if (strncmp (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
       
   619           GST_MAGIC_BINARY_REGISTRY_LEN) != 0) {
       
   620     GST_WARNING
       
   621         ("Binary registry magic is different : %02x%02x%02x%02x != %02x%02x%02x%02x",
       
   622         GST_MAGIC_BINARY_REGISTRY_STR[0] & 0xff,
       
   623         GST_MAGIC_BINARY_REGISTRY_STR[1] & 0xff,
       
   624         GST_MAGIC_BINARY_REGISTRY_STR[2] & 0xff,
       
   625         GST_MAGIC_BINARY_REGISTRY_STR[3] & 0xff, m->magic[0] & 0xff,
       
   626         m->magic[1] & 0xff, m->magic[2] & 0xff, m->magic[3] & 0xff);
       
   627     return FALSE;
       
   628   }
       
   629   if (strncmp (m->version, GST_MAJORMINOR, GST_MAGIC_BINARY_VERSION_LEN)) {
       
   630     GST_WARNING ("Binary registry magic version is different : %s != %s",
       
   631         GST_MAJORMINOR, m->version);
       
   632     return FALSE;
       
   633   }
       
   634   return TRUE;
       
   635 }
       
   636 
       
   637 
       
   638 /*
       
   639  * gst_registry_binary_load_pad_template:
       
   640  *
       
   641  * Make a new GstStaticPadTemplate from current GstBinaryPadTemplate structure
       
   642  *
       
   643  * Returns: new GstStaticPadTemplate
       
   644  */
       
   645 static gboolean
       
   646 gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in)
       
   647 {
       
   648   GstBinaryPadTemplate *pt;
       
   649   GstStaticPadTemplate *template;
       
   650 
       
   651   align32 (*in);
       
   652   GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in);
       
   653   unpack_element (*in, pt, GstBinaryPadTemplate);
       
   654 
       
   655   template = g_new0 (GstStaticPadTemplate, 1);
       
   656   template->presence = pt->presence;
       
   657   template->direction = pt->direction;
       
   658 
       
   659   /* unpack pad template strings */
       
   660   unpack_const_string (*in, template->name_template);
       
   661   unpack_string (*in, template->static_caps.string);
       
   662 
       
   663   __gst_element_factory_add_static_pad_template (factory, template);
       
   664   GST_DEBUG ("Added pad_template %s", template->name_template);
       
   665 
       
   666   return TRUE;
       
   667 }
       
   668 
       
   669 
       
   670 /*
       
   671  * gst_registry_binary_load_feature:
       
   672  *
       
   673  * Make a new GstPluginFeature from current binary plugin feature structure
       
   674  *
       
   675  * Returns: new GstPluginFeature
       
   676  */
       
   677 static gboolean
       
   678 gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
       
   679     const gchar * plugin_name)
       
   680 {
       
   681   GstBinaryPluginFeature *pf = NULL;
       
   682   GstPluginFeature *feature;
       
   683   gchar *type_name = NULL, *str;
       
   684   GType type;
       
   685   guint i;
       
   686 
       
   687   /* unpack plugin feature strings */
       
   688   unpack_string (*in, type_name);
       
   689 
       
   690   if (!type_name || !*(type_name))
       
   691     return FALSE;
       
   692 
       
   693   GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
       
   694 
       
   695   if (!(type = g_type_from_name (type_name))) {
       
   696     GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
       
   697         plugin_name);
       
   698     return FALSE;
       
   699   }
       
   700   if ((feature = g_object_new (type, NULL)) == NULL) {
       
   701     GST_ERROR ("Can't create feature from type");
       
   702     return FALSE;
       
   703   }
       
   704 
       
   705   if (!GST_IS_PLUGIN_FEATURE (feature)) {
       
   706     GST_ERROR ("typename : '%s' is not a plgin feature", type_name);
       
   707     goto fail;
       
   708   }
       
   709 
       
   710   /* unpack more plugin feature strings */
       
   711   unpack_string (*in, feature->name);
       
   712 
       
   713   if (GST_IS_ELEMENT_FACTORY (feature)) {
       
   714     GstBinaryElementFactory *ef;
       
   715     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
       
   716 
       
   717     align32 (*in);
       
   718     GST_LOG ("Reading/casting for GstBinaryElementFactory at address %p", *in);
       
   719     unpack_element (*in, ef, GstBinaryElementFactory);
       
   720     pf = (GstBinaryPluginFeature *) ef;
       
   721 
       
   722     /* unpack element factory strings */
       
   723     unpack_string (*in, factory->details.longname);
       
   724     unpack_string (*in, factory->details.klass);
       
   725     unpack_string (*in, factory->details.description);
       
   726     unpack_string (*in, factory->details.author);
       
   727     GST_DEBUG ("Element factory : '%s' with npadtemplates=%d",
       
   728         factory->details.longname, ef->npadtemplates);
       
   729 
       
   730     /* load pad templates */
       
   731     for (i = 0; i < ef->npadtemplates; i++) {
       
   732       if (!gst_registry_binary_load_pad_template (factory, in)) {
       
   733         GST_ERROR ("Error while loading binary pad template");
       
   734         goto fail;
       
   735       }
       
   736     }
       
   737 
       
   738     /* load uritypes */
       
   739     if (ef->nuriprotocols) {
       
   740       GST_DEBUG ("Reading %d UriTypes at address %p", ef->nuriprotocols, *in);
       
   741 
       
   742       align32 (*in);
       
   743       factory->uri_type = *((guint *) * in);
       
   744       *in += sizeof (factory->uri_type);
       
   745       //unpack_element(*in, &factory->uri_type, factory->uri_type);
       
   746 
       
   747       factory->uri_protocols = g_new0 (gchar *, ef->nuriprotocols + 1);
       
   748       for (i = 0; i < ef->nuriprotocols; i++) {
       
   749         unpack_string (*in, str);
       
   750         factory->uri_protocols[i] = str;
       
   751       }
       
   752     }
       
   753     /* load interfaces */
       
   754     GST_DEBUG ("Reading %d Interfaces at address %p", ef->ninterfaces, *in);
       
   755     for (i = 0; i < ef->ninterfaces; i++) {
       
   756       unpack_string (*in, str);
       
   757       __gst_element_factory_add_interface (factory, str);
       
   758       g_free (str);
       
   759     }
       
   760   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
       
   761     GstBinaryTypeFindFactory *tff;
       
   762     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
       
   763 
       
   764     align32 (*in);
       
   765     GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
       
   766     unpack_element (*in, tff, GstBinaryTypeFindFactory);
       
   767     pf = (GstBinaryPluginFeature *) tff;
       
   768 
       
   769     /* load caps */
       
   770     unpack_string (*in, str);
       
   771     factory->caps = gst_caps_from_string (str);
       
   772     g_free (str);
       
   773     /* load extensions */
       
   774     if (tff->nextensions) {
       
   775       GST_DEBUG ("Reading %d Typefind extensions at address %p",
       
   776           tff->nextensions, *in);
       
   777       factory->extensions = g_new0 (gchar *, tff->nextensions + 1);
       
   778       for (i = 0; i < tff->nextensions; i++) {
       
   779         unpack_string (*in, str);
       
   780         factory->extensions[i] = str;
       
   781       }
       
   782     }
       
   783   }
       
   784 #ifndef GST_DISABLE_INDEX
       
   785   else if (GST_IS_INDEX_FACTORY (feature)) {
       
   786     GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
       
   787 
       
   788     align32 (*in);
       
   789     GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
       
   790     unpack_element (*in, pf, GstBinaryPluginFeature);
       
   791 
       
   792     /* unpack index factory strings */
       
   793     unpack_string (*in, factory->longdesc);
       
   794   }
       
   795 #endif
       
   796 
       
   797   feature->rank = pf->rank;
       
   798 
       
   799   /* should already be the interned string, but better make sure */
       
   800   feature->plugin_name = g_intern_string (plugin_name);
       
   801 
       
   802   gst_registry_add_feature (registry, feature);
       
   803   GST_DEBUG ("Added feature %s", feature->name);
       
   804 
       
   805   g_free (type_name);
       
   806   return TRUE;
       
   807 
       
   808   /* Errors */
       
   809 fail:
       
   810   g_free (type_name);
       
   811   if (GST_IS_OBJECT (feature))
       
   812     gst_object_unref (feature);
       
   813   else
       
   814     g_object_unref (feature);
       
   815   return FALSE;
       
   816 }
       
   817 
       
   818 
       
   819 /*
       
   820  * gst_registry_binary_load_plugin:
       
   821  *
       
   822  * Make a new GstPlugin from current GstBinaryPluginElement structure
       
   823  * and save it to the GstRegistry. Return an offset to the next
       
   824  * GstBinaryPluginElement structure.
       
   825  */
       
   826 static gboolean
       
   827 gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
       
   828 {
       
   829   GstBinaryPluginElement *pe;
       
   830   GstPlugin *plugin = NULL;
       
   831   guint i;
       
   832 
       
   833   align32 (*in);
       
   834   GST_LOG ("Reading/casting for GstBinaryPluginElement at address %p", *in);
       
   835   unpack_element (*in, pe, GstBinaryPluginElement);
       
   836 
       
   837   if (pe->nfeatures < 0) {
       
   838     GST_ERROR ("The number of feature structure is not valid !");
       
   839     return FALSE;
       
   840   }
       
   841 
       
   842   if (pe->file_mtime < 0 || pe->file_size < 0) {
       
   843     GST_ERROR ("Plugin time or file size is not valid !");
       
   844     return FALSE;
       
   845   }
       
   846 
       
   847   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
       
   848 
       
   849   /* TODO: also set GST_PLUGIN_FLAG_CONST */
       
   850   plugin->flags |= GST_PLUGIN_FLAG_CACHED;
       
   851   plugin->file_mtime = pe->file_mtime;
       
   852   plugin->file_size = pe->file_size;
       
   853 
       
   854   /* unpack plugin element strings */
       
   855   unpack_const_string (*in, plugin->desc.name);
       
   856   unpack_string (*in, plugin->desc.description);
       
   857   unpack_string (*in, plugin->filename);
       
   858   unpack_const_string (*in, plugin->desc.version);
       
   859   unpack_const_string (*in, plugin->desc.license);
       
   860   unpack_const_string (*in, plugin->desc.source);
       
   861   unpack_const_string (*in, plugin->desc.package);
       
   862   unpack_const_string (*in, plugin->desc.origin);
       
   863   GST_LOG ("read strings for '%s'", plugin->desc.name);
       
   864 
       
   865   plugin->basename = g_path_get_basename (plugin->filename);
       
   866   gst_registry_add_plugin (registry, plugin);
       
   867   GST_INFO ("Added plugin '%s' plugin with %d features from binary registry",
       
   868       plugin->desc.name, pe->nfeatures);
       
   869   for (i = 0; i < pe->nfeatures; i++) {
       
   870     if (!gst_registry_binary_load_feature (registry, in, plugin->desc.name)) {
       
   871       GST_ERROR ("Error while loading binary feature");
       
   872       goto fail;
       
   873     }
       
   874   }
       
   875 
       
   876   return TRUE;
       
   877 
       
   878   /* Errors */
       
   879 fail:
       
   880   gst_object_unref (plugin);
       
   881   return FALSE;
       
   882 }
       
   883 
       
   884 
       
   885 /**
       
   886  * gst_registry_binary_read_cache:
       
   887  * @registry: a #GstRegistry
       
   888  * @location: a filename
       
   889  *
       
   890  * Read the contents of the binary cache file at @location into @registry.
       
   891  *
       
   892  * Returns: %TRUE on success.
       
   893  */
       
   894 #ifdef __SYMBIAN32__
       
   895 EXPORT_C
       
   896 #endif
       
   897 
       
   898 gboolean
       
   899 gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
       
   900 {
       
   901   GMappedFile *mapped = NULL;
       
   902   GTimer *timer = NULL;
       
   903   gchar *contents = NULL;
       
   904   gchar *in = NULL;
       
   905   gdouble seconds;
       
   906   gsize size;
       
   907   GError *err = NULL;
       
   908   gboolean res = FALSE;
       
   909 
       
   910   /* make sure these types exist */
       
   911   GST_TYPE_ELEMENT_FACTORY;
       
   912   GST_TYPE_TYPE_FIND_FACTORY;
       
   913 #ifndef GST_DISABLE_INDEX
       
   914   GST_TYPE_INDEX_FACTORY;
       
   915 #endif
       
   916 
       
   917   timer = g_timer_new ();
       
   918 
       
   919   mapped = g_mapped_file_new (location, FALSE, &err);
       
   920   if (err != NULL) {
       
   921     GST_INFO ("Unable to mmap file %s : %s", location, err->message);
       
   922     g_error_free (err);
       
   923     err = NULL;
       
   924 
       
   925     g_file_get_contents (location, &contents, &size, &err);
       
   926     if (err != NULL) {
       
   927       GST_INFO ("Unable to read file %s : %s", location, err->message);
       
   928       g_timer_destroy (timer);
       
   929       g_error_free (err);
       
   930       return FALSE;
       
   931     }
       
   932   } else {
       
   933     if ((contents = g_mapped_file_get_contents (mapped)) == NULL) {
       
   934       GST_ERROR ("Can't load file %s : %s", location, g_strerror (errno));
       
   935       goto Error;
       
   936     }
       
   937     /* check length for header */
       
   938     size = g_mapped_file_get_length (mapped);
       
   939   }
       
   940   /* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */
       
   941   in = contents;
       
   942   GST_DEBUG ("File data at address %p", in);
       
   943   if (size < sizeof (GstBinaryRegistryMagic)) {
       
   944     GST_ERROR ("No or broken registry header");
       
   945     goto Error;
       
   946   }
       
   947   /* check if header is valid */
       
   948   if (!gst_registry_binary_check_magic (&in)) {
       
   949     GST_ERROR
       
   950         ("Binary registry type not recognized (invalid magic) for file at %s",
       
   951         location);
       
   952     goto Error;
       
   953   }
       
   954 
       
   955   /* check if there are plugins in the file */
       
   956 
       
   957   if (!(((gsize) in + sizeof (GstBinaryPluginElement)) <
       
   958           (gsize) contents + size)) {
       
   959     GST_INFO ("No binary plugins structure to read");
       
   960     /* empty file, this is not an error */
       
   961   } else {
       
   962     for (;
       
   963         ((gsize) in + sizeof (GstBinaryPluginElement)) <
       
   964         (gsize) contents + size;) {
       
   965       GST_DEBUG ("reading binary registry %" G_GSIZE_FORMAT "(%x)/%"
       
   966           G_GSIZE_FORMAT, (gsize) in - (gsize) contents,
       
   967           (guint) ((gsize) in - (gsize) contents), size);
       
   968       if (!gst_registry_binary_load_plugin (registry, &in)) {
       
   969         GST_ERROR ("Problem while reading binary registry");
       
   970         goto Error;
       
   971       }
       
   972     }
       
   973   }
       
   974 
       
   975   g_timer_stop (timer);
       
   976   seconds = g_timer_elapsed (timer, NULL);
       
   977 
       
   978   GST_INFO ("loaded %s in %lf seconds", location, seconds);
       
   979 
       
   980   res = TRUE;
       
   981   /* TODO: once we re-use the pointers to registry contents return here */
       
   982 
       
   983 Error:
       
   984   g_timer_destroy (timer);
       
   985   if (mapped) {
       
   986     g_mapped_file_free (mapped);
       
   987   } else {
       
   988     g_free (contents);
       
   989   }
       
   990   return res;
       
   991 }
       
   992 
       
   993 
       
   994 /* FIXME 0.11: these are here for backwards compatibility */
       
   995 #ifdef __SYMBIAN32__
       
   996 EXPORT_C
       
   997 #endif
       
   998 
       
   999 
       
  1000 gboolean
       
  1001 gst_registry_xml_read_cache (GstRegistry * registry, const char *location)
       
  1002 {
       
  1003   return FALSE;
       
  1004 }
       
  1005 #ifdef __SYMBIAN32__
       
  1006 EXPORT_C
       
  1007 #endif
       
  1008 
       
  1009 
       
  1010 gboolean
       
  1011 gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
       
  1012 {
       
  1013   return FALSE;
       
  1014 }