Skip to content
⌘ NSIS Forum Archive

Merging two binary files

10 posts

parasoul#

Merging two binary files

Hi,
How do you suggest the best way to merge two binary files using NSIS?

My first instinct is to use FileRead,FileSeek,FileWrite, but as I understand it, if the buffer of data is greater than the maximum string length then it wouldn't capture all of the data

My next instinct is to use the system plugin and use localalloc to create a buffer and then call CreateFile/ReadFile/WriteFile via the system plugin. I really want to avoid doing it this way because it would be pretty messy.

Do you know of a more elegant way?

I appreciate the help
LoRd_MuldeR#
If with "merge" you mean that you simply want to append one file to the other, you could do it via ExecWait call:

ExecWait 'cmd.exe /c copy /b "file1.bin" + "file2.bin" "out.bin"'
parasoul#
Thanks!
I decided to do it as such:
FileOpen $0 1.zip r
FileOpen $1 2.zip r
FileOpen $4 final.zip a
${While} $2 < ${top_half_size}
FileReadByte $0 $3
FileWriteByte $4 $3
IntOp $2 $2 + 1
${EndWhile}
${While} $5 < ${bottom_half_size}
FileReadByte $1 $3
FileWriteByte $4 $3
IntOp $5 $5 + 1
${EndWhile}
FileClose $0
FileClose $1
FileClose $4 
It's messy but does this seem like the most elegant way possible (assuming NSIS alone will be used)?
aerDNA#
I don't know about elegance but it's much faster using kernel32::ReadFile/WriteFile. This may or may not be a practical concern, depending on your actual file sizes. If you want, you can use a macro from a script of mine; I wrote it to copy n bytes from a file using a buffer. You can reuse it for your purposes with only slight modifications (commented) and you just need to pass file2 as output and file1 size as n bytes to copy.
# you can customize the variables to be used
!define InputHandle $R1
!define OutputHandle $R2
!define CopyBuffer $R3
!define ByteCount $R4
!define BytesRW_in $R5
# these must be R0...R9 registers, without '$'
!define BytesRW_out R6
!define Return R7
!define CopyBufferSize 8388608 # 8 MB
!macro CopyFileBytes InputFile OutputFile CopyBytes
!define UniqueID ${__LINE__}
ClearErrors
FileOpen ${InputHandle} "${InputFile}" r
IfErrors CopyError_${UniqueID}
FileOpen ${OutputHandle} "${OutputFile}" w # change openmode to 'a'  <-- <--
IfErrors CopyError_${UniqueID}
System::Alloc ${CopyBufferSize}
Pop ${CopyBuffer}
StrCpy ${ByteCount} 0
; FileSeek ${OutputHandle} 0 END # uncomment to append data to output  <-- <--
CopyLoop_${UniqueID}:
IntOp ${BytesRW_in} ${CopyBytes} - ${ByteCount}
IntCmp ${BytesRW_in} ${CopyBufferSize} +2 +2
StrCpy ${BytesRW_in} ${CopyBufferSize}
System::Call "kernel32::ReadFile(i ${InputHandle}, i ${CopyBuffer}, i ${BytesRW_in}, *i. ${BytesRW_out}, i '') i.${Return}"
IntCmp $${Return} 0 CopyError_${UniqueID}
IntCmp ${BytesRW_in} $${BytesRW_out} 0 CopyError_${UniqueID} CopyError_${UniqueID}
System::Call "kernel32::WriteFile(i ${OutputHandle}, i ${CopyBuffer}, i ${BytesRW_in}, *i. ${BytesRW_out}, i '') i.${Return}"
IntCmp $${Return} 0 CopyError_${UniqueID}
IntCmp ${BytesRW_in} $${BytesRW_out} 0 CopyError_${UniqueID} CopyError_${UniqueID}
IntOp ${ByteCount} ${ByteCount} + $${BytesRW_out}
IntCmp ${ByteCount} ${CopyBytes} CopyEnd_${UniqueID} CopyLoop_${UniqueID}
CopyError_${UniqueID}:
StrCpy $${Return} "CopyFileBytes failed"
CopyEnd_${UniqueID}:
FileClose ${InputHandle}
FileClose ${OutputHandle}
System::Free ${CopyBuffer}
ClearErrors
!undef UniqueID
!macroend
!define CopyFileBytes "!insertmacro CopyFileBytes" 
${CopyFileBytes} "file1" "file2" file1size
StrCmp $${Return} "CopyFileBytes failed" 0 +2
MessageBox MB_OK|MB_ICONSTOP "File merge failed."

Edit: I mixed it up, for a typical merging scenario, file2 should be input and file1 output, but you get the idea.
Anders#
The NSIS instructions are just thin wrappers around the kernel32 functions, the reason they are slow is because you end up with a context switch for every single byte...
LoRd_MuldeR#
parasoul,

you can now try with AppendToFile function from latest StdUtils plug-in:
StdUtils.2015-06-19.zip

See documentation for details:
LoRd_MuldeR#
Just for the notes, here is a new StdUtils test version with some new goodies:


As always, please refer to the online documentation for details:


Version 1.07, not yet released
· New functions HashText and HashFile, which can be used to compute the cryptographic hash of the given file or string
· New functions ValidFileName and ValidPathSpec, which can be used to test if a string is a valid file name or a valid full path
· New function AppendToFile, which can be used to append the contents of one file to another (existing) file.
parasoul#
Originally Posted by LoRd_MuldeR View Post
Just for the notes, here is a new StdUtils test version with some new goodies:


As always, please refer to the online documentation for details:
http://muldersoft.com/docs/stdutils_readme.html
This worked for me. Thanks very much Mulder 😁