POSIX cksum и Boost.CRC

Я пытаюсь реализовать простой POSIX cksum используя Boost.CRC.

Код, который я использую, сводится к следующему:

for(int i = 1; i<argc; ++i)
{
support::file current(argv[i], support::file::access::read);
size_t octets = 0;
boost::crc_32_type crc;
while(true)
{
size_t bytes_read = current.read_some(buffer_size, buffer);
octets += bytes_read;
crc.process_bytes(&buffer[0], bytes_read);
if(bytes_read < buffer_size)
break;
}
if(i>1)
support::print("\n");

support::print(boost::lexical_cast<string>(crc.checksum()) + " " + boost::lexical_cast<string>(octets) + " " + argv[i]);
}

куда support::file это простой fopen/fread бинарный файл ввода / вывода, который я успешно использовал для cat реализация. support::print дает тот же результат, что и std::cout, но мне это нужно для надежного вывода без ASCII на Windows.

Заголовок Boost имеет это:

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_32_type;

как единственный 32-битный CRC typedef. Это дает неправильный ответ (проверено с помощью GNUWin32 coreutils cksum) для пустого файла (touch test && cksum test). Я попытался использовать вышеупомянутый typedef и изменить один или оба из 0xFFFFFFFF значения до 0, я получаю правильный результат для пустого файла, но любой другой файл по-прежнему дает другие результаты.

Как Boost.CRC связан с POSIX cksum Спецификация?

1

Решение

На самом деле это не ответ на ваш вопрос, а результаты проведенного мною расследования. Я имел обыкновение бороться с CRC, когда я создавал простую реализацию контроллера Ethernet в VHDL, и я делать Следует понимать, что реализации могут иногда быть очень разными по неизвестным причинам.

Хорошо, начнем. typedef что вы нашли в boost/crc.hpp :

typedef crc_optimal<32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true> crc_32_type;

Это простое объявление генератора CRC, который будет генерировать CRC для Ethernet. Параметры шаблона следующие: Bits (количество битов, выводимых генератором), TruncPoly (полином, используемый генератором), InitRem (начальный остаток для подачи в алгоритм перед обработкой первого байта ввода), FinalXor (значение, которое должно быть на выходе XORed после обработки всех байтов ввода), ReflectIn а также ReflectRem (если входные байты и / или выходные данные должны отражаться в битах, например, бит 0 становится битом 7 и т. д.). Ethernet не только требует, чтобы выходной сигнал был рассчитан с заданным полиномом, но также требует ограничений, которые вы можете прочитать из этого typedef.

Согласно спецификации cksum, typedef для генератора CRC для него должен выглядеть примерно так:

typedef crc_optimal<32, 0x04C11DB7, 0, 0xFFFFFFFF, false, false> cksum_crc_type;

Это потому что :

  • В спецификации не указывается начальное значение для генератора, поэтому 0.
  • Выходное значение должно быть дополнено в соответствии с номером 4 спецификации. Тот же результат может быть достигнут путем XOR значения с единицами.
  • Отражение битов нигде не упоминается и, следовательно, не будет выполняться.

Однако, когда дело доходит до cksum в отличие от обычных CRC:

(…) сопровождаемый одним или несколькими октетами, представляющими длину
файл в виде двоичного значения, наименее значимый октет первым. Наименьший
число октетов, которые могут представлять это целое число.

Обычные генераторы CRC не учитывают количество октетов, которые были обработаны. Это также объясняет, почему вы получили хороший результат при обработке файла нулевой длины, но плохой при обработке больших файлов.

К сожалению, я не вижу простого решения этой проблемы. Я думаю, что вы могли бы сделать, это изменить process_bytes метод следующим образом:

template < std::size_t Bits, BOOST_CRC_PARM_TYPE TruncPoly,
BOOST_CRC_PARM_TYPE InitRem, BOOST_CRC_PARM_TYPE FinalXor,
bool ReflectIn, bool ReflectRem >
inline
void
BOOST_CRC_OPTIMAL_NAME::process_bytes
(
void const *   buffer,
std::size_t  byte_count
)
{
unsigned char const * const  b = static_cast<unsigned char const *>(
buffer );
process_block( b, b + byte_count );
for(; byte_count; byte_count >>= 8)
rem_ = (rem_ << 8) ^ crc_table_type::table_[((rem_ >> 24) ^ byte_count) & 0xFF];
}

При такой реализации метод дает тот же результат, что и cksum, for Любезность цикла GNU coreutils.

Надеюсь, я помог.

1

Другие решения

Других решений пока нет …