from
指向的内存位置开始,取四个1字节字符并将它们视为无符号的长整型,以便每个字符占用4个字节的空间,并进行一些位移操作以将它们排列成大端序的32位整数。然后将其用于检查文件的有效性算法。(来自Babel条约)static int32 read_alan_int(unsigned char *from)
{
return ((unsigned long int) from[3])| ((unsigned long int)from[2] << 8) |
((unsigned long int) from[1]<<16)| ((unsigned long int)from[0] << 24);
}
/*
The claim algorithm for Alan files is:
* For Alan 3, check for the magic word
* load the file length in blocks
* check that the file length is correct
* For alan 2, each word between byte address 24 and 81 is a
word address within the file, so check that they're all within
the file
* Locate the checksum and verify that it is correct
*/
static int32 claim_story_file(void *story_file, int32 extent)
{
unsigned char *sf = (unsigned char *) story_file;
int32 bf, i, crc=0;
if (extent < 160) return INVALID_STORY_FILE_RV;
if (memcmp(sf,"ALAN",4))
{ /* Identify Alan 2.x */
bf=read_alan_int(sf+4);
if (bf > extent/4) return INVALID_STORY_FILE_RV;
for (i=24;i<81;i+=4)
if (read_alan_int(sf+i) > extent/4) return INVALID_STORY_FILE_RV;
for (i=160;i<(bf*4);i++)
crc+=sf[i];
if (crc!=read_alan_int(sf+152)) return INVALID_STORY_FILE_RV;
return VALID_STORY_FILE_RV;
}
else
{ /* Identify Alan 3 */
bf=read_alan_int(sf+12);
if (bf > (extent/4)) return INVALID_STORY_FILE_RV;
for (i=184;i<(bf*4);i++)
crc+=sf[i];
if (crc!=read_alan_int(sf+176)) return INVALID_STORY_FILE_RV;
}
return INVALID_STORY_FILE_RV;
}
我正在尝试使用Python重新实现这个功能。为了实现read_alan_int
函数,我认为导入struct
并执行struct.unpack_from('>L', data, offset)
应该可以。但是,在有效文件上,该函数始终返回24,即bf
的值,这意味着for
循环被跳过。
def read_alan_int(file_buffer, i):
i0 = ord(file_buffer[i]) * (2 ** 24)
i1 = ord(file_buffer[i + 1]) * (2 ** 16)
i2 = ord(file_buffer[i + 2]) * (2 ** 8)
i3 = ord(file_buffer[i + 3])
return i0 + i1 + i2 + i3
def is_a(file_buffer):
crc = 0
if len(file_buffer) < 160:
return False
if file_buffer[0:4] == 'ALAN':
# Identify Alan 2.x
bf = read_alan_int(file_buffer, 4)
if bf > len(file_buffer)/4:
return False
for i in range(24, 81, 4):
if read_alan_int(file_buffer, i) > len(file_buffer)/4:
return False
for i in range(160, bf * 4):
crc += ord(file_buffer[i])
if crc != read_alan_int(file_buffer, 152):
return False
return True
else:
# Identify Alan 3.x
#bf = read_long(file_buffer, 12, '>')
bf = read_alan_int(file_buffer, 12)
print bf
if bf > len(file_buffer)/4:
return False
for i in range(184, bf * 4):
crc += ord(file_buffer[i])
if crc != read_alan_int(file_buffer, 176):
return False
return True
return False
if __name__ == '__main__':
import sys, struct
data = open(sys.argv[1], 'rb').read()
print is_a(data)
...但是该死的东西仍然返回24。不幸的是,我的C语言技能不存在,所以我很难让原始程序打印一些调试输出,以便我知道bf应该是什么。
我做错了什么?
好的,所以显然我正确地执行了read_alan_int。然而,对我失败的是检查前4个字符是否为“ALAN”。我所有的测试文件都未通过此测试。我已更改代码以删除此if/else语句,并利用早期返回,现在我的所有单元测试都通过了。因此,在实际层面上,我完成了。然而,我将保持这个问题开放,以解决新问题:我如何可能操纵位来获取前4个字符中的“ALAN”?
def is_a(file_buffer):
crc = 0
if len(file_buffer) < 160:
return False
#if file_buffer.startswith('ALAN'):
# Identify Alan 2.x
bf = read_long(file_buffer, 4)
if bf > len(file_buffer)/4:
return False
for i in range(24, 81, 4):
if read_long(file_buffer, i) > len(file_buffer)/4:
return False
for i in range(160, bf * 4):
crc += ord(file_buffer[i])
if crc == read_long(file_buffer, 152):
return True
# Identify Alan 3.x
crc = 0
bf = read_long(file_buffer, 12)
if bf > len(file_buffer)/4:
return False
for i in range(184, bf * 4):
crc += ord(file_buffer[i])
if crc == read_long(file_buffer, 176):
return True
return False
print map(ord, file_buffer[12:16])
的输出结果。 你能否提供 C 代码和/或示例文件? - John Machinprint map(ord, file_buffer[12:16])
的结果是[0, 0, 0, 24]
。 - user626998foo = lambda n: struct.unpack_from('>L', file_buffer, n)
,则foo(12) * 2**24 == foo(13) * 2**16 == foo(14) * 2**8 == foo(15)
。 - user626998map(ord, file_buffer[12:16])
的内容,你在real_alan_int()
函数中得到的结果为24是正确的。 - Eric O. Lebigot