1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 /***********************************************************************
15 An IO layer to support transparent compression/uncompression.
16 (Currently only "required" functionality is supported.)
18 There are various reasons for making this a full-blown module
19 instead of just defining a few macros:
21 - Ability to switch between compressed and uncompressed at run-time
22 (zlib with compression level 0 saves uncompressed, but still with
23 gzip header, so non-zlib server cannot read the savefile).
25 - Flexibility to add other methods if desired (eg, bzip2, arbitrary
26 external filter program, etc).
28 FIXME: when zlib support _not_ included, should sanity check whether
29 the first few bytes are gzip marker and complain if so.
30 ***********************************************************************/
33 #include <fc_config.h>
36 #include "fc_prehdrs.h"
43 #ifdef FREECIV_HAVE_LIBZ
63 #ifdef FREECIV_HAVE_LIBBZ2
71 #endif /* FREECIV_HAVE_LIBBZ2 */
73 #ifdef FREECIV_HAVE_LIBLZMA
75 #define PLAIN_FILE_BUF_SIZE (1024*1024) /* 1024kb */
76 #define XZ_DECODER_TEST_SIZE (4*1024) /* 4kb */
78 /* In my tests 7Mb proved to be not enough and with 10Mb decompression
79 succeeded in typical case. */
80 #define XZ_DECODER_MEMLIMIT (65*1024*1024) /* 65Mb */
81 #define XZ_DECODER_MEMLIMIT_STEP (25*1024*1024) /* Increase 25Mb at a time */
82 #define XZ_DECODER_MEMLIMIT_FINAL (100*1024*1024) /* 100Mb */
89 /* liblzma bug workaround. This is what stream.avail_out should be,
90 calculated correctly. Used only when reading file. */
95 uint8_t *in_buf
; /* uint8_t is what xz headers use */
99 /* There seems to be bug in liblzma decompression that if all the
100 processing happened when lzma_code() last time was called with
101 LZMA_RUN action, it does not set next_out or avail_out variables
102 to sane values when lzma_code() is called with LZMA_FINISH.
103 We never call lzma_code() with LZMA_RUN action with all the input
104 we have left. This hack_byte is kept in storage in case there is no
105 more input when we try to get it. This byte can then be provided to
106 lzma_code(LZMA_FINISH) */
111 static bool xz_outbuffer_to_file(fz_FILE
*fp
, lzma_action action
);
112 static void xz_action(fz_FILE
*fp
, lzma_action action
);
114 #endif /* FREECIV_HAVE_LIBLZMA */
124 enum fz_method method
;
128 struct mem_fzFILE mem
;
129 FILE *plain
; /* FZ_PLAIN */
130 #ifdef FREECIV_HAVE_LIBZ
131 gzFile zlib
; /* FZ_ZLIB */
133 #ifdef FREECIV_HAVE_LIBBZ2
134 struct bzip2_struct bz2
;
136 #ifdef FREECIV_HAVE_LIBLZMA
142 /****************************************************************************
143 Validate the compression method.
144 ****************************************************************************/
145 static inline bool fz_method_is_valid(enum fz_method method
)
149 #ifdef FREECIV_HAVE_LIBZ
152 #ifdef FREECIV_HAVE_LIBBZ2
155 #ifdef FREECIV_HAVE_LIBLZMA
163 #define fz_method_validate(method) \
164 (fz_method_is_valid(method) ? method \
165 : (fc_assert_msg(TRUE == fz_method_is_valid(method), \
166 "Unsupported compress method %d, reverting to plain.",\
170 /***************************************************************
171 Open memory buffer for reading as fz_FILE.
172 If control is TRUE, caller gives up control of the buffer
173 so ioz will free it when fz_FILE closed.
174 ***************************************************************/
175 fz_FILE
*fz_from_memory(char *buffer
, int size
, bool control
)
179 fp
= (fz_FILE
*)fc_malloc(sizeof(*fp
));
181 fp
->u
.mem
.control
= control
;
182 fp
->u
.mem
.buffer
= buffer
;
184 fp
->u
.mem
.size
= size
;
189 /***************************************************************
190 Open file for reading/writing, like fopen.
191 Parameters compress_method and compress_level only apply
192 for writing: for reading try to use the most appropriate
194 Returns NULL if there was a problem; check errno for details.
195 (If errno is 0, and using FZ_ZLIB, probably had zlib error
196 Z_MEM_ERROR. Wishlist: better interface for errors?)
197 ***************************************************************/
198 fz_FILE
*fz_from_file(const char *filename
, const char *in_mode
,
199 enum fz_method method
, int compress_level
)
204 if (!is_reg_file_for_access(filename
, in_mode
[0] == 'w')) {
208 fp
= (fz_FILE
*)fc_malloc(sizeof(*fp
));
210 sz_strlcpy(mode
, in_mode
);
212 if (mode
[0] == 'w') {
216 #if defined(FREECIV_HAVE_LIBBZ2) || defined(FREECIV_HAVE_LIBLZMA)
218 sz_strlcpy(test_mode
, mode
);
219 sz_strlcat(test_mode
, "b");
220 #endif /* FREECIV_HAVE_LIBBZ2 || FREECIV_HAVE_LIBLZMA */
222 /* Reading: ignore specified method and try each: */
225 #ifdef FREECIV_HAVE_LIBBZ2
226 /* Try to open as bzip2 file
227 This is simplest test, so do it first. */
229 fp
->u
.bz2
.plain
= fc_fopen(filename
, test_mode
);
230 if (fp
->u
.bz2
.plain
) {
231 fp
->u
.bz2
.file
= BZ2_bzReadOpen(&fp
->u
.bz2
.error
, fp
->u
.bz2
.plain
, 1, 0,
234 /* This may currently have garbage value assigned via other union member. */
235 fp
->u
.bz2
.file
= NULL
;
237 if (!fp
->u
.bz2
.file
) {
238 if (fp
->u
.bz2
.plain
) {
239 fclose(fp
->u
.bz2
.plain
);
244 /* Try to read first byte out of stream so we can figure out if this
245 really is bzip2 file or not. Store byte for later use */
249 /* We put error to tmp variable when we don't want to overwrite
250 * error already in fp->u.bz2.error. So calls to fz_ferror() or
251 * fz_strerror() will later return what originally went wrong,
252 * and not what happened in error recovery. */
255 read_len
= BZ2_bzRead(&fp
->u
.bz2
.error
, fp
->u
.bz2
.file
, &tmp
, 1);
256 if (fp
->u
.bz2
.error
!= BZ_DATA_ERROR_MAGIC
) {
258 if (fp
->u
.bz2
.error
== BZ_STREAM_END
) {
259 /* We already reached end of file with our read of one byte */
262 fp
->u
.bz2
.firstbyte
= -1;
264 fp
->u
.bz2
.firstbyte
= tmp
;
266 fp
->u
.bz2
.eof
= TRUE
;
267 } else if (fp
->u
.bz2
.error
!= BZ_OK
) {
269 BZ2_bzReadClose(&tmp_err
, fp
->u
.bz2
.file
);
270 fclose(fp
->u
.bz2
.plain
);
274 /* Read success and we can continue reading */
275 fp
->u
.bz2
.firstbyte
= tmp
;
276 fp
->u
.bz2
.eof
= FALSE
;
278 fp
->method
= FZ_BZIP2
;
283 BZ2_bzReadClose(&tmp_err
, fp
->u
.bz2
.file
);
284 fclose(fp
->u
.bz2
.plain
);
286 #endif /* FREECIV_HAVE_LIBBZ2 */
288 #ifdef FREECIV_HAVE_LIBLZMA
289 /* Try to open as xz file */
290 fp
->u
.xz
.memlimit
= XZ_DECODER_MEMLIMIT
;
291 memset(&fp
->u
.xz
.stream
, 0, sizeof(lzma_stream
));
292 fp
->u
.xz
.error
= lzma_stream_decoder(&fp
->u
.xz
.stream
,
295 if (fp
->u
.xz
.error
!= LZMA_OK
) {
299 fp
->u
.xz
.plain
= fc_fopen(filename
, test_mode
);
300 if (fp
->u
.xz
.plain
) {
303 fp
->u
.xz
.in_buf
= fc_malloc(PLAIN_FILE_BUF_SIZE
);
305 len
= fread(fp
->u
.xz
.in_buf
, 1, XZ_DECODER_TEST_SIZE
,
310 fp
->u
.xz
.stream
.next_in
= fp
->u
.xz
.in_buf
;
311 fp
->u
.xz
.stream
.avail_in
= len
;
312 fp
->u
.xz
.out_buf
= fc_malloc(PLAIN_FILE_BUF_SIZE
);
313 fp
->u
.xz
.stream
.next_out
= fp
->u
.xz
.out_buf
;
314 fp
->u
.xz
.stream
.avail_out
= PLAIN_FILE_BUF_SIZE
;
315 len
= fread(&fp
->u
.xz
.hack_byte
, 1, 1, fp
->u
.xz
.plain
);
317 fp
->u
.xz
.hack_byte_used
= TRUE
;
320 fp
->u
.xz
.hack_byte_used
= FALSE
;
321 action
= LZMA_FINISH
;
323 xz_action(fp
, action
);
324 if (fp
->u
.xz
.error
== LZMA_OK
|| fp
->u
.xz
.error
== LZMA_STREAM_END
) {
326 fp
->u
.xz
.out_index
= 0;
327 fp
->u
.xz
.total_read
= 0;
328 fp
->u
.xz
.out_avail
= fp
->u
.xz
.stream
.total_out
;
332 free(fp
->u
.xz
.out_buf
);
334 fclose(fp
->u
.xz
.plain
);
335 lzma_end(&fp
->u
.xz
.stream
);
336 free(fp
->u
.xz
.in_buf
);
341 #endif /* FREECIV_HAVE_LIBLZMA */
343 #ifdef FREECIV_HAVE_LIBZ
350 fp
->method
= fz_method_validate(method
);
352 switch (fp
->method
) {
353 #ifdef FREECIV_HAVE_LIBLZMA
358 /* xz files are binary files, so we should add "b" to mode! */
359 sz_strlcat(mode
,"b");
360 memset(&fp
->u
.xz
.stream
, 0, sizeof(lzma_stream
));
361 ret
= lzma_easy_encoder(&fp
->u
.xz
.stream
, compress_level
, LZMA_CHECK_CRC32
);
362 fp
->u
.xz
.error
= ret
;
363 if (ret
!= LZMA_OK
) {
367 fp
->u
.xz
.in_buf
= fc_malloc(PLAIN_FILE_BUF_SIZE
);
368 fp
->u
.xz
.stream
.next_in
= fp
->u
.xz
.in_buf
;
369 fp
->u
.xz
.out_buf
= fc_malloc(PLAIN_FILE_BUF_SIZE
);
370 fp
->u
.xz
.stream
.next_out
= fp
->u
.xz
.out_buf
;
371 fp
->u
.xz
.stream
.avail_out
= PLAIN_FILE_BUF_SIZE
;
372 fp
->u
.xz
.out_index
= 0;
373 fp
->u
.xz
.total_read
= 0;
374 fp
->u
.xz
.plain
= fc_fopen(filename
, mode
);
377 #endif /* FREECIV_HAVE_LIBLZMA */
378 #ifdef FREECIV_HAVE_LIBBZ2
380 /* bz2 files are binary files, so we should add "b" to mode! */
381 sz_strlcat(mode
,"b");
382 fp
->u
.bz2
.plain
= fc_fopen(filename
, mode
);
383 if (fp
->u
.bz2
.plain
) {
384 /* Open for read handled earlier */
385 fc_assert_ret_val('w' == mode
[0], NULL
);
386 fp
->u
.bz2
.file
= BZ2_bzWriteOpen(&fp
->u
.bz2
.error
, fp
->u
.bz2
.plain
,
387 compress_level
, 1, 15);
388 if (fp
->u
.bz2
.error
!= BZ_OK
) {
389 int tmp_err
; /* See comments for similar variable
390 * near BZ2_bzReadOpen() */
391 BZ2_bzWriteClose(&tmp_err
, fp
->u
.bz2
.file
, 0, NULL
, NULL
);
392 fp
->u
.bz2
.file
= NULL
;
395 if (!fp
->u
.bz2
.file
) {
396 if (fp
->u
.bz2
.plain
) {
397 fclose(fp
->u
.bz2
.plain
);
403 #endif /* FREECIV_HAVE_LIBBZ2 */
404 #ifdef FREECIV_HAVE_LIBZ
406 /* gz files are binary files, so we should add "b" to mode! */
407 sz_strlcat(mode
,"b");
408 if (mode
[0] == 'w') {
409 cat_snprintf(mode
, sizeof(mode
), "%d", compress_level
);
411 fp
->u
.zlib
= fc_gzopen(filename
, mode
);
417 #endif /* FREECIV_HAVE_LIBZ */
419 fp
->u
.plain
= fc_fopen(filename
, mode
);
427 /* Should never happen */
428 fc_assert_msg(FALSE
, "Internal error in %s() (method = %d)",
429 __FUNCTION__
, fp
->method
);
434 /***************************************************************
435 Open uncompressed stream for reading/writing.
436 ***************************************************************/
437 fz_FILE
*fz_from_stream(FILE *stream
)
445 fp
= fc_malloc(sizeof(*fp
));
446 fp
->method
= FZ_PLAIN
;
448 fp
->u
.plain
= stream
;
452 /***************************************************************
453 Close file, like fclose.
454 Returns 0 on success, or non-zero for problems (but don't call
455 fz_ferror in that case because the struct has already been
456 free'd; wishlist: better interface for errors?)
457 (For FZ_PLAIN returns EOF and could check errno;
458 for FZ_ZLIB: returns zlib error number; see zlib.h.)
459 ***************************************************************/
460 int fz_fclose(fz_FILE
*fp
)
464 fc_assert_ret_val(NULL
!= fp
, 1);
467 if (fp
->u
.mem
.control
) {
468 FC_FREE(fp
->u
.mem
.buffer
);
475 switch (fz_method_validate(fp
->method
)) {
476 #ifdef FREECIV_HAVE_LIBLZMA
478 if (fp
->mode
== 'w' && !xz_outbuffer_to_file(fp
, LZMA_FINISH
)) {
481 lzma_end(&fp
->u
.xz
.stream
);
482 free(fp
->u
.xz
.in_buf
);
483 free(fp
->u
.xz
.out_buf
);
484 fclose(fp
->u
.xz
.plain
);
487 #endif /* FREECIV_HAVE_LIBLZMA */
488 #ifdef FREECIV_HAVE_LIBBZ2
490 if ('w' == fp
->mode
) {
491 BZ2_bzWriteClose(&fp
->u
.bz2
.error
, fp
->u
.bz2
.file
, 0, NULL
, NULL
);
493 BZ2_bzReadClose(&fp
->u
.bz2
.error
, fp
->u
.bz2
.file
);
495 error
= fp
->u
.bz2
.error
;
496 fclose(fp
->u
.bz2
.plain
);
498 return BZ_OK
== error
? 0 : 1;
499 #endif /* FREECIV_HAVE_LIBBZ2 */
500 #ifdef FREECIV_HAVE_LIBZ
502 error
= gzclose(fp
->u
.zlib
);
504 return 0 > error
? error
: 0; /* Only negative Z values are errors. */
505 #endif /* FREECIV_HAVE_LIBZ */
507 error
= fclose(fp
->u
.plain
);
512 /* Should never happen */
513 fc_assert_msg(FALSE
, "Internal error in %s() (method = %d)",
514 __FUNCTION__
, fp
->method
);
519 /***************************************************************
520 Get a line, like fgets.
521 Returns NULL in case of error, or when end-of-file reached
522 and no characters have been read.
523 ***************************************************************/
524 char *fz_fgets(char *buffer
, int size
, fz_FILE
*fp
)
526 fc_assert_ret_val(NULL
!= fp
, NULL
);
531 for (i
= fp
->u
.mem
.pos
, j
= 0;
532 i
< fp
->u
.mem
.size
&& j
< size
- 1 /* Space for '\0' */
533 && fp
->u
.mem
.buffer
[i
] != '\n'
534 && (fp
->u
.mem
.buffer
[i
] != '\r'
535 || fp
->u
.mem
.size
== i
+ 1
536 || fp
->u
.mem
.buffer
[i
+ 1] != '\n'); i
++) {
537 buffer
[j
++] = fp
->u
.mem
.buffer
[i
];
541 /* Space for both newline and terminating '\0' */
542 if (i
+ 1 < fp
->u
.mem
.size
543 && fp
->u
.mem
.buffer
[i
] == '\r'
544 && fp
->u
.mem
.buffer
[i
+ 1] == '\n') {
547 } else if (i
< fp
->u
.mem
.size
548 && fp
->u
.mem
.buffer
[i
] == '\n') {
564 switch (fz_method_validate(fp
->method
)) {
565 #ifdef FREECIV_HAVE_LIBLZMA
570 for (i
= 0; i
< size
- 1; i
+= j
) {
574 for (j
= 0, line_end
= FALSE
; fp
->u
.xz
.out_avail
> 0
577 j
++, fp
->u
.xz
.out_avail
--) {
578 buffer
[i
+ j
] = fp
->u
.xz
.out_buf
[fp
->u
.xz
.out_index
++];
579 fp
->u
.xz
.total_read
++;
580 if (buffer
[i
+ j
] == '\n') {
585 if (line_end
|| size
<= j
+ i
+ 1) {
586 buffer
[i
+ j
] = '\0';
590 if (fp
->u
.xz
.hack_byte_used
) {
593 fp
->u
.xz
.in_buf
[0] = fp
->u
.xz
.hack_byte
;
594 len
= fread(fp
->u
.xz
.in_buf
+ 1, 1, PLAIN_FILE_BUF_SIZE
- 1,
599 hblen
= fread(&fp
->u
.xz
.hack_byte
, 1, 1, fp
->u
.xz
.plain
);
602 fp
->u
.xz
.hack_byte_used
= FALSE
;
606 if (fp
->u
.xz
.error
== LZMA_STREAM_END
) {
608 /* Plain file read complete, and there was nothing in xz buffers
612 buffer
[i
+ j
] = '\0';
615 fp
->u
.xz
.stream
.next_out
= fp
->u
.xz
.out_buf
;
616 fp
->u
.xz
.stream
.avail_out
= PLAIN_FILE_BUF_SIZE
;
617 xz_action(fp
, LZMA_FINISH
);
618 fp
->u
.xz
.out_index
= 0;
620 fp
->u
.xz
.stream
.total_out
- fp
->u
.xz
.total_read
;
621 if (fp
->u
.xz
.error
!= LZMA_OK
622 && fp
->u
.xz
.error
!= LZMA_STREAM_END
) {
629 fp
->u
.xz
.stream
.next_in
= fp
->u
.xz
.in_buf
;
630 fp
->u
.xz
.stream
.avail_in
= len
;
631 fp
->u
.xz
.stream
.next_out
= fp
->u
.xz
.out_buf
;
632 fp
->u
.xz
.stream
.avail_out
= PLAIN_FILE_BUF_SIZE
;
633 if (fp
->u
.xz
.hack_byte_used
) {
636 action
= LZMA_FINISH
;
638 xz_action(fp
, action
);
640 fp
->u
.xz
.stream
.total_out
- fp
->u
.xz
.total_read
;
641 fp
->u
.xz
.out_index
= 0;
642 if (fp
->u
.xz
.error
!= LZMA_OK
&& fp
->u
.xz
.error
!= LZMA_STREAM_END
) {
652 #endif /* FREECIV_HAVE_LIBLZMA */
653 #ifdef FREECIV_HAVE_LIBBZ2
660 /* See if first byte is already read and stored */
661 if (fp
->u
.bz2
.firstbyte
>= 0) {
662 buffer
[0] = fp
->u
.bz2
.firstbyte
;
663 fp
->u
.bz2
.firstbyte
= -1;
666 if (!fp
->u
.bz2
.eof
) {
667 last_read
= BZ2_bzRead(&fp
->u
.bz2
.error
, fp
->u
.bz2
.file
, buffer
+ i
, 1);
668 i
+= last_read
; /* 0 or 1 */
671 if (!fp
->u
.bz2
.eof
) {
672 /* Leave space for trailing zero */
674 && fp
->u
.bz2
.error
== BZ_OK
&& buffer
[i
- 1] != '\n' ;
676 last_read
= BZ2_bzRead(&fp
->u
.bz2
.error
, fp
->u
.bz2
.file
,
679 if (fp
->u
.bz2
.error
!= BZ_OK
&&
680 (fp
->u
.bz2
.error
!= BZ_STREAM_END
||
686 if (fp
->u
.bz2
.error
== BZ_STREAM_END
) {
687 /* EOF reached. Do not BZ2_bzRead() any more. */
688 fp
->u
.bz2
.eof
= TRUE
;
694 #endif /* FREECIV_HAVE_LIBBZ2 */
695 #ifdef FREECIV_HAVE_LIBZ
697 return gzgets(fp
->u
.zlib
, buffer
, size
);
698 #endif /* FREECIV_HAVE_LIBZ */
700 return fgets(buffer
, size
, fp
->u
.plain
);
703 /* Should never happen */
704 fc_assert_msg(FALSE
, "Internal error in %s() (method = %d)",
705 __FUNCTION__
, fp
->method
);
709 #ifdef FREECIV_HAVE_LIBLZMA
711 /***************************************************************
712 Helper function to do given compression action and writing
713 results from output buffer to file.
714 ***************************************************************/
715 static bool xz_outbuffer_to_file(fz_FILE
*fp
, lzma_action action
)
721 fp
->u
.xz
.error
= lzma_code(&fp
->u
.xz
.stream
, action
);
723 if (fp
->u
.xz
.error
!= LZMA_OK
&& fp
->u
.xz
.error
!= LZMA_STREAM_END
) {
727 while (total
< PLAIN_FILE_BUF_SIZE
- fp
->u
.xz
.stream
.avail_out
) {
728 len
= fwrite(fp
->u
.xz
.out_buf
, 1,
729 PLAIN_FILE_BUF_SIZE
- fp
->u
.xz
.stream
.avail_out
- total
,
736 fp
->u
.xz
.stream
.avail_out
= PLAIN_FILE_BUF_SIZE
;
737 fp
->u
.xz
.stream
.next_out
= fp
->u
.xz
.out_buf
;
738 } while (fp
->u
.xz
.stream
.avail_in
> 0);
743 /***************************************************************
744 Helper function to do given decompression action.
745 ***************************************************************/
746 static void xz_action(fz_FILE
*fp
, lzma_action action
)
748 fp
->u
.xz
.error
= lzma_code(&fp
->u
.xz
.stream
, action
);
749 if (fp
->u
.xz
.error
!= LZMA_MEMLIMIT_ERROR
) {
753 while (fp
->u
.xz
.error
== LZMA_MEMLIMIT_ERROR
754 && fp
->u
.xz
.memlimit
< XZ_DECODER_MEMLIMIT_FINAL
) {
755 fp
->u
.xz
.memlimit
+= XZ_DECODER_MEMLIMIT_STEP
;
756 if (fp
->u
.xz
.memlimit
> XZ_DECODER_MEMLIMIT_FINAL
) {
757 fp
->u
.xz
.memlimit
= XZ_DECODER_MEMLIMIT_FINAL
;
759 fp
->u
.xz
.error
= lzma_memlimit_set(&fp
->u
.xz
.stream
, fp
->u
.xz
.memlimit
);
762 fp
->u
.xz
.error
= lzma_code(&fp
->u
.xz
.stream
, action
);
764 #endif /* FREECIV_HAVE_LIBLZMA */
766 /***************************************************************
767 Print formated, like fprintf.
769 Note: zlib doesn't have gzvfprintf, but thats ok because its
770 fprintf only does similar to what we do here (print to fixed
771 buffer), and in addition this way we get to use our safe
774 Returns number of (uncompressed) bytes actually written, or
776 ***************************************************************/
777 int fz_fprintf(fz_FILE
*fp
, const char *format
, ...)
782 fc_assert_ret_val(NULL
!= fp
, 0);
783 fc_assert_ret_val(!fp
->memory
, 0);
785 switch (fz_method_validate(fp
->method
)) {
786 #ifdef FREECIV_HAVE_LIBLZMA
789 va_start(ap
, format
);
790 num
= fc_vsnprintf((char *)fp
->u
.xz
.in_buf
, PLAIN_FILE_BUF_SIZE
, format
, ap
);
794 log_error("Too much data: truncated in fz_fprintf (%u)",
795 PLAIN_FILE_BUF_SIZE
);
796 num
= PLAIN_FILE_BUF_SIZE
;
798 fp
->u
.xz
.stream
.next_in
= fp
->u
.xz
.in_buf
;
799 fp
->u
.xz
.stream
.avail_in
= num
;
801 if (!xz_outbuffer_to_file(fp
, LZMA_RUN
)) {
804 return strlen((char *)fp
->u
.xz
.in_buf
);
808 #endif /* FREECIV_HAVE_LIBLZMA */
809 #ifdef FREECIV_HAVE_LIBBZ2
814 va_start(ap
, format
);
815 num
= fc_vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
818 log_error("Too much data: truncated in fz_fprintf (%lu)",
819 (unsigned long) sizeof(buffer
));
821 BZ2_bzWrite(&fp
->u
.bz2
.error
, fp
->u
.bz2
.file
, buffer
, strlen(buffer
));
822 if (fp
->u
.bz2
.error
!= BZ_OK
) {
825 return strlen(buffer
);
828 #endif /* FREECIV_HAVE_LIBBZ2 */
829 #ifdef FREECIV_HAVE_LIBZ
834 va_start(ap
, format
);
835 num
= fc_vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
838 log_error("Too much data: truncated in fz_fprintf (%lu)",
839 (unsigned long) sizeof(buffer
));
841 return gzwrite(fp
->u
.zlib
, buffer
, (unsigned int)strlen(buffer
));
843 #endif /* FREECIV_HAVE_LIBZ */
845 va_start(ap
, format
);
846 num
= vfprintf(fp
->u
.plain
, format
, ap
);
851 /* Should never happen */
852 fc_assert_msg(FALSE
, "Internal error in %s() (method = %d)",
853 __FUNCTION__
, fp
->method
);
857 /***************************************************************
858 Return non-zero if there is an error status associated with
859 this stream. Check fz_strerror for details.
860 ***************************************************************/
861 int fz_ferror(fz_FILE
*fp
)
863 fc_assert_ret_val(NULL
!= fp
, 0);
869 switch (fz_method_validate(fp
->method
)) {
870 #ifdef FREECIV_HAVE_LIBLZMA
872 if (fp
->u
.xz
.error
!= LZMA_OK
873 && fp
->u
.xz
.error
!= LZMA_STREAM_END
) {
879 #endif /* FREECIV_HAVE_LZMA */
880 #ifdef FREECIV_HAVE_LIBBZ2
882 return (BZ_OK
!= fp
->u
.bz2
.error
883 && BZ_STREAM_END
!= fp
->u
.bz2
.error
);
884 #endif /* FREECIV_HAVE_LIBBZ2 */
885 #ifdef FREECIV_HAVE_LIBZ
890 (void) gzerror(fp
->u
.zlib
, &error
); /* Ignore string result here. */
891 return 0 > error
? error
: 0; /* Only negative Z values are errors. */
893 #endif /* FREECIV_HAVE_LIBZ */
895 return ferror(fp
->u
.plain
);
899 /* Should never happen */
900 fc_assert_msg(FALSE
, "Internal error in %s() (method = %d)",
901 __FUNCTION__
, fp
->method
);
905 /***************************************************************
906 Return string (pointer to static memory) containing an error
907 description associated with the file. Should only call
908 this is you know there is an error (eg, from fz_ferror()).
909 Note the error string may be based on errno, so should call
910 this immediately after problem, or possibly something else
911 might overwrite errno.
912 ***************************************************************/
913 const char *fz_strerror(fz_FILE
*fp
)
915 fc_assert_ret_val(NULL
!= fp
, NULL
);
916 fc_assert_ret_val(!fp
->memory
, NULL
);
918 switch (fz_method_validate(fp
->method
)) {
919 #ifdef FREECIV_HAVE_LIBLZMA
922 static char xzerror
[50];
923 char *cleartext
= NULL
;
925 switch(fp
->u
.xz
.error
) {
929 case LZMA_STREAM_END
:
930 cleartext
= "Stream end";
933 cleartext
= "No integrity check";
935 case LZMA_UNSUPPORTED_CHECK
:
936 cleartext
= "Cannot calculate the integrity check";
939 cleartext
= "Mem error";
941 case LZMA_MEMLIMIT_ERROR
:
942 cleartext
= "Memory limit reached";
944 case LZMA_FORMAT_ERROR
:
945 cleartext
= "Unrecognized file format";
947 case LZMA_OPTIONS_ERROR
:
948 cleartext
= "Unsupported options";
950 case LZMA_DATA_ERROR
:
951 cleartext
= "Data error";
954 cleartext
= "Progress not possible";
960 if (NULL
!= cleartext
) {
961 fc_snprintf(xzerror
, sizeof(xzerror
), "XZ: \"%s\" (%d)",
962 cleartext
, fp
->u
.xz
.error
);
964 fc_snprintf(xzerror
, sizeof(xzerror
), "XZ error %d",
970 #endif /* FREECIV_HAVE_LIBLZMA */
971 #ifdef FREECIV_HAVE_LIBBZ2
974 static char bzip2error
[50];
975 const char *cleartext
= NULL
;
977 /* Rationale for translating these:
978 * - Some of them provide usable information to user
979 * - Messages still contain numerical error code for developers
981 switch(fp
->u
.bz2
.error
) {
986 cleartext
= "Run ok";
989 cleartext
= "Flush ok";
992 cleartext
= "Finish ok";
995 cleartext
= "Stream end";
997 case BZ_CONFIG_ERROR
:
998 cleartext
= "Config error";
1000 case BZ_SEQUENCE_ERROR
:
1001 cleartext
= "Sequence error";
1003 case BZ_PARAM_ERROR
:
1004 cleartext
= "Parameter error";
1007 cleartext
= "Mem error";
1010 cleartext
= "Data error";
1012 case BZ_DATA_ERROR_MAGIC
:
1013 cleartext
= "Not bzip2 file";
1016 cleartext
= "IO error";
1018 case BZ_UNEXPECTED_EOF
:
1019 cleartext
= "Unexpected EOF";
1021 case BZ_OUTBUFF_FULL
:
1022 cleartext
= "Output buffer full";
1028 if (cleartext
!= NULL
) {
1029 fc_snprintf(bzip2error
, sizeof(bzip2error
), "Bz2: \"%s\" (%d)",
1030 cleartext
, fp
->u
.bz2
.error
);
1032 fc_snprintf(bzip2error
, sizeof(bzip2error
), "Bz2 error %d",
1037 #endif /* FREECIV_HAVE_LIBBZ2 */
1038 #ifdef FREECIV_HAVE_LIBZ
1042 const char *estr
= gzerror(fp
->u
.zlib
, &errnum
);
1044 return Z_ERRNO
== errnum
? fc_strerror(fc_get_errno()) : estr
;
1046 #endif /* FREECIV_HAVE_LIBZ */
1048 return fc_strerror(fc_get_errno());
1051 /* Should never happen */
1052 fc_assert_msg(FALSE
, "Internal error in %s() (method = %d)",
1053 __FUNCTION__
, fp
->method
);