1 (изменено: Androgen, 2007-04-27 08:04:39)

Тема: AutoHotkey: FileRead для бинарных файлов

Понадобилось мне скриптом анализировать конфиги одной проги. А они, гадство, оказались в бинарном виде. Т.е. и текст там есть, но есть и двоичные нули (00). А команда FileRead обламывается на файлах, имеющих в содержимом двоичные нули. Об этом в AHK-справке честно сказано. Сказано и то, что содержимое прочитанного файла всё же может быть вытащено,  но некими продвинутыми методами. Примеры "продвинутых методов" отсутствуют.
Полез я на буржуйский форум и, как это часто бывает, оказалось, что для чтения и даже записи бинарных файлов уже написаны функции. Функции мощные (обычно, я люблю такие), но для моего случая они были явно избыточны. Тем более, что эти функции разнесены по 3м-4м разным файлам, объединяющимся через #Include. Стал я в них вникать, с целью укоротить. Вникал три дня и три ночи (пока вникалку не отобрали). И тут меня осенило (хотя, наверное, лучше сказать "овеснило"). Будь я посообразительней, могло бы овеснить и раньше. Однако, к делу.
Предлагаемый скрипт показывает, как можно получить целиком содержимое любого файла (не обязательно бинарного) в hex-виде. Дальше по нему уже можно пройтись RegExp'ами, или вынуть текстовые данные (скрипт Rajat'а для этого можно найти здесь), или обработать любым другим желаемым способом.

;*******************************************************************************
; AutoHotkey Version:    1.0.46.09+
; Автор:                Androgen Belkin
; Имя скрипта:            File2Hex.ahk (v.1.0)
;*******************************************************************************
; Скрипт получает содержимое указанного файла в hex-виде.
;*******************************************************************************
SetBatchLines, -1    ; максимальная скорость для скрипта
#NoEnv            ; запрещаем имена переменных как у переменных окружения

; ========== НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ ===============
FileName = c:\boot.ini
; ========== КОНЕЦ НАСТРОЕК ПОЛЬЗОВАТЕЛЯ ==========
IfNotExist, %FileName%
{
   MsgBox, Не существует файл`n"%FileName%"
   ExitApp ; конец скрипта
}
FileGetSize, FileSize, %FileName%
FileRead, Contents, %Filename% ; читаем содержимое файла
If ErrorLevel ; файл заблокирован, например
{
    MsgBox, Не удалось прочитать файл`n"%FileName%"`nErrorLevel: %ErrorLevel%
    ExitApp ; конец скрипта
}
VarSetCapacity( hexString, FileSize * 2 ) ; запрашиваем память под hex-данные
; запрашивать память здесь не обязательно, но так будет работать немного быстрее
ContAddress := &Contents ; получаем адрес данных в памяти
SetFormat, Integer, Hex
Loop, %FileSize% ; будем читать все байты содержимого файла в памяти (файл целиком)
{
    ; если написать hex := *ContAddress, то в полученном hex-числе будет отсутствовать лидирующий ноль
    ; чтобы обойти это, мы сейчас прибавим число, а в следующей строке избавимся от прибавленного
    hex := *ContAddress + 0x100 ; делаем так, чтобы hex-число было, например, не 0xF, а 0x10F
    StringRight hex, hex, 2 ; берём из числа последние 2 цифры (это и есть нужный нам hex)
    StringUpper hex, hex ; переводим число в верхний регистр (для красоты)
    hexString := hexString . hex ; плюсуем к общей hex-строке
    ContAddress++ ; переходим к следующему байту
}
MsgBox, hexString:`n%hexString% ; смотрим результат
Крокодил, крокожу и буду крокодить! (Твёрдое обещание нетрезвого кодера).