sl@0: /* inflate.c -- zlib interface to inflate modules sl@0: * Copyright (C) 1995-1998 Mark Adler sl@0: * For conditions of distribution and use, see copyright notice in zlib.h sl@0: */ sl@0: sl@0: #include "zutil.h" sl@0: #include "infblock.h" sl@0: sl@0: struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ sl@0: sl@0: typedef enum { sl@0: METHOD, /* waiting for method byte */ sl@0: FLAG, /* waiting for flag byte */ sl@0: DICT4, /* four dictionary check bytes to go */ sl@0: DICT3, /* three dictionary check bytes to go */ sl@0: DICT2, /* two dictionary check bytes to go */ sl@0: DICT1, /* one dictionary check byte to go */ sl@0: DICT0, /* waiting for inflateSetDictionary */ sl@0: BLOCKS, /* decompressing blocks */ sl@0: CHECK4, /* four check bytes to go */ sl@0: CHECK3, /* three check bytes to go */ sl@0: CHECK2, /* two check bytes to go */ sl@0: CHECK1, /* one check byte to go */ sl@0: DONE, /* finished check, done */ sl@0: BAD} /* got an error--stay here */ sl@0: inflate_mode; sl@0: sl@0: /* inflate private state */ sl@0: struct internal_state { sl@0: sl@0: /* mode */ sl@0: inflate_mode mode; /* current inflate mode */ sl@0: sl@0: /* mode dependent information */ sl@0: union { sl@0: uInt method; /* if FLAGS, method byte */ sl@0: struct { sl@0: uLong was; /* computed check value */ sl@0: uLong need; /* stream check value */ sl@0: } check; /* if CHECK, check values to compare */ sl@0: uInt marker; /* if BAD, inflateSync's marker bytes count */ sl@0: } sub; /* submode */ sl@0: sl@0: /* mode independent information */ sl@0: int nowrap; /* flag for no wrapper */ sl@0: uInt wbits; /* log2(window size) (8..15, defaults to 15) */ sl@0: inflate_blocks_statef sl@0: *blocks; /* current inflate_blocks state */ sl@0: sl@0: }; sl@0: sl@0: sl@0: EXPORT_C int ZEXPORT inflateReset( sl@0: z_streamp z) sl@0: { sl@0: if (z == Z_NULL || z->state == Z_NULL) sl@0: return Z_STREAM_ERROR; sl@0: z->total_in = z->total_out = 0; sl@0: z->msg = Z_NULL; sl@0: z->state->mode = z->state->nowrap ? BLOCKS : METHOD; sl@0: inflate_blocks_reset(z->state->blocks, z, Z_NULL); sl@0: Tracev((stderr, "inflate: reset\n")); sl@0: return Z_OK; sl@0: } sl@0: sl@0: sl@0: EXPORT_C int ZEXPORT inflateEnd( sl@0: z_streamp z) sl@0: { sl@0: if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) sl@0: return Z_STREAM_ERROR; sl@0: if (z->state->blocks != Z_NULL) sl@0: inflate_blocks_free(z->state->blocks, z); sl@0: ZFREE(z, z->state); sl@0: z->state = Z_NULL; sl@0: Tracev((stderr, "inflate: end\n")); sl@0: return Z_OK; sl@0: } sl@0: sl@0: sl@0: EXPORT_C int ZEXPORT inflateInit2_( sl@0: z_streamp z, sl@0: int w, sl@0: const char *version, sl@0: int stream_size) sl@0: { sl@0: if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || sl@0: stream_size != sizeof(z_stream)) sl@0: return Z_VERSION_ERROR; sl@0: sl@0: /* initialize state */ sl@0: if (z == Z_NULL) sl@0: return Z_STREAM_ERROR; sl@0: z->msg = Z_NULL; sl@0: if (z->zalloc == Z_NULL) sl@0: { sl@0: z->zalloc = zcalloc; sl@0: z->opaque = (voidpf)0; sl@0: } sl@0: if (z->zfree == Z_NULL) z->zfree = zcfree; sl@0: if ((z->state = (struct internal_state FAR *) sl@0: ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) sl@0: return Z_MEM_ERROR; sl@0: z->state->blocks = Z_NULL; sl@0: sl@0: /* handle undocumented nowrap option (no zlib header or check) */ sl@0: z->state->nowrap = 0; sl@0: if (w < 0) sl@0: { sl@0: w = - w; sl@0: z->state->nowrap = 1; sl@0: } sl@0: sl@0: /* set window size */ sl@0: if (w < 8 || w > 15) sl@0: { sl@0: inflateEnd(z); sl@0: return Z_STREAM_ERROR; sl@0: } sl@0: z->state->wbits = (uInt)w; sl@0: sl@0: /* create inflate_blocks state */ sl@0: if ((z->state->blocks = sl@0: inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) sl@0: == Z_NULL) sl@0: { sl@0: inflateEnd(z); sl@0: return Z_MEM_ERROR; sl@0: } sl@0: Tracev((stderr, "inflate: allocated\n")); sl@0: sl@0: /* reset state */ sl@0: inflateReset(z); sl@0: return Z_OK; sl@0: } sl@0: sl@0: sl@0: EXPORT_C int ZEXPORT inflateInit_( sl@0: z_streamp z, sl@0: const char *version, sl@0: int stream_size) sl@0: { sl@0: return inflateInit2_(z, DEF_WBITS, version, stream_size); sl@0: } sl@0: sl@0: sl@0: #define NEEDBYTE {if(z->avail_in==0)return r;r=f;} sl@0: #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) sl@0: sl@0: EXPORT_C int ZEXPORT inflate( sl@0: z_streamp z, sl@0: int f) sl@0: { sl@0: int r; sl@0: uInt b; sl@0: sl@0: if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) sl@0: return Z_STREAM_ERROR; sl@0: f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; sl@0: r = Z_BUF_ERROR; sl@0: sl@0: for (;;) switch (z->state->mode) sl@0: { sl@0: case METHOD: sl@0: NEEDBYTE sl@0: if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) sl@0: { sl@0: z->state->mode = BAD; sl@0: z->msg = (char*)"unknown compression method"; sl@0: z->state->sub.marker = 5; /* can't try inflateSync */ sl@0: break; sl@0: } sl@0: if ((z->state->sub.method >> 4) + 8 > z->state->wbits) sl@0: { sl@0: z->state->mode = BAD; sl@0: z->msg = (char*)"invalid window size"; sl@0: z->state->sub.marker = 5; /* can't try inflateSync */ sl@0: break; sl@0: } sl@0: z->state->mode = FLAG; sl@0: case FLAG: sl@0: NEEDBYTE sl@0: b = NEXTBYTE; sl@0: if (((z->state->sub.method << 8) + b) % 31) sl@0: { sl@0: z->state->mode = BAD; sl@0: z->msg = (char*)"incorrect header check"; sl@0: z->state->sub.marker = 5; /* can't try inflateSync */ sl@0: break; sl@0: } sl@0: Tracev((stderr, "inflate: zlib header ok\n")); sl@0: if (!(b & PRESET_DICT)) sl@0: { sl@0: z->state->mode = BLOCKS; sl@0: break; sl@0: } sl@0: z->state->mode = DICT4; sl@0: case DICT4: sl@0: NEEDBYTE sl@0: z->state->sub.check.need = (uLong)NEXTBYTE << 24; sl@0: z->state->mode = DICT3; sl@0: case DICT3: sl@0: NEEDBYTE sl@0: z->state->sub.check.need += (uLong)NEXTBYTE << 16; sl@0: z->state->mode = DICT2; sl@0: case DICT2: sl@0: NEEDBYTE sl@0: z->state->sub.check.need += (uLong)NEXTBYTE << 8; sl@0: z->state->mode = DICT1; sl@0: case DICT1: sl@0: NEEDBYTE sl@0: z->state->sub.check.need += (uLong)NEXTBYTE; sl@0: z->adler = z->state->sub.check.need; sl@0: z->state->mode = DICT0; sl@0: return Z_NEED_DICT; sl@0: case DICT0: sl@0: z->state->mode = BAD; sl@0: z->msg = (char*)"need dictionary"; sl@0: z->state->sub.marker = 0; /* can try inflateSync */ sl@0: return Z_STREAM_ERROR; sl@0: case BLOCKS: sl@0: r = inflate_blocks(z->state->blocks, z, r); sl@0: if (r == Z_DATA_ERROR) sl@0: { sl@0: z->state->mode = BAD; sl@0: z->state->sub.marker = 0; /* can try inflateSync */ sl@0: break; sl@0: } sl@0: if (r == Z_OK) sl@0: r = f; sl@0: if (r != Z_STREAM_END) sl@0: return r; sl@0: r = f; sl@0: inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); sl@0: if (z->state->nowrap) sl@0: { sl@0: z->state->mode = DONE; sl@0: break; sl@0: } sl@0: z->state->mode = CHECK4; sl@0: case CHECK4: sl@0: NEEDBYTE sl@0: z->state->sub.check.need = (uLong)NEXTBYTE << 24; sl@0: z->state->mode = CHECK3; sl@0: case CHECK3: sl@0: NEEDBYTE sl@0: z->state->sub.check.need += (uLong)NEXTBYTE << 16; sl@0: z->state->mode = CHECK2; sl@0: case CHECK2: sl@0: NEEDBYTE sl@0: z->state->sub.check.need += (uLong)NEXTBYTE << 8; sl@0: z->state->mode = CHECK1; sl@0: case CHECK1: sl@0: NEEDBYTE sl@0: z->state->sub.check.need += (uLong)NEXTBYTE; sl@0: sl@0: if (z->state->sub.check.was != z->state->sub.check.need) sl@0: { sl@0: z->state->mode = BAD; sl@0: z->msg = (char*)"incorrect data check"; sl@0: z->state->sub.marker = 5; /* can't try inflateSync */ sl@0: break; sl@0: } sl@0: Tracev((stderr, "inflate: zlib check ok\n")); sl@0: z->state->mode = DONE; sl@0: case DONE: sl@0: return Z_STREAM_END; sl@0: case BAD: sl@0: return Z_DATA_ERROR; sl@0: default: sl@0: return Z_STREAM_ERROR; sl@0: } sl@0: #ifdef NEED_DUMMY_RETURN sl@0: return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ sl@0: #endif sl@0: } sl@0: sl@0: sl@0: EXPORT_C int ZEXPORT inflateSetDictionary( sl@0: z_streamp z, sl@0: const Bytef *dictionary, sl@0: uInt dictLength) sl@0: { sl@0: uInt length = dictLength; sl@0: sl@0: if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) sl@0: return Z_STREAM_ERROR; sl@0: sl@0: if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; sl@0: z->adler = 1L; sl@0: sl@0: if (length >= ((uInt)1<state->wbits)) sl@0: { sl@0: length = (1<state->wbits)-1; sl@0: dictionary += dictLength - length; sl@0: } sl@0: inflate_set_dictionary(z->state->blocks, dictionary, length); sl@0: z->state->mode = BLOCKS; sl@0: return Z_OK; sl@0: } sl@0: sl@0: sl@0: EXPORT_C int ZEXPORT inflateSync( sl@0: z_streamp z) sl@0: { sl@0: uInt n; /* number of bytes to look at */ sl@0: Bytef *p; /* pointer to bytes */ sl@0: uInt m; /* number of marker bytes found in a row */ sl@0: uLong r, w; /* temporaries to save total_in and total_out */ sl@0: sl@0: /* set up */ sl@0: if (z == Z_NULL || z->state == Z_NULL) sl@0: return Z_STREAM_ERROR; sl@0: if (z->state->mode != BAD) sl@0: { sl@0: z->state->mode = BAD; sl@0: z->state->sub.marker = 0; sl@0: } sl@0: if ((n = z->avail_in) == 0) sl@0: return Z_BUF_ERROR; sl@0: p = z->next_in; sl@0: m = z->state->sub.marker; sl@0: sl@0: /* search */ sl@0: while (n && m < 4) sl@0: { sl@0: static const Byte mark[4] = {0, 0, 0xff, 0xff}; sl@0: if (*p == mark[m]) sl@0: m++; sl@0: else if (*p) sl@0: m = 0; sl@0: else sl@0: m = 4 - m; sl@0: p++, n--; sl@0: } sl@0: sl@0: /* restore */ sl@0: z->total_in += p - z->next_in; sl@0: z->next_in = p; sl@0: z->avail_in = n; sl@0: z->state->sub.marker = m; sl@0: sl@0: /* return no joy or set up to restart on a new block */ sl@0: if (m != 4) sl@0: return Z_DATA_ERROR; sl@0: r = z->total_in; w = z->total_out; sl@0: inflateReset(z); sl@0: z->total_in = r; z->total_out = w; sl@0: z->state->mode = BLOCKS; sl@0: return Z_OK; sl@0: } sl@0: sl@0: sl@0: /* Returns true if inflate is currently at the end of a block generated sl@0: * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP sl@0: * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH sl@0: * but removes the length bytes of the resulting empty stored block. When sl@0: * decompressing, PPP checks that at the end of input packet, inflate is sl@0: * waiting for these length bytes. sl@0: */ sl@0: EXPORT_C int ZEXPORT inflateSyncPoint( sl@0: z_streamp z) sl@0: { sl@0: if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) sl@0: return Z_STREAM_ERROR; sl@0: return inflate_blocks_sync_point(z->state->blocks); sl@0: }