aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/mimesh/libg3d-0.0.8/src/plugins.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/src/plugins.c')
-rw-r--r--src/others/mimesh/libg3d-0.0.8/src/plugins.c560
1 files changed, 560 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/src/plugins.c b/src/others/mimesh/libg3d-0.0.8/src/plugins.c
new file mode 100644
index 0000000..740347f
--- /dev/null
+++ b/src/others/mimesh/libg3d-0.0.8/src/plugins.c
@@ -0,0 +1,560 @@
1/* $Id$ */
2
3/*
4 libg3d - 3D object loading library
5
6 Copyright (C) 2005-2009 Markus Dahms <mad@automagically.de>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
23#include <stdlib.h>
24#include <sys/param.h> /* PATH_MAX */
25
26#include <string.h>
27#include <unistd.h>
28
29#include <g3d/config.h>
30#include <g3d/stream.h>
31#include <g3d/types.h>
32#include <g3d/plugins.h>
33
34#include <curl/curl.h>
35
36static void plugins_free_plugin(G3DPlugin *plugin)
37{
38 if(plugin->name)
39 g_free(plugin->name);
40 if(plugin->path)
41 g_free(plugin->path);
42 if(plugin->extensions)
43 g_strfreev(plugin->extensions);
44
45 if(plugin->module)
46 g_module_close(plugin->module);
47
48 g_free(plugin);
49}
50
51#define PLUGIN_GET_SYMBOL(symbol, pointer) \
52 do { \
53 if(g_module_symbol(plugin->module, symbol, \
54 (gpointer *)&(pointer)) != TRUE) \
55 pointer = NULL; \
56 } while(0);
57
58static gboolean plugins_loaddirectory(G3DContext *context,
59 const gchar *dirname)
60{
61 GDir *plugindir;
62 G3DPlugin *plugin;
63 gchar **ext, **exts;
64 gchar *path;
65 const gchar *filename;
66 guint32 type = G3D_PLUGIN_UNKNOWN;
67
68 plugindir = g_dir_open(dirname, 0, NULL);
69 if(!plugindir)
70 return FALSE;
71
72 while((filename = g_dir_read_name(plugindir)) != NULL) {
73#ifdef G_OS_WIN32
74 if(g_strcasecmp(filename + strlen(filename) - 4, ".dll") == 0) {
75#else
76/* if(g_strcasecmp(filename + strlen(filename) - 3, ".la") == 0) { */
77 if(g_strcasecmp(filename + strlen(filename) - 3, ".so") == 0) {
78#endif
79 plugin = g_new0(G3DPlugin, 1);
80
81 plugin->name = g_strdup(filename);
82 plugin->path = g_strdup(dirname);
83
84 path = g_strdup_printf("%s%c%s", dirname, G_DIR_SEPARATOR, filename);
85
86 g_warning("libg3d: plugins: loading %s", path);
87 plugin->module = g_module_open(path, 0);
88 if(plugin->module == NULL) {
89 g_warning("libg3d: plugins: failed to load %s: %s", path, g_module_error());
90
91 plugins_free_plugin(plugin);
92 } else {
93 PLUGIN_GET_SYMBOL("plugin_extensions", plugin->ext_func);
94 PLUGIN_GET_SYMBOL("plugin_description", plugin->desc_func);
95 PLUGIN_GET_SYMBOL("plugin_init", plugin->init_func);
96 PLUGIN_GET_SYMBOL("plugin_cleanup", plugin->cleanup_func);
97 PLUGIN_GET_SYMBOL("plugin_load_model_from_stream",
98 plugin->loadmodelstream_func);
99 PLUGIN_GET_SYMBOL("plugin_load_image_from_stream",
100 plugin->loadimagestream_func);
101
102 if (plugin->loadimagestream_func)
103 type = G3D_PLUGIN_IMAGE;
104 if (plugin->loadmodelstream_func)
105 type = G3D_PLUGIN_IMPORT;
106 plugin->type = type;
107
108 /* append plugin to list */
109 context->plugins = g_slist_append(context->plugins, plugin);
110
111 /* handle managed extensions */
112 if(plugin->ext_func) {
113 ext = exts = plugin->ext_func(context);
114 while(*ext != NULL) {
115 if(plugin->type == G3D_PLUGIN_IMAGE)
116 g_hash_table_insert(context->exts_image,
117 *ext, plugin);
118 else if(plugin->type == G3D_PLUGIN_IMPORT)
119 g_hash_table_insert(context->exts_import,
120 *ext, plugin);
121
122 ext ++;
123 }
124 plugin->extensions = exts;
125 }
126
127 /* init plugin if possible */
128 if(plugin->init_func)
129 {
130 plugin->user_data = plugin->init_func(context);
131 }
132
133 } /* plugin->module != NULL */
134
135 g_free(path);
136 } /* .la file */
137
138 } /* while g_dir_read_name(...) */
139
140 g_dir_close(plugindir);
141
142 return TRUE;
143}
144
145#undef PLUGIN_GET_SYMBOL
146
147#ifdef USE_LIBMAGIC
148
149static gboolean plugins_magic_init(G3DContext *context)
150{
151 context->magic_cookie = magic_open(
152 MAGIC_SYMLINK
153#if 0
154 | MAGIC_CHECK
155#endif
156#if DEBUG > 2
157 | MAGIC_DEBUG
158#endif
159 );
160
161#if DEBUG > 0
162 g_debug("checking and loading %s", MAGIC_FILENAME);
163#endif
164
165 if(context->magic_cookie == NULL) {
166 g_warning("magic_open() failed");
167 return FALSE;
168 }
169
170 if(magic_load(context->magic_cookie, MAGIC_FILENAME) != 0) {
171 g_warning("magic_load() failed: %s (%d)",
172 magic_error(context->magic_cookie),
173 magic_errno(context->magic_cookie));
174 magic_close(context->magic_cookie);
175 context->magic_cookie = NULL;
176 return FALSE;
177 }
178
179 return TRUE;
180}
181
182static void plugins_magic_cleanup(G3DContext *context)
183{
184 if(context->magic_cookie != NULL)
185 magic_close(context->magic_cookie);
186 context->magic_cookie = NULL;
187}
188
189static G3DPlugin *plugins_magic_lookup(G3DContext *context,
190 const gchar *filename)
191{
192 gchar *name;
193 const gchar *type;
194 GSList *item;
195 G3DPlugin *tp, *plugin = NULL;
196
197 if(context->magic_cookie == NULL)
198 return NULL;
199
200 type = magic_file(context->magic_cookie, filename);
201 if((type == NULL) || (strlen(type) == 0))
202 return NULL;
203
204 name = g_strdup_printf("imp_%s.la", type);
205 for(item = context->plugins; item != NULL; item = item->next) {
206 tp = (G3DPlugin *)item->data;
207 if(tp->type != G3D_PLUGIN_IMPORT)
208 continue;
209
210 if(strcmp(name, tp->name) == 0)
211 plugin = tp;
212 }
213 g_free(name);
214
215#if DEBUG > 0
216 if(plugin != NULL)
217 g_debug("libmagic detected plugin %s for %s",
218 plugin->name, filename);
219#endif
220
221 return plugin;
222}
223
224#endif /* USE_LIBMAGIC */
225
226EAPI
227gboolean g3d_plugins_init(G3DContext *context)
228{
229 context->exts_import = g_hash_table_new(g_str_hash, g_str_equal);
230 context->exts_image = g_hash_table_new(g_str_hash, g_str_equal);
231
232#ifdef G_OS_WIN32
233 plugins_loaddirectory(context, "plugins");
234#else
235 plugins_loaddirectory(context, PLUGIN_DIR);
236#endif
237
238#ifdef USE_LIBMAGIC
239 plugins_magic_init(context);
240#endif
241
242 return TRUE;
243}
244
245/**
246 * g3d_plugins_cleanup:
247 * @context: an initialized context
248 *
249 * Tries to free any memory allocated during g3d_plugins_init.
250 */
251
252EAPI
253void g3d_plugins_cleanup(G3DContext *context)
254{
255 GSList *plist;
256 G3DPlugin *plugin;
257 gchar **pext;
258
259#ifdef USE_LIBMAGIC
260 plugins_magic_cleanup(context);
261#endif
262
263 plist = context->plugins;
264 while(plist)
265 {
266 plugin = (G3DPlugin *)plist->data;
267
268#if DEBUG > 2
269 g_debug("cleaning up plugin '%s'", plugin->name);
270#endif
271
272 /* cleanup plugin-specific data */
273 if(plugin->cleanup_func)
274 plugin->cleanup_func(plugin->user_data);
275
276 /* remove extensions from hash tables */
277 pext = plugin->extensions;
278 while(*pext)
279 {
280 if(plugin->type == G3D_PLUGIN_IMAGE)
281 g_hash_table_remove(context->exts_image, *pext);
282 else if(plugin->type == G3D_PLUGIN_IMPORT)
283 g_hash_table_remove(context->exts_import, *pext);
284
285 pext ++;
286 }
287
288 /* cleanup struct data */
289 plugins_free_plugin(plugin);
290
291 /* free list item */
292 plist = g_slist_remove(plist, plugin);
293 }
294
295 /* remove hash tables */
296 g_hash_table_destroy(context->exts_image);
297 g_hash_table_destroy(context->exts_import);
298}
299
300gchar *g3d_plugins_get_filetype(const gchar *filename)
301{
302 gchar *ext, *lcext;
303
304 ext = strrchr(filename, '.');
305 if(ext == NULL) {
306 g_warning("can't determine file type: %s", filename);
307 return NULL;
308 }
309 ext ++;
310 if(strlen(ext) == 0) {
311 g_warning("zero length file extension: %s", filename);
312 return NULL;
313 }
314
315 lcext = g_strdup(ext);
316 g_strdown(lcext);
317
318 return lcext;
319}
320
321static G3DPlugin *get_plugin_for_type(G3DContext *context,
322 const gchar *filename)
323{
324 G3DPlugin *plugin = NULL;
325 gchar *lcext;
326
327#ifdef USE_LIBMAGIC
328 plugin = plugins_magic_lookup(context, filename);
329#endif
330
331 if(plugin == NULL)
332 {
333 /* try to get type by extension */
334 lcext = g3d_plugins_get_filetype(filename);
335 if(lcext == NULL)
336 return NULL;
337
338 plugin = g_hash_table_lookup(context->exts_import, lcext);
339
340 g_free(lcext);
341 }
342
343 if(plugin == NULL)
344 {
345 g_warning("no handler for file '%s' found", filename);
346 return NULL;
347 }
348
349 return plugin;
350}
351
352struct httpBuffer
353{
354 void *buffer;
355 size_t size;
356 size_t max;
357};
358
359static size_t curlWrite(void *ptr, size_t size, size_t nmemb, void *userData)
360{
361 struct httpBuffer *result = (struct httpBuffer *) userData;
362 size_t bytes = size * nmemb;
363
364 if ((result->size + bytes) > result->max)
365 {
366 result->max += bytes;
367 result->buffer = realloc(result->buffer, result->max);
368 }
369 if (result->buffer)
370 {
371 memcpy(result->buffer + result->size, ptr, bytes);
372 result->size += bytes;
373 }
374 else
375 g_warning("curlWrite() ran out of memory.");
376
377 return nmemb;
378}
379
380EAPI
381gboolean g3d_plugins_load_model(G3DContext *context, const gchar *filename,
382 G3DModel *model)
383{
384 G3DPlugin *plugin = NULL;
385 G3DStream *stream;
386 gboolean retval = FALSE;
387
388 plugin = get_plugin_for_type(context, filename);
389 if(plugin == NULL)
390 return FALSE;
391
392 if (strncmp(filename, "http://", 6) == 0)
393 {
394 struct httpBuffer result;
395#if 0
396 char curlErrorBuffer[CURL_ERROR_SIZE];
397 CURLcode curlSuccess;
398 long httpStatus = 499;
399 CURL* curlp = curl_easy_init();
400
401 result.size = 0;
402 result.max = 0;
403 result.buffer = NULL;
404
405 curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); /* don't use SIGALRM for timeouts */
406 curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 30); /* seconds */
407 curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, curlWrite);
408 curl_easy_setopt(curlp, CURLOPT_WRITEDATA, &result);
409 curl_easy_setopt(curlp, CURLOPT_URL, filename);
410 curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curlErrorBuffer);
411 curl_easy_setopt(curlp, CURLOPT_FAILONERROR, 1);
412
413 curlSuccess = curl_easy_perform(curlp);
414 curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &httpStatus);
415 if (curlSuccess != 0)
416 g_warning("CURL ERROR (HTTP Status %ld): %s", httpStatus, curlErrorBuffer);
417 else if (httpStatus != 200)
418 g_warning("HTTP Error %ld, but no Curl error.", httpStatus);
419 else
420 g_debug("CURL got the file %s", filename);
421
422 stream = g3d_stream_from_buffer(result.buffer, result.size, filename, FALSE);
423 if(stream)
424 {
425 model->stream = stream;
426 retval = plugin->loadmodelstream_func(context, stream, model, plugin->user_data);
427 g3d_stream_close(stream);
428 }
429 else
430 g_warning("failed to open '%s'", filename);
431
432 curl_easy_cleanup(curlp);
433 if (result.buffer)
434 free(result.buffer);
435#endif
436 }
437 else /* It's a file. */
438 {
439 gchar *basename, *dirname;
440 gchar *olddir;
441
442 basename = g_path_get_basename(filename);
443 dirname = g_path_get_dirname(filename);
444
445 olddir = g_get_current_dir();
446 /* TODO: since glib 2.8 there is a g_chdir() wrapper, use it if
447 * for some reason a glib >= 2.8 is required */
448 chdir(dirname);
449
450 if(plugin->loadmodelstream_func != NULL) {
451 /* try to load the model via the more generic G3DStream interface */
452 stream = g3d_stream_open_file(basename, "rb");
453 if(stream) {
454 model->stream = stream;
455 retval = plugin->loadmodelstream_func(context, stream, model,
456 plugin->user_data);
457 g3d_stream_close(stream);
458 }
459 else {
460 g_warning("failed to open '%s'", basename);
461 }
462 }
463 else
464 g_warning("No plugin_load_model_from_stream() for '%s'", basename);
465 g_free(basename);
466 g_free(dirname);
467
468 chdir(olddir);
469 g_free(olddir);
470 }
471
472 if(retval)
473 model->plugin = plugin;
474
475 return retval;
476}
477
478EAPI
479gboolean g3d_plugins_load_model_from_stream(G3DContext *context,
480 G3DStream *stream, G3DModel *model)
481{
482 G3DPlugin *plugin = NULL;
483
484/* g_return_val_if_fail(stream != NULL, FALSE); */
485
486 plugin = get_plugin_for_type(context, stream->uri);
487 if(plugin == NULL)
488 return FALSE;
489
490 if((plugin->loadmodelstream_func != NULL) && plugin->loadmodelstream_func(
491 context, stream, model, plugin->user_data)) {
492 model->plugin = plugin;
493 return TRUE;
494 }
495 return FALSE;
496}
497
498EAPI
499gboolean g3d_plugins_load_image_from_stream(G3DContext *context,
500 G3DStream *stream, G3DImage *image)
501{
502 G3DPlugin *plugin;
503 gchar *lcext;
504
505 lcext = g3d_plugins_get_filetype(stream->uri);
506 if(lcext == NULL)
507 return FALSE;
508
509 plugin = g_hash_table_lookup(context->exts_image, lcext);
510 if(plugin == NULL) {
511 g_warning("no handler for filetype '.%s' found", lcext);
512 g_free(lcext);
513 return FALSE;
514 }
515 g_free(lcext);
516
517 if(plugin->loadimagestream_func == NULL) {
518 g_warning("can't find symbol 'plugin_load_image_from_stream' in %s",
519 plugin->name);
520 return FALSE;
521 }
522
523 return plugin->loadimagestream_func(context, stream, image,
524 plugin->user_data);
525}
526
527struct plugins_ext_list {
528 guint32 pos;
529 gchar **list;
530};
531
532static void plugins_list_ext(gpointer key, gpointer value, gpointer user_data)
533{
534 struct plugins_ext_list *data;
535
536 data = (struct plugins_ext_list *)user_data;
537
538 data->list[data->pos] = g_strdup(key);
539 data->pos ++;
540}
541
542EAPI
543gchar **g3d_plugins_get_image_extensions(G3DContext *context)
544{
545 gchar **list;
546 guint32 n;
547 struct plugins_ext_list data;
548
549 n = g_hash_table_size(context->exts_image);
550 list = g_new0(gchar *, n + 1);
551
552 data.pos = 0;
553 data.list = list;
554
555 /* fill extension list */
556 g_hash_table_foreach(context->exts_image, plugins_list_ext, &data);
557
558 return list;
559}
560