; This is the advanced config install script. It requires ConfigInstaller ; version 0.0.4 ; It can be included in ConfigInstaller.nsi by adding the line ; ; !include "AdvancedConfigInstall.nsh" ; ; after the line ; ; !include "ConfigSettings.nsh" ; ; Use of this advanced script will almost certainly void your warranty. ; ; But on the other hand it allows you to distribute settings for only ; the components you need to, and merges them with the users existing ; settings for their other components at install time. It also ; uses absolute rather than relative paths for images, avoiding much ; pain in that area too. ; ; To use absolute paths rahter than relative paths, make sure ; that your config file uses absolute paths starting with the path ; specified in $COPY_CONFIG_FROM. ; (i.e. the images are in exactly the same place as for normal relative ; path operation, just referred to absolutely). Absolute paths to ; other locations will not be touched, and will not work on the target ; system when installed. ; ; To use this script, you must have the FooCfgToXml toolkit installed, ; and provide the path to it in the line below: !define FOO_CFG_TO_XML_PATH "..\FooCfgToXml\bin" ; Here, provide the list of components for which you want to distribute ; settings (separated by spaces). All other settings will be left as your user has them. ; Comment out the line to distribute *all* your settings. ; Use "Core" to represent the built-in settings (no component) !define COMPONENTS_TO_INCLUDE "Core foo_ui_columns.dll" ; Edit below this line only if you know what you are doing ; -------------------------------------------------------- ;Show details, as there is much jiggery-pokery that might need to ;be looked at, should anything have gone wrong. AutoCloseWindow false !macro AdvReplaceInFile SEARCH_TEXT REPLACEMENT START_AFTER_OCCURENCES REPLACE_OCCURRENCES SOURCE_FILE Push "${SEARCH_TEXT}" #text to be replaced Push "${REPLACEMENT}" #replace with Push "${START_AFTER_OCCURENCES}" #replace all occurrences (or all) Push "${REPLACE_OCCURRENCES}" #replace all occurrences (or all) Push "${SOURCE_FILE}" #file to replace in Call AdvReplaceInFile !macroend !macro MultiDetailPrint TEXT Push "${TEXT}" Call MultiDetailPrint !macroend ;Turn off standard config handling !undef INCLUDES_CONFIG ;These are the tools that need to be shipped ReserveFile "${FOO_CFG_TO_XML_PATH}\FooCfgToXml.exe" ReserveFile "${FOO_CFG_TO_XML_PATH}\MergeCfgXml.exe" ReserveFile "${FOO_CFG_TO_XML_PATH}\*.dll" ;Produce the XML file !system '"${FOO_CFG_TO_XML_PATH}\FooCfgToXml.exe" "${COPY_CONFIG_FROM}\foobar2000.cfg"' ;Filter to settings required !ifdef COMPONENTS_TO_INCLUDE !system '"${FOO_CFG_TO_XML_PATH}\FilterCfgXml.exe" "${COPY_CONFIG_FROM}\foobar2000.cfg.xml" ${COMPONENTS_TO_INCLUDE}' !endif ;At install time: Section "!Config File" ;Show details, as there is much jiggery-pokery that might need to ;be looked at, should anything have gone wrong. SetDetailsView show var /GLOBAL cfgPath IfFileExists "$INSTDIR\user_profiles_enabled" UserProfilesEnabled ;No user profiles StrCpy $cfgPath $INSTDIR Goto CfgPathDefined UserProfilesEnabled: ;User profiles StrCpy $cfgPath "$APPDATA\foobar2000" CfgPathDefined: ; Back up the existing config files ${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6 var /global backupExtension StrCpy $backupExtension ".$2-$1-$0 $4-$5-$6.bak" IfFileExists "$cfgPath\foobar2000.cfg" 0 +2 ;Copy rather than move, as files are merged with CopyFiles /silent "$cfgPath\foobar2000.cfg" "$cfgPath\foobar2000.cfg$backupExtension" IfFileExists "$cfgPath\*.pts" 0 +2 ;PlaylistTree configs CreateDirectory "$cfgPath\PTS$backupExtension" ;For some reason, rename doesn't work with wildcards, so copy and delete instead. CopyFiles /silent "$cfgPath\*.pts" "$cfgPath\PTS$backupExtension" Delete "$cfgPath\*.pts" IfFileExists "$cfgPath\PanelsUI\*.*" 0 +2 ;PanelsUI configs Rename "$cfgPath\PanelsUI" "$cfgPath\PanelsUI$backupExtension" ; Install the new non-cfg config files (FooCfgToXml does not support modifying them) SetOutPath $cfgPath File /nonfatal "${COPY_CONFIG_FROM}\*.pts" File /nonfatal /r "${COPY_CONFIG_FROM}\PanelsUI" ; Try to patch foobar ; Extract the FooCfgToXml tool InitPluginsDir SetOutPath "$PLUGINSDIR\FooCfgToXml" File "${FOO_CFG_TO_XML_PATH}\FooCfgToXml.exe" File "${FOO_CFG_TO_XML_PATH}\MergeCfgXml.exe" File "${FOO_CFG_TO_XML_PATH}\*.dll" DetailPrint "Patching Foobar" nsExec::ExecToStack '"$PLUGINSDIR\FooCfgToXml\FooCfgToXml.exe" "$INSTDIR\foobar2000.exe"' Pop $0 # return value/error/timeout Pop $1 # printed text, up to ${NSIS_MAX_STRLEN} !insertmacro MultiDetailPrint $1 ${StrLoc} $0 $1 "Successfully patched" ">" StrCmp $0 "" 0 FoobarPatched ${StrLoc} $0 $1 "file is already patched" ">" StrCmp $0 "" CouldNotPatchFoobar FoobarPatched: ;Foobar has been patched, so carry on with advanced installation SetOutPath $cfgPath\${CONFIG_SUBFOLDER} File "${COPY_CONFIG_FROM}\foobar2000.cfg.xml" ;Replace Absolute Paths DetailPrint "Replacing '${COPY_CONFIG_FROM}' with '$INSTDIR'..." !insertmacro AdvReplaceInFile "${COPY_CONFIG_FROM}" "$INSTDIR" all all "$cfgPath\${CONFIG_SUBFOLDER}\foobar2000.cfg.xml" DetailPrint "...Done" ;First, extract their settings IfFileExists "$cfgPath\foobar2000.cfg" 0 SkipMerge ;Skip the merge if they have no settings nsExec::ExecToLog '"$PLUGINSDIR\FooCfgToXml\FooCfgToXml.exe" "$cfgPath\foobar2000.cfg"' ;Merge new settings with theirs nsExec::ExecToLog '"$PLUGINSDIR\FooCfgToXml\MergeCfgXml.exe" "$cfgPath\foobar2000.cfg.xml" "$cfgPath\${CONFIG_SUBFOLDER}\foobar2000.cfg.xml"' Goto DoneMerge SkipMerge: DetailPrint "No existing settings found to merge with" ;Couldn't merge, so just use the new settings CopyFiles "$cfgPath\${CONFIG_SUBFOLDER}\foobar2000.cfg.xml" "$cfgPath\foobar2000.cfg.xml" DoneMerge: ;Convert settings back to cfg format nsExec::ExecToLog '"$PLUGINSDIR\FooCfgToXml\FooCfgToXml.exe" "$cfgPath\foobar2000.cfg.xml"' Goto End CouldNotPatchFoobar: DetailPrint "Could not patch foobar, not a supported version:" DetailPrint "Using fallback config installation" ; Install the config file directly File "/oname=$cfgPath\foobar2000.cfg" "${COPY_CONFIG_FROM}\foobar2000.cfg" End: SectionEnd ; This function found at http://nsis.sourceforge.net/More_advanced_replace_text_in_file ; and copied in its entirety Function AdvReplaceInFile Exch $0 ;file to replace in Exch Exch $1 ;number to replace after Exch Exch 2 Exch $2 ;replace and onwards Exch 2 Exch 3 Exch $3 ;replace with Exch 3 Exch 4 Exch $4 ;to replace Exch 4 Push $5 ;minus count Push $6 ;universal Push $7 ;end string Push $8 ;left string Push $9 ;right string Push $R0 ;file1 Push $R1 ;file2 Push $R2 ;read Push $R3 ;universal Push $R4 ;count (onwards) Push $R5 ;count (after) Push $R6 ;temp file name GetTempFileName $R6 FileOpen $R1 $0 r ;file to search in FileOpen $R0 $R6 w ;temp file StrLen $R3 $4 StrCpy $R4 -1 StrCpy $R5 -1 loop_read: ClearErrors FileRead $R1 $R2 ;read line IfErrors exit StrCpy $5 0 StrCpy $7 $R2 loop_filter: IntOp $5 $5 - 1 StrCpy $6 $7 $R3 $5 ;search StrCmp $6 "" file_write2 StrCmp $6 $4 0 loop_filter StrCpy $8 $7 $5 ;left part IntOp $6 $5 + $R3 IntCmp $6 0 is0 not0 is0: StrCpy $9 "" Goto done not0: StrCpy $9 $7 "" $6 ;right part done: StrCpy $7 $8$3$9 ;re-join IntOp $R4 $R4 + 1 StrCmp $2 all file_write1 StrCmp $R4 $2 0 file_write2 IntOp $R4 $R4 - 1 IntOp $R5 $R5 + 1 StrCmp $1 all file_write1 StrCmp $R5 $1 0 file_write1 IntOp $R5 $R5 - 1 Goto file_write2 file_write1: FileWrite $R0 $7 ;write modified line Goto loop_read file_write2: FileWrite $R0 $R2 ;write unmodified line Goto loop_read exit: FileClose $R0 FileClose $R1 SetDetailsPrint none Delete $0 Rename $R6 $0 Delete $R6 SetDetailsPrint both Pop $R6 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Pop $R1 Pop $R0 Pop $9 Pop $8 Pop $7 Pop $6 Pop $5 Pop $0 Pop $1 Pop $2 Pop $3 Pop $4 FunctionEnd ; This function found at http://forums.winamp.com/showthread.php?postid=2035797#post2035797 ; and copied in its entirety ; Function: MultiDetailPrint ; Written by: M. Mims ; Date: 9.29.2006 ; Description: Parses strings with return, newline, and tab characters to print ; correctly to the details screen. Function MultiDetailPrint Exch $R0 Push $R1 Push $R2 Push $R3 Push $R4 StrLen $R1 $R0 ; Get length of string StrCpy $R2 -1 ; Set character index loop: IntOp $R2 $R2 + 1 ; Increase character index StrCmp $R1 $R2 finish_trim ; Finish if at end of string StrCpy $R3 $R0 1 $R2 ; Get character at given index StrCmp $R3 "$\r" r_trim_needed StrCmp $R3 "$\t" t_trim_needed StrCmp $R3 "$\n" n_trim_needed loop r_trim_needed: StrCpy $R3 $R0 $R2 ; Copy left side of string IntOp $R4 $R2 + 1 ; Get index of next character StrCpy $R0 $R0 $R1 $R4 ; Copy right side of string StrCpy $R0 "$R3$R0" ; Merge string without \r IntOp $R1 $R1 - 1 ; Decrease string length IntOp $R2 $R2 - 1 ; Decrease index goto loop t_trim_needed: StrCpy $R3 $R0 $R2 ; Copy left side IntOp $R4 $R2 + 1 ; Index of next character StrCpy $R0 $R0 $R1 $R4 ; Copy right side StrCpy $R0 "$R3 $R0" ; Merge with spaces IntOp $R1 $R1 + 7 ; Increase string length IntOp $R2 $R2 + 7 ; Increase index goto loop n_trim_needed: StrCpy $R3 $R0 $R2 ; Copy left side IntOp $R4 $R2 + 1 ; Index of next character StrCpy $R0 $R0 $R1 $R4 ; Copy right side DetailPrint $R3 ; Print line IntOp $R1 $R1 - $R2 ; Adjust string length IntOp $R1 $R1 - 1 StrCpy $R2 -1 ; Adjust index goto loop finish_trim: DetailPrint $R0 ; Print final line Pop $R4 Pop $R3 Pop $R2 Pop $R1 Exch $R0 FunctionEnd