DLL CRC32

groovy

Новичок
Пример подсчета контрольной суммы любого файла, по алгоритму crc32, который имеет выигрыш по скорости примерно до 30% по сравнению с MD5.

(на моем компьютере файл в полтора гигабайта высчитывается за 4 секунды, md5 inno-вский за 6)
 

Вложения

Последнее редактирование:

Shegorat

Lord of Madness
Администратор
groovy
Серьезно, ~90 кб только для подсчета crc32? Ну а то что по скорости выигрывает, так это и неудивительно, у них разрядность разная, и, соответственно, криптостойкость и шанс появления коллизии.
 

groovy

Новичок
я никого не хотел удивлять или раздражать. вероятно, кому-то будет полезно и так, ну что ж, не задалось :scratchhead:
 

Shegorat

Lord of Madness
Администратор
groovy
Тут дело в другом. Иногда размер инсталлятора критичен, и таскать с собой непомерно раздутые библиотеки не вариант. Ее можно уменьшить килобайт до 15-20, и это со статической таблицей.
Я не против когда пользователи проявляют инициативу, а очень даже рад. Но если делать, то делать качественно.
 

groovy

Новичок
можно было бы и без зависимостей скомпилить, но код используемого исходника позволяет считать любые по размеру файлы и считать сумму у задействованных файлов. другие неправильно выделяют память под большой размер файлов или выдают ошибку при подсчете используемого файла.
сам я еще не умею дорабатывать имеющиеся исходники до должного качественного состояния. да и 80kb это может и слишком для подсчета crc32, но зато все работает без косяков.
 
Последнее редактирование:

groovy

Новичок
Обновлено до версии 1.1
v1.1 изменения: исправлена проблема с лишним девятым значением при повторном вызове функции.

Рекомендуется использовать числовой подсчет в Unicode версии компилятора, поскольку ANSI версия поддерживает максимум значение Longint, а максимальное возможное значение crc32 равно Cardinal, т.е. больше Longint в два раза.
 

Вложения

Shegorat

Lord of Madness
Администратор
Рекомендуется использовать числовой подсчет в Unicode версии компилятора, поскольку ANSI версия поддерживает максимум значение Longint, а максимальное возможное значение crc32 равно Cardinal, т.е. больше Longint в два раза.
:scratchhead:Я видимо чего-то не знаю?

Cardinal = Unsinged Integer (4 bytes)
Longint = Signed Integer (4 bytes)

P.S. Стандартный дельфовский менеджер памяти лучше не использовать. Результат лучше возвращать в Integer/Cardinal, а в инке уже форматировать. Для получения высокопроизводительного кода лучше избавиться от различных классов типа TFileStream и использовать функции WinAPI.
 

groovy

Новичок
:scratchhead:Я видимо чего-то не знаю?

Cardinal = Unsinged Integer (4 bytes)
Longint = Signed Integer (4 bytes)

P.S. Стандартный дельфовский менеджер памяти лучше не использовать. Результат лучше возвращать в Integer/Cardinal, а в инке уже форматировать. Для получения высокопроизводительного кода лучше избавиться от различных классов типа TFileStream и использовать функции WinAPI.
ANSI версия Cardinal не держит при превышении лимита в 2147483647.
Longint в диапазоне -+ столько же сколько и Cardinal, который только в + диапазоне.

И сам код тоже оптимизирован в одну строчку без выделения памяти, также убрал одну зависимость, и форматируется сразу:

Result := PChar(IntToHex(FileCRC32(FileName),8));

Была мысль возвращать число, но зато его не поймет ANSI версия, в которой можно получить значение как строку и использовать при сравнении с такой же строкой в инсталляторе:

if crc32 = 'FFFFFFFF' then
// checksum is correct!

А высокопроизводительный код может быть только на ассемблере с минимально возможным набором инструкций, до этого еще мне далековато, но потом обязательно попробую использовать ASM вставки и CreateFile вместо TFileStream и т.п.
Визуально при использовании замеров секундомером, скорость примерно одинаковая на исходниках с асм вставками и без.
 

Shegorat

Lord of Madness
Администратор
ANSI версия Cardinal не держит при превышении лимита в 2147483647.
Longint в диапазоне -+ столько же сколько и Cardinal, который только в + диапазоне.
Видимо у меня какая-то особенная инка. Пример в аттаче.

Была мысль возвращать число, но зато его не поймет ANSI версия, в которой можно получить значение как строку и использовать при сравнении с такой же строкой в инсталляторе:
Таки строка находится в пространстве памяти библиотеки, пускай и подгружающейся в память инсталлятора. Всё равно так передавать строку не есть гуд.

А высокопроизводительный код может быть только на ассемблере с минимально возможным набором инструкций, до этого еще мне далековато, но потом обязательно попробую использовать ASM вставки и CreateFile вместо TFileStream и т.п.
Визуально при использовании замеров секундомером, скорость примерно одинаковая на исходниках с асм вставками и без.
:scratchhead:
Спасибо за занимательный экскурс. Было очень познавательно...
В принципе там не так много кода для подсчета crc, просто ассемблер не поможет. Да, можно более оптимально расположить инструкции, но буст будет не такой большой. Основной прирост будет только при векторизации.
Да и я не зря советую отказаться от классов. Да, они дают удобство работы, но при этом имеют накладные расходы на инициализацию/разрушение класса.

В принципе я всё сказал. А прислушиваться к моим советам или нет - это уже ваше дело.

P.S. И у нас есть менеджер ресурсов для подобных тем. Там и обновлять проще и вообще удобнее.
 

Вложения

groovy

Новичок
Shegorat
спасибо за разъяснения, в следуещем возможном обновлении буду придерживаться советов.
 

groovy

Новичок
crc32.dll v1.3:
- за основу взят новый скоростной исходник с минимальным набором инструкций на ассемблере
- оптимизирован код, вырезаны ненужные зависимости и используются WinApi вместо TFileStream
- заменен внутренний тип цикла для корректной обработки файлов с нулевым размером

Shegorat спасибо за дельные советы, я ими воспользовался :)
 

Вложения

Последнее редактирование модератором:

groovy

Новичок
crc32.dll v1.4 final:
- использован самый скоростной исходник, благодаря чему подсчет быстрее прошлых версий и уменьшен размер

Прошу понять и простить за многочисленные обновления, зато уже сам маломальски научился адаптировать свой код.

При подсчете CRC32 у файлов с полными путями более 259 символов, используйте префикс \\?\ в начале имени, например:

tFile := '\\?\C:\SUPERLONGPATH\FILE.EXE'
 

Вложения

Последнее редактирование:

Shegorat

Lord of Madness
Администратор
При подсчете CRC32 у файлов с полными путями более 255 символов, используйте префикс \\?\ в начале имени, например:
CreateFileA всё равно не сможет обработать строку больше 255 символов, это физическое ограничение. А у вас используется именно она. Нужно использовать CreateFileW и, соответственно, преобразовывать строку в WideString.
 

groovy

Новичок
CreateFileA всё равно не сможет обработать строку больше 255 символов, это физическое ограничение. А у вас используется именно она. Нужно использовать CreateFileW и, соответственно, преобразовывать строку в WideString.
Под Inno-вским ROPS это возможно, я пробовал перед тем как запостить. Или у вас есть другие сведения? В нем вообще многие ANSI api функции работают с префиксом с длинными путями. Вот может быть W версия нужна для путей с Unicode символами в пути - это другое дело, надо проверять.

добавлено

да, так и есть, не может прочитать юникодные имена файлов, придется доработать :)
 
Последнее редактирование:

Shegorat

Lord of Madness
Администратор
groovy
Как бэ это физическое ограничение ANSI-строк.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming Files, Paths, and Namespaces.
Код:
#define MAX_PATH  260
 

groovy

Новичок
groovy
Как бэ это физическое ограничение ANSI-строк.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx

Код:
#define MAX_PATH  260
я тоже удивился, когда длинные пути обрабатываются в A версии, возможно, это особенность Unicode ROPS.

У меня теперь другой вопрос: dll я "поправил", вызвал W, заменил PChar на PWideChar, но как это все заставить понимать в Inno?
Unicode версия понимает WideString, но PWideChar нет, как быть?
 

groovy

Новичок
Что-то я уже все, непонимаю, почему Unicode версия не понимает файла с Unicode именем, например:
Код:
tFile := 'd:\führe.txt';
if FileExists(tFile) then
begin
  MsgBox(tFile, mbInformation, MB_OK);
end;
нету мессаджа, имя файла переводится почему то в ANSI: fuhre.txt

тут надо разобраться, почему Inno коцает юникодовое имя, может бы PAnsiChar нормально работало бы.

добавлено
насколько я понял их хелпа, Unicode версия имеет частичную поддержку Unicode. данные строки в коде автоматически конвертируются в Ansi, поэтому функции и не распознают эти строки, только если использовать:
tFile := 'd:\f' +Chr($FC)+ 'hre.txt';
и то это криво понимается в итоге и все равно не работает, да и не будешь автопроверки делать с постоянным указанием чаров в хекс.

вобщем не вижу смысла делать поддержку Unicode имен в пути, когда сама Inno в коде этого сделать не способна. текстовые строки она умеет конвертировать, не вопрос, есть функции, но эти строки не понимаются при использовании их в качестве путей для функций ропса.

наверное, я не знаю по этой части чего-то, пусть мудрейшие старожилы добавят или поправят информацию об этом.

а пока, dll остается такой, поддерживает длинные пути все-таки, большие файлы берет. не думаю, что большинство компонентов и библиотек для Inno умеют работать с юникод именами в пути.
 
Последнее редактирование:
Сверху