Тема: AHK: Не сохраняется переменная с двоичным(и) нулями
Есть код, шифрующий файл. На вход шифрующему циклу подается столько символов, сколько есть в файле (пробовал добавлять в него двоичные нули -функции BinRead они нисколько не мешают. Переменная, отсчитывающая число интераций цикла так-же говорит, что прошло столько "оборотов", сколько положено. Однако в выходной переменной сохраняются лишь данные до первого двоичного нуля (видно по содержимому файлов и функции StrLen после выхода из цикла). Опираясь на выдержку из описания FileRead
Если указанный файл содержит двоичные нули (которые никогда не встречаются в нормальных текстовых файлах), только текст, предшествующий первому двоичному нулю, будет "виден" для команд и функций AutoHotkey.
подозреваю, что выходная переменная все же содержит весь результат шифрования, но ни пользовательская функция-близнец BinRead'а "BinWrite" не видит всего ее содержимого, ни стандартная "FileAppend". Помогите, люди. Желательно модифицировать BinWrite, что бы она таки справилась со своей задачей, но на крайняк подойдут и другие методы.
Вот код:
#SingleInstance,Force
SetBatchLines,-1
SetWorkingDir,%A_ScriptDir%
CheckListDirectory := A_ScriptDir "\CheckFileListW.ten.decrypted"
BinRead(CheckListDirectory,data)
String := data
While Mod(StrLen(String), 2)
String := "0" String
msgbox % StrLen(String) ;проверяем длинну строки, идущей на вход циклу
Loop % StrLen(String)/2
{
if A_Index != 1
LastOut := toappend ;сохраняем результат прошлой интерации цикла, если она не первая
interCount := A_Index
Outp := "0x" SubStr(String, A_Index*2-1, 2) ;группируем строку по 2 знака и добавляем префикс 16ричного числа
const := 0x42 ;задаем константу для шифровки первой группы
if A_Index = 1
toappend := outp + const ;шифруем первую группу
else
toappend := outp + LastOut ;шифруем все прочие
num := toappend
VarSetCapacity(S,65,0)
DllCall("msvcrt\_i64toa", Int64,toappend, Str,s, Int,16) ;конвертируем результат в 16ричное число
RegExMatch(s, ".{2,2}$", toappend) ;оставляем только последние 2 цифры и добавляем префикс
noprefix := toappend ;дублируем переменную для последующей записи в файл без префикса
toappend := "0x" toappend ;добавляем префикс для дальнейшей корректной работы внутри цикла
cryptdata := cryptdata noprefix ;добавляем зашифрованный фрагмент к будущему файлу
}
msgbox, % interCount ;по этой переменной можно узнать количество интераций цикла (должно быть в 2раза меньше длинны строки, пошедшей на вход циклу)
msgbox, % StrLen(cryptdata) ;проверяем длинну строки, вышедшей из цикла.
Savedir := A_ScriptDir "\CheckFileListW.ten.HEXcrypted"
Savedir2 := A_ScriptDir "\CheckFileListW.ten.TXTcrypted"
Savedir3 := A_ScriptDir "\CheckFileListW.ten.AfterRead"
fileappend, %cryptdata%, %Savedir2%
BinWrite(Savedir, cryptdata)
BinWrite(Savedir3, data)
return
;-------------Используемые функции--------------
BinWrite(file, data, n=0, offset=0)
{
; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists
h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
IfEqual h,-1, SetEnv, ErrorLevel, -1
IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file
m = 0 ; seek to offset
IfLess offset,0, SetEnv,m,2
r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
IfEqual r,0, SetEnv, ErrorLevel, -3
IfNotEqual ErrorLevel,0, {
t = %ErrorLevel% ; save ErrorLevel to be returned
DllCall("CloseHandle", "Uint", h)
ErrorLevel = %t% ; return seek error
Return 0
}
TotalWritten = 0
m := Ceil(StrLen(data)/2)
If (n <= 0 or n > m)
n := m
Loop %n%
{
StringLeft c, data, 2 ; extract next byte
StringTrimLeft data, data, 2 ; remove used byte
c = 0x%c% ; make it number
result := DllCall("WriteFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Written,"UInt",0)
TotalWritten += Written ; count written
if (!result or Written < 1 or ErrorLevel)
break
}
IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%
h := DllCall("CloseHandle", "Uint", h)
IfEqual h,-1, SetEnv, ErrorLevel, -2
IfNotEqual t,,SetEnv, ErrorLevel, %t%
Return TotalWritten
}
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinRead ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
| - Open binary file
| - Read n bytes (n = 0: all)
| - From offset (offset < 0: counted from end)
| - Close file
| data (replaced) <- file[offset + 0..n-1]
| Return #bytes actually read
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BinRead(file, ByRef data, n=0, offset=0)
{
h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
IfEqual h,-1, SetEnv, ErrorLevel, -1
IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file
m = 0 ; seek to offset
IfLess offset,0, SetEnv,m,2
r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
IfEqual r,0, SetEnv, ErrorLevel, -3
IfNotEqual ErrorLevel,0, {
t = %ErrorLevel% ; save ErrorLevel to be returned
DllCall("CloseHandle", "Uint", h)
ErrorLevel = %t% ; return seek error
Return 0
}
TotalRead = 0
data =
IfEqual n,0, SetEnv n,0xffffffff ; almost infinite
format = %A_FormatInteger% ; save original integer format
SetFormat Integer, Hex ; for converting bytes to hex
Loop %n%
{
result := DllCall("ReadFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Read,"UInt",0)
if (!result or Read < 1 or ErrorLevel)
break
TotalRead += Read ; count read
c += 0 ; convert to hex
StringTrimLeft c, c, 2 ; remove 0x
c = 0%c% ; pad left with 0
StringRight c, c, 2 ; always 2 digits
data = %data%%c% ; append 2 hex digits
}
IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%
h := DllCall("CloseHandle", "Uint", h)
IfEqual h,-1, SetEnv, ErrorLevel, -2
IfNotEqual t,,SetEnv, ErrorLevel, %t%
SetFormat Integer, %format% ; restore original format
Totalread += 0 ; convert to original format
Return TotalRead
}
Образец файла во вложении