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 / bz2.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-10  |  12.5 KB  |  483 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  * Copyright (C) 1997 Daniel Risacher
  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. /* bzip2 plug-in for the gimp */
  21. /* this is almost exactly the same as the gz(ip) plugin by */
  22. /* Dan Risacher & Josh, so feel free to go look there. */
  23. /* GZ plugin adapted to BZ2 by Adam. I've left all other */
  24. /* Error checking added by srn. */
  25. /* credits intact since it was only a super-wussy mod. */
  26.  
  27. /* This is reads and writes bzip2ed image files for the Gimp
  28.  *
  29.  * You need to have bzip2 installed for it to work.
  30.  *
  31.  * It should work with file names of the form
  32.  * filename.foo.bz2 where foo is some already-recognized extension
  33.  */
  34.  
  35. #include "config.h"
  36.  
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <sys/types.h>
  40. #include <sys/param.h>
  41. #include <sys/wait.h>
  42. #include <sys/stat.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #include <errno.h>
  46. #ifdef __EMX__
  47. #include <fcntl.h>
  48. #include <process.h>
  49. #endif
  50.  
  51. #include <libgimp/gimp.h>
  52.  
  53. #include "libgimp/stdplugins-intl.h"
  54.  
  55.  
  56. static void          query       (void);
  57. static void          run         (gchar       *name,
  58.                   gint         nparams,
  59.                   GimpParam   *param,
  60.                   gint        *nreturn_vals,
  61.                   GimpParam  **return_vals);
  62.  
  63. static gint32        load_image  (gchar       *filename,
  64.                   gint32       run_mode,
  65.                   GimpPDBStatusType *status /* return value */);
  66. static GimpPDBStatusType save_image  (gchar       *filename,
  67.                       gint32       image_ID,
  68.                       gint32       drawable_ID,
  69.                       gint32       run_mode);
  70.  
  71. static gboolean   valid_file     (gchar       *filename);
  72. static gchar    * find_extension (gchar       *filename);
  73.  
  74. GimpPlugInInfo PLUG_IN_INFO =
  75. {
  76.   NULL,  /* init_proc  */
  77.   NULL,  /* quit_proc  */
  78.   query, /* query_proc */
  79.   run,   /* run_proc   */
  80. };
  81.  
  82. MAIN ()
  83.  
  84. static void
  85. query (void)
  86. {
  87.   static GimpParamDef load_args[] =
  88.   {
  89.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  90.     { GIMP_PDB_STRING, "filename", "The name of the file to load" },
  91.     { GIMP_PDB_STRING, "raw_filename", "The name entered" }
  92.   };
  93.   static GimpParamDef load_return_vals[] =
  94.   {
  95.     { GIMP_PDB_IMAGE, "image", "Output image" }
  96.   };
  97.   static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
  98.   static gint nload_return_vals = (sizeof (load_return_vals) /
  99.                    sizeof (load_return_vals[0]));
  100.  
  101.   static GimpParamDef save_args[] =
  102.   {
  103.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  104.     { GIMP_PDB_IMAGE, "image", "Input image" },
  105.     { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
  106.     { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
  107.     { GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" }
  108.   };
  109.   static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
  110.  
  111.   gimp_install_procedure ("file_bz2_load",
  112.                           "loads files compressed with bzip2",
  113.                           "You need to have bzip2 installed.",
  114.                           "Daniel Risacher",
  115.                           "Daniel Risacher, Spencer Kimball and Peter Mattis",
  116.                           "1995-1997",
  117.                           "<Load>/bzip2",
  118.               NULL,
  119.                           GIMP_PLUGIN,
  120.                           nload_args, nload_return_vals,
  121.                           load_args, load_return_vals);
  122.  
  123.   gimp_install_procedure ("file_bz2_save",
  124.                           "saves files compressed with bzip2",
  125.                           "You need to have bzip2 installed",
  126.                           "Daniel Risacher",
  127.                           "Daniel Risacher, Spencer Kimball and Peter Mattis",
  128.                           "1995-1997",
  129.                           "<Save>/bzip2",
  130.               "RGB*, GRAY*, INDEXED*",
  131.                           GIMP_PLUGIN,
  132.                           nsave_args, 0,
  133.                           save_args, NULL);
  134.  
  135.   gimp_register_magic_load_handler ("file_bz2_load",
  136.                     "xcf.bz2,bz2,xcfbz2",
  137.                     "",
  138.                     "0,string,BZh");
  139.   gimp_register_save_handler ("file_bz2_save",
  140.                   "xcf.bz2,bz2,xcfbz2",
  141.                   "");
  142. }
  143.  
  144. static void
  145. run (gchar      *name,
  146.      gint        nparams,
  147.      GimpParam  *param,
  148.      gint       *nreturn_vals,
  149.      GimpParam **return_vals)
  150. {
  151.   static GimpParam   values[2];
  152.   GimpRunModeType    run_mode;
  153.   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  154.   gint32 image_ID;
  155.  
  156.   run_mode = param[0].data.d_int32;
  157.  
  158.   INIT_I18N();
  159.  
  160.   *nreturn_vals = 1;
  161.   *return_vals  = values;
  162.   values[0].type          = GIMP_PDB_STATUS;
  163.   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  164.  
  165.   if (strcmp (name, "file_bz2_load") == 0)
  166.     {
  167.       image_ID = load_image (param[1].data.d_string,
  168.                  param[0].data.d_int32,
  169.                  &status);
  170.  
  171.       if (image_ID != -1 &&
  172.       status == GIMP_PDB_SUCCESS)
  173.     {
  174.       *nreturn_vals = 2;
  175.       values[1].type         = GIMP_PDB_IMAGE;
  176.       values[1].data.d_image = image_ID;
  177.     }
  178.     }
  179.   else if (strcmp (name, "file_bz2_save") == 0)
  180.     {
  181.       switch (run_mode)
  182.     {
  183.     case GIMP_RUN_INTERACTIVE:
  184.       break;
  185.     case GIMP_RUN_NONINTERACTIVE:
  186.       /*  Make sure all the arguments are there!  */
  187.       if (nparams != 4)
  188.         status = GIMP_PDB_CALLING_ERROR;
  189.       break;
  190.     case GIMP_RUN_WITH_LAST_VALS:
  191.       break;
  192.  
  193.     default:
  194.       break;
  195.     }
  196.  
  197.       if (status == GIMP_PDB_SUCCESS)
  198.     {
  199.       status = save_image (param[3].data.d_string,
  200.                    param[1].data.d_int32,
  201.                    param[2].data.d_int32,
  202.                    param[0].data.d_int32);
  203.     }
  204.     }
  205.   else
  206.     {
  207.       status = GIMP_PDB_CALLING_ERROR;
  208.     }
  209.  
  210.   values[0].data.d_status = status;
  211. }
  212.  
  213. #ifdef __EMX__
  214. static gint
  215. spawn_bz (gchar *filename,
  216.       gchar *tmpname,
  217.       gchar *parms,
  218.       gint  *pid)
  219. {
  220.   FILE *f;
  221.   gint tfd;
  222.   
  223.   if (!(f = fopen(filename,"wb")))
  224.     {
  225.       g_message ("bz: fopen failed: %s\n", g_strerror (errno));
  226.       return -1;
  227.     }
  228.  
  229.   /* save fileno(stdout) */
  230.   tfd = dup (fileno (stdout));
  231.   /* make stdout for this process be the output file */
  232.   if (dup2 (fileno (f), fileno (stdout)) == -1)
  233.     {
  234.       g_message ("bz: dup2 failed: %s\n", g_strerror (errno));
  235.       close (tfd);
  236.       return -1;
  237.     }
  238.   fcntl (tfd, F_SETFD, FD_CLOEXEC);
  239.   *pid = spawnlp (P_NOWAIT, "bzip2", "bzip2", parms, tmpname, NULL);
  240.   fclose (f);
  241.   /* restore fileno(stdout) */
  242.   dup2 (tfd, fileno (stdout));
  243.   close (tfd);
  244.   if (*pid == -1)
  245.     {
  246.       g_message ("bz: spawn failed: %s\n", g_strerror (errno));
  247.       return -1;
  248.     }
  249.   return 0;  
  250. }
  251. #endif
  252.  
  253. static GimpPDBStatusType
  254. save_image (gchar  *filename,
  255.         gint32  image_ID,
  256.         gint32  drawable_ID,
  257.         gint32  run_mode)
  258. {
  259.   FILE  *f;
  260.   gchar *ext;
  261.   gchar *tmpname;
  262.   gint   pid;
  263.   gint   wpid;
  264.   gint   process_status;
  265.  
  266.   if (NULL == (ext = find_extension (filename)))
  267.     {
  268.       g_message (_("bz2: can't open bzip2ed file without a "
  269.            "sensible extension\n"));
  270.       return GIMP_PDB_CALLING_ERROR;
  271.     }
  272.  
  273.   /* get a temp name with the right extension and save into it. */
  274.   tmpname = gimp_temp_name (ext + 1);
  275.   
  276.   if (! (gimp_file_save (run_mode,
  277.              image_ID,
  278.              drawable_ID,
  279.              tmpname, 
  280.              tmpname) && valid_file (tmpname)) )
  281.     {
  282.       unlink (tmpname);
  283.       g_free (tmpname);
  284.       return GIMP_PDB_EXECUTION_ERROR;
  285.     }
  286.  
  287. #ifndef __EMX__
  288.   /* fork off a bzip2 process */
  289.   if ((pid = fork ()) < 0)
  290.     {
  291.       g_message ("bz2: fork failed: %s\n", g_strerror (errno));
  292.       g_free (tmpname);
  293.       return GIMP_PDB_EXECUTION_ERROR;
  294.     }
  295.   else if (pid == 0)
  296.     {
  297.       if (!(f = fopen (filename, "w")))
  298.     {
  299.       g_message ("bz2: fopen failed: %s\n", g_strerror (errno));
  300.       g_free (tmpname);
  301.       _exit(127);
  302.     }
  303.  
  304.       /* make stdout for this process be the output file */
  305.       if (-1 == dup2 (fileno (f), fileno (stdout)))
  306.     g_message ("bz2: dup2 failed: %s\n", g_strerror (errno));
  307.  
  308.       /* and bzip2 into it */
  309.       execlp ("bzip2", "bzip2", "-cf", tmpname, NULL);
  310.       g_message ("bz2: exec failed: bzip2: %s\n", g_strerror (errno));
  311.       g_free (tmpname);
  312.       _exit (127);
  313.     }
  314.   else
  315. #else /* __EMX__ */
  316.   if (spawn_bz (filename, tmpname, "-cf", &pid) == -1)
  317.     {
  318.       g_free (tmpname);
  319.       return GIMP_PDB_EXECUTION_ERROR;
  320.     }
  321. #endif
  322.     {
  323.       wpid = waitpid (pid, &process_status, 0);
  324.  
  325.       if ((wpid < 0)
  326.       || !WIFEXITED (process_status)
  327.       || (WEXITSTATUS (process_status) != 0))
  328.     {
  329.       g_message ("bz2: bzip2 exited abnormally on file %s\n", tmpname);
  330.       g_free (tmpname);
  331.       return GIMP_PDB_EXECUTION_ERROR;
  332.     }
  333.     }
  334.  
  335.   unlink (tmpname);
  336.   g_free (tmpname);
  337.  
  338.   return GIMP_PDB_SUCCESS;
  339. }
  340.  
  341. static gint32
  342. load_image (gchar             *filename,
  343.         gint32             run_mode,
  344.         GimpPDBStatusType *status /* return value */)
  345. {
  346.   gint32  image_ID;
  347.   gchar  *ext;
  348.   gchar  *tmpname;
  349.   gint    pid;
  350.   gint    wpid;
  351.   gint    process_status;
  352.  
  353.   if (NULL == (ext = find_extension (filename)))
  354.     {
  355.       g_message (_("bz2: can't open bzip2ed file without a "
  356.            "sensible extension\n"));
  357.       *status = GIMP_PDB_CALLING_ERROR;
  358.       return -1;
  359.     }
  360.  
  361.   /* find a temp name */
  362.   tmpname = gimp_temp_name (ext + 1);
  363.  
  364. #ifndef __EMX__
  365.   /* fork off a g(un)zip and wait for it */
  366.   if ((pid = fork ()) < 0)
  367.     {
  368.       g_message ("bz2: fork failed: %s\n", g_strerror (errno));
  369.       g_free (tmpname);
  370.       *status = GIMP_PDB_EXECUTION_ERROR;
  371.       return -1;
  372.     }
  373.   else if (pid == 0)  /* child process */
  374.     {
  375.       FILE *f;
  376.        if (!(f = fopen (tmpname,"w")))
  377.      {
  378.        g_message ("bz2: fopen failed: %s\n", g_strerror (errno));
  379.        g_free (tmpname);
  380.        _exit (127);
  381.      }
  382.  
  383.       /* make stdout for this child process be the temp file */
  384.       if (-1 == dup2 (fileno (f), fileno (stdout)))
  385.     g_message ("bz2: dup2 failed: %s\n", g_strerror (errno));
  386.  
  387.       /* and unzip into it */
  388.       execlp ("bzip2", "bzip2", "-cfd", filename, NULL);
  389.       g_message ("bz2: exec failed: bunzip2: %s\n", g_strerror (errno));
  390.       g_free (tmpname);
  391.       _exit (127);
  392.     }
  393.   else  /* parent process */
  394. #else /* __EMX__ */
  395.   if (spawn_bz (filename, tmpname, "-cfd", &pid) == -1) 
  396.     {
  397.       g_free (tmpname);
  398.       *status = GIMP_PDB_EXECUTION_ERROR;
  399.       return -1;
  400.     }
  401. #endif
  402.     {
  403.       wpid = waitpid (pid, &process_status, 0);
  404.  
  405.       if ((wpid < 0)
  406.       || !WIFEXITED (process_status)
  407.       || (WEXITSTATUS (process_status) != 0))
  408.     {
  409.       g_message ("bz2: bzip2 exited abnormally on file %s\n", filename);
  410.       g_free (tmpname);
  411.       *status = GIMP_PDB_EXECUTION_ERROR;
  412.       return -1;
  413.     }
  414.     }
  415.  
  416.   /* now that we un-bzip2ed it, load the temp file */
  417.  
  418.   image_ID = gimp_file_load (run_mode, tmpname, tmpname);
  419.   
  420.   unlink (tmpname);
  421.   g_free (tmpname);
  422.  
  423.   if (image_ID != -1)
  424.     {
  425.       *status = GIMP_PDB_SUCCESS;
  426.       gimp_image_set_filename (image_ID, filename);
  427.     }
  428.   else
  429.     *status = GIMP_PDB_EXECUTION_ERROR;
  430.  
  431.   return image_ID;
  432. }
  433.  
  434. static gboolean
  435. valid_file (gchar* filename)
  436. {
  437.   gint stat_res;
  438.   struct stat buf;
  439.  
  440.   stat_res = stat (filename, &buf);
  441.  
  442.   if ((0 == stat_res) && (buf.st_size > 0))
  443.     return TRUE;
  444.   else
  445.     return FALSE;
  446. }
  447.  
  448. static gchar *
  449. find_extension (gchar* filename)
  450. {
  451.   gchar *filename_copy;
  452.   gchar *ext;
  453.  
  454.   /* we never free this copy - aren't we evil! */
  455.   filename_copy = g_malloc (strlen (filename) + 1);
  456.   strcpy (filename_copy, filename);
  457.  
  458.   /* find the extension, boy! */
  459.   ext = strrchr (filename_copy, '.');
  460.  
  461.   while (1)
  462.     {
  463.       if (!ext || ext[1] == 0 || strchr (ext, '/'))
  464.     {
  465.       return NULL;
  466.     }
  467.       if (0 == strcmp (ext, ".xcfbz2"))
  468.     {
  469.       return ".xcf";  /* we've found it */
  470.     }
  471.       if (0 != strcmp (ext, ".bz2"))
  472.     {
  473.       return ext;
  474.     }
  475.       else
  476.     {
  477.       /* we found ".bz2" so strip it, loop back, and look again */
  478.       *ext = 0;
  479.       ext = strrchr (filename_copy, '.');
  480.     }
  481.     }
  482. }
  483.