


#########################################################3
## Archiver Include Routines.
##
## Refined: Aug 17 2008.  Andrew Wallo,  Microneil, ArmResearch All Rights Reserved.
##########################################################

# Main objectives is as follows:
# Enable rollback of a folder to a previous folder state.
# Create the log, and store it in the archive so that it understands what it nees to rollback.
# Log should Contain, target directories, date and other relevent information.

# Dependencies:
# 1:  Requires ${GetTime} to be defined in the master install script.
# 2:  Requires ${GetBetwee} to be defined in the master install script.  Used to parse file lines.
   Var /GLOBAL SRS_CurrentArchiveFolder
   Var /GLOBAL SRS_Rollback_FileHandle
   Var /GLOBAL SRS_Rollback_FileCount
   Var /GLOBAL SRS_LogName
   
!macro StartRollbackSession _ArchivePath _LogName _RootKey _RegistryKey
  StrCpy $SRS_LogName ${_LogName}
  StrCpy $SRS_CurrentArchiveFolder ${_ArchivePath}
  StrCpy $SRS_Rollback_FileCount "0"
  ; Now put the values onto the stack for the Rollback engine.
	Push `${_ArchivePath}`
	Push `${_LogName}`
	Call OpenRollback
  ;MessageBox MB_OK "Opened rollback with: $SRS_LogName / ${_ArchivePath} / $SRS_CurrentArchiveFolder"

  ${IF} "${_RootKey}" != ""
   ${IF} "${_RegistryKey}" != ""
      ${SetRegistry_with_RollbackControl} "${_RootKey}" "${_RegistryKey}" "SRS_RollbackPath" "$SRS_CurrentArchiveFolder"
      ${SetRegistry_with_RollbackControl} "${_RootKey}" "${_RegistryKey}" "SRS_LogName" "$SRS_LogName"
    ${ENDIF}
  ${ENDIF}

!macroend
!define StartRollbackSession "!insertmacro StartRollbackSession"

#test

!macro EndRollbackSession _RootKey _RegistryKey
  ${IF} "${_RootKey}" != ""
   ${IF} "${_RegistryKey}" != ""
      ${SetRegistry_with_RollbackControl} "${_RootKey}" "${_RegistryKey}" "SRS_COMPLETE" "1"   
      ${SetRegistry_with_RollbackControl} "${_RootKey}" "${_RegistryKey}" "SRS_INSTDIR" "$INSTDIR"
      ${SetRegistry_with_RollbackControl} "${_RootKey}" "${_RegistryKey}" "SRS_SERVDIR" "$SNFServerInstallDir"
    ${ENDIF}
  ${ENDIF}

  FileWrite $SRS_Rollback_FileHandle "<FILECOUNT>$SRS_Rollback_FileCount</FILECOUNT>$\r$\n"
  StrCpy $SRS_Rollback_FileCount "0"
  FileWrite $SRS_Rollback_FileHandle "<END ROLLBACK FILE>$\r$\n"
  FileClose $SRS_Rollback_FileHandle ; close this file
  StrCpy $SRS_Rollback_FileHandle ""  ;and clear for new rollback session.
!macroend
!define EndRollbackSession "!insertmacro EndRollbackSession"

Function OpenRollback

  ; First determine if we're trying to open a second consecutive rollback session... ( this would be bad. )
  ;StrCmp $SRS_Rollback_FileHandle "" runOpenRollback 0 ; if cleared, then we can start a Rollback Session.  If not clear, then set errors.
  ;   push $1 ; saves $1
  ;   Exch
  ;   pop $1 ; removes ArchivePath off stack
  ;   Exch
  ;   pop $1 ; removes LogNme off stack
  ;   pop $1 ; restores $1
  ;   SetErrors
  ;     MessageBox MB_OK "Archive in progress?"
  ;   return ; sorry, can't do this right now....
  ;runOpenRollback: ; ok, clear for take-off:

  ; First protect the stack by saving the values of the registers we're going to use.
  ; But they're covering the parameters that were passed......
  ######################################## Stack Protection ###################################
  push $9 ; Save Register $9;
  Exch    ; Swap Zeroth element in stack with the top most, which will be _LogName from the macro
  pop $9  ; put Log into register $9

  push $8 ; Save register $8
  Exch 2  ; Swap with position 1 from the top.  So.... before exch was $1 $0  _ArchivePath
          ; After Exch was _ArchvePath $0 $1
  pop $8  ; $8 holds ArchivePath

  push $7 ; Used Locally.... save on stack....
  push $6
  push $5
  push $4
  push $3
  push $2
  push $1
  push $0
  ###################################### End Stack Protection #################################
  ; Ok,
  ifFileExists "$8\*.*" SRS_FolderExists 0 ; if the folder exists, skip create, otherwise create directory.
    CreateDirectory $8
  SRS_FolderExists:
    StrCpy $SRS_CurrentArchiveFolder $8 ; Save master variable for local var.

      ${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6  ; set vars for oldfilerename
        	; $0="01"      day
        	; $1="04"      month
        	; $2="2005"    year
        	; $3="Friday"  day of week name
        	; $4="16"      hour
        	; $5="05"      minute
        	; $6="50"      seconds
     ; Create the specific archive folder path.
     StrCpy $7 "Archive_$2$1$0$4$5$6"  ; for keying the folder.
  ; Test for valid name... otherwise use default.
  StrCmp $9 "" 0 +2
    StrCpy $9 "$7_rllbck.log"
  FileOpen $SRS_Rollback_FileHandle $8\$9 w ; Log File created for tracking rollback
  FileWrite $SRS_Rollback_FileHandle "<COMMENT>Started Rollback Log</COMMENT>$\r$\n"
  FileWrite $SRS_Rollback_FileHandle "<STARTDATE>$2.$1.$0,$4:$5:$6</STARTDATE>$\r$\n"

  ###################################### Restore the Stack ####################################
  pop $0
  pop $1
  pop $2
  pop $3
  pop $4
  pop $5
  pop $6
  pop $7
  pop $8
  pop $9
  return
FunctionEnd


#####################################################################################################################################################
##  ${SetRegistry_RollbackControl} sets a registry entry to a new value, and stores the old one.
#####################################################################################################################################################

!macro SetRegistry_with_RollbackControl _RootKey _RegistryKey _SubKey _Value
  push $1

        ${Switch} "${_RootKey}"
            ${Case} "HKLM"
                ReadRegStr $1 HKLM "${_RegistryKey}" "${_SubKey}" ; get keys value...
            ${Case} "HKCR"
               ReadRegStr  $1 HKCR "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
           ${Case} "HKCU"
               ReadRegStr  $1 HKCU "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKU"
               ReadRegStr  $1 HKU "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKCC"
                ReadRegStr  $1 HKCC "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKDD"
                ReadRegStr  $1 HKDD "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKPD"
               ReadRegStr  $1 HKPD "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "SHCTX"
               ReadRegStr  $1 SHCTX "${_RegistryKey}" "${_SubKey}" ;$R1 $R2 $R3Goto EndSNFServiceTest
        ${EndSwitch}

  
    StrCmp $1 "" 0 +4
      ; String is empty.  Test for no key.
      ifErrors 0 +3 ; Means its a DWORD or something, but I'm not handling that here.
        ; Key didn't exist.
        FileWrite $SRS_Rollback_FileHandle "<REGISTRY><NEW>1</NEW><ROOT>${_RootKey}</ROOT><KEY>${_RegistryKey}</KEY><SUBKEY>${_SubKey}</SUBKEY><VALUE>${_Value}</VALUE></REGISTRY>$\r$\n"
        Goto +2 ; skip duplicate line and alter registry....
  ; Else the key existed.
  FileWrite $SRS_Rollback_FileHandle "<REGISTRY><NEW>0</NEW><ROOT>${_RootKey}</ROOT><KEY>${_RegistryKey}</KEY><SUBKEY>${_SubKey}</SUBKEY><VALUE>$1</VALUE></REGISTRY>$\r$\n"
        ${Switch} "${_RootKey}"
            ${Case} "HKLM"
                WriteRegStr HKLM "${_RegistryKey}" "${_SubKey}" "${_Value}" ; get keys value...
            ${Case} "HKCR"
               WriteRegStr HKCR "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
           ${Case} "HKCU"
               WriteRegStr HKCU "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKU"
               WriteRegStr HKU "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKCC"
                WriteRegStr HKCC "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKDD"
                WriteRegStr HKDD "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKPD"
               WriteRegStr HKPD "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "SHCTX"
               WriteRegStr SHCTX "${_RegistryKey}" "${_SubKey}" "${_Value}" ;$R1 $R2 $R3Goto EndSNFServiceTest
        ${EndSwitch}
   pop $1
!macroend
!define SetRegistry_with_RollbackControl "!insertmacro SetRegistry_with_RollbackControl"

#####################################################################################################################################################
##  ${Install_with_RollbackControl} assumes you have set your INSTALL Directory as it will call File _someFilename and put it
##  wherever the SetOutPath is pointing....
#####################################################################################################################################################

!macro Install_with_RollbackControl _someFileName _CallbackHandler _onFailCommand
     StrCmp "1" "0" 0 +2
       File ${_someFileName} ; can't ever happen but we need it here to force the compiler to include the file.

     IfFileExists `$OUTDIR\${_someFileName}` 0 +4
     ; File exists.  We need to make a copy of the original file.
     CopyFiles /SILENT `$OUTDIR\${_someFileName}` `$SRS_CurrentArchiveFolder\${_someFileName}`
     ; We need to save the target path seperately because later when we're rolling it back, we'll need to setOutPath for each file seperately.
     ; If a file has a potential of being tied up, we can specify the action to take on an overwrite failure.
     FileWrite $SRS_Rollback_FileHandle "<FILE><NEW>0</NEW><NAME>${_someFileName}</NAME><TARGETPATH>$OUTDIR</TARGETPATH><CALLBACK>${_CallbackHandler}</CALLBACK><ONFAIL>${_onFailCommand}</ONFAIL></FILE>$\r$\n"
     Goto +2
     ; +4 jumps to here.....just Put The File
     FileWrite $SRS_Rollback_FileHandle "<FILE><NEW>1</NEW><NAME>${_someFileName}</NAME><TARGETPATH>$OUTDIR</TARGETPATH><CALLBACK>${_CallbackHandler}</CALLBACK><ONFAIL>${_onFailCommand}</ONFAIL></FILE>$\r$\n"
     File `${_someFileName}`  ; ok, output the file into the install directory.
     IntOp $SRS_Rollback_FileCount $SRS_Rollback_FileCount + 1
!macroend
!define Install_with_RollbackControl "!insertmacro Install_with_RollbackControl"

###################################################################################################################################################
## The difference here is that the macro doesn't rely on the SetOutPath or call the File "filename" command.  It just archives a file into rollback
## based on the the fully qualified path name supplied.
################################################################################################################################################
!macro Copy_with_RollbackControl _someFileName _Path _CallbackHandler _onFailCommand
   ifFileExists ${_Path}\${_someFileName} 0 +5
     CopyFiles /SILENT `${_Path}\${_someFileName}` `$SRS_CurrentArchiveFolder\${_someFileName}`
     CopyFiles /SILENT `${_Path}\${_someFileName}` `${_Path}\${_someFileName}_pre_sniffer_install.log`
     ; We need to save the target path seperately because later when we're rolling it back, we'll need to setOutPath for each file seperately.
     ; If a file has a potential of being tied up, we can specify the action to take on an overwrite failure.
     FileWrite $SRS_Rollback_FileHandle "<FILE><NEW>0</NEW><NAME>${_someFileName}</NAME><TARGETPATH>${_Path}</TARGETPATH><CALLBACK>${_CallbackHandler}</CALLBACK><ONFAIL>${_onFailCommand}</ONFAIL></FILE>$\r$\n"
     IntOp $SRS_Rollback_FileCount $SRS_Rollback_FileCount + 1
!macroend
!define Copy_with_RollbackControl "!insertmacro Copy_with_RollbackControl"

!macro RollBackTo _rollbackLocalPath _rollbackLogName
  push `${_rollbackLocalPath}`
  push `${_rollbackLogName}`
  Call RollBack
!macroend
!define RollBackTo "!insertmacro RollBackTo"

Function RollBack
  push $0  ; save register 0 on stack.  ( So stack looks like $0 "_rollbackLogName" _rollbackLocalPath Rest of Stack.....
  Exch     ; swap the top two objects on the stack....  _rollbackLogName $0 _rollbackLocalPath
  pop $0   ; stack looks like $0.._rollbackLocalPath ...Rest of Stack....  Using $0 to hld the RollBackLogName

  push $1  ; stack looks like $1 $0.._rollbackLocalPath Rest of Stack  Use this var for handling readlines.
  Exch 2   ; stack looks like _rollbackLocalPath $0 $1 Rest of Stack
  pop $1   ; Use this var for handling the local path of the list of archived files.
  Exch     ; stack looks like $1 $0 Rest of Stack
  push $2  ; stack look like $2 $1 $0 Rest of stack.  Use $2 to hold read lines.....
  push $3  ; stack looks like $3 $2 $1 $0 RestofStack.  Use this var for handling tag parsing of lines....
  push $4  ; saving $4 too... use this var for holding filename of file.
  push $5  ; saving $5 too... use this var for holding target path.
  push $6  ; use this var for the command line to exeute if failed to copy....
  push $7  ; use this var for temp file handle

  ; registry temp vars....
  push $R1 ; protect this and use for the Root of the registry handles...
  push $R2 ; protect this and use for the Key
  push $R3 ; protect this and use for the subkey
  push $R4 ; protected this and use for the Value.....

  ; Not sure what the situation would be..... but theoretically, if the file is open... then.... its still open and the caller wasn't careful about
  ; ending the rollback.
  StrCmp $SRS_Rollback_FileHandle "" ProceedToRollBack 0
    ; File is open... crap... ok..well, reguardless of what our filename is, ( and it SHOULD be the same file, logically.... ) we want the other closed properly.
    MessageBox MB_OK "Had to close the file?"
    !insertmacro EndRollbackSession "" ""  ; so end it cleanly.  THEN open our rollback log. ; We're skipping the registry keys that record
                                           ; where the logfile and rollbackpath is... if this happens.
  ProceedToRollBack:

    ifFileExists "$1\$0" StartRollBack 0
      SetErrors
        MessageBox MB_OK "Unable to find rollback file: $1\$0"
        Goto SRS_DONE
      Return ; perhaps the user just gave the file folder.... try to locate the .rllbck file in the folder.... if it exists.
  StartRollBack:
    clearerrors
    FileOpen $SRS_Rollback_FileHandle "$1\$0" r  ; open file for read.
      IfErrors 0 SRS_RESTORE_ReadLine
        MessageBox MB_OK "Error opening the file for rollback: $1\$0"
        Goto SRS_DONE
  SRS_RESTORE_ReadLine:
    ClearErrors
    FileRead $SRS_Rollback_FileHandle $2 ; get line for parsing.
    ;MessageBox MB_OK $2
      IfErrors SRS_DONE ; if errors, then EOF. Cleanup stack and exit.
    ; otherise parse line.
    StrCpy $3 $2 6 ;if this line is a file line, then the first six chars should be <FILE>

    ;Handle Registry Alterations:
    StrCmp $3 "<REGIS" 0 SRS_RESTORE_TestForFileLine
      FileOpen $7 "$1\SRS_TempFile.txt" w
      FileWrite $7 $2
      FileClose $7
      ;<FILE><NEW>1</NEW><NAME>${_someFileName}</NAME><TARGETPATH>$OUTDIR</TARGETPATH><ONFAIL>${_onFailCommand}</ONFAIL></FILE>
      ;<REGISTRY><NEW>1</NEW><ROOT>${_RootKey}</ROOT><KEY>${_RegistryKey}</KEY><SUBKEY>${_SubKey}</SUBKEY><VALUE>${_Value}</VALUE></REGISTRY>
      #MessageBox MB_OK "$2"
      ; Because GetBetween only uses files as sources.... ( stupid, that I'm using that here, but I am.... )
      ${GetBetween} "<NEW>" "</NEW>" "$1\SRS_TempFile.txt" $4  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK $4
      ${GetBetween} "<ROOT>" "</ROOT>" "$1\SRS_TempFile.txt" $R1  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"
      ${GetBetween} "<KEY>" "</KEY>" "$1\SRS_TempFile.txt" $R2  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"
      ${GetBetween} "<SUBKEY>" "</SUBKEY>" "$1\SRS_TempFile.txt" $R3  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"
      ${GetBetween} "<VALUE>" "</VALUE>" "$1\SRS_TempFile.txt" $R4  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"

      #MessageBox MB_OK "$1, $4 , $R1 , $R2 , $R3 , $R4"
      StrCmp $4 "SRS_RollbackPath" RemoveIt 0
      StrCmp $4 "SRS_Logname" RemoveIt 0
      StrCmp $4 "1" 0 SRS_RESTORE_WRITE ; if the new marker is set to 1 then a rollback means remove it entirely.....

      RemoveIt:
        ${Switch} $R1
            ${Case} "HKLM"
                DeleteRegValue HKLM $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKCR"
               DeleteRegValue HKCR $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
           ${Case} "HKCU"
               DeleteRegValue HKCU $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKU"
               DeleteRegValue HKU $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKCC"
                DeleteRegValue HKCC $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKDD"
                DeleteRegValue HKDD $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKPD"
               DeleteRegValue HKPD $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "SHCTX"
               DeleteRegValue SHCTX $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
        ${EndSwitch}
        Goto SRS_RESTORE_ReadLine
SRS_RESTORE_WRITE:
      ; if not then we need to restore the key.....
      ${Switch} $R1
            ${Case} "HKLM"
               WriteRegStr HKLM $R2 $R3 $R4
            ${Case} "HKCR"
               WriteRegStr HKCR $R2 $R3 $R4
           ${Case} "HKCU"
               WriteRegStr HKCU $R2 $R3 $R4
            ${Case} "HKU"
               WriteRegStr HKU $R2 $R3 $R4
            ${Case} "HKCC"
               WriteRegStr HKCC $R2 $R3 $R4
            ${Case} "HKDD"
               WriteRegStr HKDD $R2 $R3 $R4
            ${Case} "HKPD"
               WriteRegStr HKPD $R2 $R3 $R4
            ${Case} "SHCTX"
               WriteRegStr SHCTX $R2 $R3 $R4
        ${EndSwitch}
      Goto SRS_RESTORE_ReadLine

SRS_RESTORE_TestForFileLine:

    StrCmp $3 "<FILE>" 0 SRS_RESTORE_ReadLine ; if its a file, then handle rolling back the file, otherwise get the next line.
      FileOpen $7 "$1\SRS_TempFile.txt" w
      FileWrite $7 $2
      FileClose $7
      ; Because GetBetween only uses files as sources.... ( stupid, that I'm using that here, but I am.... )
      ${GetBetween} "<NAME>" "</NAME>" "$1\SRS_TempFile.txt" $4  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      ${GetBetween} "<NEW>" "</NEW>" "$1\SRS_TempFile.txt" $R1  ; Get the marker that informed us if there WAS something to be copied, or if it was just installed.
      ;MessageBox MB_OK "Name:$4"
      ${GetBetween} "<TARGETPATH>" "</TARGETPATH>" "$1\SRS_TempFile.txt" $5  ; Get the targetpath between the file tags of the read_line_in->$2 and stick it in $5
      ;MessageBox MB_OK "Target:$5"
      clearerrors
      ${GetBetween} "<CALLBACK>" "</CALLBACK>" "$1\SRS_TempFile.txt" $6  ; Get the CALLBACK name between the file tags of the read_line_in->$2 and stick it in $6

       iferrors NoCallbackAvailable 0
         StrCmp $6 "" NoCallbackAvailable 0
            ; Ok, we have a callback, so we don't copy, we call file, and pass the filename.
            ;MessageBox MB_OK "Pushing $1\$4"
            push "$1\$4" ; push the file and path onto the stack.
            push $6 ; push the calback value onto the stack,
            Call ResolveFunction  ; call the resolveFunction Call.
          Goto SRS_RESTORE_ReadLine ; No copy, just return for next line handle.

   NoCallbackAvailable:
      ; now deal with new vs archived files...
      StrCmp $R1 "1" 0 SRS_NOTNEW_RESTOREIT ; test to see if it was new, or if it required backin gup...
        ifFileExists "$5\$4" 0 SRS_RESTORE_ReadLine  ; if it WAS new... test to see if file still exists...
          Delete "$5\$4" ; Since it was new we'll remove it on a restore....
          Goto SRS_RESTORE_ReadLine

    SRS_NOTNEW_RESTOREIT:
      CopyFiles /SILENT "$1\$4" "$5\$4"
      iferrors 0 SRS_RESTORE_ReadLine
        clearerrors
        ${GetBetween} "<ONFAIL>" "</ONFAIL>" "$1\SRS_TempFile.txt" $6  ; Get the onfail name between the file tags of the read_line_in->$2 and stick it in $6
        ; if we're here, then we need to rexecute the copy after executing the command line
          push "$1\$4" ; push the file and path onto the stack.
          push $6 ; push the callback value onto the stack,
          Call ResolveFunction  ; call the resolveFunction Call.
        clearerrors
        CopyFiles /SILENT "$1\$4" "$5\$4"
          iferrors 0 SRS_RESTORE_ReadLine
          ; if still an error, then notify and try next line.
          ; MessageBox MB_OK "Error in rolling back file: $1\$4 to $5\$4"
        Goto SRS_RESTORE_ReadLine
  
  ; ok, either we parsed the file, or we quit with errors... either way. clean the stack....
  SRS_DONE: ; done with readling lines from the file.
  Delete "$1\SRS_TempFile.txt"
  FileClose $SRS_Rollback_FileHandle
    ; Now parse the file name
  pop $R4
  pop $R3
  pop $R2
  pop $R1
  pop $7
  pop $6
  pop $5
  pop $4
  pop $3
  pop $2   ;restore $2
  pop $1   ;restore $1
  pop $0   ; restore $0 to previous value....
  return   ; end
FunctionEnd

;!macro moveRollbackArchive _ExistingPath _ExistingLogFile _NewPath
;  ifFileExists "${_ExistingPath}" 0 +2
;    Delete "${_ExistingPath}\*.*"
;    RMDir "${_ExistingPath}"
;    rename "${_ExistingPath}\*.*" "${_NewPath}\*.*"
;                Push "${_ExistingPath}" #text to be replaced
;                Push "${_NewPath}" #replace with
;                Push 0 #replace command
;                Push 1 #replace but only one occurance.. not all close network references....
;                Push "${_NewPath}\${_ExistingLogFile}" #file to replace in
;                Call AdvReplaceInFile ;; it reads the pushed variables as parameters.... ( Hey... I didn't design that interface... its confusing. )
;
;!macroend


!macro un.RollBackTo _rollbackLocalPath _rollbackLogName
  push `${_rollbackLocalPath}`
  push `${_rollbackLogName}`
  Call un.RollBack
!macroend
!define un.RollBackTo "!insertmacro un.RollBackTo"



Function un.RollBack
  push $0  ; save register 0 on stack.  ( So stack looks like $0 "_rollbackLogName" _rollbackLocalPath Rest of Stack.....
  Exch     ; swap the top two objects on the stack....  _rollbackLogName $0 _rollbackLocalPath
  pop $0   ; stack looks like $0.._rollbackLocalPath ...Rest of Stack....  Using $0 to hld the RollBackLogName

  push $1  ; stack looks like $1 $0.._rollbackLocalPath Rest of Stack  Use this var for handling readlines.
  Exch 2   ; stack looks like _rollbackLocalPath $0 $1 Rest of Stack
  pop $1   ; Use this var for handling the local path of the list of archived files.
  Exch     ; stack looks like $1 $0 Rest of Stack
  push $2  ; stack look like $2 $1 $0 Rest of stack.  Use $2 to hold read lines.....
  push $3  ; stack looks like $3 $2 $1 $0 RestofStack.  Use this var for handling tag parsing of lines....
  push $4  ; saving $4 too... use this var for holding filename of file.
  push $5  ; saving $5 too... use this var for holding target path.
  push $6  ; use this var for the command line to exeute if failed to copy....
  push $7  ; use this var for temp file handle

  ; registry temp vars....
  push $R1 ; protect this and use for the Root of the registry handles...
  push $R2 ; protect this and use for the Key
  push $R3 ; protect this and use for the subkey
  push $R4 ; protected this and use for the Value.....


    ifFileExists "$1\$0" StartRollBack 0
      SetErrors
        MessageBox MB_OK "Unable to find rollback file for uninstall: $1\$0"
        Goto SRS_DONE
      Return ; perhaps the user just gave the file folder.... try to locate the .rllbck file in the folder.... if it exists.
  StartRollBack:
    clearerrors
    FileOpen $SRS_Rollback_FileHandle "$1\$0" r  ; open file for read.
      IfErrors 0 SRS_RESTORE_ReadLine
        MessageBox MB_OK "Error opening the file for rollback: $1\$0"
        Goto SRS_DONE
  SRS_RESTORE_ReadLine:
    ClearErrors
    FileRead $SRS_Rollback_FileHandle $2 ; get line for parsing.
    ;MessageBox MB_OK $2
      IfErrors SRS_DONE ; if errors, then EOF. Cleanup stack and exit.
    ; otherise parse line.
    StrCpy $3 $2 6 ;if this line is a file line, then the first six chars should be <FILE>

    ;Handle Registry Alterations:
    StrCmp $3 "<REGIS" 0 SRS_RESTORE_TestForFileLine
      FileOpen $7 "$1\SRS_TempFile.txt" w
      FileWrite $7 $2
      FileClose $7
      ;<FILE><NEW>1</NEW><NAME>${_someFileName}</NAME><TARGETPATH>$OUTDIR</TARGETPATH><ONFAIL>${_onFailCommand}</ONFAIL></FILE>
      ;<REGISTRY><NEW>1</NEW><ROOT>${_RootKey}</ROOT><KEY>${_RegistryKey}</KEY><SUBKEY>${_SubKey}</SUBKEY><VALUE>${_Value}</VALUE></REGISTRY>
      #MessageBox MB_OK "$2"
      ; Because GetBetween only uses files as sources.... ( stupid, that I'm using that here, but I am.... )
      ${un.GetBetween} "<NEW>" "</NEW>" "$1\SRS_TempFile.txt" $4  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK $4
      ${un.GetBetween} "<ROOT>" "</ROOT>" "$1\SRS_TempFile.txt" $R1  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"
      ${un.GetBetween} "<KEY>" "</KEY>" "$1\SRS_TempFile.txt" $R2  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"
      ${un.GetBetween} "<SUBKEY>" "</SUBKEY>" "$1\SRS_TempFile.txt" $R3  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"
      ${un.GetBetween} "<VALUE>" "</VALUE>" "$1\SRS_TempFile.txt" $R4  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      #MessageBox MB_OK "$R1,$R2,$R3,$R4"

      #MessageBox MB_OK "$1, $4 , $R1 , $R2 , $R3 , $R4"
      StrCmp $4 "SRS_RollbackPath" RemoveIt 0
      StrCmp $4 "SRS_Logname" RemoveIt 0
      StrCmp $4 "1" 0 SRS_RESTORE_WRITE ; if the new marker is set to 1 then a rollback means remove it entirely.....

      RemoveIt:
        ${Switch} $R1
            ${Case} "HKLM"
                DeleteRegValue HKLM $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKCR"
               DeleteRegValue HKCR $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
           ${Case} "HKCU"
               DeleteRegValue HKCU $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKU"
               DeleteRegValue HKU $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKCC"
                DeleteRegValue HKCC $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKDD"
                DeleteRegValue HKDD $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "HKPD"
               DeleteRegValue HKPD $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
            ${Case} "SHCTX"
               DeleteRegValue SHCTX $R2 $R3 ;$R1 $R2 $R3Goto EndSNFServiceTest
        ${EndSwitch}
        Goto SRS_RESTORE_ReadLine
SRS_RESTORE_WRITE:
      ; if not then we need to restore the key.....
      ${Switch} $R1
            ${Case} "HKLM"
               WriteRegStr HKLM $R2 $R3 $R4
            ${Case} "HKCR"
               WriteRegStr HKCR $R2 $R3 $R4
           ${Case} "HKCU"
               WriteRegStr HKCU $R2 $R3 $R4
            ${Case} "HKU"
               WriteRegStr HKU $R2 $R3 $R4
            ${Case} "HKCC"
               WriteRegStr HKCC $R2 $R3 $R4
            ${Case} "HKDD"
               WriteRegStr HKDD $R2 $R3 $R4
            ${Case} "HKPD"
               WriteRegStr HKPD $R2 $R3 $R4
            ${Case} "SHCTX"
               WriteRegStr SHCTX $R2 $R3 $R4
        ${EndSwitch}
      Goto SRS_RESTORE_ReadLine

SRS_RESTORE_TestForFileLine:

    StrCmp $3 "<FILE>" 0 SRS_RESTORE_ReadLine ; if its a file, then handle rolling back the file, otherwise get the next line.
      FileOpen $7 "$1\SRS_TempFile.txt" w
      FileWrite $7 $2
      FileClose $7
      ; Because GetBetween only uses files as sources.... ( stupid, that I'm using that here, but I am.... )
      ${un.GetBetween} "<NAME>" "</NAME>" "$1\SRS_TempFile.txt" $4  ; Get the file name between the file tags of the read_line_in->$2 and stick it in $4
      ${un.GetBetween} "<NEW>" "</NEW>" "$1\SRS_TempFile.txt" $R1  ; Get the marker that informed us if there WAS something to be copied, or if it was just installed.
      ;MessageBox MB_OK "Name:$4"
      ${un.GetBetween} "<TARGETPATH>" "</TARGETPATH>" "$1\SRS_TempFile.txt" $5  ; Get the targetpath between the file tags of the read_line_in->$2 and stick it in $5
      ;MessageBox MB_OK "Target:$5"
      clearerrors
      ${un.GetBetween} "<CALLBACK>" "</CALLBACK>" "$1\SRS_TempFile.txt" $6  ; Get the CALLBACK name between the file tags of the read_line_in->$2 and stick it in $6

       iferrors NoCallbackAvailable 0
         StrCmp $6 "" NoCallbackAvailable 0
            ; Ok, we have a callback, so we don't copy, we call file, and pass the filename.
            ;MessageBox MB_OK "Pushing $1\$4"
            push "$1\$4" ; push the file and path onto the stack.
            push $6 ; push the calback value onto the stack,
            Call un.ResolveFunction  ; call the resolveFunction Call.
          Goto SRS_RESTORE_ReadLine ; No copy, just return for next line handle.

   NoCallbackAvailable:
      ; now deal with new vs archived files...
      StrCmp $R1 "1" 0 SRS_NOTNEW_RESTOREIT ; test to see if it was new, or if it required backin gup...
        ifFileExists "$5\$4" 0 SRS_RESTORE_ReadLine  ; if it WAS new... test to see if file still exists...
          Delete "$5\$4" ; Since it was new we'll remove it on a restore....
          Goto SRS_RESTORE_ReadLine

    SRS_NOTNEW_RESTOREIT:
      CopyFiles /SILENT "$1\$4" "$5\$4"
      iferrors 0 SRS_RESTORE_ReadLine
        clearerrors
        ${un.GetBetween} "<ONFAIL>" "</ONFAIL>" "$1\SRS_TempFile.txt" $6  ; Get the onfail name between the file tags of the read_line_in->$2 and stick it in $6
        ; if we're here, then we need to rexecute the copy after executing the command line
          push "$1\$4" ; push the file and path onto the stack.
          push $6 ; push the callback value onto the stack,
          Call un.ResolveFunction  ; call the resolveFunction Call.
        clearerrors
        CopyFiles /SILENT "$1\$4" "$5\$4"
          iferrors 0 SRS_RESTORE_ReadLine
          ; if still an error, then notify and try next line.
          ; MessageBox MB_OK "Error in rolling back file: $1\$4 to $5\$4"
        Goto SRS_RESTORE_ReadLine

  ; ok, either we parsed the file, or we quit with errors... either way. clean the stack....
  SRS_DONE: ; done with readling lines from the file.
  Delete "$1\SRS_TempFile.txt"
  FileClose $SRS_Rollback_FileHandle

    ; Now parse the file name
  pop $R4
  pop $R3
  pop $R2
  pop $R1
  pop $7
  pop $6
  pop $5
  pop $4
  pop $3
  pop $2   ;restore $2
  pop $1   ;restore $1
  pop $0   ; restore $0 to previous value....
  return   ; end
FunctionEnd
