gdk-pixbuf-io.c 68.1 KB
Newer Older
1
/* -*- mode: C; c-file-style: "linux" -*- */
2
/* GdkPixbuf library - Main loading interface.
Arturo Espinosa's avatar
Arturo Espinosa committed
3
 *
4 5 6 7 8 9
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Authors: Miguel de Icaza <miguel@gnu.org>
 *          Federico Mena-Quintero <federico@gimp.org>
 *
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11 12 13 14 15 16
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20 21 22
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Arturo Espinosa's avatar
Arturo Espinosa committed
23
 */
24

25
#include "config.h"
26

27 28
#include <stdlib.h>
#include <stdio.h>
29
#include <string.h>
30
#include <errno.h>
31 32 33 34
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

35 36 37
#include <glib.h>
#include <gio/gio.h>

38
#include "gdk-pixbuf-private.h"
39
#include "gdk-pixbuf-io.h"
40
#include "gdk-pixbuf-loader.h"
41
#include "gdk-pixbuf-alias.h"
Arturo Espinosa's avatar
Arturo Espinosa committed
42

43 44
#include <glib/gstdio.h>

45 46 47 48 49 50
#ifdef G_OS_WIN32
#define STRICT
#include <windows.h>
#undef STRICT
#endif

51 52 53
#define SNIFF_BUFFER_SIZE 4096
#define LOAD_BUFFER_SIZE 65536

54
#ifndef GDK_PIXBUF_USE_GIO_MIME 
55 56
static gint 
format_check (GdkPixbufModule *module, guchar *buffer, int size)
57
{
58
	int i, j;
59 60
	gchar m;
	GdkPixbufModulePattern *pattern;
61
	gboolean anchored;
Matthias Clasen's avatar
Matthias Clasen committed
62 63
	guchar *prefix;
	gchar *mask;
64 65

	for (pattern = module->info->signature; pattern->prefix; pattern++) {
66
		if (pattern->mask && pattern->mask[0] == '*') {
Matthias Clasen's avatar
Matthias Clasen committed
67
			prefix = (guchar *)pattern->prefix + 1;
68
			mask = pattern->mask + 1;
69
			anchored = FALSE;
70 71
		}
		else {
Matthias Clasen's avatar
Matthias Clasen committed
72
			prefix = (guchar *)pattern->prefix;
73
			mask = pattern->mask;
74
			anchored = TRUE;
75
		}
76
		for (i = 0; i < size; i++) {
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
			for (j = 0; i + j < size && prefix[j] != 0; j++) {
				m = mask ? mask[j] : ' ';
				if (m == ' ') {
					if (buffer[i + j] != prefix[j])
						break;
				}
				else if (m == '!') {
					if (buffer[i + j] == prefix[j])
						break;
				}
				else if (m == 'z') {
					if (buffer[i + j] != 0)
						break;
				}
				else if (m == 'n') {
					if (buffer[i + j] == 0)
						break;
				}
			} 
96

97 98
			if (prefix[j] == 0) 
				return pattern->relevance;
99 100 101

			if (anchored)
				break;
102
		}
103 104
	}
	return 0;
105
}
106
#endif
107

108 109 110
G_LOCK_DEFINE_STATIC (init_lock);
G_LOCK_DEFINE_STATIC (threadunsafe_loader_lock);

111
gboolean
112 113
_gdk_pixbuf_lock (GdkPixbufModule *image_module)
{
114 115
 	if (g_threads_got_initialized &&
	    !(image_module->info->flags & GDK_PIXBUF_FORMAT_THREADSAFE)) {
116
 		G_LOCK (threadunsafe_loader_lock);
117 118

		return TRUE;
119
 	}
120 121

	return FALSE;
122 123 124 125 126 127 128 129 130 131
}
 
void
_gdk_pixbuf_unlock (GdkPixbufModule *image_module)
{
	if (!(image_module->info->flags & GDK_PIXBUF_FORMAT_THREADSAFE)) {
		G_UNLOCK (threadunsafe_loader_lock);
	}
}

132
static GSList *file_formats = NULL;
133

Matthias Clasen's avatar
Matthias Clasen committed
134
static void gdk_pixbuf_io_init (void);
135

136
static GSList *
Matthias Clasen's avatar
Matthias Clasen committed
137
get_file_formats (void)
138
{
139
	G_LOCK (init_lock);
140 141
	if (file_formats == NULL)
		gdk_pixbuf_io_init ();
142
	G_UNLOCK (init_lock);
143 144
	
	return file_formats;
145 146
}

147

148
#ifdef USE_GMODULE 
149 150

static gboolean
151
scan_string (const char **pos, GString *out)
152
{
153 154 155 156 157 158 159 160
	const char *p = *pos, *q = *pos;
	char *tmp, *tmp2;
	gboolean quoted;
	
	while (g_ascii_isspace (*p))
		p++;
	
	if (!*p)
161
		return FALSE;
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
	else if (*p == '"') {
		p++;
		quoted = FALSE;
		for (q = p; (*q != '"') || quoted; q++) {
			if (!*q)
				return FALSE;
			quoted = (*q == '\\') && !quoted;
		}
		
		tmp = g_strndup (p, q - p);
		tmp2 = g_strcompress (tmp);
		g_string_truncate (out, 0);
		g_string_append (out, tmp2);
		g_free (tmp);
		g_free (tmp2);
177
	}
178 179 180 181
	
	q++;
	*pos = q;
	
182 183 184
	return TRUE;
}

185
static gboolean
186
scan_int (const char **pos, int *out)
187
{
188 189 190 191 192 193 194 195
	int i = 0;
	char buf[32];
	const char *p = *pos;
	
	while (g_ascii_isspace (*p))
		p++;
	
	if (*p < '0' || *p > '9')
196
		return FALSE;
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	
	while ((*p >= '0') && (*p <= '9') && i < sizeof (buf)) {
		buf[i] = *p;
		i++;
		p++;
	}
	
	if (i == sizeof (buf))
  		return FALSE;
	else
		buf[i] = '\0';
	
	*out = atoi (buf);
	
	*pos = p;
212 213 214 215

	return TRUE;
}

216
static gboolean
217
skip_space (const char **pos)
218
{
219 220 221 222 223 224 225 226
	const char *p = *pos;
	
	while (g_ascii_isspace (*p))
		p++;
  
	*pos = p;
	
	return !(*p == '\0');
227
}
228
  
229 230
#ifdef G_OS_WIN32

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
/* DllMain function needed to tuck away the gdk-pixbuf DLL handle */

static HMODULE gdk_pixbuf_dll;

BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
	 DWORD     fdwReason,
	 LPVOID    lpvReserved)
{
	switch (fdwReason) {
	case DLL_PROCESS_ATTACH:
		gdk_pixbuf_dll = (HMODULE) hinstDLL;
		break;
	}

  return TRUE;
}
248 249 250 251 252 253 254

static char *
get_toplevel (void)
{
  static char *toplevel = NULL;

  if (toplevel == NULL)
255
	  toplevel = g_win32_get_package_installation_directory_of_module (gdk_pixbuf_dll);
256 257 258 259 260 261 262 263 264 265

  return toplevel;
}

static char *
get_sysconfdir (void)
{
  static char *sysconfdir = NULL;

  if (sysconfdir == NULL)
266
	  sysconfdir = g_build_filename (get_toplevel (), "etc", NULL);
267 268 269 270 271 272 273 274 275 276 277 278 279

  return sysconfdir;
}

#undef GTK_SYSCONFDIR
#define GTK_SYSCONFDIR get_sysconfdir()

static void
correct_prefix (gchar **path)
{
  if (strncmp (*path, GTK_PREFIX "/", strlen (GTK_PREFIX "/")) == 0 ||
      strncmp (*path, GTK_PREFIX "\\", strlen (GTK_PREFIX "\\")) == 0)
    {
280
	  gchar *tem = NULL;
281 282 283 284 285 286
      if (strlen(*path) > 5 && strncmp (*path - 5, ".libs", 5) == 0)
        {
          /* We are being run from inside the build tree, and shouldn't mess about. */
          return;
	}

287 288 289 290 291 292 293
      /* This is an entry put there by gdk-pixbuf-query-loaders on the
       * packager's system. On Windows a prebuilt GTK+ package can be
       * installed in a random location. The gdk-pixbuf.loaders file
       * distributed in such a package contains paths from the package
       * builder's machine. Replace the build-time prefix with the
       * installation prefix on this machine.
       */
294
      tem = *path;
295 296 297 298 299
      *path = g_strconcat (get_toplevel (), tem + strlen (GTK_PREFIX), NULL);
      g_free (tem);
    }
}

300
#endif  /* G_OS_WIN32 */
301

302 303
static gchar *
gdk_pixbuf_get_module_file (void)
304
{
305
  gchar *result = g_strdup (g_getenv ("GDK_PIXBUF_MODULE_FILE"));
306

307 308
  if (!result)
	  result = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gdk-pixbuf.loaders", NULL);
309

310
  return result;
311 312
}

313 314
#endif	/* USE_GMODULE */

315 316 317 318 319

static gboolean
gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
				 GError         **error);

320
static void 
Matthias Clasen's avatar
Matthias Clasen committed
321
gdk_pixbuf_io_init (void)
322
{
323
#ifdef USE_GMODULE
324 325 326 327 328 329 330 331 332 333 334
	GIOChannel *channel;
	gchar *line_buf;
	gsize term;
	GString *tmp_buf = g_string_new (NULL);
	gboolean have_error = FALSE;
	GdkPixbufModule *module = NULL;
	gchar *filename = gdk_pixbuf_get_module_file ();
	int flags;
	int n_patterns = 0;
	GdkPixbufModulePattern *pattern;
	GError *error = NULL;
335
#endif
336 337 338 339 340 341
	GdkPixbufModule *builtin_module ;

        /*  initialize on separate line to avoid compiler warnings in the
         *  common case of no compiled-in modules.
         */
	builtin_module = NULL;
342 343 344 345

#define load_one_builtin_module(format)					\
	builtin_module = g_new0 (GdkPixbufModule, 1);			\
	builtin_module->module_name = #format;				\
346
	if (gdk_pixbuf_load_module_unlocked (builtin_module, NULL))		\
347 348 349
		file_formats = g_slist_prepend (file_formats, builtin_module);\
	else								\
		g_free (builtin_module)
350

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
#ifdef INCLUDE_ani
	load_one_builtin_module (ani);
#endif
#ifdef INCLUDE_png
	load_one_builtin_module (png);
#endif
#ifdef INCLUDE_bmp
	load_one_builtin_module (bmp);
#endif
#ifdef INCLUDE_wbmp
	load_one_builtin_module (wbmp);
#endif
#ifdef INCLUDE_gif
	load_one_builtin_module (gif);
#endif
#ifdef INCLUDE_ico
	load_one_builtin_module (ico);
#endif
#ifdef INCLUDE_jpeg
	load_one_builtin_module (jpeg);
#endif
#ifdef INCLUDE_pnm
	load_one_builtin_module (pnm);
#endif
#ifdef INCLUDE_ras
	load_one_builtin_module (ras);
#endif
#ifdef INCLUDE_tiff
	load_one_builtin_module (tiff);
#endif
#ifdef INCLUDE_xpm
	load_one_builtin_module (xpm);
#endif
#ifdef INCLUDE_xbm
	load_one_builtin_module (xbm);
#endif
#ifdef INCLUDE_tga
	load_one_builtin_module (tga);
#endif
#ifdef INCLUDE_pcx
	load_one_builtin_module (pcx);
#endif
393 394 395 396 397 398
#ifdef INCLUDE_icns
	load_one_builtin_module (icns);
#endif
#ifdef INCLUDE_jasper
	load_one_builtin_module (jasper);
#endif
Kevin Peng's avatar
Kevin Peng committed
399 400 401
#ifdef INCLUDE_qtif
	load_one_builtin_module (qtif);
#endif
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
#ifdef INCLUDE_gdiplus
	/* We don't bother having the GDI+ loaders individually selectable
	 * for building in or not.
	 */
	load_one_builtin_module (ico);
	load_one_builtin_module (wmf);
	load_one_builtin_module (emf);
	load_one_builtin_module (bmp);
	load_one_builtin_module (gif);
	load_one_builtin_module (jpeg);
	load_one_builtin_module (tiff);
#endif
#ifdef INCLUDE_gdip_png
	/* Except the gdip-png loader which normally isn't built at all even */
	load_one_builtin_module (png);
#endif
418 419 420 421

#undef load_one_builtin_module

#ifdef USE_GMODULE
422 423
	channel = g_io_channel_new_file (filename, "r",  &error);
	if (!channel) {
424 425 426 427
		/* Don't bother warning if we have some built-in loaders */
		if (file_formats == NULL)
			g_warning ("Cannot open pixbuf loader module file '%s': %s",
				   filename, error->message);
Matthias Clasen's avatar
Matthias Clasen committed
428
		g_string_free (tmp_buf, TRUE);
429
		g_free (filename);
430 431 432 433 434 435 436
		return;
	}
	
	while (!have_error && g_io_channel_read_line (channel, &line_buf, NULL, &term, NULL) == G_IO_STATUS_NORMAL) {
		const char *p;
		
		p = line_buf;
437

438
		line_buf[term] = 0;
439

440 441 442 443
		if (!skip_space (&p)) {
				/* Blank line marking the end of a module
				 */
			if (module && *p != '#') {
444 445 446
#ifdef G_OS_WIN32
				correct_prefix (&module->module_path);
#endif
447 448 449 450 451 452
				file_formats = g_slist_prepend (file_formats, module);
				module = NULL;
			}
			
			goto next_line;
		}
Arturo Espinosa's avatar
Arturo Espinosa committed
453

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
		if (*p == '#') 
			goto next_line;
		
		if (!module) {
				/* Read a module location
				 */
			module = g_new0 (GdkPixbufModule, 1);
			n_patterns = 0;
			
			if (!scan_string (&p, tmp_buf)) {
				g_warning ("Error parsing loader info in '%s'\n  %s", 
					   filename, line_buf);
				have_error = TRUE;
			}
			module->module_path = g_strdup (tmp_buf->str);
		}
		else if (!module->module_name) {
			module->info = g_new0 (GdkPixbufFormat, 1);
			if (!scan_string (&p, tmp_buf)) {
				g_warning ("Error parsing loader info in '%s'\n  %s", 
					   filename, line_buf);
				have_error = TRUE;
			}
			module->info->name =  g_strdup (tmp_buf->str);
			module->module_name = module->info->name;
Federico Mena Quintero's avatar
Federico Mena Quintero committed
479

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
			if (!scan_int (&p, &flags)) {
				g_warning ("Error parsing loader info in '%s'\n  %s", 
					   filename, line_buf);
				have_error = TRUE;
			}
			module->info->flags = flags;
			
			if (!scan_string (&p, tmp_buf)) {
				g_warning ("Error parsing loader info in '%s'\n  %s", 
					   filename, line_buf);
				have_error = TRUE;
			}			
			if (tmp_buf->str[0] != 0)
				module->info->domain = g_strdup (tmp_buf->str);

			if (!scan_string (&p, tmp_buf)) {
				g_warning ("Error parsing loader info in '%s'\n  %s", 
					   filename, line_buf);
				have_error = TRUE;
			}			
			module->info->description = g_strdup (tmp_buf->str);
501 502 503 504

			if (scan_string (&p, tmp_buf)) {
				module->info->license = g_strdup (tmp_buf->str);
			}
505 506 507 508 509 510 511 512 513
		}
		else if (!module->info->mime_types) {
			int n = 1;
			module->info->mime_types = g_new0 (gchar*, 1);
			while (scan_string (&p, tmp_buf)) {
				if (tmp_buf->str[0] != 0) {
					module->info->mime_types =
						g_realloc (module->info->mime_types, (n + 1) * sizeof (gchar*));
					module->info->mime_types[n - 1] = g_strdup (tmp_buf->str);
Matthias Clasen's avatar
Matthias Clasen committed
514
					module->info->mime_types[n] = NULL;
515 516 517 518 519 520 521 522 523 524 525 526
					n++;
				}
			}
		}
		else if (!module->info->extensions) {
			int n = 1;
			module->info->extensions = g_new0 (gchar*, 1);
			while (scan_string (&p, tmp_buf)) {
				if (tmp_buf->str[0] != 0) {
					module->info->extensions =
						g_realloc (module->info->extensions, (n + 1) * sizeof (gchar*));
					module->info->extensions[n - 1] = g_strdup (tmp_buf->str);
Matthias Clasen's avatar
Matthias Clasen committed
527
					module->info->extensions[n] = NULL;
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
					n++;
				}
			}
		}
		else {
			n_patterns++;
			module->info->signature = (GdkPixbufModulePattern *)
				g_realloc (module->info->signature, (n_patterns + 1) * sizeof (GdkPixbufModulePattern));
			pattern = module->info->signature + n_patterns;
			pattern->prefix = NULL;
			pattern->mask = NULL;
			pattern->relevance = 0;
			pattern--;
			if (!scan_string (&p, tmp_buf))
				goto context_error;
			pattern->prefix = g_strdup (tmp_buf->str);
			
			if (!scan_string (&p, tmp_buf))
				goto context_error;
			if (*tmp_buf->str)
				pattern->mask = g_strdup (tmp_buf->str);
			else
				pattern->mask = NULL;
			
			if (!scan_int (&p, &pattern->relevance))
				goto context_error;
			
			goto next_line;

		context_error:
			g_free (pattern->prefix);
			g_free (pattern->mask);
			g_free (pattern);
			g_warning ("Error parsing loader info in '%s'\n  %s", 
				   filename, line_buf);
			have_error = TRUE;
		}
	next_line:
		g_free (line_buf);
	}
	g_string_free (tmp_buf, TRUE);
	g_io_channel_unref (channel);
	g_free (filename);
571
#endif
Federico Mena Quintero's avatar
Federico Mena Quintero committed
572
}
573

Federico Mena Quintero's avatar
Federico Mena Quintero committed
574

575
#define module(type) \
576 577
  extern void _gdk_pixbuf__##type##_fill_info   (GdkPixbufFormat *info);   \
  extern void _gdk_pixbuf__##type##_fill_vtable (GdkPixbufModule *module)
578 579

module (png);
580
module (jpeg);
581 582 583 584 585
module (gif);
module (ico);
module (ani);
module (ras);
module (xpm);
586 587 588 589
module (tiff);
module (pnm);
module (bmp);
module (wbmp);
590 591
module (xbm);
module (tga);
592
module (pcx);
593 594
module (icns);
module (jasper);
Kevin Peng's avatar
Kevin Peng committed
595
module (qtif);
596 597 598 599 600 601 602 603
module (gdip_ico);
module (gdip_wmf);
module (gdip_emf);
module (gdip_bmp);
module (gdip_gif);
module (gdip_jpeg);
module (gdip_png);
module (gdip_tiff);
Federico Mena Quintero's avatar
Federico Mena Quintero committed
604

605 606
#undef module

607 608 609 610 611 612
/* actually load the image handler - gdk_pixbuf_get_module only get a */
/* reference to the module to load, it doesn't actually load it       */
/* perhaps these actions should be combined in one function           */
static gboolean
gdk_pixbuf_load_module_unlocked (GdkPixbufModule *image_module,
				 GError         **error)
Federico Mena Quintero's avatar
Federico Mena Quintero committed
613
{
614 615
	GdkPixbufModuleFillInfoFunc fill_info = NULL;
        GdkPixbufModuleFillVtableFunc fill_vtable = NULL;
616 617 618
		
        if (image_module->module != NULL)
               return TRUE;
619

620
#define try_module(format,id)						\
621 622
	if (fill_info == NULL &&					\
	    strcmp (image_module->module_name, #format) == 0) {		\
623 624
                fill_info = _gdk_pixbuf__##id##_fill_info;		\
                fill_vtable = _gdk_pixbuf__##id##_fill_vtable;	\
Federico Mena Quintero's avatar
Federico Mena Quintero committed
625
	}
626
#ifdef INCLUDE_png	
627
	try_module (png,png);
628
#endif
629
#ifdef INCLUDE_bmp
630
	try_module (bmp,bmp);
631 632
#endif
#ifdef INCLUDE_wbmp
633
	try_module (wbmp,wbmp);
634 635
#endif
#ifdef INCLUDE_gif
636
	try_module (gif,gif);
637 638
#endif
#ifdef INCLUDE_ico
639
	try_module (ico,ico);
640
#endif
641
#ifdef INCLUDE_ani
642
	try_module (ani,ani);
643
#endif
644
#ifdef INCLUDE_jpeg
645
	try_module (jpeg,jpeg);
646 647
#endif
#ifdef INCLUDE_pnm
648
	try_module (pnm,pnm);
649 650
#endif
#ifdef INCLUDE_ras
651
	try_module (ras,ras);
652 653
#endif
#ifdef INCLUDE_tiff
654
	try_module (tiff,tiff);
655
#endif
656
#ifdef INCLUDE_xpm
657
	try_module (xpm,xpm);
658
#endif
659
#ifdef INCLUDE_xbm
660
	try_module (xbm,xbm);
661
#endif
662
#ifdef INCLUDE_tga
663
	try_module (tga,tga);
664
#endif
665
#ifdef INCLUDE_pcx
666 667
	try_module (pcx,pcx);
#endif
668 669 670 671 672 673
#ifdef INCLUDE_icns
	try_module (icns,icns);
#endif
#ifdef INCLUDE_jasper
	try_module (jasper,jasper);
#endif
Kevin Peng's avatar
Kevin Peng committed
674 675 676
#ifdef INCLUDE_qtif
	try_module (qtif,qtif);
#endif
677 678 679 680 681 682 683 684 685 686 687
#ifdef INCLUDE_gdiplus
	try_module (ico,gdip_ico);
	try_module (wmf,gdip_wmf);
	try_module (emf,gdip_emf);
	try_module (bmp,gdip_bmp);
	try_module (gif,gdip_gif);
	try_module (jpeg,gdip_jpeg);
	try_module (tiff,gdip_tiff);
#endif
#ifdef INCLUDE_gdip_png
	try_module (png,gdip_png);
688
#endif
689 690

#undef try_module
691
        
692
        if (fill_vtable) {
693
		image_module->module = (void *) 1;
694
                (* fill_vtable) (image_module);
Matthias Clasen's avatar
Matthias Clasen committed
695 696 697 698
		if (image_module->info == NULL) {
			image_module->info = g_new0 (GdkPixbufFormat, 1);
			(* fill_info) (image_module->info);
		}
699
                return TRUE;
700
	}
701
	else 
702
#ifdef USE_GMODULE
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
	{
		char *path;
		GModule *module;
		gpointer sym;

		path = image_module->module_path;
		module = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);

        	if (!module) {
                	g_set_error (error,
                             	     GDK_PIXBUF_ERROR,
                             	     GDK_PIXBUF_ERROR_FAILED,
                             	     _("Unable to load image-loading module: %s: %s"),
                             	     path, g_module_error ());
                	return FALSE;
        	}

		image_module->module = module;        
        
        	if (g_module_symbol (module, "fill_vtable", &sym)) {
                	fill_vtable = (GdkPixbufModuleFillVtableFunc) sym;
                	(* fill_vtable) (image_module);
                	return TRUE;
        	} else {
                	g_set_error (error,
                        	     GDK_PIXBUF_ERROR,
                             	     GDK_PIXBUF_ERROR_FAILED,
                             	     _("Image-loading module %s does not export the proper interface; perhaps it's from a different GTK version?"),
                             	     path);
                	return FALSE;
        	}
	}
735
#else
736 737 738
	g_set_error (error,
		     GDK_PIXBUF_ERROR,
		     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
739
		     _("Image type '%s' is not supported"),
740 741 742 743
		     image_module->module_name);
	return FALSE;
#endif  /* !USE_GMODULE */
}
744

745 746 747 748 749 750 751 752 753 754 755 756 757 758

gboolean
_gdk_pixbuf_load_module (GdkPixbufModule *image_module,
			 GError         **error)
{
	gboolean ret;
	gboolean locked = FALSE;

	/* be extra careful, maybe the module initializes
	 * the thread system
	 */
	if (g_threads_got_initialized) {
		G_LOCK (init_lock);
		locked = TRUE;
759
	}
760

761 762
        ret = gdk_pixbuf_load_module_unlocked (image_module, error);

763 764 765
	if (locked)
		G_UNLOCK (init_lock);

766
	return ret;
767
}
Arturo Espinosa's avatar
Arturo Espinosa committed
768

769 770


771
GdkPixbufModule *
772 773
_gdk_pixbuf_get_named_module (const char *name,
                              GError **error)
774
{
775
	GSList *modules;
776

777 778
	for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
		GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
779 780 781 782

		if (module->info->disabled)
			continue;

783 784
		if (!strcmp (name, module->module_name))
			return module;
785 786
	}

Havoc Pennington's avatar
Havoc Pennington committed
787 788 789 790 791 792
        g_set_error (error,
                     GDK_PIXBUF_ERROR,
                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
                     _("Image type '%s' is not supported"),
                     name);
        
793 794 795
	return NULL;
}

796
GdkPixbufModule *
797 798 799
_gdk_pixbuf_get_module (guchar *buffer, guint size,
                        const gchar *filename,
                        GError **error)
800
{
801 802 803
	GSList *modules;

	GdkPixbufModule *selected = NULL;
804
	gchar *display_name = NULL;
805 806 807
#ifdef GDK_PIXBUF_USE_GIO_MIME
	gchar *mime_type;
	gchar **mimes;
808
	gchar *type;
809
	gint j;
810
	gboolean uncertain;
811

812 813 814
	mime_type = g_content_type_guess (NULL, buffer, size, &uncertain);
	if (uncertain)
		mime_type = g_content_type_guess (filename, buffer, size, NULL);
815 816 817 818 819 820 821 822 823 824

	for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
		GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
		GdkPixbufFormat *info = module->info;

		if (info->disabled)
			continue;

		mimes = info->mime_types;
		for (j = 0; mimes[j] != NULL; j++) {
825 826 827
			type = g_content_type_from_mime_type (mimes[j]);
			if (g_ascii_strcasecmp (type, mime_type) == 0) {
				g_free (type);
828 829 830
				selected = module;
				break;
			}
831
			g_free (type);
832 833 834 835 836
		}
	}
	g_free (mime_type);
#else
	gint score, best = 0;
837

838 839
	for (modules = get_file_formats (); modules; modules = g_slist_next (modules)) {
		GdkPixbufModule *module = (GdkPixbufModule *)modules->data;
840 841 842 843

		if (module->info->disabled)
			continue;

844 845 846 847 848 849 850
		score = format_check (module, buffer, size);
		if (score > best) {
			best = score; 
			selected = module;
		}
		if (score >= 100) 
			break;
851
	}
852 853
#endif

854 855
	if (selected != NULL)
		return selected;
856

Havoc Pennington's avatar
Havoc Pennington committed
857
        if (filename)
858 859
	{
		display_name = g_filename_display_name (filename);
860 861 862 863
		g_set_error (error,
			     GDK_PIXBUF_ERROR,
			     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
			     _("Couldn't recognize the image file format for file '%s'"),
864 865
			     display_name);
		g_free (display_name);
866
	}
Havoc Pennington's avatar
Havoc Pennington committed
867
        else
868 869 870 871
                g_set_error_literal (error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
                                     _("Unrecognized image file format"));
Havoc Pennington's avatar
Havoc Pennington committed
872

873

874 875 876
	return NULL;
}

877 878 879 880 881 882 883 884 885 886 887

static void
prepared_notify (GdkPixbuf *pixbuf, 
		 GdkPixbufAnimation *anim, 
		 gpointer user_data)
{
	if (pixbuf != NULL)
		g_object_ref (pixbuf);
	*((GdkPixbuf **)user_data) = pixbuf;
}

888 889 890 891
GdkPixbuf *
_gdk_pixbuf_generic_image_load (GdkPixbufModule *module,
				FILE *f,
				GError **error)
892
{
893
	guchar buffer[LOAD_BUFFER_SIZE];
894 895
	size_t length;
	GdkPixbuf *pixbuf = NULL;
896
	GdkPixbufAnimation *animation = NULL;
897
	gpointer context;
898
	gboolean locked;
899

900
	locked = _gdk_pixbuf_lock (module);
901 902 903 904

	if (module->load != NULL) {
		pixbuf = (* module->load) (f, error);
	} else if (module->begin_load != NULL) {
905 906
		
		context = module->begin_load (NULL, prepared_notify, NULL, &pixbuf, error);
907
	
908
		if (!context)
909
			goto out;
910
		
911
		while (!feof (f) && !ferror (f)) {
912 913 914 915
			length = fread (buffer, 1, sizeof (buffer), f);
			if (length > 0)
				if (!module->load_increment (context, buffer, length, error)) {
					module->stop_load (context, NULL);
916
					if (pixbuf != NULL) {
917
						g_object_unref (pixbuf);
918 919 920
						pixbuf = NULL;
					}
					goto out;
921 922 923 924
				}
		}
		
		if (!module->stop_load (context, error)) {
925
			if (pixbuf != NULL) {
926
				g_object_unref (pixbuf);
927 928
				pixbuf = NULL;
			}
929
		}
930
	} else if (module->load_animation != NULL) {
931 932 933
		animation = (* module->load_animation) (f, error);
		if (animation != NULL) {
			pixbuf = gdk_pixbuf_animation_get_static_image (animation);
934

935 936 937
			g_object_ref (pixbuf);
			g_object_unref (animation);
		}
938
	}
939

940
 out:
941 942
	if (locked)
		_gdk_pixbuf_unlock (module);
943
	return pixbuf;
944 945
}

Federico Mena Quintero's avatar
Federico Mena Quintero committed
946 947
/**
 * gdk_pixbuf_new_from_file:
948
 * @filename: Name of file to load, in the GLib file name encoding
Havoc Pennington's avatar
Havoc Pennington committed
949
 * @error: Return location for an error
Federico Mena Quintero's avatar
Federico Mena Quintero committed
950
 *
Federico Mena Quintero's avatar
Federico Mena Quintero committed
951
 * Creates a new pixbuf by loading an image from a file.  The file format is
Matthias Clasen's avatar
Matthias Clasen committed
952
 * detected automatically. If %NULL is returned, then @error will be set.
Havoc Pennington's avatar
Havoc Pennington committed
953
 * Possible errors are in the #GDK_PIXBUF_ERROR and #G_FILE_ERROR domains.
Federico Mena Quintero's avatar
Federico Mena Quintero committed
954
 *
Matthias Clasen's avatar
Matthias Clasen committed
955
 * Return value: A newly-created pixbuf with a reference count of 1, or %NULL if
Federico Mena Quintero's avatar
Federico Mena Quintero committed
956 957 958
 * any of several error conditions occurred:  the file could not be opened,
 * there was no loader for the file's format, there was not enough memory to
 * allocate the image buffer, or the image file contained invalid data.
Federico Mena Quintero's avatar
Federico Mena Quintero committed
959
 **/
960
GdkPixbuf *
Havoc Pennington's avatar
Havoc Pennington committed
961 962
gdk_pixbuf_new_from_file (const char *filename,
                          GError    **error)
Arturo Espinosa's avatar
Arturo Espinosa committed
963
{
964
	GdkPixbuf *pixbuf;
965
	int size;
Arturo Espinosa's avatar
Arturo Espinosa committed
966
	FILE *f;
967
	guchar buffer[SNIFF_BUFFER_SIZE];
968
	GdkPixbufModule *image_module;
969
	gchar *display_name;
Arturo Espinosa's avatar
Arturo Espinosa committed
970

971
	g_return_val_if_fail (filename != NULL, NULL);
972
        g_return_val_if_fail (error == NULL || *error == NULL, NULL);
973 974
	
	display_name = g_filename_display_name (filename);	
975

976
	f = g_fopen (filename, "rb");
Havoc Pennington's avatar
Havoc Pennington committed
977
	if (!f) {
Matthias Clasen's avatar