|
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 } |