gst/gstregistrybinary.c: Return the old CRC instead of 0 if we give a NULL buffer...
[platform/upstream/gstreamer.git] / gst / gstregistrybinary.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  *
7  * gstregistrybinary.c: GstRegistryBinary object, support routines
8  *
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.
13  *
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.
18  *
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.
23  */
24
25 /* FIXME:
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() ?
29  *   - GstPlugin:
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
36  *     in parent chunk
37  * - need more robustness
38  *   - don't parse beyond mem-block size
39  */
40
41 #ifdef HAVE_CONFIG_H
42 #  include "config.h"
43 #endif
44
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48
49 #include <errno.h>
50 #include <stdio.h>
51
52 #if defined (_MSC_VER) && _MSC_VER >= 1400
53 #include <io.h>
54 #endif
55
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>
65
66 #include <gst/gstregistrybinary.h>
67
68 #include <glib/gstdio.h>        /* for g_stat(), g_mapped_file(), ... */
69
70 #include "glib-compat-private.h"
71
72
73 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
74
75 /* macros */
76
77 #define unpack_element(_inptr, _outptr, _element)  \
78   _outptr = (_element *) _inptr; \
79   _inptr += sizeof (_element)
80
81 #define unpack_const_string(_inptr, _outptr) \
82   _outptr = g_intern_string ((const gchar *)_inptr); \
83   _inptr += strlen(_outptr) + 1
84
85 #define unpack_string(_inptr, _outptr)  \
86   _outptr = g_strdup ((gchar *)_inptr); \
87   _inptr += strlen(_outptr) + 1
88
89 #define ALIGNMENT            (sizeof (void *))
90 #define alignment(_address)  (gsize)_address%ALIGNMENT
91 #define align(_ptr)          _ptr += (( alignment(_ptr) == 0) ? 0 : ALIGNMENT-alignment(_ptr))
92
93
94 /* CRC32 calculation */
95
96 /* The crc32() function is copyrighted and licensed as specified below.
97  * This only applies to this single function:
98
99   crc32.c -- compute the CRC-32 of a data stream
100   Copyright (C) 1995-1998 Mark Adler
101
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.
105
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:
109
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.
117
118   Jean-loup Gailly        Mark Adler
119   jloup@gzip.org          madler@alumni.caltech.edu
120 */
121
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
126  */
127
128 /* ========================================================================
129  * Table of CRC-32's of all single-byte values (made by make_crc_table)
130  */
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,
183   0x2d02ef8dL
184 };
185
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);
191
192 /* ========================================================================= */
193 static guint32
194 _gst_crc32 (guint32 crc, const gchar * buf, guint len)
195 {
196   if (buf == NULL || len == 0)
197     return crc;
198
199   crc = crc ^ 0xffffffffL;
200   while (len >= 8) {
201     DO8 (buf);
202     len -= 8;
203   }
204   if (len)
205     do {
206       DO1 (buf);
207     } while (--len);
208   return crc ^ 0xffffffffL;
209 }
210
211 #undef DO1
212 #undef DO2
213 #undef DO4
214 #undef DO8
215
216 /* Registry saving */
217
218 /*
219  * gst_registry_binary_write:
220  *
221  * Write from a memory location to the registry cache file
222  *
223  * Returns: %TRUE for success
224  */
225 inline static gboolean
226 gst_registry_binary_write (GstRegistry * registry, const void *mem,
227     const gssize size, unsigned long *file_position, gboolean align,
228     guint32 * crc32)
229 {
230   gchar padder[ALIGNMENT] = { 0, };
231   int padsize = 0;
232
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");
238       return FALSE;
239     }
240     if (padsize > 0)
241       *crc32 = _gst_crc32 (*crc32, padder, padsize);
242     *file_position = *file_position + padsize;
243   }
244
245   if (write (registry->cache_file, mem, size) != size) {
246     GST_ERROR ("Failed to write binary registry element");
247     return FALSE;
248   }
249   if (size > 0)
250     *crc32 = _gst_crc32 (*crc32, mem, size);
251
252   *file_position = *file_position + size;
253   return TRUE;
254 }
255
256
257 /*
258  * gst_registry_binary_initialize_magic:
259  *
260  * Initialize the GstBinaryRegistryMagic, setting both our magic number and
261  * gstreamer major/minor version
262  */
263 inline static gboolean
264 gst_registry_binary_initialize_magic (GstBinaryRegistryMagic * m)
265 {
266   memset (m, 0, sizeof (GstBinaryRegistryMagic));
267
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");
273     return FALSE;
274   }
275
276   m->crc32 = 0;
277
278   return TRUE;
279 }
280
281
282 /*
283  * gst_registry_binary_save_const_string:
284  *
285  * Store a const string in a binary chunk.
286  *
287  * Returns: %TRUE for success
288  */
289 inline static gboolean
290 gst_registry_binary_save_const_string (GList ** list, const gchar * str)
291 {
292   GstBinaryChunk *chunk;
293
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);
300   return TRUE;
301 }
302
303 /*
304  * gst_registry_binary_save_string:
305  *
306  * Store a string in a binary chunk.
307  *
308  * Returns: %TRUE for success
309  */
310 inline static gboolean
311 gst_registry_binary_save_string (GList ** list, gchar * str)
312 {
313   GstBinaryChunk *chunk;
314
315   chunk = g_malloc (sizeof (GstBinaryChunk));
316   chunk->data = str;
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);
321   return TRUE;
322 }
323
324
325 /*
326  * gst_registry_binary_save_data:
327  *
328  * Store some data in a binary chunk.
329  *
330  * Returns: the initialized chunk
331  */
332 inline static GstBinaryChunk *
333 gst_registry_binary_make_data (gpointer data, gulong size)
334 {
335   GstBinaryChunk *chunk;
336
337   chunk = g_malloc (sizeof (GstBinaryChunk));
338   chunk->data = data;
339   chunk->size = size;
340   chunk->flags = GST_BINARY_REGISTRY_FLAG_NONE;
341   chunk->align = TRUE;
342   return chunk;
343 }
344
345
346 /*
347  * gst_registry_binary_save_pad_template:
348  *
349  * Store pad_templates in binary chunks.
350  *
351  * Returns: %TRUE for success
352  */
353 static gboolean
354 gst_registry_binary_save_pad_template (GList ** list,
355     GstStaticPadTemplate * template)
356 {
357   GstBinaryPadTemplate *pt;
358   GstBinaryChunk *chk;
359
360   pt = g_malloc (sizeof (GstBinaryPadTemplate));
361   chk = gst_registry_binary_make_data (pt, sizeof (GstBinaryPadTemplate));
362
363   pt->presence = template->presence;
364   pt->direction = template->direction;
365
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);
370
371   *list = g_list_prepend (*list, chk);
372
373   return TRUE;
374 }
375
376
377 /*
378  * gst_registry_binary_save_feature:
379  *
380  * Store features in binary chunks.
381  *
382  * Returns: %TRUE for success
383  */
384 static gboolean
385 gst_registry_binary_save_feature (GList ** list, GstPluginFeature * feature)
386 {
387   const gchar *type_name = g_type_name (G_OBJECT_TYPE (feature));
388   GstBinaryPluginFeature *pf = NULL;
389   GstBinaryChunk *chk = NULL;
390   GList *walk;
391
392   if (!type_name) {
393     GST_ERROR ("NULL feature type_name, aborting.");
394     return FALSE;
395   }
396
397   if (GST_IS_ELEMENT_FACTORY (feature)) {
398     GstBinaryElementFactory *ef;
399     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
400
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;
405
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);
410     }
411     GST_DEBUG ("Saved %d Interfaces", ef->ninterfaces);
412     /* save uritypes */
413     if (GST_URI_TYPE_IS_VALID (factory->uri_type)) {
414       if (factory->uri_protocols && *factory->uri_protocols) {
415         GstBinaryChunk *subchk;
416         gchar **protocol;
417
418         subchk =
419             gst_registry_binary_make_data (&factory->uri_type,
420             sizeof (factory->uri_type));
421         subchk->flags = GST_BINARY_REGISTRY_FLAG_CONST;
422
423         protocol = factory->uri_protocols;
424         while (*protocol) {
425           gst_registry_binary_save_const_string (list, *protocol++);
426           ef->nuriprotocols++;
427         }
428         *list = g_list_prepend (*list, subchk);
429         GST_DEBUG ("Saved %d UriTypes", ef->nuriprotocols);
430       } else {
431         g_warning ("GStreamer feature '%s' is URI handler but does not provide"
432             " any protocols it can handle", feature->name);
433       }
434     }
435
436     /* save pad-templates */
437     for (walk = factory->staticpadtemplates; walk;
438         walk = g_list_next (walk), ef->npadtemplates++) {
439       GstStaticPadTemplate *template = walk->data;
440
441       if (!gst_registry_binary_save_pad_template (list, template)) {
442         GST_ERROR ("Can't fill pad template, aborting.");
443         goto fail;
444       }
445     }
446
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);
455     gchar *str;
456
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);
460
461     tff = g_malloc (sizeof (GstBinaryTypeFindFactory));
462     chk =
463         gst_registry_binary_make_data (tff, sizeof (GstBinaryTypeFindFactory));
464     tff->nextensions = 0;
465     pf = (GstBinaryPluginFeature *) tff;
466
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++]);
472       }
473     }
474     /* save caps */
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);
479   }
480 #ifndef GST_DISABLE_INDEX
481   else if (GST_IS_INDEX_FACTORY (feature)) {
482     GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
483
484     pf = g_malloc (sizeof (GstBinaryPluginFeature));
485     chk = gst_registry_binary_make_data (pf, sizeof (GstBinaryPluginFeature));
486     pf->rank = feature->rank;
487
488     /* pack element factory strings */
489     gst_registry_binary_save_const_string (list, factory->longdesc);
490   }
491 #endif
492   else {
493     GST_WARNING ("unhandled feature type '%s'", type_name);
494   }
495
496   if (pf) {
497     pf->rank = feature->rank;
498     *list = g_list_prepend (*list, chk);
499
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);
503
504     return TRUE;
505   }
506
507   /* Errors */
508 fail:
509   g_free (chk);
510   g_free (pf);
511   return FALSE;
512 }
513
514
515 /*
516  * gst_registry_binary_save_plugin:
517  *
518  * Adapt a GstPlugin to our GstBinaryPluginElement structure, and write it to
519  * the registry file.
520  */
521 static gboolean
522 gst_registry_binary_save_plugin (GList ** list, GstRegistry * registry,
523     GstPlugin * plugin)
524 {
525   GstBinaryPluginElement *pe;
526   GstBinaryChunk *chk;
527   GList *plugin_features = NULL;
528   GList *walk;
529
530   pe = g_malloc (sizeof (GstBinaryPluginElement));
531   chk = gst_registry_binary_make_data (pe, sizeof (GstBinaryPluginElement));
532
533   pe->file_size = plugin->file_size;
534   pe->file_mtime = plugin->file_mtime;
535   pe->nfeatures = 0;
536
537   /* pack plugin features */
538   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);
542
543     if (!gst_registry_binary_save_feature (list, feature)) {
544       GST_ERROR ("Can't fill plugin feature, aborting.");
545       goto fail;
546     }
547   }
548   GST_DEBUG ("Save plugin '%s' with %d features", plugin->desc.name,
549       pe->nfeatures);
550
551   gst_plugin_feature_list_free (plugin_features);
552
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);
562
563   *list = g_list_prepend (*list, chk);
564
565   GST_DEBUG ("Found %d features in plugin \"%s\"", pe->nfeatures,
566       plugin->desc.name);
567   return TRUE;
568
569   /* Errors */
570 fail:
571   gst_plugin_feature_list_free (plugin_features);
572   g_free (chk);
573   g_free (pe);
574   return FALSE;
575 }
576
577
578 /**
579  * gst_registry_binary_write_cache:
580  * @registry: a #GstRegistry
581  * @location: a filename
582  *
583  * Write the @registry to a cache to file at given @location.
584  * 
585  * Returns: %TRUE on success.
586  */
587 gboolean
588 gst_registry_binary_write_cache (GstRegistry * registry, const char *location)
589 {
590   GList *walk;
591   gchar *tmp_location;
592   GstBinaryRegistryMagic magic;
593   GList *to_write = NULL;
594   unsigned long file_position = 0;
595
596   GST_INFO ("Building binary registry cache image");
597
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) {
602     gchar *dir;
603
604     /* oops, I bet the directory doesn't exist */
605     dir = g_path_get_dirname (location);
606     g_mkdir_with_parents (dir, 0777);
607     g_free (dir);
608
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);
613
614     if (registry->cache_file == -1) {
615       GST_DEBUG ("g_mkstemp() failed: %s", g_strerror (errno));
616       g_free (tmp_location);
617       return FALSE;
618     }
619   }
620
621   if (!gst_registry_binary_initialize_magic (&magic))
622     goto fail;
623
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);
627
628     if (!plugin->filename)
629       continue;
630
631     if (plugin->flags & GST_PLUGIN_FLAG_CACHED) {
632       int ret;
633       struct stat statbuf;
634
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)
639         continue;
640     }
641
642     if (!gst_registry_binary_save_plugin (&to_write, registry, plugin)) {
643       GST_ERROR ("Can't write binary plugin information for \"%s\"",
644           plugin->filename);
645     }
646   }
647
648   GST_INFO ("Writing binary registry cache");
649
650   /* write magic */
651   if (write (registry->cache_file, &magic,
652           sizeof (GstBinaryRegistryMagic)) != sizeof (GstBinaryRegistryMagic)) {
653     GST_ERROR ("Failed to write binary registry magic");
654     goto fail_free_list;
655   }
656   file_position += sizeof (GstBinaryRegistryMagic);
657
658   /* write out data chunks */
659   for (walk = to_write; walk; walk = g_list_next (walk)) {
660     GstBinaryChunk *cur = walk->data;
661
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))
665         g_free (cur->data);
666       g_free (cur);
667       walk->data = NULL;
668       goto fail_free_list;
669     }
670     if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
671       g_free (cur->data);
672     g_free (cur);
673     walk->data = NULL;
674   }
675   g_list_free (to_write);
676
677   if (lseek (registry->cache_file, 0, SEEK_SET) != 0) {
678     GST_ERROR ("Seeking to rewrite the binary registry CRC32 failed");
679   } else {
680     if (write (registry->cache_file, &magic,
681             sizeof (GstBinaryRegistryMagic)) != sizeof (GstBinaryRegistryMagic))
682       GST_ERROR ("Failed to rewrite binary registry magic");
683   }
684
685   if (close (registry->cache_file) < 0)
686     goto close_failed;
687
688   if (g_file_test (tmp_location, G_FILE_TEST_EXISTS)) {
689 #ifdef WIN32
690     g_remove (location);
691 #endif
692     if (g_rename (tmp_location, location) < 0)
693       goto rename_failed;
694   } else {
695     /* FIXME: shouldn't we return FALSE here? */
696   }
697
698   g_free (tmp_location);
699   GST_INFO ("Wrote binary registry cache");
700   return TRUE;
701
702   /* Errors */
703 fail_free_list:
704   {
705     for (walk = to_write; walk; walk = g_list_next (walk)) {
706       GstBinaryChunk *cur = walk->data;
707
708       if (!(cur->flags & GST_BINARY_REGISTRY_FLAG_CONST))
709         g_free (cur->data);
710       g_free (cur);
711     }
712     g_list_free (to_write);
713     /* fall through */
714   }
715 fail:
716   {
717     (void) close (registry->cache_file);
718     /* fall through */
719   }
720 fail_after_close:
721   {
722     g_remove (tmp_location);
723     g_free (tmp_location);
724     return FALSE;
725   }
726 close_failed:
727   {
728     GST_ERROR ("close() failed: %s", g_strerror (errno));
729     goto fail_after_close;
730   }
731 rename_failed:
732   {
733     GST_ERROR ("g_rename() failed: %s", g_strerror (errno));
734     goto fail_after_close;
735   }
736 }
737
738
739 /* Registry loading */
740
741 /*
742  * gst_registry_binary_check_magic:
743  *
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.
748  */
749 static gint
750 gst_registry_binary_check_magic (gchar ** in, gsize size)
751 {
752   GstBinaryRegistryMagic *m;
753   guint32 crc32 = 0;
754
755   align (*in);
756   GST_DEBUG ("Reading/casting for GstBinaryRegistryMagic at address %p", *in);
757   unpack_element (*in, m, GstBinaryRegistryMagic);
758
759   if (m == NULL || m->magic == NULL || m->version == NULL) {
760     GST_WARNING ("Binary registry magic structure is broken");
761     return -1;
762   }
763   if (strncmp (m->magic, GST_MAGIC_BINARY_REGISTRY_STR,
764           GST_MAGIC_BINARY_REGISTRY_LEN) != 0) {
765     GST_WARNING
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);
772     return -1;
773   }
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);
778     return -2;
779   }
780
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,
784         m->crc32);
785     return -1;
786   }
787
788   return 0;
789 }
790
791
792 /*
793  * gst_registry_binary_load_pad_template:
794  *
795  * Make a new GstStaticPadTemplate from current GstBinaryPadTemplate structure
796  *
797  * Returns: new GstStaticPadTemplate
798  */
799 static gboolean
800 gst_registry_binary_load_pad_template (GstElementFactory * factory, gchar ** in)
801 {
802   GstBinaryPadTemplate *pt;
803   GstStaticPadTemplate *template;
804
805   align (*in);
806   GST_DEBUG ("Reading/casting for GstBinaryPadTemplate at address %p", *in);
807   unpack_element (*in, pt, GstBinaryPadTemplate);
808
809   template = g_new0 (GstStaticPadTemplate, 1);
810   template->presence = pt->presence;
811   template->direction = pt->direction;
812
813   /* unpack pad template strings */
814   unpack_const_string (*in, template->name_template);
815   unpack_string (*in, template->static_caps.string);
816
817   __gst_element_factory_add_static_pad_template (factory, template);
818   GST_DEBUG ("Added pad_template %s", template->name_template);
819
820   return TRUE;
821 }
822
823
824 /*
825  * gst_registry_binary_load_feature:
826  *
827  * Make a new GstPluginFeature from current binary plugin feature structure
828  *
829  * Returns: new GstPluginFeature
830  */
831 static gboolean
832 gst_registry_binary_load_feature (GstRegistry * registry, gchar ** in,
833     const gchar * plugin_name)
834 {
835   GstBinaryPluginFeature *pf = NULL;
836   GstPluginFeature *feature;
837   gchar *type_name = NULL, *str;
838   GType type;
839   guint i;
840
841   /* unpack plugin feature strings */
842   unpack_string (*in, type_name);
843
844   if (!type_name || !*(type_name)) {
845     GST_ERROR ("No feature type name");
846     return FALSE;
847   }
848
849   GST_DEBUG ("Plugin '%s' feature typename : '%s'", plugin_name, type_name);
850
851   if (!(type = g_type_from_name (type_name))) {
852     GST_ERROR ("Unknown type from typename '%s' for plugin '%s'", type_name,
853         plugin_name);
854     return FALSE;
855   }
856   if ((feature = g_object_new (type, NULL)) == NULL) {
857     GST_ERROR ("Can't create feature from type");
858     return FALSE;
859   }
860
861   if (!GST_IS_PLUGIN_FEATURE (feature)) {
862     GST_ERROR ("typename : '%s' is not a plugin feature", type_name);
863     goto fail;
864   }
865
866   /* unpack more plugin feature strings */
867   unpack_string (*in, feature->name);
868
869   if (GST_IS_ELEMENT_FACTORY (feature)) {
870     GstBinaryElementFactory *ef;
871     GstElementFactory *factory = GST_ELEMENT_FACTORY (feature);
872
873     align (*in);
874     GST_LOG ("Reading/casting for GstBinaryElementFactory at address %p", *in);
875     unpack_element (*in, ef, GstBinaryElementFactory);
876     pf = (GstBinaryPluginFeature *) ef;
877
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);
885
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");
890         goto fail;
891       }
892     }
893
894     /* load uritypes */
895     if (ef->nuriprotocols) {
896       GST_DEBUG ("Reading %d UriTypes at address %p", ef->nuriprotocols, *in);
897
898       align (*in);
899       factory->uri_type = *((guint *) * in);
900       *in += sizeof (factory->uri_type);
901       //unpack_element(*in, &factory->uri_type, factory->uri_type);
902
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;
907       }
908     }
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);
914       g_free (str);
915     }
916   } else if (GST_IS_TYPE_FIND_FACTORY (feature)) {
917     GstBinaryTypeFindFactory *tff;
918     GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (feature);
919
920     align (*in);
921     GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
922     unpack_element (*in, tff, GstBinaryTypeFindFactory);
923     pf = (GstBinaryPluginFeature *) tff;
924
925     /* load caps */
926     unpack_string (*in, str);
927     factory->caps = gst_caps_from_string (str);
928     g_free (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;
937       }
938     }
939   }
940 #ifndef GST_DISABLE_INDEX
941   else if (GST_IS_INDEX_FACTORY (feature)) {
942     GstIndexFactory *factory = GST_INDEX_FACTORY (feature);
943
944     align (*in);
945     GST_DEBUG ("Reading/casting for GstBinaryPluginFeature at address %p", *in);
946     unpack_element (*in, pf, GstBinaryPluginFeature);
947
948     /* unpack index factory strings */
949     unpack_string (*in, factory->longdesc);
950   }
951 #endif
952
953   feature->rank = pf->rank;
954
955   /* should already be the interned string, but better make sure */
956   feature->plugin_name = g_intern_string (plugin_name);
957
958   gst_registry_add_feature (registry, feature);
959   GST_DEBUG ("Added feature %s", feature->name);
960
961   g_free (type_name);
962   return TRUE;
963
964   /* Errors */
965 fail:
966   g_free (type_name);
967   if (GST_IS_OBJECT (feature))
968     gst_object_unref (feature);
969   else
970     g_object_unref (feature);
971   return FALSE;
972 }
973
974
975 /*
976  * gst_registry_binary_load_plugin:
977  *
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.
981  */
982 static gboolean
983 gst_registry_binary_load_plugin (GstRegistry * registry, gchar ** in)
984 {
985   GstBinaryPluginElement *pe;
986   GstPlugin *plugin = NULL;
987   guint i;
988
989   align (*in);
990   GST_LOG ("Reading/casting for GstBinaryPluginElement at address %p", *in);
991   unpack_element (*in, pe, GstBinaryPluginElement);
992
993   if (pe->nfeatures < 0) {
994     GST_ERROR ("The number of feature structure is not valid !");
995     return FALSE;
996   }
997
998   if (pe->file_mtime < 0 || pe->file_size < 0) {
999     GST_ERROR ("Plugin time or file size is not valid !");
1000     return FALSE;
1001   }
1002
1003   plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
1004
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;
1009
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);
1020
1021   plugin->basename = g_path_get_basename (plugin->filename);
1022
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");
1030       goto fail;
1031     }
1032   }
1033
1034   return TRUE;
1035
1036   /* Errors */
1037 fail:
1038   return FALSE;
1039 }
1040
1041
1042 /**
1043  * gst_registry_binary_read_cache:
1044  * @registry: a #GstRegistry
1045  * @location: a filename
1046  *
1047  * Read the contents of the binary cache file at @location into @registry.
1048  *
1049  * Returns: %TRUE on success.
1050  */
1051 gboolean
1052 gst_registry_binary_read_cache (GstRegistry * registry, const char *location)
1053 {
1054   GMappedFile *mapped = NULL;
1055   GTimer *timer = NULL;
1056   gchar *contents = NULL;
1057   gchar *in = NULL;
1058   gdouble seconds;
1059   gsize size;
1060   GError *err = NULL;
1061   gboolean res = FALSE;
1062   gint check_magic_result;
1063
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;
1069 #endif
1070
1071   timer = g_timer_new ();
1072
1073   mapped = g_mapped_file_new (location, FALSE, &err);
1074   if (err != NULL) {
1075     GST_INFO ("Unable to mmap file %s : %s", location, err->message);
1076     g_error_free (err);
1077     err = NULL;
1078
1079     g_file_get_contents (location, &contents, &size, &err);
1080     if (err != NULL) {
1081       GST_INFO ("Unable to read file %s : %s", location, err->message);
1082       g_timer_destroy (timer);
1083       g_error_free (err);
1084       return FALSE;
1085     }
1086   } else {
1087     if ((contents = g_mapped_file_get_contents (mapped)) == NULL) {
1088       GST_ERROR ("Can't load file %s : %s", location, g_strerror (errno));
1089       goto Error;
1090     }
1091     /* check length for header */
1092     size = g_mapped_file_get_length (mapped);
1093   }
1094   /* in is a cursor pointer, we initialize it with the begin of registry and is updated on each read */
1095   in = contents;
1096   GST_DEBUG ("File data at address %p", in);
1097   if (size < sizeof (GstBinaryRegistryMagic)) {
1098     GST_ERROR ("No or broken registry header");
1099     goto Error;
1100   }
1101   /* check if header is valid */
1102   if ((check_magic_result = gst_registry_binary_check_magic (&in, size)) < 0) {
1103
1104     if (check_magic_result == -1)
1105       GST_ERROR
1106           ("Binary registry type not recognized (invalid magic) for file at %s",
1107           location);
1108     goto Error;
1109   }
1110
1111   /* check if there are plugins in the file */
1112
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 */
1117   } else {
1118     for (;
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");
1126         goto Error;
1127       }
1128     }
1129   }
1130
1131   g_timer_stop (timer);
1132   seconds = g_timer_elapsed (timer, NULL);
1133
1134   GST_INFO ("loaded %s in %lf seconds", location, seconds);
1135
1136   res = TRUE;
1137   /* TODO: once we re-use the pointers to registry contents return here */
1138
1139 Error:
1140   g_timer_destroy (timer);
1141   if (mapped) {
1142     g_mapped_file_free (mapped);
1143   } else {
1144     g_free (contents);
1145   }
1146   return res;
1147 }
1148
1149
1150 /* FIXME 0.11: these are here for backwards compatibility */
1151
1152 gboolean
1153 gst_registry_xml_read_cache (GstRegistry * registry, const char *location)
1154 {
1155   return FALSE;
1156 }
1157
1158 gboolean
1159 gst_registry_xml_write_cache (GstRegistry * registry, const char *location)
1160 {
1161   return FALSE;
1162 }