C解压缩位掩码源

时间:2015-08-11 23:44:28

标签: c bitwise-operators

这可能是一个奇怪的问题以及我在这个网站上的第一个问题和一个相当复杂的问题基本上我要求这个解压缩器用于一个非常具体的存档文件,我几乎无法理解这个但是从我能掌握的东西它的某种"位掩码"它从目标文件中读取前2个字节,并将它们存储为序列。

第一个for循环是让我感到困惑的地方

为参数说谎,为掩码是2字节10 04,或1040(十进制),这通常是这些文件中的内容

    for (t = 0; t<16; t++) {
        if (mask & (1 << (15 - t))) { 

这似乎是循环遍历这两个字节的所有16位并在每个位上的掩码(1040)上运行AND操作?
if语句是我完全不了解的内容?是什么触发了if?如果该位大于0?

因为如果面具是1040,那么真正看的是

if(1040 & 32768)    index 15
if(1040 & 16384)    index 14
if(1040 & 8192)     index 13
if(1040 & 4096)     index 12
if(1040 & 2048)     index 11
if(1040 & 1024)     index 10
if(1040 & 512)      and so on.....
if(1040 & 256)

我真的需要知道什么是触发这个if语句?我想我可能会过度思考它,但如果当前位大于0,它是否会触发?

我能做的唯一其他事情就是自己编译这个源代码,在关键变量上插入printfs并与十六进制编辑器携手并尝试弄清楚这里真正发生了什么,如果有人能帮我一把真棒。

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

uint8_t  dest[1024 * 1024 * 4]; // holds the actual data

int main(int argc, char *argv[]) {
    FILE *fi, *fo;
    char fname[255];

    uint16_t mask, tmp, offset, length;
    uint16_t seq;
    uint32_t dptr, sptr;
    uint16_t l, ct;
    uint16_t t, s;
    int test_len;
    int t_length, t_off;


    // Print Usage if filename is missing
    if (argc<3) {
        printf("sld_unpack - Decompressor for .sld files ()\nsld_unpack <filename.sld> <filename.t2>\n");
        return(-1);
    }

    // Open .SLD-file
    if (!(fi = fopen(argv[1], "rb"))) {
        printf("Error opening %s\n", argv[1]);
        return(-1);
    }

    dptr = 0;

    fread((uint16_t*)&seq, 1, 2, fi); // read 1st 2 bytes in file
    test_len = ftell(fi);

    printf("[Main Header sequence: %d]\n 'offset' : %d \n", seq, test_len);
    sptr = 0;

    fread((uint16_t*)&seq, 1, 2, fi);



    while (!feof(fi)) { // while not at the end of the file set mask equal to sequence (first 2 bytes of header)
        mask = seq;
        // loop through 16 bit mask

        for (t = 0; t<16; t++) {
            if (mask & (1 << (15 - t))) { // check all bit fields and run AND check to if value greater then 0?

                test_len = ftell(fi);
                fread((uint16_t*)&seq, 1, 2, fi); // read 


                sptr = sptr + 2; // set from 0 to 2
                tmp = seq; // set tmp to sequence
                offset = ((uint32_t)tmp & 0x07ff) * 2; 


                length = ((tmp >> 11) & 0x1f) * 2; //  32 - 1?



                if (length>0) {

                    for (l = 0; l<length; l++) {
                        dest[dptr] = dest[dptr - offset];
                        dptr++;

                    }
                }
                else { // if length == 0 

                    t_length = ftell(fi);
                    fread((uint16_t*)&seq, 1, 2, fi);


                    sptr = sptr + 2;
                    length = seq * 2;

                    for (s = 0; s<length; s++) {
                        dest[dptr] = dest[dptr - offset];
                        dptr++;

                    }
                }
            }
            else { // if sequence AND returns 0 (or less)?

                fread((uint16_t*)&seq, 1, 2, fi);
                t_length = ftell(fi);

                sptr = sptr + 2;
                dest[dptr++] = seq & 0xff;
                dest[dptr++] = (seq >> 8) & 0xff;
            }
        }
        fread((uint16_t*)&seq, 1, 2, fi);

    }

    fclose(fi);

    sprintf(fname, "%s\0", argv[2]);

    if (!(fo = fopen(fname, "wb"))) { // if file 
        printf("Error creating %s\n", fname);
        return(-1);
    }

    fwrite((uint8_t*)&dest, 1, dptr, fo);


    fclose(fo);

    printf("Done.\n");

    return(0);
}

2 个答案:

答案 0 :(得分:0)

  

if语句是我完全不了解的内容?什么触发了if?如果该位大于0? ...我真的需要知道什么是触发这个if语句?我想我可能会过度思考它,但如果当前位大于0,它是否会触发?

C(和C ++)if语句&#34;触发&#34;当条件语句的计算结果为true时,这是任何非零值;零等于假。

Straight C没有布尔类型,它只使用零(0)的约定为假,其他任何值都为真。

if (mask & (1 << (15 - t))) {...}

相同
if ((mask & (1 << (15 - t))) != 0) {...}

当掩码位于1移位的相同位置时,您给出的表达式仅为真(非零)。即是掩码集中的第15位等。

N.b。

mask & (1 << (15 - t)) 

只能是0或1 呃...只会设置一个位。

答案 1 :(得分:0)

这里要小心。

  

for arguments sake mask is 2 bytes 10 04, or 1040(decimal)

这个假设可能无处可去。您需要显示mask的定义方式,但通常掩码为1000001010)和4000101000)为二进制{{1} }或十进制(101000101000)不完全是1040.

26002600时,bits 4,6,10 & 12十进制的常规掩码将匹配。请记住,位掩码只不过是一个数字,当setanded和第二个数字产生某些所需结果时,其二进制表示形式。没有任何关于位掩码的神奇之处,它只是一个为您的预期目的设置了正确位的数字。

当你ored两个数字并且进行测试时,你正在测试两个数字中是否都设置了公共位。使用and循环和for,您正在对设置了哪些公共位进行逐位测试。当shift位为mask时,将2600 4,6,10 & 12与循环计数器一起使用将测试为真。换句话说,当测试子句等于set时。

以下是8, 32, 512 or 2048loop陈述中发生的事情的简短示例。

if

<强>输出

#include <stdio.h>

/* BUILD_64 */
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64   1
#endif

/* BITS_PER_LONG */
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif

/* CHAR_BIT */
#ifndef CHAR_BIT
# define CHAR_BIT  8
#endif

char *binpad (unsigned long n, size_t sz);

int main (void) {

    unsigned short t, mask;

    mask = (10 << 8) | 40;

    printf ("\n mask : %s  (%hu)\n\n",
            binpad (mask, sizeof mask * CHAR_BIT), mask);

    for (t = 0; t<16; t++)
        if (mask & (1 << (15 - t)))
            printf (" t %2hu : %s  (%hu)\n", t, 
                    binpad (mask & (1 << (15 - t)), sizeof mask * CHAR_BIT), 
                    mask & (1 << (15 - t)));


    return 0;
}

/** returns pointer to binary representation of 'n' zero padded to 'sz'.
 *  returns pointer to string contianing binary representation of
 *  unsigned 64-bit (or less ) value zero padded to 'sz' digits.
 */
char *binpad (unsigned long n, size_t sz)
{
    static char s[BITS_PER_LONG + 1] = {0};
    char *p = s + BITS_PER_LONG;
    register size_t i;

    for (i = 0; i < sz; i++)
        *--p = (n>>i & 1) ? '1' : '0';

    return p;
}