home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / gz.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  16.0 KB  |  605 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * Copyright (C) 1997 Daniel Risacher, magnus@alum.mit.edu
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  */
  19.  
  20. /* Minor changes to support file magic */
  21. /* 4 Oct 1997 -- Risacher */
  22.  
  23. /* gzip plug-in for the gimp */
  24. /* loosley based on url.c by */
  25. /* Josh MacDonald, jmacd@cs.berkeley.edu */
  26.  
  27. /* and, very loosely on hrz.c by */
  28. /* Albert Cahalan <acahalan at cs.uml.edu> */
  29.  
  30. /* This is reads and writes gziped image files for the Gimp
  31.  *
  32.  * You need to have gzip installed for it to work.
  33.  *
  34.  * It should work with file names of the form
  35.  * filename.foo.gz where foo is some already-recognized extension
  36.  *
  37.  * and it also works for names of the form
  38.  * filename.xcfgz - which is equivalent to
  39.  * filename.xcf.gz
  40.  *
  41.  * I added the xcfgz bit because having a default extension of xcf.gz
  42.  * can confuse the file selection dialog box somewhat, forcing the
  43.  * user to type sometimes when he/she otherwise wouldn't need to.
  44.  *
  45.  * I later decided I didn't like it because I don't like to bloat
  46.  * the file-extension namespace.  But I left in the recognition
  47.  * feature/bug so if people want to use files named foo.xcfgz by
  48.  * default, they can just hack their pluginrc file.
  49.  *
  50.  * to do this hack, change :
  51.  *                      "xcf.gz,gz,xcfgz"
  52.  * to
  53.  *                      "xcfgz,gz,xcf.gz"
  54.  *
  55.  *
  56.  * -Dan Risacher, 0430 CDT, 26 May 1997
  57.  */
  58.  
  59. #include "config.h"
  60.  
  61. #include <stdlib.h>
  62. #include <stdio.h>
  63. #include <sys/types.h>
  64. #ifdef HAVE_SYS_PARAM_H
  65. #include <sys/param.h>
  66. #endif
  67. #ifdef HAVE_SYS_WAIT_H
  68. #include <sys/wait.h>
  69. #endif
  70. #include <sys/stat.h>
  71. #include <string.h>
  72. #ifdef HAVE_UNISTD_H
  73. #include <unistd.h>
  74. #endif
  75. #include <errno.h>
  76.  
  77. #ifdef __EMX__
  78. #include <fcntl.h>
  79. #include <process.h>
  80. #endif
  81.  
  82. #include <libgimp/gimp.h>
  83.  
  84. #ifdef G_OS_WIN32
  85. #define STRICT
  86. #define WinMain WinMain_foo
  87. #include <windows.h>
  88. #undef WinMain
  89. #endif
  90.  
  91. #include "libgimp/stdplugins-intl.h"
  92.  
  93.  
  94. /* Author 1: Josh MacDonald (url.c) */
  95. /* Author 2: Daniel Risacher (gz.c) */
  96.  
  97. /* According to USAF Lt Steve Werhle, US DoD software development
  98.  * contracts average about $25 USD per source line of code (SLOC).  By
  99.  * that metric, I figure this plug-in is worth about $10,000 USD */
  100. /* But you got it free.   Magic of Gnu. */
  101.  
  102.  
  103. static void          query       (void);
  104. static void          run         (gchar       *name,
  105.                   gint         nparams,
  106.                   GimpParam      *param,
  107.                   gint        *nreturn_vals,
  108.                   GimpParam     **return_vals);
  109.  
  110. static gint32        load_image  (gchar       *filename,
  111.                   gint32       run_mode,
  112.                   GimpPDBStatusType *status /* return value */);
  113. static GimpPDBStatusType   save_image  (gchar       *filename,
  114.                   gint32       image_ID,
  115.                   gint32       drawable_ID,
  116.                   gint32       run_mode);
  117.  
  118. static gboolean   valid_file     (gchar       *filename);
  119. static gchar    * find_extension (gchar       *filename);
  120.  
  121. GimpPlugInInfo PLUG_IN_INFO =
  122. {
  123.   NULL,  /* init_proc  */
  124.   NULL,  /* quit_proc  */
  125.   query, /* query_proc */
  126.   run,   /* run_proc   */
  127. };
  128.  
  129. MAIN ()
  130.  
  131. static void
  132. query (void)
  133. {
  134.   static GimpParamDef load_args[] =
  135.   {
  136.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  137.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  138.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  139.   };
  140.   static GimpParamDef load_return_vals[] =
  141.   {
  142.     { GIMP_PDB_IMAGE, "image", "Output image" },
  143.   };
  144.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  145.   static gint nload_return_vals = (sizeof (load_return_vals) /
  146.                    sizeof (load_return_vals[0]));
  147.  
  148.   static GimpParamDef save_args[] =
  149.   {
  150.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  151.     { GIMP_PDB_IMAGE, "image", "Input image" },
  152.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  153.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  154.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" }
  155.   };
  156.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  157.  
  158.   gimp_install_procedure ("file_gz_load",
  159.                           "loads files compressed with gzip",
  160.                           "You need to have gzip installed.",
  161.                           "Daniel Risacher",
  162.                           "Daniel Risacher, Spencer Kimball and Peter Mattis",
  163.                           "1995-1997",
  164.                           "<Load>/gzip",
  165.               NULL,
  166.                           GIMP_PLUGIN,
  167.                           nload_args, nload_return_vals,
  168.                           load_args, load_return_vals);
  169.  
  170.   gimp_install_procedure ("file_gz_save",
  171.                           "saves files compressed with gzip",
  172.                           "You need to have gzip installed.",
  173.                           "Daniel Risacher",
  174.                           "Daniel Risacher, Spencer Kimball and Peter Mattis",
  175.                           "1995-1997",
  176.                           "<Save>/gzip",
  177.               "RGB*, GRAY*, INDEXED*",
  178.                           GIMP_PLUGIN,
  179.                           nsave_args, 0,
  180.                           save_args, NULL);
  181.  
  182.   gimp_register_magic_load_handler ("file_gz_load",
  183.                     "xcf.gz,gz,xcfgz", 
  184.                     "",
  185.                     "0,string,\037\213");
  186.   gimp_register_save_handler       ("file_gz_save",
  187.                     "xcf.gz,gz,xcfgz",
  188.                     "");
  189. }
  190.  
  191. static void
  192. run (gchar   *name,
  193.      gint     nparams,
  194.      GimpParam  *param,
  195.      gint    *nreturn_vals,
  196.      GimpParam **return_vals)
  197. {
  198.   static GimpParam values[2];
  199.   GimpRunModeType  run_mode;
  200.   GimpPDBStatusType   status = GIMP_PDB_SUCCESS;
  201.   gint32        image_ID;
  202.  
  203.   run_mode = param[0].data.d_int32;
  204.  
  205.   INIT_I18N();
  206.  
  207.   *nreturn_vals = 1;
  208.   *return_vals  = values;
  209.   values[0].type          = GIMP_PDB_STATUS;
  210.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  211.  
  212.   if (strcmp (name, "file_gz_load") == 0)
  213.     {
  214.       image_ID = load_image (param[1].data.d_string,
  215.                  param[0].data.d_int32,
  216.                  &status);
  217.  
  218.       if (image_ID != -1 &&
  219.       status == GIMP_PDB_SUCCESS)
  220.     {
  221.       *nreturn_vals = 2;
  222.       values[1].type         = GIMP_PDB_IMAGE;
  223.       values[1].data.d_image = image_ID;
  224.     }
  225.     }
  226.   else if (strcmp (name, "file_gz_save") == 0)
  227.     {
  228.       switch (run_mode)
  229.     {
  230.     case GIMP_RUN_INTERACTIVE:
  231.       break;
  232.     case GIMP_RUN_NONINTERACTIVE:
  233.       /*  Make sure all the arguments are there!  */
  234.       if (nparams != 4)
  235.         status = GIMP_PDB_CALLING_ERROR;
  236.       break;
  237.     case GIMP_RUN_WITH_LAST_VALS:
  238.       break;
  239.  
  240.     default:
  241.       break;
  242.     }
  243.  
  244.       if (status == GIMP_PDB_SUCCESS)
  245.     {
  246.       status = save_image (param[3].data.d_string,
  247.                    param[1].data.d_int32,
  248.                    param[2].data.d_int32,
  249.                    param[0].data.d_int32);
  250.      }
  251.     }
  252.   else
  253.     {
  254.       status = GIMP_PDB_CALLING_ERROR;
  255.     }
  256.  
  257.   values[0].data.d_status = status;
  258. }
  259.  
  260. #ifdef __EMX__
  261. static gint
  262. spawn_gzip (gchar *filename,
  263.         gchar *tmpname,
  264.         gchar *parms,
  265.         gint  *pid)
  266. {
  267.   FILE *f;
  268.   gint tfd;
  269.   
  270.   if (!(f = fopen (filename,"w")))
  271.     {
  272.       g_message ("gz: fopen failed: %s\n", g_strerror (errno));
  273.       return -1;
  274.     }
  275.  
  276.   /* save fileno(stdout) */
  277.   tfd = dup (fileno (stdout));
  278.   /* make stdout for this process be the output file */
  279.   if (dup2 (fileno (f), fileno (stdout)) == -1)
  280.     {
  281.       g_message ("gz: dup2 failed: %s\n", g_strerror (errno));
  282.       close (tfd);
  283.       return -1;
  284.     }
  285.   fcntl (tfd, F_SETFD, FD_CLOEXEC);
  286.   *pid = spawnlp (P_NOWAIT, "gzip", "gzip", parms, tmpname, NULL);
  287.   fclose (f);
  288.   /* restore fileno(stdout) */
  289.   dup2 (tfd, fileno (stdout));
  290.   close (tfd);
  291.   if (*pid == -1)
  292.     {
  293.       g_message ("gz: spawn failed: %s\n", g_strerror (errno));
  294.       return -1;
  295.     }
  296.   return 0;
  297. }
  298. #endif
  299.  
  300. static GimpPDBStatusType
  301. save_image (gchar  *filename,
  302.         gint32  image_ID,
  303.         gint32  drawable_ID,
  304.         gint32  run_mode)
  305. {
  306.   gchar *ext;
  307.   gchar *tmpname;
  308. #ifndef G_OS_WIN32
  309.   FILE  *f;
  310.   gint   pid;
  311.   gint   wpid;
  312.   gint   process_status;
  313. #else
  314.   FILE  *in, *out;
  315.   STARTUPINFO         startupinfo;
  316.   PROCESS_INFORMATION processinfo;
  317. #endif
  318.  
  319.   if (NULL == (ext = find_extension (filename)))
  320.     {
  321.       g_message (_("gz: no sensible extension, saving as gzip'd xcf\n"));
  322.       ext = ".xcf";
  323.     }
  324.  
  325.   /* get a temp name with the right extension and save into it. */
  326.  
  327.   tmpname = gimp_temp_name (ext + 1);
  328.  
  329.   if (! (gimp_file_save (run_mode,
  330.              image_ID,
  331.              drawable_ID,
  332.              tmpname, 
  333.              tmpname) && valid_file (tmpname)) )
  334.     {
  335.       unlink (tmpname);
  336.       g_free (tmpname);
  337.       return GIMP_PDB_EXECUTION_ERROR;
  338.     }
  339.  
  340. #ifndef G_OS_WIN32
  341. #ifdef __EMX__
  342.    if (spawn_gzip (filename, tmpname, "-cf", &pid) == -1)  
  343.     {
  344.       g_free (tmpname);
  345.       return GIMP_PDB_EXECUTION_ERROR;
  346.     }
  347.   sleep (2); /* silly wait */
  348. #else /* UNIX */
  349.   /* fork off a gzip process */
  350.   if ((pid = fork ()) < 0)
  351.     {
  352.       g_message ("gz: fork failed: %s\n", g_strerror (errno));
  353.       g_free (tmpname);
  354.       return GIMP_PDB_EXECUTION_ERROR;
  355.     }
  356.   else if (pid == 0)
  357.     {
  358.  
  359.       if (!(f = fopen (filename, "w")))
  360.     {
  361.       g_message ("gz: fopen failed: %s\n", g_strerror (errno));
  362.       g_free (tmpname);
  363.       _exit (127);
  364.     }
  365.  
  366.       /* make stdout for this process be the output file */
  367.       if (-1 == dup2 (fileno (f), fileno (stdout)))
  368.     g_message ("gz: dup2 failed: %s\n", g_strerror (errno));
  369.  
  370.       /* and gzip into it */
  371.       execlp ("gzip", "gzip", "-cf", tmpname, NULL);
  372.       g_message ("gz: exec failed: gzip: %s\n", g_strerror (errno));
  373.       g_free (tmpname);
  374.       _exit(127);
  375.     }
  376.   else
  377.     {
  378.       wpid = waitpid (pid, &process_status, 0);
  379.  
  380.       if ((wpid < 0)
  381.       || !WIFEXITED (process_status)
  382.       || (WEXITSTATUS (process_status) != 0))
  383.     {
  384.       g_message ("gz: gzip exited abnormally on file %s\n", tmpname);
  385.       g_free (tmpname);
  386.       return 0;
  387.     }
  388.     }
  389. #endif
  390. #else  /* G_OS_WIN32 */
  391.   in = fopen (tmpname, "rb");
  392.   out = fopen (filename, "wb");
  393.  
  394.   startupinfo.cb = sizeof (STARTUPINFO);
  395.   startupinfo.lpReserved = NULL;
  396.   startupinfo.lpDesktop = NULL;
  397.   startupinfo.lpTitle = NULL;
  398.   startupinfo.dwFlags =
  399.     STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  400.   startupinfo.wShowWindow = SW_SHOWMINNOACTIVE;
  401.   startupinfo.cbReserved2 = 0;
  402.   startupinfo.lpReserved2 = NULL;
  403.   startupinfo.hStdInput = (HANDLE) _get_osfhandle (fileno (in));
  404.   startupinfo.hStdOutput = (HANDLE)  _get_osfhandle (fileno (out));
  405.   startupinfo.hStdError = GetStdHandle (STD_ERROR_HANDLE);
  406.  
  407.   if (!CreateProcess (NULL, "minigzip", NULL, NULL,
  408.               TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL,
  409.               &startupinfo, &processinfo))
  410.     {
  411.       g_message ("gz: CreateProcess failed. Minigzip.exe not in the ?\n");
  412.       g_free (tmpname);
  413.       _exit (127);
  414.     }
  415.   CloseHandle (processinfo.hThread);
  416.   WaitForSingleObject (processinfo.hProcess, INFINITE);
  417. #endif /* G_OS_WIN32 */
  418.  
  419.   unlink (tmpname);
  420.   g_free (tmpname);
  421.  
  422.   return GIMP_PDB_SUCCESS;
  423. }
  424.  
  425. static gint32
  426. load_image (gchar             *filename,
  427.         gint32             run_mode,
  428.         GimpPDBStatusType *status /* return value */)
  429. {
  430.   gint32  image_ID;
  431.   gchar  *ext;
  432.   gchar  *tmpname;
  433. #ifndef G_OS_WIN32
  434.   gint    pid;
  435.   gint    wpid;
  436.   gint    process_status;
  437. #else
  438.   FILE   *in, *out;
  439.   SECURITY_ATTRIBUTES secattr;
  440.   STARTUPINFO         startupinfo;
  441.   PROCESS_INFORMATION processinfo;
  442. #endif
  443.  
  444.   if (NULL == (ext = find_extension (filename)))
  445.     {
  446.       g_message (_("gz: no sensible extension, attempting to load with file magic\n"));
  447.     }
  448.  
  449.   /* find a temp name */
  450.   tmpname = gimp_temp_name (ext + 1);
  451.  
  452. #ifndef G_OS_WIN32  
  453. #ifdef __EMX__
  454.    if (spawn_gzip (tmpname, filename, "-cfd", &pid) == -1)
  455.      {
  456.        g_free (tmpname);
  457.        *status = GIMP_PDB_EXECUTION_ERROR;
  458.        return -1;
  459.      }
  460. #else /* UNIX */
  461. /* fork off a g(un)zip and wait for it */
  462.   if ((pid = fork ()) < 0)
  463.     {
  464.       g_message ("gz: fork failed: %s\n", g_strerror (errno));
  465.       g_free (tmpname);
  466.       *status = GIMP_PDB_EXECUTION_ERROR;
  467.       return -1;
  468.     }
  469.   else if (pid == 0)  /* child process */
  470.     {
  471.       FILE *f;
  472.        if (!(f = fopen (tmpname, "w")))
  473.      {
  474.        g_message ("gz: fopen failed: %s\n", g_strerror (errno));
  475.        g_free (tmpname);
  476.        _exit(127);
  477.      }
  478.  
  479.       /* make stdout for this child process be the temp file */
  480.       if (-1 == dup2 (fileno (f), fileno (stdout)))
  481.     {
  482.       g_free (tmpname);
  483.       g_message ("gz: dup2 failed: %s\n", g_strerror (errno));
  484.     }
  485.  
  486.       /* and unzip into it */
  487.       execlp ("gzip", "gzip", "-cfd", filename, NULL);
  488.       g_message ("gz: exec failed: gunzip: %s\n", g_strerror (errno));
  489.       g_free (tmpname);
  490.       _exit(127);
  491.     }
  492.   else  /* parent process */
  493.     {
  494.       wpid = waitpid (pid, &process_status, 0);
  495.  
  496.       if ((wpid < 0)
  497.       || !WIFEXITED (process_status)
  498.       || (WEXITSTATUS (process_status) != 0))
  499.     {
  500.       g_message ("gz: gzip exited abnormally on file %s\n", filename);
  501.       g_free (tmpname);
  502.       *status = GIMP_PDB_EXECUTION_ERROR;
  503.       return -1;
  504.     }
  505.     }
  506. #endif
  507. #else
  508.   in = fopen (filename, "rb");
  509.   out = fopen (tmpname, "wb");
  510.  
  511.   startupinfo.cb = sizeof (STARTUPINFO);
  512.   startupinfo.lpReserved = NULL;
  513.   startupinfo.lpDesktop = NULL;
  514.   startupinfo.lpTitle = NULL;
  515.   startupinfo.dwFlags =
  516.     STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  517.   startupinfo.wShowWindow = SW_SHOWMINNOACTIVE;
  518.   startupinfo.cbReserved2 = 0;
  519.   startupinfo.lpReserved2 = NULL;
  520.   startupinfo.hStdInput = (HANDLE) _get_osfhandle (fileno (in));
  521.   startupinfo.hStdOutput = (HANDLE) _get_osfhandle (fileno (out));
  522.   startupinfo.hStdError = GetStdHandle (STD_ERROR_HANDLE);
  523.  
  524.   if (!CreateProcess (NULL, "minigzip -d", NULL, NULL,
  525.               TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL,
  526.               &startupinfo, &processinfo))
  527.     {
  528.       g_message ("gz: CreateProcess failed: %d\n", GetLastError ());
  529.       g_free (tmpname);
  530.       _exit (127);
  531.     }
  532.   CloseHandle (processinfo.hThread);
  533.   WaitForSingleObject (processinfo.hProcess, INFINITE);
  534.   fclose (in);
  535.   fclose (out);
  536. #endif /* G_OS_WIN32 */
  537.  
  538.   /* now that we un-gziped it, load the temp file */
  539.  
  540.   image_ID = gimp_file_load (run_mode, tmpname, tmpname);
  541.  
  542.   unlink (tmpname);
  543.   g_free (tmpname);
  544.  
  545.   if (image_ID != -1)
  546.     {
  547.       *status = GIMP_PDB_SUCCESS;
  548.       gimp_image_set_filename (image_ID, filename);
  549.     }
  550.   else
  551.     *status = GIMP_PDB_EXECUTION_ERROR;
  552.  
  553.   return image_ID;
  554. }
  555.  
  556. static gboolean
  557. valid_file (gchar *filename)
  558. {
  559.   gint stat_res;
  560.   struct stat buf;
  561.  
  562.   stat_res = stat(filename, &buf);
  563.  
  564.   if ((0 == stat_res) && (buf.st_size > 0))
  565.     return TRUE;
  566.   else
  567.     return FALSE;
  568. }
  569.  
  570. static gchar *
  571. find_extension (gchar *filename)
  572. {
  573.   gchar *filename_copy;
  574.   gchar *ext;
  575.  
  576.   /* we never free this copy - aren't we evil! */
  577.   filename_copy = g_malloc (strlen (filename) + 1);
  578.   strcpy (filename_copy, filename);
  579.  
  580.   /* find the extension, boy! */
  581.   ext = strrchr (filename_copy, '.');
  582.  
  583.   while (1)
  584.     {
  585.       if (!ext || ext[1] == 0 || strchr (ext, '/'))
  586.     {
  587.       return NULL;
  588.     }
  589.       if (0 == strcmp (ext, ".xcfgz"))
  590.     {
  591.       return ".xcf";  /* we've found it */
  592.     }
  593.       if (0 != strcmp (ext,".gz"))
  594.     {
  595.       return ext;
  596.     }
  597.       else
  598.     {
  599.       /* we found ".gz" so strip it, loop back, and look again */
  600.       *ext = 0;
  601.       ext = strrchr (filename_copy, '.');
  602.     }
  603.     }
  604. }
  605.