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