|
@@ -0,0 +1,303 @@
|
|
|
+using System;
|
|
|
+using System.Globalization;
|
|
|
+using System.Reflection;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+
|
|
|
+namespace WinSCP
|
|
|
+{
|
|
|
+ [Guid("70253534-C5DC-4EF3-9C98-65C57D79C324")]
|
|
|
+ [ClassInterface(Constants.ClassInterface)]
|
|
|
+ [ComVisible(true)]
|
|
|
+ public sealed class RemotePath : IReflect
|
|
|
+ {
|
|
|
+ public static string EscapeFileMask(string fileMask)
|
|
|
+ {
|
|
|
+ if (fileMask == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("fileMask");
|
|
|
+ }
|
|
|
+ int lastSlash = fileMask.LastIndexOf('/');
|
|
|
+ string path = lastSlash > 0 ? fileMask.Substring(0, lastSlash + 1) : string.Empty;
|
|
|
+ string mask = lastSlash > 0 ? fileMask.Substring(lastSlash + 1) : fileMask;
|
|
|
+ // Keep in sync with EscapeFileMask in GenerateUrl.cpp
|
|
|
+ mask = mask.Replace("[", "[[]").Replace("*", "[*]").Replace("?", "[?]");
|
|
|
+ return path + mask;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string CombinePaths(string path1, string path2)
|
|
|
+ {
|
|
|
+ if (path1 == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("path1");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (path2 == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("path2");
|
|
|
+ }
|
|
|
+
|
|
|
+ string result;
|
|
|
+
|
|
|
+ if (path2.StartsWith("/", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ result = path2;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result =
|
|
|
+ path1 +
|
|
|
+ ((path1.Length == 0) || (path2.Length == 0) || path1.EndsWith("/", StringComparison.Ordinal) ? string.Empty : "/") +
|
|
|
+ path2;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string TranslateRemotePathToLocal(string remotePath, string remoteRoot, string localRoot)
|
|
|
+ {
|
|
|
+ if (remotePath == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("remotePath");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (remoteRoot == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("remoteRoot");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (localRoot == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("localRoot");
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((localRoot.Length > 0) && !localRoot.EndsWith("\\", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ localRoot += "\\";
|
|
|
+ }
|
|
|
+
|
|
|
+ // not adding to empty root paths, because the path may not even start with slash
|
|
|
+ if ((remoteRoot.Length > 0) && !remoteRoot.EndsWith("/", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ remoteRoot += "/";
|
|
|
+ }
|
|
|
+
|
|
|
+ string localPath;
|
|
|
+ // special case
|
|
|
+ if (remotePath == remoteRoot)
|
|
|
+ {
|
|
|
+ localPath = localRoot;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (!remotePath.StartsWith(remoteRoot, StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "{0} does not start with {1}", remotePath, remoteRoot));
|
|
|
+ }
|
|
|
+
|
|
|
+ string subPath = remotePath.Substring(remoteRoot.Length);
|
|
|
+ // can happen only when remoteRoot is empty
|
|
|
+ if (subPath.StartsWith("/", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ subPath = subPath.Substring(1);
|
|
|
+ }
|
|
|
+ subPath = subPath.Replace('/', '\\');
|
|
|
+ localPath = localRoot + subPath;
|
|
|
+ }
|
|
|
+ return localPath;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string TranslateLocalPathToRemote(string localPath, string localRoot, string remoteRoot)
|
|
|
+ {
|
|
|
+ if (localPath == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("localPath");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (localRoot == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("localRoot");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (remoteRoot == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("remoteRoot");
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((localRoot.Length > 0) && !localRoot.EndsWith("\\", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ localRoot += "\\";
|
|
|
+ }
|
|
|
+
|
|
|
+ // not adding to empty root paths, because the path may not even start with slash
|
|
|
+ if ((remoteRoot.Length > 0) && !remoteRoot.EndsWith("/", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ remoteRoot += "/";
|
|
|
+ }
|
|
|
+
|
|
|
+ string remotePath;
|
|
|
+ // special case
|
|
|
+ if (localPath == localRoot)
|
|
|
+ {
|
|
|
+ remotePath = remoteRoot;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (!localPath.StartsWith(localRoot, StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "{0} does not start with {1}", localPath, localRoot));
|
|
|
+ }
|
|
|
+
|
|
|
+ string subPath = localPath.Substring(localRoot.Length);
|
|
|
+ // can happen only when localRoot is empty
|
|
|
+ if (subPath.StartsWith("\\", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ subPath = subPath.Substring(1);
|
|
|
+ }
|
|
|
+ subPath = subPath.Replace('\\', '/');
|
|
|
+ remotePath = remoteRoot + subPath;
|
|
|
+ }
|
|
|
+ return remotePath;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string GetDirectoryName(string path)
|
|
|
+ {
|
|
|
+ string result;
|
|
|
+ if (path == null)
|
|
|
+ {
|
|
|
+ result = null;
|
|
|
+ }
|
|
|
+ else if (path.Length == 0)
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Path cannot be empty", "path");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int i = path.LastIndexOf('/');
|
|
|
+ if (i < 0)
|
|
|
+ {
|
|
|
+ result = null;
|
|
|
+ }
|
|
|
+ else if (i == 0)
|
|
|
+ {
|
|
|
+ if (path.Length == 1)
|
|
|
+ {
|
|
|
+ result = null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result = "/";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result = path.Substring(0, i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string AddDirectorySeparator(string path)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrEmpty(path))
|
|
|
+ {
|
|
|
+ throw new ArgumentException("Path cannot be empty", "path");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!path.EndsWith("/", StringComparison.Ordinal))
|
|
|
+ {
|
|
|
+ path += "/";
|
|
|
+ }
|
|
|
+
|
|
|
+ return path;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string GetFileName(string path)
|
|
|
+ {
|
|
|
+ string result;
|
|
|
+ if (string.IsNullOrEmpty(path))
|
|
|
+ {
|
|
|
+ result = null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int i = path.LastIndexOf('/');
|
|
|
+ if (i >= 0)
|
|
|
+ {
|
|
|
+ result = path.Substring(i + 1);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result = string.Empty;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetField(name, bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetFields(bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetMember(name, bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetMembers(bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetMethod(name, bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
|
|
|
+ {
|
|
|
+ return GetType().GetMethod(name, bindingAttr, binder, types, modifiers);
|
|
|
+ }
|
|
|
+
|
|
|
+ MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetMethods(bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetProperties(bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
|
|
|
+ {
|
|
|
+ return GetType().GetProperty(name, bindingAttr, binder, returnType, types, modifiers);
|
|
|
+ }
|
|
|
+
|
|
|
+ PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr)
|
|
|
+ {
|
|
|
+ return GetType().GetProperty(name, bindingAttr);
|
|
|
+ }
|
|
|
+
|
|
|
+ object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
|
|
|
+ {
|
|
|
+ if (target == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("target");
|
|
|
+ }
|
|
|
+
|
|
|
+ Type type = target.GetType();
|
|
|
+
|
|
|
+ // This trivial implementation allows calling static methods over COM
|
|
|
+ return type.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
|
|
|
+ }
|
|
|
+
|
|
|
+ Type IReflect.UnderlyingSystemType
|
|
|
+ {
|
|
|
+ get { return GetType(); }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|