1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * GIMP PSD Plug-in
5  * Copyright 2007 by John Marshall
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 #include <errno.h>
25 
26 #include <glib/gstdio.h>
27 #include <libgimp/gimp.h>
28 
29 #include "psd.h"
30 #include "psd-util.h"
31 #include "psd-image-res-load.h"
32 #include "psd-thumb-load.h"
33 
34 #include "libgimp/stdplugins-intl.h"
35 
36 /*  Local function prototypes  */
37 static gint    read_header_block          (PSDimage     *img_a,
38                                            FILE         *f,
39                                            GError      **error);
40 
41 static gint    read_color_mode_block      (PSDimage     *img_a,
42                                            FILE         *f,
43                                            GError      **error);
44 
45 static gint    read_image_resource_block  (PSDimage     *img_a,
46                                            FILE         *f,
47                                            GError      **error);
48 
49 static gint32  create_gimp_image          (PSDimage     *img_a,
50                                            const gchar  *filename);
51 
52 static gint    add_image_resources        (gint32        image_id,
53                                            PSDimage     *img_a,
54                                            FILE         *f,
55                                            GError      **error);
56 
57 /* Main file load function */
58 gint32
load_thumbnail_image(const gchar * filename,gint * width,gint * height,GError ** load_error)59 load_thumbnail_image (const gchar  *filename,
60                       gint         *width,
61                       gint         *height,
62                       GError      **load_error)
63 {
64   FILE        *f;
65   GStatBuf     st;
66   PSDimage     img_a;
67   gint32       image_id = -1;
68   GError      *error    = NULL;
69 
70   /* ----- Open PSD file ----- */
71   if (g_stat (filename, &st) == -1)
72     return -1;
73 
74   gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
75                              gimp_filename_to_utf8 (filename));
76 
77   IFDBG(1) g_debug ("Open file %s", gimp_filename_to_utf8 (filename));
78   f = g_fopen (filename, "rb");
79   if (f == NULL)
80     {
81       g_set_error (load_error, G_FILE_ERROR, g_file_error_from_errno (errno),
82                    _("Could not open '%s' for reading: %s"),
83                    gimp_filename_to_utf8 (filename), g_strerror (errno));
84       return -1;
85     }
86 
87   /* ----- Read the PSD file Header block ----- */
88   IFDBG(2) g_debug ("Read header block");
89   if (read_header_block (&img_a, f, &error) < 0)
90     goto load_error;
91   gimp_progress_update (0.2);
92 
93   /* ----- Read the PSD file Color Mode block ----- */
94   IFDBG(2) g_debug ("Read color mode block");
95   if (read_color_mode_block (&img_a, f, &error) < 0)
96     goto load_error;
97   gimp_progress_update (0.4);
98 
99   /* ----- Read the PSD file Image Resource block ----- */
100   IFDBG(2) g_debug ("Read image resource block");
101   if (read_image_resource_block (&img_a, f, &error) < 0)
102     goto load_error;
103   gimp_progress_update (0.6);
104 
105   /* ----- Create GIMP image ----- */
106   IFDBG(2) g_debug ("Create GIMP image");
107   image_id = create_gimp_image (&img_a, filename);
108   if (image_id < 0)
109     goto load_error;
110 
111   /* ----- Add image resources ----- */
112   IFDBG(2) g_debug ("Add image resources");
113   if (add_image_resources (image_id, &img_a, f, &error) < 1)
114     goto load_error;
115   gimp_progress_update (1.0);
116 
117   gimp_image_clean_all (image_id);
118   gimp_image_undo_enable (image_id);
119   fclose (f);
120 
121   *width = img_a.columns;
122   *height = img_a.rows;
123   return image_id;
124 
125   /* ----- Process load errors ----- */
126  load_error:
127   if (error)
128     {
129       g_set_error (load_error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
130                    _("Error loading PSD file: %s"), error->message);
131       g_error_free (error);
132     }
133 
134   /* Delete partially loaded image */
135   if (image_id > 0)
136     gimp_image_delete (image_id);
137 
138   /* Close file if Open */
139   if (! (f == NULL))
140     fclose (f);
141 
142   return -1;
143 }
144 
145 
146 /* Local functions */
147 
148 static gint
read_header_block(PSDimage * img_a,FILE * f,GError ** error)149 read_header_block (PSDimage  *img_a,
150                    FILE      *f,
151                    GError   **error)
152 {
153   guint16  version;
154   gchar    sig[4];
155   gchar    buf[6];
156 
157   if (fread (sig, 4, 1, f) < 1
158       || fread (&version, 2, 1, f) < 1
159       || fread (buf, 6, 1, f) < 1
160       || fread (&img_a->channels, 2, 1, f) < 1
161       || fread (&img_a->rows, 4, 1, f) < 1
162       || fread (&img_a->columns, 4, 1, f) < 1
163       || fread (&img_a->bps, 2, 1, f) < 1
164       || fread (&img_a->color_mode, 2, 1, f) < 1)
165     {
166       psd_set_error (feof (f), errno, error);
167       return -1;
168     }
169   version = GUINT16_FROM_BE (version);
170   img_a->channels = GUINT16_FROM_BE (img_a->channels);
171   img_a->rows = GUINT32_FROM_BE (img_a->rows);
172   img_a->columns = GUINT32_FROM_BE (img_a->columns);
173   img_a->bps = GUINT16_FROM_BE (img_a->bps);
174   img_a->color_mode = GUINT16_FROM_BE (img_a->color_mode);
175 
176   IFDBG(1) g_debug ("\n\n\tSig: %.4s\n\tVer: %d\n\tChannels: "
177                     "%d\n\tSize: %dx%d\n\tBPS: %d\n\tMode: %d\n",
178                     sig, version, img_a->channels,
179                     img_a->columns, img_a->rows,
180                     img_a->bps, img_a->color_mode);
181 
182   if (memcmp (sig, "8BPS", 4) != 0)
183     return -1;
184 
185   if (version != 1)
186     return -1;
187 
188   if (img_a->channels > MAX_CHANNELS)
189     return -1;
190 
191   if (img_a->rows < 1 || img_a->rows > GIMP_MAX_IMAGE_SIZE)
192     return -1;
193 
194   if (img_a->columns < 1 || img_a->columns > GIMP_MAX_IMAGE_SIZE)
195     return -1;
196 
197   return 0;
198 }
199 
200 static gint
read_color_mode_block(PSDimage * img_a,FILE * f,GError ** error)201 read_color_mode_block (PSDimage  *img_a,
202                        FILE      *f,
203                        GError   **error)
204 {
205   guint32 block_len;
206   guint32 block_start;
207   guint32 block_end;
208 
209   if (fread (&block_len, 4, 1, f) < 1)
210     {
211       psd_set_error (feof (f), errno, error);
212       return -1;
213     }
214   block_len = GUINT32_FROM_BE (block_len);
215 
216   block_start = ftell (f);
217   block_end = block_start + block_len;
218 
219   if (fseek (f, block_end, SEEK_SET) < 0)
220     {
221       psd_set_error (feof (f), errno, error);
222       return -1;
223     }
224 
225   return 0;
226 }
227 
228 static gint
read_image_resource_block(PSDimage * img_a,FILE * f,GError ** error)229 read_image_resource_block (PSDimage  *img_a,
230                            FILE      *f,
231                            GError   **error)
232 {
233   guint32 block_len;
234   guint32 block_end;
235 
236   if (fread (&block_len, 4, 1, f) < 1)
237     {
238       psd_set_error (feof (f), errno, error);
239       return -1;
240     }
241   img_a->image_res_len = GUINT32_FROM_BE (block_len);
242 
243   IFDBG(1) g_debug ("Image resource block size = %d", (int)img_a->image_res_len);
244 
245   img_a->image_res_start = ftell (f);
246   block_end = img_a->image_res_start + img_a->image_res_len;
247 
248   if (fseek (f, block_end, SEEK_SET) < 0)
249     {
250       psd_set_error (feof (f), errno, error);
251       return -1;
252     }
253 
254   return 0;
255 }
256 
257 static gint32
create_gimp_image(PSDimage * img_a,const gchar * filename)258 create_gimp_image (PSDimage    *img_a,
259                    const gchar *filename)
260 {
261   gint32 image_id = -1;
262 
263   img_a->base_type = GIMP_RGB;
264 
265   /* Create gimp image */
266   IFDBG(2) g_debug ("Create image");
267   image_id = gimp_image_new (img_a->columns, img_a->rows, img_a->base_type);
268 
269   gimp_image_set_filename (image_id, filename);
270   gimp_image_undo_disable (image_id);
271 
272   return image_id;
273 }
274 
275 static gint
add_image_resources(gint32 image_id,PSDimage * img_a,FILE * f,GError ** error)276 add_image_resources (gint32     image_id,
277                      PSDimage  *img_a,
278                      FILE      *f,
279                      GError   **error)
280 {
281   PSDimageres   res_a;
282   gint          status;
283 
284   if (fseek (f, img_a->image_res_start, SEEK_SET) < 0)
285     {
286       psd_set_error (feof (f), errno, error);
287       return -1;
288     }
289 
290   while (ftell (f) < img_a->image_res_start + img_a->image_res_len)
291     {
292       if (get_image_resource_header (&res_a, f, error) < 0)
293         return -1;
294 
295       if (res_a.data_start + res_a.data_len >
296           img_a->image_res_start + img_a->image_res_len)
297         return 0;
298 
299       status = load_thumbnail_resource (&res_a, image_id, f, error);
300       /* Error */
301       if (status < 0)
302         return -1;
303       /* Thumbnail Loaded */
304       if (status > 0)
305         return 1;
306     }
307 
308   return 0;
309 }
310