Repair path names with ..: Difference between revisions
From NSIS Wiki
Jump to navigationJump to search
(better solution) |
No edit summary |
||
Line 1: | Line 1: | ||
you have a path with relative path parts, such as | |||
<highlight-nsis> | |||
\\ ; does nothing | |||
\.\ ; stay in same folder | |||
\..\ ; go up a folder | |||
</highlight-nsis> | |||
And you need the absolute path, then you can use the "GetFullPathName" command in NSIS to get the absolute path. For example: | |||
<highlight-nsis> | |||
Section Test | |||
GetFullPathName $0 "c:\program files\myApp\somedir\subdir\..\somefile.ext" | |||
; $0 will now contain "c:\program files\myApp\somedir\somefile.ext" | |||
SectionEnd | |||
</highlight-nsis> | |||
Please note that if you specify a filename, that file has to exist or the result is null. It is therefore recommended that if you need the absolute path without necessarily having the file in existence, that you strip the filename from the path. | |||
Please also note that this command is limited to a 256-character string, even if the resulting absolute path is shorter than 256 characters. | |||
If you have a longer string, you may try the below function. | |||
<highlight-nsis> | <highlight-nsis> | ||
Function Abs2Rel | |||
; Stack -> ; <relative path> ; This and the stuff in the column below is just to keep track of the stack before and after the function so that it's clean at the end. | |||
Exch $R0 ; R0 ; $R0 now holds the relative path | |||
Push $0 ; 0 R0 ; $0 will hold the absolute path as it is being built | |||
Push $1 ; 1 0 R0 ; $1 will hold the length of the relative path | |||
Push $2 ; 2 1 0 R0 ; $2 will hold a counter for running along the path | |||
Push $3 ; 3 2 1 0 R0 ; $3 will hold a substring of the paths to test against | |||
$ | |||
StrCpy $0 $R0 1 0 ; Start by getting the first character of the relative path into the absolute path var | |||
StrLen $1 $R0 ; Get the length of the relative path | |||
StrCpy $2 0 ; And start the counter off at zero | |||
; example path at this point | |||
; c:\Alpha\\\Bravo\\Charlie..charles\\.\delta\\echo\\..\..\foxtrot\\..\Golf\\.\Hotel\\.\india\\..\\\\juliet\\..\kilo\\\..\Li.....ma\\.\..Mike\\\November\\.\oscar\\..\Papa\\\Quebec..\\\\\\\\Romeo\\sierra\\..\tang.o\\uniform\\victor\\..\whiskey\\..\\x-ray\\yankee\\..\..\.\..\..\Zu.lu\\file.ext | |||
; double ; This section will get rid of all double backslashes. | |||
_loop_double: ; top of the loop | |||
IntOp $2 $2 + 1 ; increase the counter | |||
IntCmp $2 $1 0 0 _sameDir ; if the counter exceeds the relative path's length, move on | |||
StrCpy $3 $R0 2 $2 ; get two characters from the relative pah, starting at the position of the counter | |||
StrCmp $3 "\\" _loop_double ; if it's a double backslash, just go back to the top of the loop | |||
StrCpy $3 $R0 1 $2 ; otherwise, get a single character from the relative path, starting at the position of the counter | |||
StrCpy $0 "$0$3" ; and add that character to the absolute path being built | |||
goto _loop_double ; then go back to the top of the loop | |||
; example path at this point | |||
; c:\Alpha\Bravo\Charlie..charles\.\delta\echo\..\..\foxtrot\..\Golf\.\Hotel\.\india\..\juliet\..\kilo\..\Li.....ma\.\..Mike\November\.\oscar\..\Papa\Quebec..\Romeo\sierra\..\tang.o\uniform\victor\..\whiskey\..\x-ray\yankee\..\..\.\..\..\Zu.lu\file.ext | |||
_sameDir: ; This section will get rid of all \.\ occurrences. | |||
StrCpy $R0 $0 ; First, copy the working copy absolute path into the relative path var. We won't need the original anymore. | |||
StrCpy $0 $R0 1 0 ; Again, get the first character | |||
StrLen $1 $R0 ; Get the length | |||
StrCpy $2 0 ; Start the counter at zero | |||
_loop_sameDir: ; top of the loop | |||
IntOp $2 $2 + 1 ; increase the counter | |||
IntCmp $2 $1 0 0 _dirup ; if the counter exceeds the relative path's length, move on | |||
StrCpy $3 $R0 3 $2 ; get three characters from the relative path, starting at the position of the counter | |||
StrCmp $3 "\.\" 0 +3 ; if that's \.\ , then we'll have to... | |||
IntOp $2 $2 + 1 ; increase the counter by 1 to stop going over the period. | |||
goto _loop_sameDir ; and go back to the top of the loop | |||
StrCpy $3 $R0 1 $2 ; otherwise, get a single character from the relative path, starting at the position of the counter | |||
StrCpy $0 "$0$3" ; and add that character to the absolute path being built | |||
goto _loop_sameDir ; then go back to the top of the loop | |||
; example path at this point | |||
; c:\Alpha\Bravo\Charlie..charles\delta\echo\..\..\foxtrot\..\Golf\Hotel\india\..\juliet\..\kilo\..\Li.....ma\..Mike\November\oscar\..\Papa\Quebec..\Romeo\sierra\..\tang.o\uniform\victor\..\whiskey\..\x-ray\yankee\..\..\..\..\Zu.lu\file.ext | |||
_dirup: ; This section will deal with \..\ occurrences, removing them -and- the parent folder | |||
StrCpy $R0 $0 ; this | |||
StrCpy $0 $R0 1 0 ; should | |||
StrLen $1 $R0 ; look | |||
StrCpy $2 0 ; familar | |||
Push "Rel2Abs" ; push a tag to the top of the stack. We'll be doing some popping further down and want to make sure we don't exceed the stack/etc. | |||
_loop_dirup: ; more | |||
IntOp $2 $2 + 1 ; familiar | |||
IntCmp $2 $1 0 0 _loop_cleanStack ; things | |||
StrCpy $3 $R0 1 $2 ; get a single character from the relative path, starting at the position of the counter | |||
StrCpy $0 "$0$3" ; add that character to the absolute path being built | |||
StrCmp $3 "\" 0 _loop_dirup ; if the character was a backslash, continue - otherwise, go back to the top of the stack | |||
StrCpy $3 $0 4 -4 ; get -four- characters from the relative path, starting at the position of the counter | |||
StrCmp $3 "\..\" 0 _subDir ; if those four were \..\, continue to process this as going up a dir - otherwise we're just going down a dir | |||
Pop $0 ; Get the top of the stack into our absolute path. Say the stack looked like "c:\test\", "c:\test\hello\", and we just encountered "c:\test\hello\,,\", then this will be "c:\test\hello\" | |||
StrCmp $0 "Rel2Abs" _error ; If the value is our tag, then we just went up the stack too far, and the path this function was fed is invalid, so error out. | |||
Pop $0 ; Get the top of the stack in our absolute path. Going with the previous example, this value will now be "c:\test\", and as such as we just moved up a dir. | |||
StrCmp $0 "Rel2Abs" _error ; If the value is our tag, then we just went up the stack too far, and the path this function was fed is invalid, so error out. | |||
Push $0 ; Push this value back onto the stack because we'll need it on there. | |||
goto _loop_dirup ; And go back to the top of the loop | |||
_subDir: ; Otherwise we went down a dir | |||
Push $0 ; So we'll just push this absolute path so far onto the stacak. | |||
goto _loop_dirup ; and go back to the top of the loop | |||
; example path at this point | |||
; c:\Alpha\Bravo\Charlie..charles\Golf\Hotel\Li.....ma\..Mike\November\Papa\Quebec..\Romeo\Zu.lu\file.ext | |||
_loop_cleanStack: ; At this point we already have our relative path - but there's a bunch of bits stuck on the stack | |||
Pop $1 ; So we pop the stack | |||
StrCmp $1 "Rel2Abs" 0 _loop_cleanStack ; and as long as the value isn't our tag, we'll keep on popping | |||
StrCpy $R0 $0 ; Once it is, we're done entirely - copy the absolute path into $R0 for end-function stack purposes | |||
goto _end ; goto the end (skip over the error) | |||
_error: ; This is where we went if the path being fed was mangled or we ran into our tag early otherwise | |||
StrCpy $R0 "-1" ; we'll just set the return value to -1 | |||
_end: ; end of the function, time to restore variables off the stack and push the result onto it. | |||
; Stack -> ; 3 2 1 0 R0 | |||
Pop $3 ; 2 1 0 R0 | |||
Pop $2 ; 1 0 R0 | |||
Pop $1 ; 0 R0 | |||
Pop $0 ; R0 | |||
Exch $R0 ; <absolute path> | |||
FunctionEnd | |||
</highlight-nsis> |
Revision as of 21:01, 1 October 2006
you have a path with relative path parts, such as
\\ ; does nothing \.\ ; stay in same folder \..\ ; go up a folder
And you need the absolute path, then you can use the "GetFullPathName" command in NSIS to get the absolute path. For example:
Section Test GetFullPathName $0 "c:\program files\myApp\somedir\subdir\..\somefile.ext" ; $0 will now contain "c:\program files\myApp\somedir\somefile.ext" SectionEnd
Please note that if you specify a filename, that file has to exist or the result is null. It is therefore recommended that if you need the absolute path without necessarily having the file in existence, that you strip the filename from the path.
Please also note that this command is limited to a 256-character string, even if the resulting absolute path is shorter than 256 characters.
If you have a longer string, you may try the below function.
Function Abs2Rel ; Stack -> ; <relative path> ; This and the stuff in the column below is just to keep track of the stack before and after the function so that it's clean at the end. Exch $R0 ; R0 ; $R0 now holds the relative path Push $0 ; 0 R0 ; $0 will hold the absolute path as it is being built Push $1 ; 1 0 R0 ; $1 will hold the length of the relative path Push $2 ; 2 1 0 R0 ; $2 will hold a counter for running along the path Push $3 ; 3 2 1 0 R0 ; $3 will hold a substring of the paths to test against StrCpy $0 $R0 1 0 ; Start by getting the first character of the relative path into the absolute path var StrLen $1 $R0 ; Get the length of the relative path StrCpy $2 0 ; And start the counter off at zero ; example path at this point ; c:\Alpha\\\Bravo\\Charlie..charles\\.\delta\\echo\\..\..\foxtrot\\..\Golf\\.\Hotel\\.\india\\..\\\\juliet\\..\kilo\\\..\Li.....ma\\.\..Mike\\\November\\.\oscar\\..\Papa\\\Quebec..\\\\\\\\Romeo\\sierra\\..\tang.o\\uniform\\victor\\..\whiskey\\..\\x-ray\\yankee\\..\..\.\..\..\Zu.lu\\file.ext ; double ; This section will get rid of all double backslashes. _loop_double: ; top of the loop IntOp $2 $2 + 1 ; increase the counter IntCmp $2 $1 0 0 _sameDir ; if the counter exceeds the relative path's length, move on StrCpy $3 $R0 2 $2 ; get two characters from the relative pah, starting at the position of the counter StrCmp $3 "\\" _loop_double ; if it's a double backslash, just go back to the top of the loop StrCpy $3 $R0 1 $2 ; otherwise, get a single character from the relative path, starting at the position of the counter StrCpy $0 "$0$3" ; and add that character to the absolute path being built goto _loop_double ; then go back to the top of the loop ; example path at this point ; c:\Alpha\Bravo\Charlie..charles\.\delta\echo\..\..\foxtrot\..\Golf\.\Hotel\.\india\..\juliet\..\kilo\..\Li.....ma\.\..Mike\November\.\oscar\..\Papa\Quebec..\Romeo\sierra\..\tang.o\uniform\victor\..\whiskey\..\x-ray\yankee\..\..\.\..\..\Zu.lu\file.ext _sameDir: ; This section will get rid of all \.\ occurrences. StrCpy $R0 $0 ; First, copy the working copy absolute path into the relative path var. We won't need the original anymore. StrCpy $0 $R0 1 0 ; Again, get the first character StrLen $1 $R0 ; Get the length StrCpy $2 0 ; Start the counter at zero _loop_sameDir: ; top of the loop IntOp $2 $2 + 1 ; increase the counter IntCmp $2 $1 0 0 _dirup ; if the counter exceeds the relative path's length, move on StrCpy $3 $R0 3 $2 ; get three characters from the relative path, starting at the position of the counter StrCmp $3 "\.\" 0 +3 ; if that's \.\ , then we'll have to... IntOp $2 $2 + 1 ; increase the counter by 1 to stop going over the period. goto _loop_sameDir ; and go back to the top of the loop StrCpy $3 $R0 1 $2 ; otherwise, get a single character from the relative path, starting at the position of the counter StrCpy $0 "$0$3" ; and add that character to the absolute path being built goto _loop_sameDir ; then go back to the top of the loop ; example path at this point ; c:\Alpha\Bravo\Charlie..charles\delta\echo\..\..\foxtrot\..\Golf\Hotel\india\..\juliet\..\kilo\..\Li.....ma\..Mike\November\oscar\..\Papa\Quebec..\Romeo\sierra\..\tang.o\uniform\victor\..\whiskey\..\x-ray\yankee\..\..\..\..\Zu.lu\file.ext _dirup: ; This section will deal with \..\ occurrences, removing them -and- the parent folder StrCpy $R0 $0 ; this StrCpy $0 $R0 1 0 ; should StrLen $1 $R0 ; look StrCpy $2 0 ; familar Push "Rel2Abs" ; push a tag to the top of the stack. We'll be doing some popping further down and want to make sure we don't exceed the stack/etc. _loop_dirup: ; more IntOp $2 $2 + 1 ; familiar IntCmp $2 $1 0 0 _loop_cleanStack ; things StrCpy $3 $R0 1 $2 ; get a single character from the relative path, starting at the position of the counter StrCpy $0 "$0$3" ; add that character to the absolute path being built StrCmp $3 "\" 0 _loop_dirup ; if the character was a backslash, continue - otherwise, go back to the top of the stack StrCpy $3 $0 4 -4 ; get -four- characters from the relative path, starting at the position of the counter StrCmp $3 "\..\" 0 _subDir ; if those four were \..\, continue to process this as going up a dir - otherwise we're just going down a dir Pop $0 ; Get the top of the stack into our absolute path. Say the stack looked like "c:\test\", "c:\test\hello\", and we just encountered "c:\test\hello\,,\", then this will be "c:\test\hello\" StrCmp $0 "Rel2Abs" _error ; If the value is our tag, then we just went up the stack too far, and the path this function was fed is invalid, so error out. Pop $0 ; Get the top of the stack in our absolute path. Going with the previous example, this value will now be "c:\test\", and as such as we just moved up a dir. StrCmp $0 "Rel2Abs" _error ; If the value is our tag, then we just went up the stack too far, and the path this function was fed is invalid, so error out. Push $0 ; Push this value back onto the stack because we'll need it on there. goto _loop_dirup ; And go back to the top of the loop _subDir: ; Otherwise we went down a dir Push $0 ; So we'll just push this absolute path so far onto the stacak. goto _loop_dirup ; and go back to the top of the loop ; example path at this point ; c:\Alpha\Bravo\Charlie..charles\Golf\Hotel\Li.....ma\..Mike\November\Papa\Quebec..\Romeo\Zu.lu\file.ext _loop_cleanStack: ; At this point we already have our relative path - but there's a bunch of bits stuck on the stack Pop $1 ; So we pop the stack StrCmp $1 "Rel2Abs" 0 _loop_cleanStack ; and as long as the value isn't our tag, we'll keep on popping StrCpy $R0 $0 ; Once it is, we're done entirely - copy the absolute path into $R0 for end-function stack purposes goto _end ; goto the end (skip over the error) _error: ; This is where we went if the path being fed was mangled or we ran into our tag early otherwise StrCpy $R0 "-1" ; we'll just set the return value to -1 _end: ; end of the function, time to restore variables off the stack and push the result onto it. ; Stack -> ; 3 2 1 0 R0 Pop $3 ; 2 1 0 R0 Pop $2 ; 1 0 R0 Pop $1 ; 0 R0 Pop $0 ; R0 Exch $R0 ; <absolute path> FunctionEnd