Что нового

Бинарное забивание нулями

maxd2007

Новичок
Сообщения
89
Репутация
0
Здравствуйте, подскажите есть ли в AutoIt возможность забить нулями бинарный фаил? Т.е. что мне надо, есть бинарный фаил, его основной заголовок равен 1084 байт, первые 101 байт неизменны, далее идет имя которое вбивает пользователь (оно может быть любым, а следовательно разного размера), затем 60 байт по маске, и далее до 1084 байта нули, т.е. все это я могу посчитать и к тому моменту когда надо забить это все нулями мне в голову лезет только вариант:
Код:
$Offset = 101 + $NameWeightInput + 60
$AllNull = 1084 - $Offset
$FileEdit = FileOpen (@ScriptDir & "\OR.dat",1 + 16)
FileSetPos ($FileEdit, $offset, 0)
For 0 to $AllNull
 FileWrite ($FileEdit, "0x00")
Next

Весь вопрос как сделать это грамотней или так и оставить? Может есть какой то _insertBinaryNull или что то в этом роде =)
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
ma:rofl:2007
Уверен, что вы запутались. Странно выглядят смещения полей и заголовок в целом. Судя по вашему описанию вот: (для ANSI версии)

Код:
#Include <WinAPIEx.au3>

Local $hFile, $tHdr, $iHdr, $iOffset, $iBytes
; ---
$hFile = _WinAPI_CreateFile(@ScriptDir & '\OR.doc', 2, 6)
If $hFile Then
    $tHdr = DllStructCreate('byte Raw[1084]')
	$iHdr = DllStructGetSize($tHdr)
    ; *
    _WinAPI_ReadFile($hFile, $tHdr, $iHdr, $iBytes)

    ; ANSI - 1 byte, UNICODE - 2 bytes (for null-terminated string)
    $iOffset = 0x65 + (lstrlen(DllStructGetPtr($tHdr) + 0x65) + 1) + 0x3B ; 3C - 1
	If $iOffset < $iHdr Then
		$tHdr.Raw = 0
		_WinAPI_SetFilePointer($hFile, $iOffset)
		_WinAPI_WriteFile($hFile, $tHdr, $iHdr - $iOffset, $iBytes)
	EndIf

    _WinAPI_CloseHandle($hFile)
EndIf


Func lstrlen($pv)
    Local $aRet
    ; ---
    $aRet = DllCall('kernel32.dll', 'int', 'lstrlen', 'ptr', $pv) ; or lstrlenW for UNICODE
    If @error Then _
        Return 0
    ; ---
    Return $aRet[0]
EndFunc     ; ANSI version
 
Автор
M

maxd2007

Новичок
Сообщения
89
Репутация
0
Странно выглядит потому что 1084 а не 1024? И извиняюсь наверное за глупый вопрос, но почему весь скрипт написан через WinApi без использования FileOpen, FileRead итд? Щас попробую разобраться то, что Вы написали что бы сформулировать вопрос (если он появится конечно =) )
 
Автор
M

maxd2007

Новичок
Сообщения
89
Репутация
0
firex сказал(а):
ma:rofl:2007
Уверен, что вы запутались. Странно выглядят смещения полей и заголовок в целом. Судя по вашему описанию вот: (для ANSI версии)

Код:
#Include <WinAPIEx.au3>

Local $hFile, $tHeader, $pHeader, $pOffset, $iNameLen, $iBytes
; ---
$hFile = _WinAPI_CreateFile(@ScriptDir & '\OR.dat', 2)
If $hFile Then
	$tHeader = DllStructCreate('byte Raw[1084]')
	$pHeader = DllStructGetPtr($tHeader)
	; *
	_WinAPI_ReadFile($hFile, $pHeader, DllStructGetSize($tHeader), $iBytes)

	; ANSI - 1 byte, UNICODE - 2 bytes (for null-terminated string)
	$iNameLen = lstrlen($pHeader + 101) + 1
	$pOffset = $pHeader + 101 + $iNameLen + 60

	$tHeader.Raw = 0
	_WinAPI_SetFilePointer($hFile, $pOffset)
	_WinAPI_WriteFile($hFile, $pHeader, DllStructGetSize($tHeader) - $pOffset, $iBytes)

	_WinAPI_CloseHandle($hFile)
EndIf


Func lstrlen($pv)
    Local $aRet
	; ---
	$aRet = DllCall('kernel32.dll', 'int', 'lstrlen', 'ptr', $pv) ; or lstrlenW for UNICODE
    If @error Then _
		Return 0
	; ---
    Return $aRet[0]
EndFunc		; ANSI version
Извиняюсь, что исчез (пришлось уехать на дня). Разобрав Ваш пример (что смог), я вижу что Вы использовали указатели и структуру (как в С++), но я с ними плохо дружу (можно даже сказать совсем не дружу) =(. Вы написали готовый пример по забиванию нулей, как я понимаю, и я просто не понимаю как к нему приделать пользовательское имя (то которое вбивает пользователь)
После Вашего скрипта файл стал весить 53Мб (до этого был 109Кб) =), на всякий случай прикрепил его во вложение (пришлось переименовать в doc т.к. dat запрещено вкладывать).
 

Вложения

  • OR.doc
    108.5 КБ · Просмотры: 12

firex

AutoIT Гуру
Сообщения
943
Репутация
208
ma:rofl:2007
Поправил предыдущее сообщение, чет там совсем все плохо было.
 
A

Alofa

Гость
Все гораздо проще.
Код:
; Читаем данные из файла
$sFileEdit = @ScriptDir & '\OR.dat'
$sChars = FileRead($sFileEdit)
If @error Then Exit MsgBox(4096+16, 'Ошибка', 'Невозможно открыть файл.')

$tStruct = DllStructCreate('byte data[1084]')
$tStruct.data = $sChars ; Эта форма записи аналогична DllStructSetData($tStruct, 'data', $sChars)

; Записываем данные в файл
$hFileEdit = FileOpen($sFileEdit, 2 + 16)
FileWrite($hFileEdit, $tStruct.data)
FileClose($hFileEdit)
 
Автор
M

maxd2007

Новичок
Сообщения
89
Репутация
0
firex сказал(а):
ma:rofl:2007
Поправил предыдущее сообщение, чет там совсем все плохо было.
В таком варианте первые 169 байт записываются дважды (подряд), а нули верно до 1084.




Добавлено:
Сообщение автоматически объединено:

Alofa сказал(а):
Все гораздо проще.
Код:
; Читаем данные из файла
$sFileEdit = @ScriptDir & '\OR.dat'
$sChars = FileRead($sFileEdit)
If @error Then Exit MsgBox(4096+16, 'Ошибка', 'Невозможно открыть файл.')

$tStruct = DllStructCreate('byte data[1084]')
$tStruct.data = $sChars ; Эта форма записи аналогична DllStructSetData($tStruct, 'data', $sChars)

; Записываем данные в файл
$hFileEdit = FileOpen($sFileEdit, 2 + 16)
FileWrite($hFileEdit, $tStruct.data)
FileClose($hFileEdit)
Извиняюсь за мою неграмотность, но по моему в Вашем скрипте не хватает
Код:
FileOpen ($sFileEdit, 0)
я попробовал его добавить (естевствено перед следующим FoleOpen я использовал FileClose) но я не могу понять срабатывает оно или нет, я наверное плохо описал задачу, попробую по пунктам описать все что мне надо сделать (просто я застрял на нулях а все другое уже реализовал поэтому не писал про это):
1) С 36 байта правим 2 байта 0x00 c 56 байта правим 2 байта на 0xA44A
2) Идет пользовательское имя которое вбивается при запуске программа (я использовал InputBox и преобразовывал бинарно StringToBinary) оно может быть любой длинны, чем длиньше имя тем меньше нулей надо вбивать
3) 60 байт
0x00000000310001000000736F75726365206C6576656C2032206E616D6500736F75726365206C6576656C2032206E616D65006D61786432303037000A
4) А это как раз и был мой вопрос: забить нулями основываясь на длинне имени которое вбил пользователь, т.е. колличество нулей = 1084 - 101 - 60 - длинна имени которое вбил пользователь через InputBox


Добавлено:
Сообщение автоматически объединено:

Вот как это работает у меня сейчас:
Код:
#include <File.au3>
#include <Array.au3>

$NameMap = StringToBinary (InputBox ("Имя карт", "Введите имя карты", "maxd2007"))
$DirFile = FileSelectFolder ("Выберите папку JNX", @ScriptDir )
$FileList = _FileListToArray ($DirFile, "*.jnx", 1)

For $i = 1 to $FileList[0] Step 1
	_jnxEdit ($DirFile & "\" & $FileList[$i], $NameMap)
Next


Func _jnxEdit ($DirFile,$NameMap)

	$JNXNameWeightInput = (StringLen ($NameMap) - 2) / 2


	$AllNull = 1084 - 101 - 60 - $JNXNameWeightInput - 1

	$FileEdit = FileOpen ( $DirFile, 1 + 16)


	FileSetPos ($FileEdit, 36, 0 )
	FileWrite ($FileEdit, "0x0000")
	FileSetPos ($FileEdit, 56, 0 )
	FileWrite ($FileEdit, "0xA44A")


	FileSetPos ($FileEdit, 101, 0)
	FileWrite ($FileEdit,  $NameMap)
	FileWrite ($FileEdit, '0x00000000310001000000736F75726365206C6576656C2032206E616D6500736F75726365206C6576656C2032206E616D65006D61786432303037000A')

	_editNull ($FileEdit, $AllNull)
EndFunc

Func _editNull ($FileEdit, $AllNull)
	For  $i = 0 to $AllNull Step 1
		FileWrite ($FileEdit, "0x00")
	Next
EndFunc
 

joiner

Модератор
Локальный модератор
Сообщения
3,570
Репутация
632
читаю уже четвертый раз :smile:
проблема в подсчете куда ставить указатель?
Код:
Local $pos = 101 + StringLen('Имя пользователя') + 60; высчитываем нужную длину. одновременно это будет точкой в файле, куда будет перемещен указатель
Local $diff = 1084 - $pos; проверка разницы
If $diff >= 1084 Then Exit

или уже все решено?
 
Автор
M

maxd2007

Новичок
Сообщения
89
Репутация
0
joiner сказал(а):
читаю уже четвертый раз :smile:
проблема в подсчете куда ставить указатель?
Код:
Local $pos = 101 + StringLen('Имя пользователя') + 60; высчитываем нужную длину. одновременно это будет точкой в файле, куда будет перемещен указатель
Local $diff = 1084 - $pos; проверка разницы
If $diff >= 1084 Then Exit

или уже все решено?
=) Нет, проблема в том как я забиваю нулями, мне кажется, что моя функция _editNull это неправильно и есть какой то более правильный вариант заполнения нулями - по сути все =)
 

joiner

Модератор
Локальный модератор
Сообщения
3,570
Репутация
632
если известна разница, то набираешь "строчку" нулей под эту разницу, ставишь указатель и вписываешь их сразу
это если файл небольшой.
а можно и в цикле. тоже быстро будет.
я тут на скорую руку накидал, примерно так я делал в своем проекте, только там тоже блоками за один раз писал
Код:
#include <WinAPI.au3>
Local $nb
Local $sn = StringLen('Имя пользователя')
Local $pos = 101 + $sn + 60
Local $diff = 1084 - $pos
If $diff >= 1084 Then Exit
Local $of = _WinAPI_CreateFile(@ScriptDir & '\12.txt', 2, 4)
If Not $of Then Exit
Local $bd = DllStructCreate('byte[' & $sn & ']')
DllStructSetData($bd, 1, 'Имя пользователя')
_WinAPI_SetFilePointer($of, 101, 0)
_WinAPI_WriteFile($of, DllStructGetPtr($bd), $sn, $nb)
$bd = DllStructCreate('byte[1]')
_WinAPI_SetFilePointer($of, $pos, 0)
Local $ptr = DllStructGetPtr($bd)
While 1
	_WinAPI_WriteFile($of, $ptr, 1, $nb)
	_WinAPI_SetFilePointer($of, $pos, 0)
	If $pos = 1084 Then ExitLoop
	$pos += 1
WEnd
_WinAPI_CloseHandle($of)
то есть вместо цикла подставляешь блок нулей , ставишь указатель и пишешь
 
Автор
M

maxd2007

Новичок
Сообщения
89
Репутация
0
joiner сказал(а):
если известна разница, то набираешь "строчку" нулей под эту разницу, ставишь указатель и вписываешь их сразу
это если файл небольшой.
а можно и в цикле. тоже быстро будет.
я тут на скорую руку накидал, примерно так я делал в своем проекте, только там тоже блоками за один раз писал
Код:
#include <WinAPI.au3>
Local $nb
Local $sn = StringLen('Имя пользователя')
Local $pos = 101 + $sn + 60
Local $diff = 1084 - $pos
If $diff >= 1084 Then Exit
Local $of = _WinAPI_CreateFile(@ScriptDir & '\12.txt', 2, 4)
If Not $of Then Exit
Local $bd = DllStructCreate('byte[' & $sn & ']')
DllStructSetData($bd, 1, 'Имя пользователя')
_WinAPI_SetFilePointer($of, 101, 0)
_WinAPI_WriteFile($of, DllStructGetPtr($bd), $sn, $nb)
$bd = DllStructCreate('byte[1]')
_WinAPI_SetFilePointer($of, $pos, 0)
Local $ptr = DllStructGetPtr($bd)
While 1
	_WinAPI_WriteFile($of, $ptr, 1, $nb)
	_WinAPI_SetFilePointer($of, $pos, 0)
	If $pos = 1084 Then ExitLoop
	$pos += 1
WEnd
_WinAPI_CloseHandle($of)
то есть вместо цикла подставляешь блок нулей , ставишь указатель и пишешь
Спасибо, теперь я понимаю, что мне надо почаще с указателями работать =). А что Вы подразумевали под большими файлами? У меня максимальный размер файла не будет превышать 32МБ - это большой?
 

joiner

Модератор
Локальный модератор
Сообщения
3,570
Репутация
632
ну если нулями забивать файл , к примеру, с гиг размером, то блоком не получится. точнее в память гиг читать это может вызвать крах программы.
тогда в цикле забиваешь. а так у тебя несколько десятков байт, то тогда проще сразу блок писать
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
ma:rofl:2007 [?]
В таком варианте первые 169 байт записываются дважды (подряд), а нули верно до 1084.
А это уже не мой косяк, а разрабов AutoIt'а

Замените:
Код:
$tHdr.Raw = 0

На:
Код:
DllCall('msvcrt.dll', 'ptr:cdecl', 'memset', 'struct*', $tHdr, 'int', 0, 'ulong_ptr', $iHdr)



P.S. Надо бы им по шапке настучать за это.
 
Верх