loaders: BMP: Add support for BITFIELDS formats.
[gfxprim.git] / libs / loaders / GP_BMP.c
blob70f701dff1cfb078e4844f74fcb3e381d885d216
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
25 BMP loader and writer.
27 Thanks Wikipedia for the format specification.
31 #include <stdint.h>
32 #include <inttypes.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <stdio.h>
39 #include "core/GP_Debug.h"
40 #include "core/GP_Pixel.h"
41 #include "core/GP_GetPutPixel.h"
43 #include "loaders/GP_ByteUtils.h"
44 #include "loaders/GP_BMP.h"
46 #define BMP_HEADER_OFFSET 0x0a /* info header offset - 4 bytes */
48 #define BUF_TO_4(buf, off) \
49 (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24))
51 #define BUF_TO_2(buf, off) \
52 (buf[off] + (buf[off+1]<<8))
55 struct bitmap_info_header {
57 * Offset to image data.
59 uint32_t pixel_offset;
62 * Header size (palette is on offset header_size + 14)
64 uint32_t header_size;
66 /*
67 * Image size in pixels.
68 * If h is negative image is top-down (bottom-up is default)
70 int32_t w;
71 int32_t h;
73 uint16_t bpp;
74 uint32_t compress_type;
75 /*
76 * if 0 image uses whole range (2^bpp colors)
78 uint32_t palette_colors;
80 * RGBA masks for bitfields compression
82 uint32_t R_mask;
83 uint32_t G_mask;
84 uint32_t B_mask;
85 uint32_t A_mask;
88 enum bitmap_compress {
89 COMPRESS_RGB = 0, /* uncompressed */
90 COMPRESS_RLE8 = 1, /* run-length encoded bitmap */
91 COMPRESS_RLE4 = 2, /* run-length encoded bitmap */
92 COMPRESS_BITFIELDS = 3, /* bitfield for each channel */
93 COMPRESS_JPEG = 4, /* only for printers */
94 COMPRESS_PNG = 5, /* only for printers */
95 COMPRESS_ALPHABITFIELDS = 6,
96 COMPRESS_MAX = COMPRESS_ALPHABITFIELDS,
99 static const char *bitmap_compress_names[] = {
100 "RGB",
101 "RLE8",
102 "RLE4",
103 "BITFIELDS",
104 "JPEG",
105 "PNG",
106 "ALPHABITFIELDS",
109 static const char *bitmap_compress_name(uint32_t compress)
111 if (compress >= COMPRESS_MAX)
112 return "Unknown";
114 return bitmap_compress_names[compress];
117 enum bitmap_info_header_sizes {
118 BITMAPCOREHEADER = 12, /* old OS/2 format + win 3.0 */
119 BITMAPCOREHEADER2 = 64, /* OS/2 */
120 BITMAPINFOHEADER = 40, /* most common */
121 BITMAPINFOHEADER2 = 52, /* Undocummented */
122 BITMAPINFOHEADER3 = 56, /* Undocummented */
123 BITMAPINFOHEADER4 = 108, /* adds color space + gamma - win 95/NT4 */
124 BITMAPINFOHEADER5 = 124, /* adds ICC color profiles win 98+ */
127 static const char *bitmap_header_size_name(uint32_t size)
129 switch (size) {
130 case BITMAPCOREHEADER:
131 return "BitmapCoreHeader";
132 case BITMAPCOREHEADER2:
133 return "BitmapCoreHeader2";
134 case BITMAPINFOHEADER:
135 return "BitmapInfoHeader";
136 case BITMAPINFOHEADER2:
137 return "BitmapInfoHeader2";
138 case BITMAPINFOHEADER3:
139 return "BitmapInfoHeader3";
140 case BITMAPINFOHEADER4:
141 return "BitmapInfoHeader4";
142 case BITMAPINFOHEADER5:
143 return "BitmapInfoHeader5";
146 return "Unknown";
149 static uint32_t get_palette_size(struct bitmap_info_header *header)
152 if (header->palette_colors)
153 return header->palette_colors;
155 return (1 << header->bpp);
158 static int read_bitfields(FILE *f, struct bitmap_info_header *header)
160 int ret;
162 ret = GP_FRead(f, "L4 L4 L4",
163 &header->R_mask,
164 &header->G_mask,
165 &header->B_mask);
167 if (ret != 3) {
168 GP_DEBUG(1, "Failed to read BITFIELDS");
169 return EIO;
172 header->A_mask = 0;
174 GP_DEBUG(1, "BITFIELDS R=0x%08x, G=0x%08x, B=0x%08x",
175 header->R_mask, header->G_mask, header->B_mask);
177 return 0;
180 static int read_alphabitfields(FILE *f, struct bitmap_info_header *header)
182 int ret;
184 ret = GP_FRead(f, "L4 L4 L4 L4",
185 &header->R_mask,
186 &header->G_mask,
187 &header->B_mask,
188 &header->A_mask);
190 if (ret != 4) {
191 GP_DEBUG(1, "Failed to read BITFIELDS");
192 return EIO;
195 GP_DEBUG(1, "BITFILES R=0x%08x, G=0x%08x, B=0x%08x, A=0x%08x",
196 header->R_mask, header->G_mask, header->B_mask,
197 header->A_mask);
199 return 0;
202 static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header)
204 uint16_t nr_planes;
206 if (GP_FRead(f, "L4 L4 L2 L2 L4 I12 L4 I4",
207 &header->w, &header->h, &nr_planes, &header->bpp,
208 &header->compress_type, &header->palette_colors) != 8) {
210 GP_DEBUG(1, "Failed to read bitmap info header");
211 return EIO;
214 /* This must be 1 according to specs */
215 if (nr_planes != 1)
216 GP_DEBUG(1, "Number of planes is %"PRId16" should be 1",
217 nr_planes);
219 GP_DEBUG(2, "Have BMP bitmap size %"PRId32"x%"PRId32" %"PRIu16" "
220 "bpp, %"PRIu32" pallete colors, '%s' compression",
221 header->w, header->h, header->bpp,
222 get_palette_size(header),
223 bitmap_compress_name(header->compress_type));
225 switch (header->compress_type) {
226 case COMPRESS_BITFIELDS:
227 switch (header->header_size) {
228 case BITMAPINFOHEADER:
229 case BITMAPINFOHEADER2:
230 return read_bitfields(f, header);
231 default:
232 /* Alpha is default in BITMAPINFOHEADER3 and newer */
233 return read_alphabitfields(f, header);
235 /* Only in BITMAPINFOHEADER */
236 case COMPRESS_ALPHABITFIELDS:
237 if (header->header_size != BITMAPINFOHEADER)
238 GP_DEBUG(1, "Unexpected ALPHABITFIELDS in %s",
239 bitmap_header_size_name(header->header_size));
240 return read_alphabitfields(f, header);
243 return 0;
246 static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header)
248 uint8_t buf[12];
250 if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
251 GP_DEBUG(1, "Failed to read bitmap core header");
252 return EIO;
255 header->w = BUF_TO_2(buf, 0);
256 header->h = BUF_TO_2(buf, 2);
257 header->bpp = BUF_TO_2(buf, 6);
258 header->compress_type = COMPRESS_RGB;
259 header->palette_colors = 0;
261 uint16_t nr_planes = BUF_TO_2(buf, 4);
263 /* This must be 1 according to specs */
264 if (nr_planes != 1)
265 GP_DEBUG(1, "Number of planes is %"PRId16" should be 1",
266 nr_planes);
268 GP_DEBUG(2, "Have BMP bitmap size %"PRId32"x%"PRId32" %"PRIu16" bpp",
269 header->h, header->w, header->bpp);
271 return 0;
274 static int read_bitmap_header(FILE *f, struct bitmap_info_header *header)
276 uint8_t buf[8];
277 int err;
279 if (fseek(f, BMP_HEADER_OFFSET, SEEK_SET)) {
280 err = errno;
281 GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
282 BMP_HEADER_OFFSET, strerror(errno));
283 return err;
286 /* Read info header size, header size determines header type */
287 if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) {
288 GP_DEBUG(1, "Failed to read info header size");
289 return EIO;
292 header->pixel_offset = BUF_TO_4(buf, 0);
293 header->header_size = BUF_TO_4(buf, 4);
295 GP_DEBUG(2, "BMP header type '%s'",
296 bitmap_header_size_name(header->header_size));
298 switch (header->header_size) {
299 case BITMAPCOREHEADER:
300 err = read_bitmap_core_header(f, header);
301 break;
302 case BITMAPCOREHEADER2:
303 return ENOSYS;
304 /* The bitmap core header only adds filelds to the end of the header */
305 case BITMAPINFOHEADER:
306 case BITMAPINFOHEADER2:
307 case BITMAPINFOHEADER3:
308 case BITMAPINFOHEADER4:
309 err = read_bitmap_info_header(f, header);
310 break;
311 default:
312 GP_DEBUG(1, "Unknown header type, continuing anyway");
313 err = read_bitmap_info_header(f, header);
314 break;
317 return err;
321 * Reads palette, the format is R G B X, each one byte.
323 static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header,
324 GP_Pixel *palette)
326 uint32_t palette_colors = get_palette_size(header);
327 uint32_t palette_offset = header->header_size + 14;
328 uint8_t pixel_size;
329 uint32_t i;
330 int err;
332 switch (header->header_size) {
333 case BITMAPCOREHEADER:
334 pixel_size = 3;
335 break;
336 default:
337 pixel_size = 4;
338 break;
341 GP_DEBUG(2, "Offset to BMP palette is 0x%x (%ubytes) "
342 "pixel size %"PRIu8"bytes",
343 palette_offset, palette_offset, pixel_size);
345 if (fseek(f, palette_offset, SEEK_SET)) {
346 err = errno;
347 GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
348 BMP_HEADER_OFFSET, strerror(errno));
349 return err;
352 for (i = 0; i < palette_colors; i++) {
353 uint8_t buf[4];
355 if (fread(buf, 1, pixel_size, f) != pixel_size) {
356 GP_DEBUG(1, "Failed to read palette %"PRIu32, i);
357 return EIO;
360 palette[i] = GP_Pixel_CREATE_RGB888(buf[2], buf[1], buf[0]);
362 GP_DEBUG(3, "Palette[%"PRIu32"] = [0x%02x, 0x%02x, 0x%02x]", i,
363 GP_Pixel_GET_R_RGB888(palette[i]),
364 GP_Pixel_GET_G_RGB888(palette[i]),
365 GP_Pixel_GET_B_RGB888(palette[i]));
368 return 0;
371 static int seek_pixels_offset(struct bitmap_info_header *header, FILE *f)
373 int err;
375 GP_DEBUG(2, "Offset to BMP pixels is 0x%x (%ubytes)",
376 header->pixel_offset, header->pixel_offset);
378 if (fseek(f, header->pixel_offset, SEEK_SET)) {
379 err = errno;
380 GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'",
381 header->pixel_offset, strerror(errno));
382 return err;
385 return 0;
388 static GP_PixelType match_pixel_type(struct bitmap_info_header *header)
390 /* handle bitfields */
391 switch (header->compress_type) {
392 case COMPRESS_BITFIELDS:
393 case COMPRESS_ALPHABITFIELDS:
394 return GP_PixelRGBMatch(header->R_mask, header->G_mask,
395 header->B_mask, header->A_mask,
396 header->bpp);
399 switch (header->bpp) {
400 /* palette formats -> expanded to RGB888 */
401 case 1:
402 case 2:
403 case 4:
404 case 8:
405 /* RGB888 */
406 case 24:
407 return GP_PIXEL_RGB888;
408 case 16:
409 #ifdef GP_PIXEL_RGB555
410 //TODO: May have 1-bit ALPHA channel for BITMAPINFOHEADER3 and newer
411 return GP_PIXEL_RGB555;
412 #else
413 //TODO: Conversion to RGB888?
414 break;
415 #endif
416 case 32:
417 //TODO: May have ALPHA channel for BITMAPINFOHEADER3 and newer
418 return GP_PIXEL_xRGB8888;
421 return GP_PIXEL_UNKNOWN;
425 * Returns four byte aligned row size for palette formats.
427 static uint32_t bitmap_row_size(struct bitmap_info_header *header)
429 uint32_t row_size = 0;
431 /* align width to whole bytes */
432 switch (header->bpp) {
433 case 1:
434 row_size = header->w / 8 + !!(header->w%8);
435 break;
436 case 2:
437 row_size = header->w / 4 + !!(header->w%4);
438 break;
439 case 4:
440 row_size = header->w / 2 + !!(header->w%2);
441 break;
442 case 8:
443 row_size = header->w;
444 break;
447 /* align row_size to four byte boundary */
448 switch (row_size % 4) {
449 case 1:
450 row_size++;
451 case 2:
452 row_size++;
453 case 3:
454 row_size++;
455 case 0:
456 break;
459 GP_DEBUG(2, "bpp = %"PRIu16", width = %"PRId32", row_size = %"PRIu32,
460 header->bpp, header->w, row_size);
462 return row_size;
465 static uint8_t get_idx(struct bitmap_info_header *header,
466 uint8_t row[], int32_t x)
468 switch (header->bpp) {
469 case 1:
470 return !!(row[x/8] & (1<<(7 - x%8)));
471 case 2:
472 return (row[x/4] >> (2*(3 - x%4))) & 0x03;
473 case 4:
474 return (row[x/2] >> (4*(!(x%2)))) & 0x0f;
475 break;
476 case 8:
477 return row[x];
480 return 0;
483 static int read_palette(FILE *f, struct bitmap_info_header *header,
484 GP_Context *context, GP_ProgressCallback *callback)
486 uint32_t palette_size = get_palette_size(header);
487 GP_Pixel palette[get_palette_size(header)];
488 int err;
490 if ((err = read_bitmap_palette(f, header, palette)))
491 return err;
493 if ((err = seek_pixels_offset(header, f)))
494 return err;
496 uint32_t row_size = bitmap_row_size(header);
497 int32_t y;
499 for (y = 0; y < GP_ABS(header->h); y++) {
500 int32_t x;
501 uint8_t row[row_size];
503 if (fread(row, 1, row_size, f) != row_size) {
504 GP_DEBUG(1, "Failed to read row %"PRId32, y);
505 return EIO;
508 for (x = 0; x < header->w; x++) {
509 uint8_t idx = get_idx(header, row, x);
510 GP_Pixel p;
512 if (idx >= palette_size) {
513 GP_DEBUG(1, "Index out of palette, ignoring");
514 p = 0;
515 } else {
516 p = palette[idx];
519 int32_t ry;
521 if (header->h < 0)
522 ry = y;
523 else
524 ry = GP_ABS(header->h) - 1 - y;
526 GP_PutPixel_Raw_24BPP(context, x, ry, p);
529 if (GP_ProgressCallbackReport(callback, header->h - y -1,
530 context->h, context->w)) {
531 GP_DEBUG(1, "Operation aborted");
532 return ECANCELED;
536 GP_ProgressCallbackDone(callback);
537 return 0;
540 static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
541 GP_Context *context,
542 GP_ProgressCallback *callback)
544 uint32_t row_size = header->w * (header->bpp / 8);
545 int32_t y;
546 int err;
548 if ((err = seek_pixels_offset(header, f)))
549 return err;
551 for (y = 0; y < GP_ABS(header->h); y++) {
552 int32_t ry;
554 if (header->h < 0)
555 ry = y;
556 else
557 ry = GP_ABS(header->h) - 1 - y;
559 uint8_t *row = GP_PIXEL_ADDR(context, 0, ry);
561 if (fread(row, 1, row_size, f) != row_size) {
562 GP_DEBUG(1, "Failed to read row %"PRId32, y);
563 return EIO;
566 /* Rows are four byte aligned */
567 switch (row_size % 4) {
568 case 1:
569 fgetc(f);
570 case 2:
571 fgetc(f);
572 case 3:
573 fgetc(f);
574 case 0:
575 break;
578 if (GP_ProgressCallbackReport(callback, header->h - y -1,
579 context->h, context->w)) {
580 GP_DEBUG(1, "Operation aborted");
581 return ECANCELED;
585 GP_ProgressCallbackDone(callback);
586 return 0;
589 static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header,
590 GP_Context *context, GP_ProgressCallback *callback)
592 switch (header->bpp) {
593 case 1:
594 /* I haven't been able to locate 2bpp palette bmp file => not tested */
595 case 2:
596 case 4:
597 case 8:
598 return read_palette(f, header, context, callback);
599 case 16:
600 case 24:
601 case 32:
602 return read_bitfields_or_rgb(f, header, context, callback);
605 return ENOSYS;
608 int GP_MatchBMP(const void *buf)
610 return !memcmp(buf, "BM", 2);
613 int GP_OpenBMP(const char *src_path, FILE **f,
614 GP_Size *w, GP_Size *h, GP_PixelType *pixel_type)
616 int err;
618 *f = fopen(src_path, "rb");
620 if (*f == NULL) {
621 err = errno;
622 GP_DEBUG(1, "Failed to open '%s' : %s",
623 src_path, strerror(errno));
624 goto err2;
627 int ch1 = fgetc(*f);
628 int ch2 = fgetc(*f);
630 if (ch1 != 'B' || ch2 != 'M') {
631 GP_DEBUG(1, "Unexpected bitmap header 0x%02x (%c) 0x%02x (%c)",
632 ch1, isascii(ch1) ? ch1 : ' ',
633 ch2, isascii(ch2) ? ch2 : ' ');
634 err = EIO;
635 goto err1;
638 if (w != NULL || h != NULL || pixel_type != NULL) {
639 struct bitmap_info_header header;
641 if ((err = read_bitmap_header(*f, &header)))
642 goto err1;
644 if (w != NULL)
645 *w = header.w;
647 if (h != NULL)
648 *h = header.h;
650 if (pixel_type != NULL)
651 *pixel_type = match_pixel_type(&header);
654 return 0;
655 err1:
656 fclose(*f);
657 err2:
658 errno = err;
659 return 1;
662 GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback)
664 struct bitmap_info_header header;
665 GP_PixelType pixel_type;
666 GP_Context *context;
667 int err;
669 if ((err = read_bitmap_header(f, &header)))
670 goto err1;
672 if (header.w <= 0 || header.h == 0) {
673 GP_WARN("Width and/or Height is not > 0");
674 err = EIO;
675 goto err1;
678 switch (header.compress_type) {
679 case COMPRESS_RGB:
680 case COMPRESS_BITFIELDS:
681 case COMPRESS_ALPHABITFIELDS:
682 break;
683 default:
684 GP_DEBUG(2, "Unknown/Unimplemented compression type");
685 err = ENOSYS;
686 goto err1;
689 if ((pixel_type = match_pixel_type(&header)) == GP_PIXEL_UNKNOWN) {
690 GP_DEBUG(2, "Unknown pixel type");
691 err = ENOSYS;
692 goto err1;
695 context = GP_ContextAlloc(header.w, GP_ABS(header.h), pixel_type);
697 if (context == NULL) {
698 err = ENOMEM;
699 goto err1;
702 if ((err = read_bitmap_pixels(f, &header, context, callback)))
703 goto err2;
705 return context;
706 err2:
707 GP_ContextFree(context);
708 err1:
709 errno = err;
710 return NULL;
713 GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback)
715 FILE *f;
716 GP_Context *res;
718 if (GP_OpenBMP(src_path, &f, NULL, NULL, NULL))
719 return NULL;
721 res = GP_ReadBMP(f, callback);
722 fclose(f);
724 return res;
728 * Rows in bmp are four byte aligned.
730 static uint32_t bmp_align_row_size(uint32_t width_bits)
732 uint32_t bytes = (width_bits/8) + !!(width_bits%8);
734 if (bytes%4)
735 bytes += 4 - bytes%4;
737 return bytes;
741 * For uncompressd images
743 static uint32_t bmp_count_bitmap_size(struct bitmap_info_header *header)
745 return header->h * bmp_align_row_size(header->bpp * header->w);
748 static int bmp_write_header(struct bitmap_info_header *header, FILE *f)
750 uint32_t bitmap_size = bmp_count_bitmap_size(header);
751 uint32_t file_size = bitmap_size + header->header_size + 14;
753 /* Bitmap Header */
754 if (GP_FWrite(f, "A2 L4 0x00 0x00 0x00 0x00 L4", "BM",
755 file_size, header->pixel_offset) != 7)
756 return EIO;
758 /* Bitmap Info Header */
759 if (GP_FWrite(f, "L4 L4 L4 L2 L2 L4 L4 L4 L4 L4 L4",
760 header->header_size, header->w, header->h, 1,
761 header->bpp, header->compress_type, bitmap_size, 0, 0,
762 header->palette_colors, 0) != 11)
763 return EIO;
765 return 0;
768 static int bmp_fill_header(const GP_Context *src, struct bitmap_info_header *header)
770 switch (src->pixel_type) {
771 case GP_PIXEL_RGB888:
772 header->bpp = 24;
773 break;
774 default:
775 GP_DEBUG(1, "Unsupported pixel type (%s)",
776 GP_PixelTypeName(src->pixel_type));
777 return ENOSYS;
780 header->w = src->w;
781 header->h = src->h;
783 /* Most common 40 bytes Info Header */
784 header->header_size = BITMAPINFOHEADER;
786 /* No compression or palette */
787 header->palette_colors = 0;
788 header->compress_type = COMPRESS_RGB;
790 /* image data follows the header */
791 header->pixel_offset = header->header_size + 14;
793 return 0;
796 static int bmp_write_data(FILE *f, const GP_Context *src, GP_ProgressCallback *callback)
798 int y;
799 uint32_t padd_len = 0;
800 char padd[3] = {0};
802 if (src->bytes_per_row%4)
803 padd_len = 4 - src->bytes_per_row%4;
805 for (y = src->h - 1; y >= 0; y--) {
806 void *row = GP_PIXEL_ADDR(src, 0, y);
808 if (fwrite(row, src->bytes_per_row, 1, f) != 1)
809 return EIO;
811 /* write padding */
812 if (padd_len)
813 if (fwrite(padd, padd_len, 1, f) != 1)
814 return EIO;
816 if (GP_ProgressCallbackReport(callback, y, src->h, src->w)) {
817 GP_DEBUG(1, "Operation aborted");
818 return ECANCELED;
822 return 0;
825 int GP_SaveBMP(const GP_Context *src, const char *dst_path,
826 GP_ProgressCallback *callback)
828 struct bitmap_info_header header;
829 FILE *f;
830 int err;
832 GP_DEBUG(1, "Saving BMP Image '%s'", dst_path);
834 if ((err = bmp_fill_header(src, &header)))
835 goto err0;
837 f = fopen(dst_path, "wb");
839 if (f == NULL) {
840 err = errno;
841 GP_DEBUG(1, "Failed to open '%s' for writing: %s",
842 dst_path, strerror(errno));
843 goto err0;
846 if ((err = bmp_write_header(&header, f)))
847 goto err1;
849 if ((err = bmp_write_data(f, src, callback)))
850 goto err1;
852 if (fclose(f)) {
853 err = errno;
854 GP_DEBUG(1, "Failed to close file '%s': %s",
855 dst_path, strerror(errno));
856 goto err1;
859 GP_ProgressCallbackDone(callback);
861 return 0;
862 err1:
863 fclose(f);
864 err0:
865 errno = err;
866 return 1;