depacks.c

来自「一些初级的网络编程」· C语言 代码 · 共 228 行

C
228
字号
/*
 * aPLib compression library  -  the smaller the better :)
 *
 * C safe depacker
 *
 * Copyright (c) 1998-2004 by Joergen Ibsen / Jibz
 * All Rights Reserved
 *
 * http://www.ibsensoftware.com/
 */

#include "depacks.h"

/* internal data structure */
typedef struct {
    const unsigned char *source;
    unsigned int srclen;
    unsigned char *destination;
    unsigned int dstlen;
    unsigned int tag;
    unsigned int bitcount;
} APDEPACKSAFEDATA;

static int aP_getbit_safe(APDEPACKSAFEDATA *ud, unsigned int *result)
{
    unsigned int bit;

    /* check if tag is empty */
    if (!ud->bitcount--)
    {
        if (!ud->srclen--) return 0;
        
        /* load next tag */
        ud->tag = *ud->source++;
        ud->bitcount = 7;
    }

    /* shift bit out of tag */
    bit = (ud->tag >> 7) & 0x01;
    ud->tag <<= 1;

    *result = bit;

    return 1;
}

static int aP_getgamma_safe(APDEPACKSAFEDATA *ud, unsigned int *result)
{
    unsigned int bit;
    unsigned int v = 1;

    /* input gamma2-encoded bits */
    do {

        if (!aP_getbit_safe(ud, &bit)) return 0;

        v = (v << 1) + bit;

        if (!aP_getbit_safe(ud, &bit)) return 0;

    } while (bit);

    *result = v;

    return 1;
}

unsigned int aP_depack_safe(const void *source,
                            unsigned int srclen,
                            void *destination,
                            unsigned int dstlen)
{
    APDEPACKSAFEDATA ud;
    unsigned int offs, len, R0, LWM, bit;
    int done;
    int i;

    if (!source || !destination) return APLIB_ERROR;

    ud.source = (const unsigned char *) source;
    ud.srclen = srclen;
    ud.destination = (unsigned char *) destination;
    ud.dstlen = dstlen;
    ud.bitcount = 0;

    LWM = 0;
    done = 0;

    /* first byte verbatim */
    if (!ud.srclen-- || !ud.dstlen--) return APLIB_ERROR;
    *ud.destination++ = *ud.source++;

    /* main decompression loop */
    while (!done)
    {
        if (!aP_getbit_safe(&ud, &bit)) return APLIB_ERROR;

        if (bit)
        {
            if (!aP_getbit_safe(&ud, &bit)) return APLIB_ERROR;

            if (bit)
            {
                if (!aP_getbit_safe(&ud, &bit)) return APLIB_ERROR;

                if (bit)
                {
                    offs = 0;

                    for (i = 4; i; i--)
                    {
                        if (!aP_getbit_safe(&ud, &bit)) return APLIB_ERROR;
                        offs = (offs << 1) + bit;
                    }

                    if (offs)
                    {
                        if (offs > (dstlen - ud.dstlen)) return APLIB_ERROR;

                        if (!ud.dstlen--) return APLIB_ERROR;

                        *ud.destination = *(ud.destination - offs);
                        ud.destination++;

                    } else {

                        if (!ud.dstlen--) return APLIB_ERROR;

                        *ud.destination++ = 0x00;
                    }

                    LWM = 0;

                } else {

                    if (!ud.srclen--) return APLIB_ERROR;

                    offs = *ud.source++;

                    len = 2 + (offs & 0x0001);

                    offs >>= 1;

                    if (offs)
                    {
                        if (offs > (dstlen - ud.dstlen)) return APLIB_ERROR;

                        if (len > ud.dstlen) return APLIB_ERROR;

                        ud.dstlen -= len;

                        for (; len; len--)
                        {
                            *ud.destination = *(ud.destination - offs);
                            ud.destination++;
                        }
                    } else done = 1;

                    R0 = offs;
                    LWM = 1;
                }

            } else {

                if (!aP_getgamma_safe(&ud, &offs)) return APLIB_ERROR;

                if ((LWM == 0) && (offs == 2))
                {
                    offs = R0;

                    if (!aP_getgamma_safe(&ud, &len)) return APLIB_ERROR;

                    if (offs > (dstlen - ud.dstlen)) return APLIB_ERROR;

                    if (len > ud.dstlen) return APLIB_ERROR;

                    ud.dstlen -= len;

                    for (; len; len--)
                    {
                        *ud.destination = *(ud.destination - offs);
                        ud.destination++;
                    }

                } else {

                    if (LWM == 0) offs -= 3; else offs -= 2;

                    if (!ud.srclen--) return APLIB_ERROR;

                    offs <<= 8;
                    offs += *ud.source++;

                    if (!aP_getgamma_safe(&ud, &len)) return APLIB_ERROR;

                    if (offs >= 32000) len++;
                    if (offs >= 1280) len++;
                    if (offs < 128) len += 2;

                    if (offs > (dstlen - ud.dstlen)) return APLIB_ERROR;

                    if (len > ud.dstlen) return APLIB_ERROR;

                    ud.dstlen -= len;

                    for (; len; len--)
                    {
                        *ud.destination = *(ud.destination - offs);
                        ud.destination++;
                    }

                    R0 = offs;
                }

                LWM = 1;
            }

        } else {

            if (!ud.srclen-- || !ud.dstlen--) return APLIB_ERROR;
            *ud.destination++ = *ud.source++;
            LWM = 0;
        }
    }

    return ud.destination - (unsigned char *) destination;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?