1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
5
using System.Collections.Generic;
8
using System.Text.RegularExpressions;
9
using System.Windows.Forms;
11
using Microsoft.Win32;
13
namespace ICSharpCode.Reports.Core.Globals
16
/// A utility class related to file utilities.
18
public sealed class FileUtility
20
readonly static char[] separators = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, Path.VolumeSeparatorChar };
21
const string fileNameRegEx = @"^([a-zA-Z]:)?[^:]+$";
22
// This is an arbitrary limitation built into the .NET Framework.
23
// Windows supports paths up to 32k length.
24
public const int MaxPathLength = 260;
30
public static string Combine(params string[] paths)
32
if (paths == null || paths.Length == 0) {
36
string result = paths[0];
37
for (int i = 1; i < paths.Length; i++) {
38
result = Path.Combine(result, paths[i]);
43
public static bool IsUrl(string path)
45
return path.IndexOf(':') >= 2;
49
/// Converts a given absolute path and a given base path to a path that leads
50
/// from the base path to the absoulte path. (as a relative path)
52
public static string GetRelativePath(string baseDirectoryPath, string absPath)
54
if (IsUrl(absPath) || IsUrl(baseDirectoryPath)){
58
baseDirectoryPath = NormalizePath(baseDirectoryPath);
59
absPath = NormalizePath(absPath);
61
string[] bPath = baseDirectoryPath.Split(separators);
62
string[] aPath = absPath.Split(separators);
64
for(; indx < Math.Min(bPath.Length, aPath.Length); ++indx){
65
if(!bPath[indx].Equals(aPath[indx], StringComparison.OrdinalIgnoreCase))
73
StringBuilder erg = new StringBuilder();
75
if(indx == bPath.Length) {
77
// erg.Append(Path.DirectorySeparatorChar);
79
for (int i = indx; i < bPath.Length; ++i) {
81
erg.Append(Path.DirectorySeparatorChar);
84
erg.Append(String.Join(Path.DirectorySeparatorChar.ToString(), aPath, indx, aPath.Length-indx));
85
return erg.ToString();
89
/// Converts a given relative path and a given base path to a path that leads
90
/// to the relative path absoulte.
92
public static string GetAbsolutePath(string baseDirectoryPath, string relPath)
94
return NormalizePath(Path.Combine(baseDirectoryPath, relPath));
98
/// Gets the normalized version of fileName.
99
/// Slashes are replaced with backslashes, backreferences "." and ".." are 'evaluated'.
101
public static string NormalizePath(string fileName)
103
if (string.IsNullOrEmpty(fileName)) return fileName;
108
for (i = 0; i < fileName.Length; i++) {
109
if (fileName[i] == '/' || fileName[i] == '\\')
111
if (fileName[i] == ':') {
118
char outputSeparator = isWeb ? '/' : '\\';
120
StringBuilder result = new StringBuilder();
121
if (isWeb == false && fileName.StartsWith(@"\\") || fileName.StartsWith("//")) {
123
result.Append(outputSeparator);
127
int segmentStartPos = i;
128
for (; i <= fileName.Length; i++) {
129
if (i == fileName.Length || fileName[i] == '/' || fileName[i] == '\\') {
130
int segmentLength = i - segmentStartPos;
131
switch (segmentLength) {
133
// ignore empty segment (if not in web mode)
135
result.Append(outputSeparator);
139
// ignore /./ segment, but append other one-letter segments
140
if (fileName[segmentStartPos] != '.') {
141
if (result.Length > 0) result.Append(outputSeparator);
142
result.Append(fileName[segmentStartPos]);
146
if (fileName[segmentStartPos] == '.' && fileName[segmentStartPos + 1] == '.') {
147
// remove previous segment
149
for (j = result.Length - 1; j >= 0 && result[j] != outputSeparator; j--);
155
// append normal segment
159
if (result.Length > 0) result.Append(outputSeparator);
160
result.Append(fileName, segmentStartPos, segmentLength);
163
segmentStartPos = i + 1; // remember start position for next segment
166
if (isWeb == false) {
167
if (result.Length > 0 && result[result.Length - 1] == outputSeparator) {
170
if (result.Length == 2 && result[1] == ':') {
171
result.Append(outputSeparator);
174
return result.ToString();
177
public static bool IsEqualFileName(string fileName1, string fileName2)
179
return string.Equals(NormalizePath(fileName1),
180
NormalizePath(fileName2),
181
StringComparison.OrdinalIgnoreCase);
184
public static bool IsBaseDirectory(string baseDirectory, string testDirectory)
187
baseDirectory = NormalizePath(baseDirectory).ToUpperInvariant();
188
testDirectory = NormalizePath(testDirectory).ToUpperInvariant();
189
baseDirectory = baseDirectory.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
190
testDirectory = testDirectory.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
192
if (baseDirectory[baseDirectory.Length - 1] != Path.DirectorySeparatorChar)
193
baseDirectory += Path.DirectorySeparatorChar;
194
if (testDirectory[testDirectory.Length - 1] != Path.DirectorySeparatorChar)
195
testDirectory += Path.DirectorySeparatorChar;
197
return testDirectory.StartsWith(baseDirectory);
198
} catch (Exception) {
203
public static string RenameBaseDirectory(string fileName, string oldDirectory, string newDirectory)
205
fileName = NormalizePath(fileName);
206
oldDirectory = NormalizePath(oldDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
207
newDirectory = NormalizePath(newDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
208
if (IsBaseDirectory(oldDirectory, fileName)) {
209
if (fileName.Length == oldDirectory.Length) {
212
return Path.Combine(newDirectory, fileName.Substring(oldDirectory.Length + 1));
219
/// This method checks the file fileName if it is valid.
221
public static bool IsValidFileName(string fileName)
223
// Fixme: 260 is the hardcoded maximal length for a path on my Windows XP system
224
// I can't find a .NET property or method for determining this variable.
226
if (fileName == null || fileName.Length == 0 || fileName.Length >= MaxPathLength) {
230
// platform independend : check for invalid path chars
232
if (fileName.IndexOfAny(Path.GetInvalidPathChars()) >= 0) {
235
if (fileName.IndexOf('?') >= 0 || fileName.IndexOf('*') >= 0) {
239
if (!Regex.IsMatch(fileName, fileNameRegEx)) {
243
// platform dependend : Check for invalid file names (DOS)
244
// this routine checks for follwing bad file names :
245
// CON, PRN, AUX, NUL, COM1-9 and LPT1-9
247
string nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
248
if (nameWithoutExtension != null) {
249
nameWithoutExtension = nameWithoutExtension.ToUpperInvariant();
252
if (nameWithoutExtension == "CON" ||
253
nameWithoutExtension == "PRN" ||
254
nameWithoutExtension == "AUX" ||
255
nameWithoutExtension == "NUL") {
259
char ch = nameWithoutExtension.Length == 4 ? nameWithoutExtension[3] : '\0';
261
return !((nameWithoutExtension.StartsWith("COM") ||
262
nameWithoutExtension.StartsWith("LPT")) &&
267
/// Checks that a single directory name (not the full path) is valid.
269
public static bool IsValidDirectoryName(string name)
271
if (String.IsNullOrEmpty(name)) {
272
throw new ArgumentNullException("name");
274
if (!IsValidFileName(name)) {
277
if (name.IndexOfAny(new char[]{Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar}) >= 0) {
280
if (name.Trim(' ').Length == 0) {
286
public static bool IsDirectory(string filename)
288
if (String.IsNullOrEmpty(filename)) {
289
throw new ArgumentNullException("filename");
292
if (!Directory.Exists(filename)) {
295
FileAttributes attr = File.GetAttributes(filename);
296
return (attr & FileAttributes.Directory) != 0;
299
//TODO This code is Windows specific
300
static bool MatchN (string src, int srcidx, string pattern, int patidx)
302
int patlen = pattern.Length;
303
int srclen = src.Length;
307
if (patidx == patlen)
308
return (srcidx == srclen);
309
next_char = pattern[patidx++];
310
if (next_char == '?') {
311
if (srcidx == src.Length)
315
else if (next_char != '*') {
316
if ((srcidx == src.Length) || (src[srcidx] != next_char))
321
if (patidx == pattern.Length)
323
while (srcidx < srclen) {
324
if (MatchN(src, srcidx, pattern, patidx))
333
static bool Match(string src, string pattern)
335
if (pattern[0] == '*') {
336
// common case optimization
337
int i = pattern.Length;
340
if (pattern[i] == '*')
341
return MatchN(src, 0, pattern, 0);
344
if ((pattern[i] != src[j]) && (pattern[i] != '?'))
349
return MatchN(src, 0, pattern, 0);
352
public static bool MatchesPattern(string filename, string pattern)
354
filename = filename.ToUpper(System.Globalization.CultureInfo.InstalledUICulture);
355
pattern = pattern.ToUpper();
356
string[] patterns = pattern.Split(';');
357
foreach (string p in patterns) {
358
if (Match(filename, p)) {