C 解压位掩码源
C decompress Bitmask source
这可能是一个有点奇怪的问题,也是我在这个网站上的第一个问题,而且是一个非常复杂的问题,基本上我有一个用于非常具体的存档文件的解压缩器,我几乎不明白这个,但从我的情况来看可以掌握它的某种"bit mask" 它从目标文件中读取前 2 个字节,并将它们存储为一个序列。
第一个 for 循环让我感到困惑
为了参数的缘故,说掩码是 2 个字节 10 04
,或者 1040(十进制)这就是这些文件中通常的值
for (t = 0; t<16; t++) {
if (mask & (1 << (15 - t))) {
这似乎是循环遍历这 2 个字节的所有 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[=12=]", 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);
}
The if statement is what I don't understand completely? Whats triggering the if? If the bit is greater then 0? ... I just really need to know whats triggering this if statement? i think i might be over thinking it, but is it simply trigger if the current bit is greater then 0?
C(和C++)if语句"triggers"当条件语句计算为真时,它是任何非零值;零等于假。
Straight C 没有布尔类型,它只是使用零 (0) 为假,任何其他值为真的约定。
if (mask & (1 << (15 - t))) {...}
与
相同
if ((mask & (1 << (15 - t))) != 0) {...}
只有当掩码中有一个位与 1 移动的位置相同时,您给出的表达式才为真(非零)。即是掩码集中的第 15 位,等等
N.b。
mask & (1 << (15 - t))
只能是 0 或 1 呃...只会设置一位。
注意这里。
for arguments sake mask is 2 bytes 10 04, or 1040(decimal)
这个假设可能远非真实。您需要显示 mask
是如何定义的,但通常字节掩码 10
(00001010
) 和 40
(00101000
) 是二进制 101000101000
或小数 (2600
) 不完全是 1040。
当 bits 4,6,10 & 12
为 set
时,2600
十进制的通用掩码将匹配。请记住, 位掩码 只不过是一个数字,当 anded
或 ored
与第二个数字产生某些所需结果时,其二进制表示形式。 位掩码 没什么神奇的,它只是一个为您的预期目的设置了正确位的数字。
当您 and
将两个数字放在一起进行测试时,您正在测试两个数字中是否设置了公共位。使用 for
循环和 shift
,您正在对设置了公共位的位进行逐位测试。当位 4,6,10 & 12
为 set
时,将 2600
的 mask
与循环计数器一起使用将测试为真。换句话说,当测试子句等于 8, 32, 512 or 2048
.
以下是 loop
和 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;
}
输出
$ ./bin/bitmask1040
mask : 0000101000101000 (2600)
t 4 : 0000100000000000 (2048)
t 6 : 0000001000000000 (512)
t 10 : 0000000000100000 (32)
t 12 : 0000000000001000 (8)
这可能是一个有点奇怪的问题,也是我在这个网站上的第一个问题,而且是一个非常复杂的问题,基本上我有一个用于非常具体的存档文件的解压缩器,我几乎不明白这个,但从我的情况来看可以掌握它的某种"bit mask" 它从目标文件中读取前 2 个字节,并将它们存储为一个序列。
第一个 for 循环让我感到困惑
为了参数的缘故,说掩码是 2 个字节 10 04
,或者 1040(十进制)这就是这些文件中通常的值
for (t = 0; t<16; t++) {
if (mask & (1 << (15 - t))) {
这似乎是循环遍历这 2 个字节的所有 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[=12=]", 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);
}
The if statement is what I don't understand completely? Whats triggering the if? If the bit is greater then 0? ... I just really need to know whats triggering this if statement? i think i might be over thinking it, but is it simply trigger if the current bit is greater then 0?
C(和C++)if语句"triggers"当条件语句计算为真时,它是任何非零值;零等于假。
Straight C 没有布尔类型,它只是使用零 (0) 为假,任何其他值为真的约定。
if (mask & (1 << (15 - t))) {...}
与
相同if ((mask & (1 << (15 - t))) != 0) {...}
只有当掩码中有一个位与 1 移动的位置相同时,您给出的表达式才为真(非零)。即是掩码集中的第 15 位,等等
N.b。
mask & (1 << (15 - t))
只能是 0 或 1 呃...只会设置一位。
注意这里。
for arguments sake mask is 2 bytes 10 04, or 1040(decimal)
这个假设可能远非真实。您需要显示 mask
是如何定义的,但通常字节掩码 10
(00001010
) 和 40
(00101000
) 是二进制 101000101000
或小数 (2600
) 不完全是 1040。
当 bits 4,6,10 & 12
为 set
时,2600
十进制的通用掩码将匹配。请记住, 位掩码 只不过是一个数字,当 anded
或 ored
与第二个数字产生某些所需结果时,其二进制表示形式。 位掩码 没什么神奇的,它只是一个为您的预期目的设置了正确位的数字。
当您 and
将两个数字放在一起进行测试时,您正在测试两个数字中是否设置了公共位。使用 for
循环和 shift
,您正在对设置了公共位的位进行逐位测试。当位 4,6,10 & 12
为 set
时,将 2600
的 mask
与循环计数器一起使用将测试为真。换句话说,当测试子句等于 8, 32, 512 or 2048
.
以下是 loop
和 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;
}
输出
$ ./bin/bitmask1040
mask : 0000101000101000 (2600)
t 4 : 0000100000000000 (2048)
t 6 : 0000001000000000 (512)
t 10 : 0000000000100000 (32)
t 12 : 0000000000001000 (8)