(я отредактировал это для ясности и немного изменил реальный вопрос, основываясь на ответе EOL)
Я пытаюсь перевести следующую функцию в C на Python, но с треском провалился (см. Код C ниже). Насколько я понимаю, требуется четыре 1-байтовых символа, начиная с области памяти, на которую указывает from
, обрабатывает их как длинные беззнаковые целые, чтобы дать каждому из них 4 байта пространства, и выполняет сдвиг битов, чтобы расположить их как 32-разрядное целое число с прямым порядком байтов Затем он используется в алгоритме проверки правильности файла. (из Вавилонского договора )
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 символа - «АЛАН». Все мои тестовые файлы не проходят этот тест. Я изменил код, чтобы удалить этот оператор if / else и вместо этого просто воспользоваться преимуществами ранних возвратов, и теперь все мои модульные тесты пройдены. Итак, на практическом уровне, я сделал. Тем не менее, я оставлю вопрос открытым для решения новой проблемы: как я могу разбить биты, чтобы получить «ALAN» из первых 4 символов?
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