]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-pcx.c
Fold two similar strings into on. (#126204, Danilo Segan)
[~andy/gtk] / gdk-pixbuf / io-pcx.c
1 /*
2  * GdkPixbuf library - PCX image loader
3  *
4  * Copyright (C) 2003 Josh A. Beam
5  *
6  * Authors: Josh A. Beam <josh@joshbeam.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include "gdk-pixbuf-private.h"
27 #include "gdk-pixbuf-io.h"
28
29 #define PCX_DEBUG
30
31 #define PCX_TASK_DONE 0
32 #define PCX_TASK_LOAD_HEADER 1
33 #define PCX_TASK_LOAD_DATA 2
34 #define PCX_TASK_LOAD_PALETTE 3
35
36 struct pcx_header {
37         guint8 manufacturer;
38         guint8 version;
39         guint8 encoding;
40         guint8 bitsperpixel;
41         gint16 xmin;
42         gint16 ymin;
43         gint16 xmax;
44         gint16 ymax;
45         guint16 horizdpi;
46         guint16 vertdpi;
47         guint8 palette[48];
48         guint8 reserved;
49         guint8 colorplanes;
50         guint16 bytesperline;
51         guint16 palettetype;
52         guint16 hscrsize;
53         guint16 vscrsize;
54         guint8 filler[54];
55 };
56
57 struct pcx_context {
58         GdkPixbuf *pixbuf;
59         gint rowstride;
60
61         GdkPixbufModuleSizeFunc size_func;
62         GdkPixbufModuleUpdatedFunc updated_func;
63         GdkPixbufModulePreparedFunc prepared_func;
64         gpointer user_data;
65
66         guchar current_task;
67
68         gboolean header_loaded;
69         struct pcx_header *header;
70         guint bpp;
71         gint width, height;
72         guint num_planes;
73         guint bytesperline;
74
75         guchar *buf;
76         guint buf_size;
77         guint buf_pos;
78         guchar *data;
79         guchar *line;
80         guint current_line;
81         guchar *p_data;
82 };
83
84 /*
85  * set context's image information based on the header
86  */
87 static void
88 fill_pcx_context(struct pcx_context *context)
89 {
90         struct pcx_header *header = context->header;
91
92         context->bpp = header->bitsperpixel;
93         context->width = header->xmax - header->xmin + 1;
94         context->height = header->ymax - header->ymin + 1;
95         context->num_planes = header->colorplanes;
96         context->bytesperline = header->bytesperline;
97
98         if(header->version == 5 && context->bpp == 8 && context->num_planes == 3)
99                 context->bpp = 24;
100 }
101
102 static void
103 free_pcx_context(struct pcx_context *context, gboolean unref_pixbuf)
104 {
105         if(context->header)
106                 g_free(context->header);
107         if(context->buf)
108                 g_free(context->buf);
109         if(unref_pixbuf && context->pixbuf)
110                 g_object_unref(context->pixbuf);
111         if(context->line)
112                 g_free(context->line);
113         if(context->p_data)
114                 g_free(context->p_data);
115
116         g_free(context);
117 }
118
119 /*
120  * read each plane of a single scanline. store_planes is
121  * the number of planes that can be stored in the planes array.
122  * data is the pointer to the block of memory to read
123  * from, size is the length of that data, and line_bytes
124  * is where the number of bytes read will be stored.
125  */
126 static gboolean
127 read_scanline_data(guchar *data, guint size, guchar *planes[],
128                    guint store_planes, guint num_planes, guint bytesperline,
129                    guint *line_bytes)
130 {
131         guint i, j;
132         guint p, count;
133         guint d = 0;
134         guint8 byte;
135
136         for(p = 0; p < num_planes; p++) {
137                 for(i = 0; i < bytesperline;) { /* i incremented when line byte set */
138                         if(d >= size)
139                                 return FALSE;
140                         byte = data[d++];
141
142                         if(byte >> 6 == 0x3) {
143                                 count = byte & ~(0x3 << 6);
144                                 if(count == 0)
145                                         return FALSE;
146                                 if(d >= size)
147                                         return FALSE;
148                                 byte = data[d++];
149                         } else {
150                                 count = 1;
151                         }
152
153                         for(j = 0; j < count; j++) {
154                                 if(p < store_planes)
155                                         planes[p][i++] = byte;
156                                 else
157                                         i++;
158
159                                 if(i >= bytesperline) {
160                                         p++;
161                                         if(p >= num_planes) {
162                                                 *line_bytes = d;
163                                                 return TRUE;
164                                         }
165                                         i = 0;
166                                 }
167                         }
168                 }
169         }
170
171         *line_bytes = d; /* number of bytes read for scanline */
172         return TRUE;
173 }
174
175 static gpointer
176 gdk_pixbuf__pcx_begin_load(GdkPixbufModuleSizeFunc size_func,
177                            GdkPixbufModulePreparedFunc prepared_func,
178                            GdkPixbufModuleUpdatedFunc updated_func,
179                            gpointer user_data, GError **error)
180 {
181         struct pcx_context *context;
182
183         context = g_new0(struct pcx_context, 1);
184         if(!context)
185                 return NULL;
186
187         context->header = g_try_malloc(sizeof(struct pcx_header));
188         if(!context->header) {
189                 g_free(context);
190                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for header"));
191                 return NULL;
192         }
193
194         context->size_func = size_func;
195         context->updated_func = updated_func;
196         context->prepared_func = prepared_func;
197         context->user_data = user_data;
198
199         context->current_task = PCX_TASK_LOAD_HEADER;
200
201         context->buf = g_try_malloc(sizeof(guchar) * 512);
202         if(!context->buf) {
203                 g_free(context->header);
204                 g_free(context);
205                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for context buffer"));
206                 return NULL;
207         }
208         context->buf_size = 512;
209
210         context->header_loaded = FALSE;
211
212         return context;
213 }
214
215 static gboolean
216 pcx_resize_context_buf(struct pcx_context *context, guint size)
217 {
218         guchar *new_buf;
219
220         new_buf = g_try_realloc(context->buf, size);
221         if(!new_buf)
222                 return FALSE;
223
224         context->buf = new_buf;
225         context->buf_size = size;
226         return TRUE;
227 }
228
229 /*
230  * remove a number of bytes (specified by size) from the
231  * beginning of a context's buf
232  */
233 static gboolean
234 pcx_chop_context_buf(struct pcx_context *context, guint size)
235 {
236         guint i, j;
237
238         if(size > context->buf_pos)
239                 return FALSE;
240         else if(size < 0)
241                 return FALSE;
242         else if(size == 0)
243                 return TRUE;
244
245         for(i = 0, j = size; j < context->buf_pos; i++, j++)
246                 context->buf[i] = context->buf[j];
247
248         context->buf_pos -= size;
249
250         return TRUE;
251 }
252
253 static guchar
254 read_pixel_1(guchar *data, guint offset)
255 {
256         guchar retval;
257         guint bit_offset;
258
259         if(!(offset % 8)) {
260                 offset /= 8;
261                 retval = data[offset] >> 7;
262         } else {
263                 bit_offset = offset % 8;
264                 offset -= bit_offset;
265                 offset /= 8;
266                 retval = (data[offset] >> (7 - bit_offset)) & 0x1;
267         }
268
269         return retval;
270 }
271
272 static guchar
273 read_pixel_4(guchar *data, guint offset)
274 {
275         guchar retval;
276
277         if(!(offset % 2)) {
278                 offset /= 2;
279                 retval = data[offset] >> 4;
280         } else {
281                 offset--;
282                 offset /= 2;
283                 retval = data[offset] & 0xf;
284         }
285
286         return retval;
287 }
288
289 static gboolean
290 pcx_increment_load_data_1(struct pcx_context *context)
291 {
292         guint i;
293         guchar *planes[4];
294         guint line_bytes;
295         guint store_planes;
296
297         if(context->num_planes == 4) {
298                 planes[0] = context->line;
299                 planes[1] = planes[0] + context->bytesperline;
300                 planes[2] = planes[1] + context->bytesperline;
301                 planes[3] = planes[2] + context->bytesperline;
302                 store_planes = 4;
303         } else if(context->num_planes == 3) {
304                 planes[0] = context->line;
305                 planes[1] = planes[0] + context->bytesperline;
306                 planes[2] = planes[1] + context->bytesperline;
307                 store_planes = 3;
308         } else if(context->num_planes == 2) {
309                 planes[0] = context->line;
310                 planes[1] = planes[0] + context->bytesperline;
311                 store_planes = 2;
312         } else if(context->num_planes == 1) {
313                 planes[0] = context->line;
314                 store_planes = 1;
315         } else {
316                 return FALSE;
317         }
318
319         while(read_scanline_data(context->buf, context->buf_pos, planes, store_planes, context->num_planes, context->bytesperline, &line_bytes)) {
320                 pcx_chop_context_buf(context, line_bytes);
321
322                 for(i = 0; i < context->width; i++) {
323                         guchar p;
324
325                         if(context->num_planes == 4) {
326                                 p = read_pixel_1(planes[3], i);
327                                 p <<= 1;
328                                 p |= read_pixel_1(planes[2], i);
329                                 p <<= 1;
330                                 p |= read_pixel_1(planes[1], i);
331                                 p <<= 1;
332                                 p |= read_pixel_1(planes[0], i);
333                         } else if(context->num_planes == 3) {
334                                 p = read_pixel_1(planes[2], i);
335                                 p <<= 1;
336                                 p |= read_pixel_1(planes[1], i);
337                                 p <<= 1;
338                                 p |= read_pixel_1(planes[0], i);
339                         } else if(context->num_planes == 2) {
340                                 p = read_pixel_1(planes[1], i);
341                                 p <<= 1;
342                                 p |= read_pixel_1(planes[0], i);
343                         } else if(context->num_planes == 1) {
344                                 p = read_pixel_1(planes[0], i);
345                         } else {
346                                 return FALSE;
347                         }
348                         p &= 0xf;
349                         context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[p * 3 + 0];
350                         context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[p * 3 + 1];
351                         context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[p * 3 + 2];
352                 }
353
354                 if(context->updated_func)
355                         context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
356
357                 context->current_line++;
358
359                 if(context->current_line == context->height) {
360                         context->current_task = PCX_TASK_DONE;
361                         return TRUE;
362                 }
363         }
364
365         return TRUE;
366 }
367
368 static gboolean
369 pcx_increment_load_data_2(struct pcx_context *context)
370 {
371         guint i;
372         guchar *planes[1];
373         guint line_bytes;
374         guint shift, h;
375
376         planes[0] = context->line;
377
378         while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
379                 pcx_chop_context_buf(context, line_bytes);
380
381                 for(i = 0; i < context->width; i++) {
382                         shift = 6 - 2 * (i % 4);
383                         h = (planes[0][i / 4] >> shift) & 0x3;
384                         context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[h * 3 + 0];
385                         context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[h * 3 + 1];
386                         context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[h * 3 + 2];
387                 }
388
389                 if(context->updated_func)
390                         context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
391
392                 context->current_line++;
393
394                 if(context->current_line == context->height) {
395                         context->current_task = PCX_TASK_DONE;
396                         return TRUE;
397                 }
398         }
399
400         return TRUE;
401 }
402
403 static gboolean
404 pcx_increment_load_data_4(struct pcx_context *context)
405 {
406         guint i;
407         guchar *planes[1];
408         guint line_bytes;
409
410         planes[0] = context->line;
411
412         while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
413                 pcx_chop_context_buf(context, line_bytes);
414
415                 for(i = 0; i < context->width; i++) {
416                         guchar p;
417
418                         p = read_pixel_4(planes[0], i) & 0xf;
419                         context->data[context->current_line * context->rowstride + i * 3 + 0] = context->header->palette[p * 3 + 0];
420                         context->data[context->current_line * context->rowstride + i * 3 + 1] = context->header->palette[p * 3 + 1];
421                         context->data[context->current_line * context->rowstride + i * 3 + 2] = context->header->palette[p * 3 + 2];
422                 }
423
424                 if(context->updated_func)
425                         context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
426
427                 context->current_line++;
428
429                 if(context->current_line == context->height) {
430                         context->current_task = PCX_TASK_DONE;
431                         return TRUE;
432                 }
433         }
434
435         return TRUE;
436 }
437
438 /*
439  * for loading 8-bit pcx images, we keep a buffer containing
440  * each pixel's palette number; once we've loaded each scanline,
441  * we wait for loading to stop and call pcx_load_palette_8,
442  * which finds the palette at the end of the pcx data and sets the
443  * RGB data.
444  */
445 static gboolean
446 pcx_increment_load_data_8(struct pcx_context *context)
447 {
448         guint i;
449         guchar *planes[1];
450         guint line_bytes;
451
452         planes[0] = context->line;
453
454         while(read_scanline_data(context->buf, context->buf_pos, planes, 1, context->num_planes, context->bytesperline, &line_bytes)) {
455                 pcx_chop_context_buf(context, line_bytes);
456
457                 for(i = 0; i < context->width; i++)
458                         context->p_data[context->current_line * context->width + i + 0] = planes[0][i];
459
460                 context->current_line++;
461
462                 if(context->current_line == context->height) {
463                         context->current_task = PCX_TASK_LOAD_PALETTE;
464                         return TRUE;
465                 }
466         }
467
468         return TRUE;
469 }
470
471 /*
472  * read the palette and set the RGB data
473  */
474 static gboolean
475 pcx_load_palette_8(struct pcx_context *context)
476 {
477         guint i, j;
478
479         if(context->current_line < context->height)
480                 return FALSE;
481
482         if(context->buf_pos >= 769) {
483                 guchar *palette = context->buf + (context->buf_pos - 769);
484
485                 if(palette[0] == 12) {
486                         palette++;
487                         for(i = 0; i < context->height; i++) {
488                                 for(j = 0; j < context->width; j++) {
489                                         context->data[i * context->rowstride + j * 3 + 0] = palette[(context->p_data[i * context->width + j]) * 3 + 0];
490                                         context->data[i * context->rowstride + j * 3 + 1] = palette[(context->p_data[i * context->width + j]) * 3 + 1];
491                                         context->data[i * context->rowstride + j * 3 + 2] = palette[(context->p_data[i * context->width + j]) * 3 + 2];
492                                 }
493
494                                 if(context->updated_func)
495                                         context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
496                         }
497
498 #ifdef PCX_DEBUG
499                         g_print("read palette\n");
500 #endif
501
502                         context->current_task = PCX_TASK_DONE;
503                         return TRUE;
504                 } else {
505 #ifdef PCX_DEBUG
506                         g_print("this ain't a palette\n");
507 #endif
508                         return FALSE;
509                 }
510         }
511
512         return FALSE;
513 }
514
515 /*
516  * in 24-bit images, each scanline has three color planes
517  * for red, green, and blue, respectively.
518  */
519 static gboolean
520 pcx_increment_load_data_24(struct pcx_context *context)
521 {
522         guint i;
523         guchar *planes[3];
524         guint line_bytes;
525
526         planes[0] = context->line;
527         planes[1] = planes[0] + context->bytesperline;
528         planes[2] = planes[1] + context->bytesperline;
529
530         while(read_scanline_data(context->buf, context->buf_pos, planes, 3, context->num_planes, context->bytesperline, &line_bytes)) {
531                 pcx_chop_context_buf(context, line_bytes);
532
533                 for(i = 0; i < context->width; i++) {
534                         context->data[context->current_line * context->rowstride + i * 3 + 0] = planes[0][i];
535                         context->data[context->current_line * context->rowstride + i * 3 + 1] = planes[1][i];
536                         context->data[context->current_line * context->rowstride + i * 3 + 2] = planes[2][i];
537                 }
538
539                 if(context->updated_func)
540                         context->updated_func(context->pixbuf, 0, context->current_line, context->width, 1, context->user_data);
541
542                 context->current_line++;
543
544                 if(context->current_line == context->height) {
545                         context->current_task = PCX_TASK_DONE;
546                         return TRUE;
547                 }
548         }
549
550         return TRUE;
551 }
552
553 static gboolean
554 gdk_pixbuf__pcx_load_increment(gpointer data, const guchar *buf, guint size,
555                                GError **error)
556 {
557         struct pcx_context *context = (struct pcx_context *)data;
558         struct pcx_header *header;
559         guint i;
560         gboolean retval = TRUE;
561
562         /* if context's buf isn't large enough to hold its current data plus the passed buf, increase its size */
563         if(context->buf_pos + size > context->buf_size) {
564                 if(!pcx_resize_context_buf(context, sizeof(guchar) * (context->buf_pos + size))) {
565                         g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for context buffer"));
566                         return FALSE;
567                 }
568         }
569
570         for(i = 0; i < size; i++)
571                 context->buf[context->buf_pos++] = buf[i];
572
573         if(context->current_task == PCX_TASK_LOAD_HEADER) {
574                 if(!context->header_loaded && context->buf_pos > sizeof(struct pcx_header)) { /* set header */
575                         gint width, height;
576
577                         memcpy(context->header, context->buf, sizeof(struct pcx_header));
578                         pcx_chop_context_buf(context, sizeof(struct pcx_header));
579                         header = context->header;
580
581                         /* convert the multi-byte header variables that will be used */
582                         header->xmin = GINT16_FROM_LE(header->xmin);
583                         header->ymin = GINT16_FROM_LE(header->ymin);
584                         header->xmax = GINT16_FROM_LE(header->xmax);
585                         header->ymax = GINT16_FROM_LE(header->ymax);
586                         header->bytesperline = GUINT16_FROM_LE(header->bytesperline);
587
588 #ifdef PCX_DEBUG
589                         g_print ("Manufacturer %d\n"
590                                  "Version %d\n"
591                                  "Encoding %d\n"
592                                  "Bits/Pixel %d\n"
593                                  "Planes %d\n"
594                                  "Palette %d\n", 
595                                  header->manufacturer, header->version, 
596                                  header->encoding, header->bitsperpixel,
597                                  header->colorplanes, header->palettetype);
598 #endif
599
600                         context->header_loaded = TRUE;
601                         fill_pcx_context(context);
602
603                         width = context->width;
604                         height = context->height;
605                         if(width <= 0 || height <= 0) {
606                                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image has invalid width and/or height"));
607                                 return FALSE;
608                         }
609                         if(context->size_func)
610                                 context->size_func(&width, &height, context->user_data);
611
612                         switch(context->bpp) {
613                                 default:
614                                         g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported bpp"));
615                                         return FALSE;
616                                         break;
617                                 case 1:
618                                         if(context->num_planes < 1 || context->num_planes > 4) {
619                                                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported number of %d-bit planes"), 1);
620                                                 return FALSE;
621                                         }
622                                         break;
623                                 case 2:
624                                 case 4:
625                                 case 8:
626                                         if(context->num_planes != 1) {
627                                                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported number of %d-bit planes"), context->bpp);
628                                                 return FALSE;
629                                         }
630                                         break;
631                                 case 24:
632                                         break; /* context's bpp is set to 24 if there are three 8-bit planes */
633                         }
634
635 #ifdef PCX_DEBUG
636                         g_print("io-pcx: header loaded\n");
637                         g_print("bpp: %u\n", context->bpp);
638                         g_print("dimensions: %ux%u\n", context->width, context->height);
639 #endif
640
641                         context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
642                         if(!context->pixbuf) {
643                                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't create new pixbuf"));
644                                 return FALSE;
645                         }
646                         context->data = gdk_pixbuf_get_pixels(context->pixbuf);
647                         context->rowstride = gdk_pixbuf_get_rowstride(context->pixbuf);
648
649                         context->line = g_try_malloc(sizeof(guchar) * context->bytesperline * context->num_planes);
650                         if(!context->line) {
651                                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for line data"));
652                                 return FALSE;
653                         }
654
655                         if(context->bpp == 8) {
656                                 context->p_data = g_try_malloc(sizeof(guchar) * context->width * context->height);
657                                 if(!context->p_data) {
658                                         g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for paletted data"));
659                                         return FALSE;
660                                 }
661                         }
662
663                         if(context->prepared_func)
664                                 context->prepared_func(context->pixbuf, NULL, context->user_data);
665
666                         context->current_task = PCX_TASK_LOAD_DATA;
667                 }
668
669                 retval = TRUE;
670         }
671
672         if(context->current_task == PCX_TASK_LOAD_DATA) {
673                 switch(context->bpp) {
674                         default:
675                                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Image has unsupported bpp"));
676                                 retval = FALSE;
677                                 break;
678                         case 1:
679                                 retval = pcx_increment_load_data_1(context);
680                                 break;
681                         case 2:
682                                 retval = pcx_increment_load_data_2(context);
683                                 break;
684                         case 4:
685                                 retval = pcx_increment_load_data_4(context);
686                                 break;
687                         case 8:
688                                 retval = pcx_increment_load_data_8(context);
689                                 break;
690                         case 24:
691                                 retval = pcx_increment_load_data_24(context);
692                                 break;
693                 }
694         }
695
696         return retval;
697 }
698
699 static gboolean
700 gdk_pixbuf__pcx_stop_load(gpointer data, GError **error)
701 {
702         struct pcx_context *context = (struct pcx_context *)data;
703
704         if(context->current_line != context->height) {
705                 g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("Didn't get all lines of PCX image"));
706                 free_pcx_context(context, FALSE);
707                 return FALSE;
708         }
709
710         if(context->current_task == PCX_TASK_LOAD_PALETTE) {
711                 if(!pcx_load_palette_8(context)) {
712                         g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, _("No palette found at end of PCX data"));
713                         free_pcx_context(context, FALSE);
714                         return FALSE;
715                 }
716         }
717
718         free_pcx_context(context, FALSE);
719
720         return TRUE;
721 }
722
723 void
724 MODULE_ENTRY (pcx, fill_vtable) (GdkPixbufModule *module)
725 {
726         module->begin_load = gdk_pixbuf__pcx_begin_load;
727         module->stop_load = gdk_pixbuf__pcx_stop_load;
728         module->load_increment = gdk_pixbuf__pcx_load_increment;
729 }
730
731 void
732 MODULE_ENTRY (pcx, fill_info) (GdkPixbufFormat *info)
733 {
734         static GdkPixbufModulePattern signature[] = {
735                 { "\x0a \x01", NULL, 100 },
736                 { "\x0a\x02\x01", NULL, 100 },
737                 { "\x0a\x03\x01", NULL, 100 },
738                 { "\x0a\x04\x01", NULL, 100 },
739                 { "\x0a\x05\x01", NULL, 100 },
740                 { NULL, NULL, 0 }
741         };
742         static gchar *mime_types[] = {
743                 "image/x-pcx",
744                 NULL,
745         };
746         static gchar *extensions[] = {
747                 "pcx",
748                 NULL,
749         };
750
751         info->name = "pcx";
752         info->signature = signature;
753         info->description = N_("The PCX image format");
754         info->mime_types = mime_types;
755         info->extensions = extensions;
756         info->flags = 0;
757 }