123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /*
- misc_z.c - miscellaneous zlib functions
- Copyright (c) 2001 - 2004, 2015 dbjh
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h" // USE_ZLIB
- #endif
- #ifdef USE_ZLIB
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable: 4820) // 'bytes' bytes padding added after construct 'member_name'
- #endif
- #include <sys/stat.h>
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #include <zlib.h>
- #include "misc_z.h"
- #include "misc.h"
- #include "map.h"
- #include "unzip.h"
- #if defined DJGPP && defined DLL
- #include "dxedll_priv.h"
- #endif
- int
- q_fsize (const char *filename)
- // If USE_ZLIB is defined this function is very slow. Please avoid to use
- // it much.
- {
- FILE *file;
- unsigned char magic[4] = { 0 };
- #undef fopen
- #undef fread
- #undef fclose
- if ((file = fopen (filename, "rb")) == NULL)
- {
- errno = ENOENT;
- return -1;
- }
- fread (magic, 1, sizeof (magic), file);
- fclose (file);
- #define fopen fopen2
- #define fclose fclose2
- #define fread fread2
- if (magic[0] == 0x1f && magic[1] == 0x8b && magic[2] == 0x08)
- { // ID1, ID2 and CM. gzip uses Compression Method 8
- int size = 0;
- if ((file = (FILE *) gzopen (filename, "rb")) == NULL)
- { // Shouldn't fail because we could open it with fopen()
- errno = ENOENT;
- return -1;
- }
- #if 1
- // This is not much faster than the method below
- while (!gzeof ((gzFile) file))
- {
- gzseek ((gzFile) file, 1024 * 1024, SEEK_CUR);
- gzgetc ((gzFile) file); // necessary in order to set EOF (zlib 1.2.8)
- }
- #else
- // Is there a more efficient way to determine the uncompressed size?
- unsigned char buf[MAXBUFSIZE];
- while (gzread ((gzFile) file, buf, MAXBUFSIZE) > 0)
- ;
- #endif
- size = gztell ((gzFile) file);
- gzclose ((gzFile) file);
- return size;
- }
- else if (magic[0] == 'P' && magic[1] == 'K' && magic[2] == 0x03 && magic[3] == 0x04)
- {
- unz_file_info info;
- if ((file = (FILE *) unzOpen (filename)) == NULL)
- {
- errno = ENOENT;
- return -1;
- }
- unzip_goto_file (file, unzip_current_file_nr);
- unzGetCurrentFileInfo (file, &info, NULL, 0, NULL, 0, NULL, 0);
- unzClose (file);
- return info.uncompressed_size;
- }
- else
- {
- struct stat fstate;
- if (!stat (filename, &fstate))
- return fstate.st_size;
- errno = ENOENT;
- return -1;
- }
- }
- /*
- The zlib functions gzwrite() and gzputc() write compressed data if the file
- was opened with a "w" in the mode string, but we want to control whether we
- write compressed data. Note that for the mode string "w+", zlib ignores the
- '+'. zlib does the same for "r+".
- Currently we never write compressed data. That is, no code fopen()s files
- with a mode string containing 'f', 'h' or a number, but writing compressed
- output does work.
- */
- st_map_t *fh_map = NULL; // associative array: file handle -> file mode
- typedef enum { FM_NORMAL, FM_GZIP, FM_ZIP, FM_UNDEF } fmode2_t;
- typedef struct st_finfo
- {
- fmode2_t fmode;
- int compressed;
- } st_finfo_t;
- static st_finfo_t finfo_list[6] = { {FM_NORMAL, 0},
- {FM_NORMAL, 1}, // should never be used
- {FM_GZIP, 0},
- {FM_GZIP, 1},
- {FM_ZIP, 0}, // should never be used
- {FM_ZIP, 1} };
- int unzip_current_file_nr = 0;
- static void
- init_fh_map (void)
- {
- fh_map = map_create (20); // 20 simultaneous open files
- map_put (fh_map, stdin, &finfo_list[0]); // should be enough to start with
- map_put (fh_map, stdout, &finfo_list[0]);
- map_put (fh_map, stderr, &finfo_list[0]);
- }
- static st_finfo_t *
- get_finfo (FILE *file)
- {
- st_finfo_t *finfo;
- if (fh_map == NULL)
- init_fh_map ();
- if ((finfo = (st_finfo_t *) map_get (fh_map, file)) == NULL)
- {
- fprintf (stderr, "\nINTERNAL ERROR: File pointer was not present in map (%p)\n", file);
- map_dump (fh_map);
- exit (1);
- }
- return finfo;
- }
- static fmode2_t
- get_fmode (FILE *file)
- {
- return get_finfo (file)->fmode;
- }
- int
- unzip_get_number_entries (const char *filename)
- {
- FILE *file;
- unsigned char magic[4] = { 0 };
- #undef fopen
- #undef fread
- #undef fclose
- if ((file = fopen (filename, "rb")) == NULL)
- {
- errno = ENOENT;
- return -1;
- }
- fread (magic, 1, sizeof (magic), file);
- fclose (file);
- #define fopen fopen2
- #define fclose fclose2
- #define fread fread2
- if (magic[0] == 'P' && magic[1] == 'K' && magic[2] == 0x03 && magic[3] == 0x04)
- {
- unz_global_info info;
- file = (FILE *) unzOpen (filename);
- unzGetGlobalInfo (file, &info);
- unzClose (file);
- return info.number_entry;
- }
- else
- return -1;
- }
- int
- unzip_goto_file (unzFile file, int file_index)
- {
- int retval = unzGoToFirstFile (file), n = 0;
- if (file_index > 0)
- while (n < file_index)
- {
- retval = unzGoToNextFile (file);
- n++;
- }
- return retval;
- }
- static int
- unzip_seek_helper (FILE *file, int offset)
- {
- char buffer[MAXBUFSIZE];
- int n, tmp, pos = unztell (file); // returns ftell() of the "current file"
- if (pos == offset)
- return 0;
- else if (pos > offset)
- {
- unzCloseCurrentFile (file);
- unzip_goto_file (file, unzip_current_file_nr);
- unzOpenCurrentFile (file);
- pos = 0;
- }
- n = offset - pos;
- while (n > 0 && !unzeof (file))
- {
- tmp = unzReadCurrentFile (file, buffer, n > MAXBUFSIZE ? MAXBUFSIZE : n);
- if (tmp < 0)
- return -1;
- n -= tmp;
- }
- return n > 0 ? -1 : 0;
- }
- FILE *
- fopen2 (const char *filename, const char *mode)
- {
- #undef fopen
- int n, len = strlen (mode), read = 0, compressed = 0;
- fmode2_t fmode = FM_UNDEF;
- st_finfo_t *finfo;
- FILE *file = NULL;
- // printf ("opening %s", filename);
- if (fh_map == NULL)
- init_fh_map ();
- for (n = 0; n < len; n++)
- {
- switch (mode[n])
- {
- case 'r':
- read = 1;
- break;
- case 'f':
- case 'h':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- fmode = FM_GZIP;
- break;
- case 'w':
- case 'a':
- fmode = FM_NORMAL;
- break;
- case '+':
- if (fmode == FM_UNDEF)
- fmode = FM_NORMAL;
- break;
- }
- }
- if (read)
- {
- #undef fread
- #undef fclose
- unsigned char magic[4] = { 0 };
- FILE *fh;
- // TODO?: check if mode is valid for fopen(), i.e., no 'f', 'h' or number
- if ((fh = fopen (filename, mode)) != NULL)
- {
- fread (magic, sizeof (magic), 1, fh);
- if (magic[0] == 0x1f && magic[1] == 0x8b && magic[2] == 0x08)
- { // ID1, ID2 and CM. gzip uses Compression Method 8
- fmode = FM_GZIP;
- compressed = 1;
- }
- else if (magic[0] == 'P' && magic[1] == 'K' &&
- magic[2] == 0x03 && magic[3] == 0x04)
- {
- fmode = FM_ZIP;
- compressed = 1;
- }
- else
- /*
- Files that are opened with mode "r+" will probably be written to.
- zlib doesn't support mode "r+", so we have to use FM_NORMAL.
- Mode "r" doesn't require FM_NORMAL and FM_GZIP works, but we
- shouldn't introduce needless overhead.
- */
- fmode = FM_NORMAL;
- fclose (fh);
- }
- #define fread fread2
- #define fclose fclose2
- }
- if (fmode == FM_NORMAL)
- file = fopen (filename, mode);
- else if (fmode == FM_GZIP)
- file = (FILE *) gzopen (filename, mode);
- else if (fmode == FM_ZIP)
- {
- file = (FILE *) unzOpen (filename);
- if (file != NULL)
- {
- unzip_goto_file (file, unzip_current_file_nr);
- unzOpenCurrentFile (file);
- }
- }
- if (file == NULL)
- return NULL;
- finfo = &finfo_list[fmode * 2 + compressed];
- fh_map = map_put (fh_map, file, finfo);
- /*
- printf (", ptr = %p, mode = %s, fmode = %s\n", file, mode,
- fmode == FM_NORMAL ? "FM_NORMAL" :
- (fmode == FM_GZIP ? "FM_GZIP" :
- (fmode == FM_ZIP ? "FM_ZIP" : "FM_UNDEF")));
- map_dump (fh_map);
- */
- return file;
- #define fopen fopen2
- }
- int
- fclose2 (FILE *file)
- {
- #undef fclose
- fmode2_t fmode = get_fmode (file);
- map_del (fh_map, file);
- if (fmode == FM_NORMAL)
- return fclose (file);
- else if (fmode == FM_GZIP)
- return gzclose ((gzFile) file);
- else if (fmode == FM_ZIP)
- {
- unzCloseCurrentFile (file);
- return unzClose (file);
- }
- else
- return EOF;
- #define fclose fclose2
- }
- int
- fseek2 (FILE *file, long offset, int mode)
- {
- #undef fseek
- st_finfo_t *finfo = get_finfo (file);
- /*
- // if (fmode != FM_NORMAL)
- printf ("fmode = %s\n", finfo->fmode == FM_NORMAL ? "FM_NORMAL" :
- (finfo->fmode == FM_GZIP ? "FM_GZIP" :
- (finfo->fmode == FM_ZIP ? "FM_ZIP" : "FM_UNDEF")));
- */
- if (finfo->fmode == FM_NORMAL)
- return fseek (file, offset, mode);
- else if (finfo->fmode == FM_GZIP)
- {
- if (mode == SEEK_END) // zlib doesn't support SEEK_END
- {
- // Note that this is _slow_...
- unsigned char buf[MAXBUFSIZE];
- while (gzread ((gzFile) file, buf, MAXBUFSIZE) > 0)
- ;
- offset += gztell ((gzFile) file);
- mode = SEEK_SET;
- }
- return gzseek ((gzFile) file, offset, mode) == -1 ? -1 : 0;
- }
- else if (finfo->fmode == FM_ZIP)
- {
- int base;
- if (mode != SEEK_SET && mode != SEEK_CUR && mode != SEEK_END)
- {
- errno = EINVAL;
- return -1;
- }
- if (mode == SEEK_SET)
- base = 0;
- else if (mode == SEEK_CUR)
- base = unztell (file);
- else // mode == SEEK_END
- {
- unz_file_info info;
- unzip_goto_file (file, unzip_current_file_nr);
- unzGetCurrentFileInfo (file, &info, NULL, 0, NULL, 0, NULL, 0);
- base = info.uncompressed_size;
- }
- return unzip_seek_helper (file, base + offset);
- }
- return -1;
- #define fseek fseek2
- }
- size_t
- fread2 (void *buffer, size_t size, size_t number, FILE *file)
- {
- #undef fread
- fmode2_t fmode = get_fmode (file);
- if (size == 0 || number == 0)
- return 0;
- if (fmode == FM_NORMAL)
- return fread (buffer, size, number, file);
- else if (fmode == FM_GZIP)
- {
- int n = gzread ((gzFile) file, buffer, number * size);
- return n / size;
- }
- else if (fmode == FM_ZIP)
- {
- int n = unzReadCurrentFile (file, buffer, number * size);
- return n / size;
- }
- return 0;
- #define fread fread2
- }
- int
- fgetc2 (FILE *file)
- {
- #undef fgetc
- fmode2_t fmode = get_fmode (file);
- if (fmode == FM_NORMAL)
- return fgetc (file);
- else if (fmode == FM_GZIP)
- return gzgetc ((gzFile) file);
- else if (fmode == FM_ZIP)
- {
- char c;
- int retval = unzReadCurrentFile (file, &c, 1);
- return retval <= 0 ? EOF : c & 0xff; // avoid sign bit extension
- }
- else
- return EOF;
- #define fgetc fgetc2
- }
- char *
- fgets2 (char *buffer, int maxlength, FILE *file)
- {
- #undef fgets
- fmode2_t fmode = get_fmode (file);
- if (fmode == FM_NORMAL)
- return fgets (buffer, maxlength, file);
- else if (fmode == FM_GZIP)
- {
- char *retval = gzgets ((gzFile) file, buffer, maxlength);
- return retval == Z_NULL ? NULL : retval;
- }
- else if (fmode == FM_ZIP)
- {
- int n = 0, c = 0;
- while (n < maxlength - 1 && (c = fgetc (file)) != EOF)
- {
- buffer[n] = (char) c; // '\n' must also be stored in buffer
- n++;
- if (c == '\n')
- {
- buffer[n] = 0;
- break;
- }
- }
- if (n >= maxlength - 1 || c == EOF)
- buffer[n] = 0;
- return n > 0 ? buffer : NULL;
- }
- else
- return NULL;
- #define fgets fgets2
- }
- int
- feof2 (FILE *file)
- {
- #undef feof
- fmode2_t fmode = get_fmode (file);
- if (fmode == FM_NORMAL)
- return feof (file);
- else if (fmode == FM_GZIP)
- return gzeof ((gzFile) file);
- else if (fmode == FM_ZIP)
- return unzeof (file); // returns feof() of the "current file"
- else
- return -1;
- #define feof feof2
- }
- size_t
- fwrite2 (const void *buffer, size_t size, size_t number, FILE *file)
- {
- #undef fwrite
- fmode2_t fmode = get_fmode (file);
- if (size == 0 || number == 0)
- return 0;
- if (fmode == FM_NORMAL)
- return fwrite (buffer, size, number, file);
- else if (fmode == FM_GZIP)
- {
- int n = gzwrite ((gzFile) file, (void *) buffer, number * size);
- return n / size;
- }
- else
- return 0; // writing to zip files is not supported
- #define fwrite fwrite2
- }
- int
- fputc2 (int character, FILE *file)
- {
- #undef fputc
- fmode2_t fmode = get_fmode (file);
- if (fmode == FM_NORMAL)
- return fputc (character, file);
- else if (fmode == FM_GZIP)
- return gzputc ((gzFile) file, character);
- else
- return EOF; // writing to zip files is not supported
- #define fputc fputc2
- }
- long
- ftell2 (FILE *file)
- {
- #undef ftell
- fmode2_t fmode = get_fmode (file);
- if (fmode == FM_NORMAL)
- return ftell (file);
- else if (fmode == FM_GZIP)
- return gztell ((gzFile) file);
- else if (fmode == FM_ZIP)
- return unztell (file); // returns ftell() of the "current file"
- else
- return -1;
- #define ftell ftell2
- }
- void
- rewind2 (FILE *file)
- {
- fseek2 (file, 0, SEEK_SET);
- }
- FILE *
- popen2 (const char *command, const char *mode)
- {
- #undef popen
- #if defined _WIN32 || defined AMIGA
- #define popen _popen
- #endif
- int compressed = 0;
- fmode2_t fmode = FM_NORMAL;
- st_finfo_t *finfo;
- FILE *file;
- if (fh_map == NULL)
- init_fh_map ();
- if ((file = popen (command, mode)) == NULL)
- return NULL;
- finfo = &finfo_list[fmode * 2 + compressed];
- fh_map = map_put (fh_map, file, finfo);
- return file;
- #undef popen
- #define popen popen2
- }
- int
- pclose2 (FILE *stream)
- {
- #undef pclose
- #if defined _WIN32 || defined AMIGA
- #define pclose _pclose
- #endif
- fmode2_t fmode = get_fmode (stream);
- if (fmode == FM_NORMAL)
- return pclose (stream);
- else if (fmode == FM_GZIP || fmode == FM_ZIP)
- return -1;
- else
- return -1;
- #undef pclose
- #define pclose pclose2
- }
- #endif // USE_ZLIB
|