Archive: Binary read


Binary read
Hi,

I must modify some parts of a 153 Mb binary file. The only function I've found that performs this is FileReadByte and FileWriteByte but are toooooooooo slow.

Is there any way to read/write strings of non-character bytes using FileRead/FileWrite? Or I must making an external program who performs that?

Thanks


If you want to patch a binary file, why not use VPatch?


Could you write the link?


It's in your Contrib folder.


Sorry, I'm a total newbie and I don't know where that folder is. I'll search other posts ;)


Where you installed NSIS, there's a folder named Contrib. Inside that folder, there's a folder named VPatch. Normally, that should be:

C:\Program Files\NSIS\Contrib\VPatch


Have a good look around your NSIS directory. It's always a good idea to know what's available to you :)

-Stu


I had to write my own binary read script for license page. It was empty installer with all files located in CVS folders including installer itself and license file, and like Joost wrote long ago we can use WM_SETTEXT for txt files. The only problem I found - System plug-in can not allocate variable size memory (&t$1), but calloc() can ;) Sample script attached.
Might be good to allow users to skip License file name for such situations in MUI page definition, 0 parameters may create warning only, in this script I had to use additional short "dummy.txt" file (not committed to our CVS, this may create problems with later installer rebuilds :( ).


The System.dll plug-in should have no problem allocating variable size memory blocks. The problem you've encountered is probably NSIS's string size limit (1024 by default). If you read using FileRead and then append using a call to lstrcat, it should be OK.

BTW, it's not a good idea to allocate using calloc and free using System::Free. They use two different allocation methods. In the worst case, it can cause a crash. Usually, it should just create a memory leak.


Thanks, KichiK!
Might be something was wrong in my syntax, this not worked with System::Call allocation, but looks OK now with Alloc and Free.
BTW I used
System::Alloc '$1 .r0'
syntax in the updated file, and this works fine, but System.htm uses
System::Alloc 64
Pop $0
Is my variant correct?


Your variant is incorrect. Take a look at Contrib\System\Source\Buffers.c. Alloc is right on the top.


OK, I'll better use my favourite msvcrt calls ;)


I've found very interesting all you have talk.

Where can I find more info about system calls and the parameters for that functions?

BTW, I made an patch.exe file which does the patching logic and I call externally.


You can find information about the System plug-in in its readme. You can find the readme, the source code and some examples in <nsis folder>\Contrib\System.


Take a look of that code. I have a binary file "prueba.bin" who is 1024 bytes and I try to copy into another file, but nothing happens.

Need more code? (includes, defines) or simplily the params are wrong?


System::Call 'msvcrt.dll::calloc(i 1024, i 1) i .r0' ; creates a 1024 size buffer

System::Call 'msvcrt.dll::_open(t "$INSTDIR\prueba.bin, i 0x8000) i .r1' ; open first file
System::Call 'msvcrt.dll::_open(t "$INSTDIR\prueba2.bin, i 0x8101) i .r2' ; open second file
System::Call 'msvcrt.dll::_read(i r1, i r0, 1024) i .r3' ;read the first file
System::Call 'msvcrt.dll::_write(i r2, i r0, 1024) i .r3' ;and writes to the second

System::Call 'msvcrt.dll::_close(i r1)' ; close file 1
System::Call 'msvcrt.dll::_close(i r2)' ; close file 2

You're missing closing quotes for the file names in both _open calls.


Originally posted by kichik
You're missing closing quotes for the file names in both _open calls.
:eek: Ups. Now file is created but nothing is readed nor writed. I'll continue investigating about that :cool:

It might be because you're missing an `i` before 1024 in the _read and _write lines.


I got it! :D

It failed type for 1024. Well, hope this will serve for others.


System::Call 'msvcrt.dll::_read(i r1, i r0, /* this -> */ i 1024) i .r3'
System::Call 'msvcrt.dll::_write(i r2, i r0, /* and this -> */ i 1024) i .r3'

It seems we are writing at time, ;)

Thanks for all, guys


And
System::Call 'msvcrt.dll::free(i ro)'
at the end of code :)


I've used System::Alloc and System::Free for that.

Is a good idea to allocate memory with those functions and then use the memory allocated with msvcrt.dll call functions?


This is not a problem I guess, both allocs should work with this code 100%. But System::Alloc + Pop take 2 lines of script :( - this is the only reason why I used direct msvcrt calls.


What if msvcrt.dll isn't installed? Must I include in the installer? And then, extract and installing?


Don't worry about msvcrt.dll ;)
Only msvcrtd.dll (debug version) may not present.