Path: blob/main/sys/contrib/zstd/zlibWrapper/gzlib.c
48254 views
/* gzlib.c contains minimal changes required to be compiled with zlibWrapper:1* - gz_statep was converted to union to work with -Wstrict-aliasing=1 */23/* gzlib.c -- zlib functions common to reading and writing gzip files4* Copyright (C) 2004-2017 Mark Adler5* For conditions of distribution and use, see http://www.zlib.net/zlib_license.html6*/78#include "gzguts.h"910#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)11# define LSEEK _lseeki6412#else13#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-014# define LSEEK lseek6415#else16# define LSEEK lseek17#endif18#endif1920/* Local functions */21local void gz_reset OF((gz_statep));22local gzFile gz_open OF((const void *, int, const char *));2324#if defined UNDER_CE2526/* Map the Windows error number in ERROR to a locale-dependent error message27string and return a pointer to it. Typically, the values for ERROR come28from GetLastError.2930The string pointed to shall not be modified by the application, but may be31overwritten by a subsequent call to gz_strwinerror3233The gz_strwinerror function does not change the current setting of34GetLastError. */35char ZLIB_INTERNAL *gz_strwinerror (error)36DWORD error;37{38static char buf[1024];3940wchar_t *msgbuf;41DWORD lasterr = GetLastError();42DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM43| FORMAT_MESSAGE_ALLOCATE_BUFFER,44NULL,45error,460, /* Default language */47(LPVOID)&msgbuf,480,49NULL);50if (chars != 0) {51/* If there is an \r\n appended, zap it. */52if (chars >= 253&& msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {54chars -= 2;55msgbuf[chars] = 0;56}5758if (chars > sizeof (buf) - 1) {59chars = sizeof (buf) - 1;60msgbuf[chars] = 0;61}6263wcstombs(buf, msgbuf, chars + 1);64LocalFree(msgbuf);65}66else {67sprintf(buf, "unknown win32 error (%ld)", error);68}6970SetLastError(lasterr);71return buf;72}7374#endif /* UNDER_CE */7576/* Reset gzip file state */77local void gz_reset(state)78gz_statep state;79{80state.state->x.have = 0; /* no output data available */81if (state.state->mode == GZ_READ) { /* for reading ... */82state.state->eof = 0; /* not at end of file */83state.state->past = 0; /* have not read past end yet */84state.state->how = LOOK; /* look for gzip header */85}86state.state->seek = 0; /* no seek request pending */87gz_error(state, Z_OK, NULL); /* clear error */88state.state->x.pos = 0; /* no uncompressed data yet */89state.state->strm.avail_in = 0; /* no input data yet */90}9192/* Open a gzip file either by name or file descriptor. */93local gzFile gz_open(path, fd, mode)94const void *path;95int fd;96const char *mode;97{98gz_statep state;99z_size_t len;100int oflag;101#ifdef O_CLOEXEC102int cloexec = 0;103#endif104#ifdef O_EXCL105int exclusive = 0;106#endif107108/* check input */109if (path == NULL)110return NULL;111112/* allocate gzFile structure to return */113state.state = (gz_state*)malloc(sizeof(gz_state));114if (state.state == NULL)115return NULL;116state.state->size = 0; /* no buffers allocated yet */117state.state->want = GZBUFSIZE; /* requested buffer size */118state.state->msg = NULL; /* no error message yet */119120/* interpret mode */121state.state->mode = GZ_NONE;122state.state->level = Z_DEFAULT_COMPRESSION;123state.state->strategy = Z_DEFAULT_STRATEGY;124state.state->direct = 0;125while (*mode) {126if (*mode >= '0' && *mode <= '9')127state.state->level = *mode - '0';128else129switch (*mode) {130case 'r':131state.state->mode = GZ_READ;132break;133#ifndef NO_GZCOMPRESS134case 'w':135state.state->mode = GZ_WRITE;136break;137case 'a':138state.state->mode = GZ_APPEND;139break;140#endif141case '+': /* can't read and write at the same time */142free(state.state);143return NULL;144case 'b': /* ignore -- will request binary anyway */145break;146#ifdef O_CLOEXEC147case 'e':148cloexec = 1;149break;150#endif151#ifdef O_EXCL152case 'x':153exclusive = 1;154break;155#endif156case 'f':157state.state->strategy = Z_FILTERED;158break;159case 'h':160state.state->strategy = Z_HUFFMAN_ONLY;161break;162case 'R':163state.state->strategy = Z_RLE;164break;165case 'F':166state.state->strategy = Z_FIXED;167break;168case 'T':169state.state->direct = 1;170break;171default: /* could consider as an error, but just ignore */172;173}174mode++;175}176177/* must provide an "r", "w", or "a" */178if (state.state->mode == GZ_NONE) {179free(state.state);180return NULL;181}182183/* can't force transparent read */184if (state.state->mode == GZ_READ) {185if (state.state->direct) {186free(state.state);187return NULL;188}189state.state->direct = 1; /* for empty file */190}191192/* save the path name for error messages */193#ifdef WIDECHAR194if (fd == -2) {195len = wcstombs(NULL, path, 0);196if (len == (z_size_t)-1)197len = 0;198}199else200#endif201len = strlen((const char *)path);202state.state->path = (char *)malloc(len + 1);203if (state.state->path == NULL) {204free(state.state);205return NULL;206}207#ifdef WIDECHAR208if (fd == -2)209if (len)210wcstombs(state.state->path, path, len + 1);211else212*(state.state->path) = 0;213else214#endif215#if !defined(NO_snprintf) && !defined(NO_vsnprintf)216(void)snprintf(state.state->path, len + 1, "%s", (const char *)path);217#else218strcpy(state.state->path, (const char*)path);219#endif220221/* compute the flags for open() */222oflag =223#ifdef O_LARGEFILE224O_LARGEFILE |225#endif226#ifdef O_BINARY227O_BINARY |228#endif229#ifdef O_CLOEXEC230(cloexec ? O_CLOEXEC : 0) |231#endif232(state.state->mode == GZ_READ ?233O_RDONLY :234(O_WRONLY | O_CREAT |235#ifdef O_EXCL236(exclusive ? O_EXCL : 0) |237#endif238(state.state->mode == GZ_WRITE ?239O_TRUNC :240O_APPEND)));241242/* open the file with the appropriate flags (or just use fd) */243state.state->fd = fd > -1 ? fd : (244#ifdef WIDECHAR245fd == -2 ? _wopen(path, oflag, 0666) :246#endif247open((const char *)path, oflag, 0666));248if (state.state->fd == -1) {249free(state.state->path);250free(state.state);251return NULL;252}253if (state.state->mode == GZ_APPEND) {254LSEEK(state.state->fd, 0, SEEK_END); /* so gzoffset() is correct */255state.state->mode = GZ_WRITE; /* simplify later checks */256}257258/* save the current position for rewinding (only if reading) */259if (state.state->mode == GZ_READ) {260state.state->start = LSEEK(state.state->fd, 0, SEEK_CUR);261if (state.state->start == -1) state.state->start = 0;262}263264/* initialize stream */265gz_reset(state);266267/* return stream */268return state.file;269}270271/* -- see zlib.h -- */272gzFile ZEXPORT gzopen(path, mode)273const char *path;274const char *mode;275{276return gz_open(path, -1, mode);277}278279/* -- see zlib.h -- */280gzFile ZEXPORT gzopen64(path, mode)281const char *path;282const char *mode;283{284return gz_open(path, -1, mode);285}286287/* -- see zlib.h -- */288gzFile ZEXPORT gzdopen(fd, mode)289int fd;290const char *mode;291{292char *path; /* identifier for error messages */293gzFile gz;294295if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)296return NULL;297#if !defined(NO_snprintf) && !defined(NO_vsnprintf)298(void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);299#else300sprintf(path, "<fd:%d>", fd); /* for debugging */301#endif302gz = gz_open(path, fd, mode);303free(path);304return gz;305}306307/* -- see zlib.h -- */308#ifdef WIDECHAR309gzFile ZEXPORT gzopen_w(path, mode)310const wchar_t *path;311const char *mode;312{313return gz_open(path, -2, mode);314}315#endif316317/* -- see zlib.h -- */318int ZEXPORT gzbuffer(file, size)319gzFile file;320unsigned size;321{322gz_statep state;323324/* get internal structure and check integrity */325if (file == NULL)326return -1;327state.file = file;328if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)329return -1;330331/* make sure we haven't already allocated memory */332if (state.state->size != 0)333return -1;334335/* check and set requested size */336if ((size << 1) < size)337return -1; /* need to be able to double it */338if (size < 2)339size = 2; /* need two bytes to check magic header */340state.state->want = size;341return 0;342}343344/* -- see zlib.h -- */345int ZEXPORT gzrewind(file)346gzFile file;347{348gz_statep state;349350/* get internal structure */351if (file == NULL)352return -1;353state.file = file;354355/* check that we're reading and that there's no error */356if (state.state->mode != GZ_READ ||357(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))358return -1;359360/* back up and start over */361if (LSEEK(state.state->fd, state.state->start, SEEK_SET) == -1)362return -1;363gz_reset(state);364return 0;365}366367/* -- see zlib.h -- */368z_off64_t ZEXPORT gzseek64(file, offset, whence)369gzFile file;370z_off64_t offset;371int whence;372{373unsigned n;374z_off64_t ret;375gz_statep state;376377/* get internal structure and check integrity */378if (file == NULL)379return -1;380state.file = file;381if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)382return -1;383384/* check that there's no error */385if (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)386return -1;387388/* can only seek from start or relative to current position */389if (whence != SEEK_SET && whence != SEEK_CUR)390return -1;391392/* normalize offset to a SEEK_CUR specification */393if (whence == SEEK_SET)394offset -= state.state->x.pos;395else if (state.state->seek)396offset += state.state->skip;397state.state->seek = 0;398399/* if within raw area while reading, just go there */400if (state.state->mode == GZ_READ && state.state->how == COPY &&401state.state->x.pos + offset >= 0) {402ret = LSEEK(state.state->fd, offset - state.state->x.have, SEEK_CUR);403if (ret == -1)404return -1;405state.state->x.have = 0;406state.state->eof = 0;407state.state->past = 0;408state.state->seek = 0;409gz_error(state, Z_OK, NULL);410state.state->strm.avail_in = 0;411state.state->x.pos += offset;412return state.state->x.pos;413}414415/* calculate skip amount, rewinding if needed for back seek when reading */416if (offset < 0) {417if (state.state->mode != GZ_READ) /* writing -- can't go backwards */418return -1;419offset += state.state->x.pos;420if (offset < 0) /* before start of file! */421return -1;422if (gzrewind(file) == -1) /* rewind, then skip to offset */423return -1;424}425426/* if reading, skip what's in output buffer (one less gzgetc() check) */427if (state.state->mode == GZ_READ) {428n = GT_OFF(state.state->x.have) || (z_off64_t)state.state->x.have > offset ?429(unsigned)offset : state.state->x.have;430state.state->x.have -= n;431state.state->x.next += n;432state.state->x.pos += n;433offset -= n;434}435436/* request skip (if not zero) */437if (offset) {438state.state->seek = 1;439state.state->skip = offset;440}441return state.state->x.pos + offset;442}443444/* -- see zlib.h -- */445z_off_t ZEXPORT gzseek(file, offset, whence)446gzFile file;447z_off_t offset;448int whence;449{450z_off64_t ret;451452ret = gzseek64(file, (z_off64_t)offset, whence);453return ret == (z_off_t)ret ? (z_off_t)ret : -1;454}455456/* -- see zlib.h -- */457z_off64_t ZEXPORT gztell64(file)458gzFile file;459{460gz_statep state;461462/* get internal structure and check integrity */463if (file == NULL)464return -1;465state.file = file;466if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)467return -1;468469/* return position */470return state.state->x.pos + (state.state->seek ? state.state->skip : 0);471}472473/* -- see zlib.h -- */474z_off_t ZEXPORT gztell(file)475gzFile file;476{477z_off64_t ret;478479ret = gztell64(file);480return ret == (z_off_t)ret ? (z_off_t)ret : -1;481}482483/* -- see zlib.h -- */484z_off64_t ZEXPORT gzoffset64(file)485gzFile file;486{487z_off64_t offset;488gz_statep state;489490/* get internal structure and check integrity */491if (file == NULL)492return -1;493state.file = file;494if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)495return -1;496497/* compute and return effective offset in file */498offset = LSEEK(state.state->fd, 0, SEEK_CUR);499if (offset == -1)500return -1;501if (state.state->mode == GZ_READ) /* reading */502offset -= state.state->strm.avail_in; /* don't count buffered input */503return offset;504}505506/* -- see zlib.h -- */507z_off_t ZEXPORT gzoffset(file)508gzFile file;509{510z_off64_t ret;511512ret = gzoffset64(file);513return ret == (z_off_t)ret ? (z_off_t)ret : -1;514}515516/* -- see zlib.h -- */517int ZEXPORT gzeof(file)518gzFile file;519{520gz_statep state;521522/* get internal structure and check integrity */523if (file == NULL)524return 0;525state.file = file;526if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)527return 0;528529/* return end-of-file state */530return state.state->mode == GZ_READ ? state.state->past : 0;531}532533/* -- see zlib.h -- */534const char * ZEXPORT gzerror(file, errnum)535gzFile file;536int *errnum;537{538gz_statep state;539540/* get internal structure and check integrity */541if (file == NULL)542return NULL;543state.file = file;544if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)545return NULL;546547/* return error information */548if (errnum != NULL)549*errnum = state.state->err;550return state.state->err == Z_MEM_ERROR ? "out of memory" :551(state.state->msg == NULL ? "" : state.state->msg);552}553554/* -- see zlib.h -- */555void ZEXPORT gzclearerr(file)556gzFile file;557{558gz_statep state;559560/* get internal structure and check integrity */561if (file == NULL)562return;563state.file = file;564if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)565return;566567/* clear error and end-of-file */568if (state.state->mode == GZ_READ) {569state.state->eof = 0;570state.state->past = 0;571}572gz_error(state, Z_OK, NULL);573}574575/* Create an error message in allocated memory and set state.state->err and576state.state->msg accordingly. Free any previous error message already there. Do577not try to free or allocate space if the error is Z_MEM_ERROR (out of578memory). Simply save the error message as a static string. If there is an579allocation failure constructing the error message, then convert the error to580out of memory. */581void ZLIB_INTERNAL gz_error(state, err, msg)582gz_statep state;583int err;584const char *msg;585{586/* free previously allocated message and clear */587if (state.state->msg != NULL) {588if (state.state->err != Z_MEM_ERROR)589free(state.state->msg);590state.state->msg = NULL;591}592593/* if fatal, set state.state->x.have to 0 so that the gzgetc() macro fails */594if (err != Z_OK && err != Z_BUF_ERROR)595state.state->x.have = 0;596597/* set error code, and if no message, then done */598state.state->err = err;599if (msg == NULL)600return;601602/* for an out of memory error, return literal string when requested */603if (err == Z_MEM_ERROR)604return;605606/* construct error message with path */607if ((state.state->msg = (char *)malloc(strlen(state.state->path) + strlen(msg) + 3)) ==608NULL) {609state.state->err = Z_MEM_ERROR;610return;611}612#if !defined(NO_snprintf) && !defined(NO_vsnprintf)613(void)snprintf(state.state->msg, strlen(state.state->path) + strlen(msg) + 3,614"%s%s%s", state.state->path, ": ", msg);615#else616strcpy(state.state->msg, state.state->path);617strcat(state.state->msg, ": ");618strcat(state.state->msg, msg);619#endif620}621622#ifndef INT_MAX623/* portably return maximum value for an int (when limits.h presumed not624available) -- we need to do this to cover cases where 2's complement not625used, since C standard permits 1's complement and sign-bit representations,626otherwise we could just use ((unsigned)-1) >> 1 */627unsigned ZLIB_INTERNAL gz_intmax()628{629unsigned p, q;630631p = 1;632do {633q = p;634p <<= 1;635p++;636} while (p > q);637return q >> 1;638}639#endif640641642