Skip to content
⌘ NSIS Forum Archive

How to speed this up?

12 posts

s793016#

How to speed this up?

Sorry, my English is very very poor.

For some reason, I must chop some file when install running.

so I write this script to do it, and it really work:

!macro Chop SrcID TarID BeginOff EndOff
push $1
push $2
push $3
IntOP $3 ${EndOff} + 0
FileSeek ${SrcID} 0 Cur $2
push $2
FileSeek ${SrcID} ${BeginOff}
IntOP $2 ${BeginOff} - 1

IntOP $2 $2 + 1
FileReadByte ${SrcID} $1
FileWriteByte ${TarID} $1
StrCmp $2 $3 0 -3
pop $2
FileSeek ${SrcID} $2
pop $3
pop $2
pop $1
!macroend
And my problem is: if I want to chop more than 64K (65535), the performance time for chop will become very slow.

I wished to do this chop by pure NSIS Script or NSIS Script + plugin.

Does anyone got any good idea?

Thank you very much.
deguix#
I did halfway I did in StrFunc.nsh, I transformed your macro into a function (less size) with simple call for only Install function.

To call the function use "${Chop} SrcID TarID BeginOff EndOff".

(I don't know if your function has a return, if it returns something, say what returns for me and I'll give another piece of code)

(The same thing applies if you use it in an Uninstaller, it it is for Install, Uninstall or both, say it to me and I'll do the complete implementation I did on StrFunc.nsh if necessary)

!define Chop "!insertmacro Chop"
Function Chop
  Exch $R3
  Exch
  Exch $R2
  Exch
  Exch 2
  Exch $R1
  Exch 2
  Exch 3
  Exch $R0
  Exch 3
  push $1
  push $2
  push $3
  IntOP $3 ${EndOff} + 0
  FileSeek ${SrcID} 0 Cur $2
  push $2
  FileSeek ${SrcID} ${BeginOff}
  IntOP $2 ${BeginOff} - 1
  IntOP $2 $2 + 1
  FileReadByte ${SrcID} $1
  FileWriteByte ${TarID} $1
  StrCmp $2 $3 0 -3
  pop $2
  FileSeek ${SrcID} $2
  pop $3
  pop $2
  pop $1
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
FunctionEnd
!macro Chop SrcID TarID BeginOff EndOff
  Push ${StcID}
  Push ${TarID}
  Push ${BeginOff}
  Push ${EndOff}
  Call Chop
!macroend 
s793016#
Thank you, deguix. 😉

This macro has no return.

I just use it for install phase right now, maybe somebody need it in other phase?

By the way, if you CHOP a piece longer than 60K bytes, the CHOP performance will become very slow.

I tried to CHOP for 64381 bytes before, and done it with 5 minutes ... 😠
kichik#
If you want something fast, simply call SetEndOfFile using the System plug-in or your own plug-in.
deguix#
SetEndOfFile

The SetEndOfFile function moves the end-of-file (EOF) position for the specified file to the current position of the file pointer.
Input: Handle ($R0).
Output: Nothing.

NOTE: The file has to be opened in append or write mode.

System::Call "Kernel32.lib::SetEndOfFile(i)i(R0)" 
(Not tested.)
s793016#
Fix something from deguix's function. This code is equal to above code.

!define Chop "!insertmacro Chop"
Function Chop
  Exch $R3
  Exch
  Exch $R2
  Exch
  Exch 2
  Exch $R1
  Exch 2
  Exch 3
  Exch $R0
  Exch 3
  push $1
  FileSeek $R0 0 Cur $1
  push $1
  FileSeek $R0 $R2
  IntOP $R2 $R2 - 1
  IntOP $R2 $R2 + 1
  FileReadByte $R0 $1
  FileWriteByte $R1 $1
  StrCmp $R2 $R3 0 -3
  pop $1
  FileSeek $R0 $1
  pop $1
  Pop $R3
  Pop $R2
  Pop $R1
  Pop $R0
FunctionEnd
!macro Chop SrcID TarID BeginOff EndOff
  Push ${SrcID}
  Push ${TarID}
  Push ${BeginOff}
  Push ${EndOff}
  Call Chop
!macroend 
And ... SetEndOfFile looks like no use ... 🙄
deguix#
It is just an alternative way. This one uses the file current position to know to set the file end, and it cuts automatically every additional byte, or it adds bytes if not on this size.

And sorry for that of my code, it happens commonly.
brainsucker#
To use SetEndOfFile:

CreateFile
SetFilePointer
SetEndOfFile
CloseHandle

Will work instantly
brainsucker#
Full deguix's sample, 70000 - position to cut. Haven't tested it yet. But should work 🙂

FileOpen $1 "cutfile" "rw"
FileSeek $1 70000
System::Call "Kernel32::SetEndOfFile(i r1) i"
FileClose $1
s793016#
Sorry, my English is very very poor.

Why I said that SetEndOfFile API looks like no use?

Because we offen chop a file for just the middle part.

I make you an easy example. Assume those string is a file contains, looks like this:

"1234567890"

If we just need to get locate 4 ~ 9, we may insert a line like this:

${Chop} SrcID TarID 4 9

See? There is nothing left for SetEndOfFile API to do.

And the real problem is: Nometer SetEndOfFile do work or not, you still need to drop off 1 ~ 3 and cut off 4 ~ 9 by my slowest function itself.

... Maybe a Win32API for "Read File to Memory" and "Write Memory to File" could accerator this slowest function?
brainsucker#
Crops 'cutfile' to $3 bytes starting at $2 position.

FileOpen $1 "cutfile" "a"
FileSeek $1 $2
System::Alloc $3
System::Call "Kernel32::ReadFile(i r1, i sr4, i r3, *i 0 r5, i 0)"
FileSeek $1 0
System::Call "Kernel32::WriteFile(i r1, i r4, i r5, *i 0 r5, i 0)"
System::Call "Kernel32::SetEndOfFile(i r1) i"
FileClose $1
System::Free $4
s793016#
Great Work!!!👍 Big Thanks to brainsucker!👍 👍 👍

And the merged new code is here:
!define Chop "!insertmacro Chop"
!macro Chop SrcID TarID BeginOff EndOff
  Push ${SrcID}     ; -> $0
  Push ${TarID}     ; -> $1
  Push ${BeginOff}  ; -> $2
  Push ${EndOff}    ; -> $3
  Call Chop
!macroend
Function Chop
  Exch $3        ; <- ${EndOff}
  Exch
  Exch $2        ; <- ${BeginOff}
  Exch
  Exch 2
  Exch $1        ; <- ${TarID}
  Exch 2
  Exch 3
  Exch $0        ; <- ${SrcID}
  Exch 3
  push $4
  FileSeek $0 0 Cur $4
  push $4
  push $5
  FileSeek $0 $2
  IntOP $2 $3 - $2
  IntOP $2 $2 + 1
  StrCpy $3 ''
System::Alloc $2
System::Call "Kernel32::ReadFile(i r0, i sr5, i r2, *i 0 r3, i 0)"
System::Call "Kernel32::WriteFile(i r1, i r5, i r3, *i 0 r3, i 0)"
System::Free $5
  pop $5
  pop $4
  FileSeek $0 $4
  pop $4
  Pop $3
  Pop $2
  Pop $1
  Pop $0
FunctionEnd