gimp/plug-ins/common/gz.c
Tor Lillqvist 970ad834d1 libgimp/gimp.def libgimp/gimpui.def libgimp/makefile.{cygwin,msc}
2000-02-15  Tor Lillqvist  <tml@iki.fi>

* libgimp/gimp.def
* libgimp/gimpui.def
* libgimp/makefile.{cygwin,msc}
* app/makefile.{cygwin,msc}
* plug-ins/makefile.{cygwin,msc}: Updates.

* app/datafiles.c (is_script): New Win32-only function, which
tests if a file's extension matches one of the extensions in the
PATHEXT environment variable (which the cmd.exe command
interpreter also uses). This is to avoid starting applications
associated with any random data file the user might have dropped
in the plug-ins folder, while still supporting plug-ins written in
scripting languages.

* app/gimpparasite.c (gimp_parasiterc_save): (Win32:) Cannot
rename to an existing file.

* plug-ins/Lighting/lighting_image.c
* plug-ins/Lighting/lighting_share.c
* plug-ins/MapObject/mapobject_preview.c
* plug-ins/MapObject/mapobject_shade.c: Use G_PI.

* plug-ins/common/gz.c: #ifdef G_OS_WIN32 was used before its
potential definition via glib.h.

* plug-ins/common/jpeg.c: Also recognize Exif files, which are
typically produced by digital cameras. The usually have a .jpg
file name extension, and would thus already match this plug-in,
but add the magic string just in case. They are loaded just fine
by libjpeg even if they don't have the JFIF signature.

* plug-ins/common/tiff.c: Set TIFF warning and error handler, so
we get to pass libtiff's messages through the normal channels.
2000-02-14 22:44:06 +00:00

663 lines
17 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
* Copyright (C) 1997 Daniel Risacher, magnus@alum.mit.edu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Minor changes to support file magic */
/* 4 Oct 1997 -- Risacher */
/* gzip plug-in for the gimp */
/* loosley based on url.c by */
/* Josh MacDonald, jmacd@cs.berkeley.edu */
/* and, very loosely on hrz.c by */
/* Albert Cahalan <acahalan at cs.uml.edu> */
/* This is reads and writes gziped image files for the Gimp
*
* You need to have gzip installed for it to work.
*
* It should work with file names of the form
* filename.foo.gz where foo is some already-recognized extension
*
* and it also works for names of the form
* filename.xcfgz - which is equivalent to
* filename.xcf.gz
*
* I added the xcfgz bit because having a default extension of xcf.gz
* can confuse the file selection dialog box somewhat, forcing the
* user to type sometimes when he/she otherwise wouldn't need to.
*
* I later decided I didn't like it because I don't like to bloat
* the file-extension namespace. But I left in the recognition
* feature/bug so if people want to use files named foo.xcfgz by
* default, they can just hack their pluginrc file.
*
* to do this hack, change :
* "xcf.gz,gz,xcfgz"
* to
* "xcfgz,gz,xcf.gz"
*
*
* -Dan Risacher, 0430 CDT, 26 May 1997
*/
#include "config.h"
#include <glib.h> /* For G_OS_WIN32 */
#ifdef G_OS_WIN32
#define STRICT
#define WinMain WinMain_foo
#include <windows.h>
#undef WinMain
#endif
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <sys/stat.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#ifdef __EMX__
#include <fcntl.h>
#include <process.h>
#endif
#include <libgimp/gimp.h>
#include "libgimp/stdplugins-intl.h"
/* Author 1: Josh MacDonald (url.c) */
/* Author 2: Daniel Risacher (gz.c) */
/* According to USAF Lt Steve Werhle, US DoD software development
* contracts average about $25 USD per source line of code (SLOC). By
* that metric, I figure this plug-in is worth about $10,000 USD */
/* But you got it free. Magic of Gnu. */
static void query (void);
static void run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals);
static gint32 load_image (gchar *filename,
gint32 run_mode,
GStatusType *status /* return value */);
static GStatusType save_image (gchar *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode);
static gboolean valid_file (gchar *filename);
static gchar * find_extension (gchar *filename);
GPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
MAIN ()
static void
query (void)
{
static GParamDef load_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_STRING, "filename", "The name of the file to load" },
{ PARAM_STRING, "raw_filename", "The name entered" },
};
static GParamDef load_return_vals[] =
{
{ PARAM_IMAGE, "image", "Output image" },
};
static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
static gint nload_return_vals = (sizeof (load_return_vals) /
sizeof (load_return_vals[0]));
static GParamDef save_args[] =
{
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
{ PARAM_IMAGE, "image", "Input image" },
{ PARAM_DRAWABLE, "drawable", "Drawable to save" },
{ PARAM_STRING, "filename", "The name of the file to save the image in" },
{ PARAM_STRING, "raw_filename", "The name of the file to save the image in" }
};
static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
INIT_I18N();
gimp_install_procedure ("file_gz_load",
"loads files compressed with gzip",
"You need to have gzip installed.",
"Daniel Risacher",
"Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Load>/gzip",
NULL,
PROC_PLUG_IN,
nload_args, nload_return_vals,
load_args, load_return_vals);
gimp_install_procedure ("file_gz_save",
"saves files compressed with gzip",
"You need to have gzip installed.",
"Daniel Risacher",
"Daniel Risacher, Spencer Kimball and Peter Mattis",
"1995-1997",
"<Save>/gzip",
"RGB*, GRAY*, INDEXED*",
PROC_PLUG_IN,
nsave_args, 0,
save_args, NULL);
gimp_register_magic_load_handler ("file_gz_load",
"xcf.gz,gz,xcfgz",
"",
"0,string,\037\213");
gimp_register_save_handler ("file_gz_save",
"xcf.gz,gz,xcfgz",
"");
}
static void
run (gchar *name,
gint nparams,
GParam *param,
gint *nreturn_vals,
GParam **return_vals)
{
static GParam values[2];
GRunModeType run_mode;
GStatusType status = STATUS_SUCCESS;
gint32 image_ID;
run_mode = param[0].data.d_int32;
INIT_I18N();
*nreturn_vals = 1;
*return_vals = values;
values[0].type = PARAM_STATUS;
values[0].data.d_status = STATUS_EXECUTION_ERROR;
if (strcmp (name, "file_gz_load") == 0)
{
image_ID = load_image (param[1].data.d_string,
param[0].data.d_int32,
&status);
if (image_ID != -1 &&
status == STATUS_SUCCESS)
{
*nreturn_vals = 2;
values[1].type = PARAM_IMAGE;
values[1].data.d_image = image_ID;
}
}
else if (strcmp (name, "file_gz_save") == 0)
{
switch (run_mode)
{
case RUN_INTERACTIVE:
break;
case RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 4)
status = STATUS_CALLING_ERROR;
break;
case RUN_WITH_LAST_VALS:
break;
default:
break;
}
if (status == STATUS_SUCCESS)
{
status = save_image (param[3].data.d_string,
param[1].data.d_int32,
param[2].data.d_int32,
param[0].data.d_int32);
}
}
else
{
status = STATUS_CALLING_ERROR;
}
values[0].data.d_status = status;
}
#ifdef __EMX__
static gint
spawn_gzip (gchar *filename,
gchar *tmpname,
gchar *parms,
gint *pid)
{
FILE *f;
gint tfd;
if (!(f = fopen (filename,"w")))
{
g_message ("gz: fopen failed: %s\n", g_strerror (errno));
return -1;
}
/* save fileno(stdout) */
tfd = dup (fileno (stdout));
/* make stdout for this process be the output file */
if (dup2 (fileno (f), fileno (stdout)) == -1)
{
g_message ("gz: dup2 failed: %s\n", g_strerror (errno));
close (tfd);
return -1;
}
fcntl (tfd, F_SETFD, FD_CLOEXEC);
*pid = spawnlp (P_NOWAIT, "gzip", "gzip", parms, tmpname, NULL);
fclose (f);
/* restore fileno(stdout) */
dup2 (tfd, fileno (stdout));
close (tfd);
if (*pid == -1)
{
g_message ("gz: spawn failed: %s\n", g_strerror (errno));
return -1;
}
return 0;
}
#endif
static GStatusType
save_image (gchar *filename,
gint32 image_ID,
gint32 drawable_ID,
gint32 run_mode)
{
GParam* params;
gint retvals;
gchar *ext;
gchar *tmpname;
#ifndef G_OS_WIN32
FILE *f;
gint pid;
gint status;
#else
SECURITY_ATTRIBUTES secattr;
HANDLE f;
STARTUPINFO startupinfo;
PROCESS_INFORMATION processinfo;
gchar *cmdline;
#endif
if (NULL == (ext = find_extension (filename)))
{
g_message (_("gz: no sensible extension, saving as gzip'd xcf\n"));
ext = ".xcf";
}
/* get a temp name with the right extension and save into it. */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = g_strdup (params[1].data.d_string);
gimp_destroy_params (params, retvals);
params = gimp_run_procedure ("gimp_file_save",
&retvals,
PARAM_INT32, run_mode,
PARAM_IMAGE, image_ID,
PARAM_DRAWABLE, drawable_ID,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
if (!valid_file (tmpname) ||
params[0].data.d_status != STATUS_SUCCESS)
{
unlink (tmpname);
g_free (tmpname);
return params[0].data.d_status;
}
/* if (! file_save(image_ID, tmpname, tmpname)) { */
/* unlink (tmpname); */
/* return -1; */
/* } */
#ifndef G_OS_WIN32
#ifndef __EMX__
/* fork off a gzip process */
if ((pid = fork ()) < 0)
{
g_message ("gz: fork failed: %s\n", g_strerror (errno));
g_free (tmpname);
return STATUS_EXECUTION_ERROR;
}
else if (pid == 0)
{
if (!(f = fopen (filename, "w")))
{
g_message ("gz: fopen failed: %s\n", g_strerror (errno));
g_free (tmpname);
_exit (127);
}
/* make stdout for this process be the output file */
if (-1 == dup2 (fileno (f), fileno (stdout)))
g_message ("gz: dup2 failed: %s\n", g_strerror (errno));
/* and gzip into it */
execlp ("gzip", "gzip", "-cf", tmpname, NULL);
g_message ("gz: exec failed: gzip: %s\n", g_strerror (errno));
g_free (tmpname);
_exit(127);
}
else
#else /* __EMX__ */
if (spawn_gzip (filename, tmpname, "-cf", &pid) == -1)
{
g_free (tmpname);
return STATUS_EXECUTION_ERROR;
}
#endif
{
waitpid (pid, &status, 0);
if (!WIFEXITED (status) ||
WEXITSTATUS (status) != 0)
{
g_message ("gz: gzip exited abnormally on file %s\n", tmpname);
g_free (tmpname);
return 0;
}
}
#else /* G_OS_WIN32 */
secattr.nLength = sizeof (SECURITY_ATTRIBUTES);
secattr.lpSecurityDescriptor = NULL;
secattr.bInheritHandle = TRUE;
if ((f = CreateFile (filename, GENERIC_WRITE, FILE_SHARE_READ,
&secattr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))
== INVALID_HANDLE_VALUE)
{
g_message ("gz: CreateFile failed\n");
g_free (tmpname);
_exit (127);
}
startupinfo.cb = sizeof (STARTUPINFO);
startupinfo.lpReserved = NULL;
startupinfo.lpDesktop = NULL;
startupinfo.lpTitle = NULL;
startupinfo.dwFlags =
STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
startupinfo.wShowWindow = SW_SHOWMINNOACTIVE;
startupinfo.cbReserved2 = 0;
startupinfo.lpReserved2 = NULL;
startupinfo.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
startupinfo.hStdOutput = f;
startupinfo.hStdError = GetStdHandle (STD_ERROR_HANDLE);
cmdline = g_strdup_printf ("gzip -cf %s", tmpname);
if (!CreateProcess (NULL, cmdline, NULL, NULL,
TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL,
&startupinfo, &processinfo))
{
g_message ("gz: CreateProcess failed\n");
g_free (tmpname);
_exit (127);
}
CloseHandle (f);
CloseHandle (processinfo.hThread);
WaitForSingleObject (processinfo.hProcess, INFINITE);
#endif /* G_OS_WIN32 */
unlink (tmpname);
g_free (tmpname);
return STATUS_SUCCESS;
}
static gint32
load_image (gchar *filename,
gint32 run_mode,
GStatusType *status /* return value */)
{
GParam* params;
gint retvals;
gchar *ext;
gchar *tmpname;
#ifndef G_OS_WIN32
gint pid;
gint process_status;
#else
SECURITY_ATTRIBUTES secattr;
HANDLE f;
STARTUPINFO startupinfo;
PROCESS_INFORMATION processinfo;
gchar *cmdline;
#endif
if (NULL == (ext = find_extension (filename)))
{
g_message (_("gz: no sensible extension, attempting to load with file magic\n"));
}
/* find a temp name */
params = gimp_run_procedure ("gimp_temp_name",
&retvals,
PARAM_STRING, ext + 1,
PARAM_END);
tmpname = g_strdup (params[1].data.d_string);
gimp_destroy_params (params, retvals);
#ifndef G_OS_WIN32
#ifndef __EMX__
/* fork off a g(un)zip and wait for it */
if ((pid = fork ()) < 0)
{
g_message ("gz: fork failed: %s\n", g_strerror (errno));
g_free (tmpname);
*status = STATUS_EXECUTION_ERROR;
return -1;
}
else if (pid == 0) /* child process */
{
FILE *f;
if (!(f = fopen (tmpname, "w")))
{
g_message ("gz: fopen failed: %s\n", g_strerror (errno));
g_free (tmpname);
_exit(127);
}
/* make stdout for this child process be the temp file */
if (-1 == dup2 (fileno (f), fileno (stdout)))
{
g_free (tmpname);
g_message ("gz: dup2 failed: %s\n", g_strerror (errno));
}
/* and unzip into it */
execlp ("gzip", "gzip", "-cfd", filename, NULL);
g_message ("gz: exec failed: gunzip: %s\n", g_strerror (errno));
g_free (tmpname);
_exit(127);
}
else /* parent process */
#else /* __EMX__ */
if (spawn_gzip (tmpname, filename, "-cfd", &pid) == -1)
{
g_free (tmpname);
*status = STATUS_EXECUTION_ERROR;
return -1;
}
#endif
{
waitpid (pid, &process_status, 0);
if (!WIFEXITED (process_status) ||
WEXITSTATUS (process_status) != 0)
{
g_message ("gz: gzip exited abnormally on file %s\n", filename);
g_free (tmpname);
*status = STATUS_EXECUTION_ERROR;
return -1;
}
}
#else
secattr.nLength = sizeof (SECURITY_ATTRIBUTES);
secattr.lpSecurityDescriptor = NULL;
secattr.bInheritHandle = TRUE;
if ((f = CreateFile (tmpname, GENERIC_WRITE, FILE_SHARE_READ,
&secattr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))
== INVALID_HANDLE_VALUE)
{
g_message ("gz: CreateFile failed\n");
g_free (tmpname);
_exit (127);
}
startupinfo.cb = sizeof (STARTUPINFO);
startupinfo.lpReserved = NULL;
startupinfo.lpDesktop = NULL;
startupinfo.lpTitle = NULL;
startupinfo.dwFlags =
STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
startupinfo.wShowWindow = SW_SHOWMINNOACTIVE;
startupinfo.cbReserved2 = 0;
startupinfo.lpReserved2 = NULL;
startupinfo.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
startupinfo.hStdOutput = f;
startupinfo.hStdError = GetStdHandle (STD_ERROR_HANDLE);
cmdline = g_strdup_printf ("gzip -cfd %s", filename);
if (!CreateProcess (NULL, cmdline, NULL, NULL,
TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL,
&startupinfo, &processinfo))
{
g_message ("gz: CreateProcess failed: %d\n", GetLastError ());
g_free (tmpname);
_exit (127);
}
CloseHandle (f);
CloseHandle (processinfo.hThread);
WaitForSingleObject (processinfo.hProcess, INFINITE);
#endif /* G_OS_WIN32 */
/* now that we un-gziped it, load the temp file */
params = gimp_run_procedure ("gimp_file_load",
&retvals,
PARAM_INT32, run_mode,
PARAM_STRING, tmpname,
PARAM_STRING, tmpname,
PARAM_END);
unlink (tmpname);
g_free (tmpname);
*status = params[0].data.d_status;
if (params[0].data.d_status != STATUS_SUCCESS)
{
return -1;
}
else
{
gimp_image_set_filename (params[1].data.d_int32, filename);
return params[1].data.d_int32;
}
}
static gboolean
valid_file (gchar *filename)
{
gint stat_res;
struct stat buf;
stat_res = stat(filename, &buf);
if ((0 == stat_res) && (buf.st_size > 0))
return TRUE;
else
return FALSE;
}
static gchar *
find_extension (gchar *filename)
{
gchar *filename_copy;
gchar *ext;
/* we never free this copy - aren't we evil! */
filename_copy = g_malloc (strlen (filename) + 1);
strcpy (filename_copy, filename);
/* find the extension, boy! */
ext = strrchr (filename_copy, '.');
while (1)
{
if (!ext || ext[1] == 0 || strchr (ext, '/'))
{
return NULL;
}
if (0 == strcmp (ext, ".xcfgz"))
{
return ".xcf"; /* we've found it */
}
if (0 != strcmp (ext,".gz"))
{
return ext;
}
else
{
/* we found ".gz" so strip it, loop back, and look again */
*ext = 0;
ext = strrchr (filename_copy, '.');
}
}
}