📄 mccpdecompress.c
字号:
/* * Client decompression module for the mud client compression protocol. * See http://homepages.ihug.co.nz/~icecube/compress/ for more details. * * mccpDecompress.c - module code. Link this with your client code. * * Oliver Jowett <icecube$ihug.co.nz>. Demangle address as needed. * * This code is placed in the public domain. * *//* Modified: 981203 *//* See mccpDecompress.h for API information */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <zlib.h>#include "mccpDecompress.h"/* Telnet values we're interested in */#define IAC 255#define DONT 254#define DO 253#define WONT 252#define WILL 251#define SB 250#define SE 240#define TELOPT_COMPRESS 85/* Server sends IAC WILL COMPRESS * We reply with IAC DO COMPRESS * * Later the server sends IAC SB COMPRESS WILL SE, and immediately following * that, begins compressing * * Compression ends on a Z_STREAM_END, no other marker is used */static char will_sig[] = { IAC, WILL, TELOPT_COMPRESS, 0 };static char do_sig[] = { IAC, DO, TELOPT_COMPRESS, 0 };static char on_sig[] = { IAC, SB, TELOPT_COMPRESS, WILL, SE, 0 };/* this is used on every call to mudcompress_receive */#define will_sig_len 3#define on_sig_len 5/* "Opaque" state object */struct mc_state_s { z_stream *stream; /* stream we're using */ unsigned char *inbuf; /* input buffer (data from mud) */ unsigned int insize; /* .. and how much is used */ unsigned int inalloc; /* .. and how much is allocated */ unsigned char *outbuf; /* output buffer (data to user) */ unsigned int outsize; /* .. and how much is used */ unsigned int outalloc; /* .. and how much is allocated */ int error; int response; unsigned long comp; unsigned long uncomp;};/* Initialise a new state object */mc_state *mudcompress_new(void){ mc_state *state; state = malloc(sizeof(*state)); state->stream = NULL; /* Not decompressing */ state->inalloc = 2048; state->outalloc = 2048; state->inbuf = malloc(state->inalloc); state->outbuf = malloc(state->outalloc); state->insize = 0; state->outsize = 0; state->error = 0; state->comp = 0; state->uncomp = 0; state->response = 0; return state;}/* Clean up a state object */void mudcompress_delete(mc_state *state){ if (state->stream) { inflateEnd(state->stream); free(state->stream); } free(state->inbuf); free(state->outbuf); free(state);}/* zlib helpers */static void *zlib_alloc(void *opaque, unsigned int items, unsigned int size){ return calloc(items, size);}static void zlib_free(void *opaque, void *address){ free(address);}static void grow_inbuf(mc_state *state, int needed){ int old = state->inalloc; while (state->inalloc < state->insize + needed) state->inalloc *= 2; if (old != state->inalloc) state->inbuf = realloc(state->inbuf, state->inalloc);} static void grow_outbuf(mc_state *state, int needed){ int old = state->outalloc; while (state->outalloc < state->outsize + needed) state->outalloc *= 2; if (old != state->outalloc) state->outbuf = realloc(state->outbuf, state->outalloc);}static void decompress_inbuf(mc_state *state){ int status; /* We are now decompressing from inbuf to outbuf */ if (!state->insize) return; /* nothing to decompress? */ state->stream->next_in = state->inbuf; state->stream->next_out = state->outbuf + state->outsize; state->stream->avail_in = state->insize; state->stream->avail_out = state->outalloc - state->outsize; status = inflate(state->stream, Z_PARTIAL_FLUSH); if (status == Z_OK || status == Z_STREAM_END) { /* Successful decompression */ /* Remove used data from inbuf */ state->comp += state->insize - state->stream->avail_in; state->uncomp += state->stream->next_out - state->outbuf; memmove(state->inbuf, state->stream->next_in, state->stream->avail_in); state->insize = state->stream->avail_in; /* Update outbuf pointers */ state->outsize = state->stream->next_out - state->outbuf; /* Done */ if (status == Z_STREAM_END) { /* Turn off compression too */ grow_outbuf(state, state->insize); memcpy(state->outbuf + state->outsize, state->inbuf, state->insize); state->outsize += state->insize; state->insize = 0; inflateEnd(state->stream); free(state->stream); state->stream = NULL; } return; } if (status == Z_BUF_ERROR) { /* Full buffers? Maybe we need more output space.. */ if (state->outsize * 2 > state->outalloc) { grow_outbuf(state, state->outalloc); decompress_inbuf(state); } return; } /* Error */ state->error = 1;}/* We received some data */void mudcompress_receive(mc_state *state, const char *data, unsigned len){ int i; if (state->error) return; if (!state->stream) { int residual = -1; int clen; /* Just copy to outbuf. Also copy any residual inbuf */ grow_outbuf(state, len + state->insize); memcpy(state->outbuf + state->outsize, data, len); state->outsize += len; memcpy(state->outbuf + state->outsize, state->inbuf, state->insize); state->outsize += state->insize; state->insize = 0; /* Check for Magic Marker. ugh this is messy */ for (i=0; i < state->outsize; i++) { if (state->outbuf[i] == IAC) { if (i + 1 < state->outsize && state->outbuf[i+1] == IAC) { /* IAC IAC - ignore */ i++; continue; } clen = (i + will_sig_len < state->outsize) ? will_sig_len : state->outsize - i; if (!memcmp(&state->outbuf[i], will_sig, clen)) { if (clen != will_sig_len) { /* Partial match. Save it. */ residual = i; break; } /* Say we'll do compression. remove sig from inbuf */ state->response = 1; memmove(&state->outbuf[i], &state->outbuf[i + will_sig_len], state->outsize - will_sig_len); state->outsize -= strlen(will_sig); i--; continue; } clen = (i + on_sig_len < state->outsize) ? on_sig_len : state->outsize - i; if (!memcmp(&state->outbuf[i], on_sig, clen)) { if (clen != on_sig_len) { /* Partial match. Save it. */ residual = i; break; } /* Switch to compression */ /* copy any compressible bits to our inbuf */ grow_inbuf(state, state->outsize - i - strlen(on_sig)); memcpy(state->inbuf, state->outbuf + i + strlen(on_sig), state->outsize - i - strlen(on_sig)); state->insize = state->outsize - i - strlen(on_sig); /* clean up our output buffer */ state->outsize = i; /* init stream */ state->stream = malloc(sizeof(z_stream)); state->stream->zalloc = zlib_alloc; state->stream->zfree = zlib_free; state->stream->opaque = NULL; if (inflateInit(state->stream) != Z_OK) { state->error = 1; free(state->stream); state->stream = NULL; return; } /* Continue with decompression */ break; } } } if (!state->stream) { /* didn't start decompressing? */ /* We might have some residual, copy to inbuf for later checking */ if (residual != -1) { grow_inbuf(state, state->outsize - residual); memcpy(state->inbuf + state->insize, state->outbuf + residual, state->outsize - residual); state->outsize = residual; } return; } } else { /* New data to decompress. Copy to inbuf */ grow_inbuf(state, len); memcpy(state->inbuf + state->insize, data, len); state->insize += len; } decompress_inbuf(state);}/* How much data is available? */int mudcompress_pending(mc_state *state){ return state->error ? 0 : state->outsize;}/* Was there an error? */int mudcompress_error(mc_state *state){ return state->error;}/* Get some data */int mudcompress_get(mc_state *state, char *buf, int size){ int copied; if (state->error || !state->outsize) return 0; if (size > state->outsize) copied = state->outsize; else copied = size; memcpy(buf, state->outbuf, copied); state->outsize -= copied; if (state->outsize) memmove(state->outbuf, state->outbuf + copied, state->outsize); /* Do some more decompression */ decompress_inbuf(state); return copied;}void mudcompress_stats(mc_state *state, unsigned long *comp, unsigned long *uncomp){ *comp = state->comp; *uncomp = state->uncomp;}const char *mudcompress_response(mc_state *state){ if (state->response) { state->response = 0; return do_sig; } return NULL;}int mudcompress_compressing(mc_state *state){ return (state->stream != NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -