ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/RomCheater/trunk/RomCheater.UserSettingsSupport/IsolatedStoragePath.cs
Revision: 722
Committed: Tue Jun 18 19:18:05 2013 UTC (9 years, 11 months ago) by william
File size: 32330 byte(s)
Log Message:

File Contents

# Content
1 using System;
2 using System.Collections;
3 using System.IO;
4 using System.Reflection;
5 using System.Runtime.CompilerServices;
6 using System.Runtime.InteropServices;
7 using System.Runtime.Serialization.Formatters.Binary;
8 using System.Security;
9 using System.Security.Cryptography;
10 using System.Security.Policy;
11 using System.Security.Permissions;
12 using System.Text;
13 using System.Globalization;
14 using Microsoft.Win32;
15
16 namespace RomCheater.UserSettingsSupport
17 {
18 public interface IIsolatedStoragePath
19 {
20 Assembly AssemblyInfo { get; }
21 string ConfigFilePath { get; }
22 }
23 internal sealed class IsolatedStoragePath : IIsolatedStoragePath
24 {
25 const string EVIDENCE_STRONGNAME = "StrongName";
26 const string EVIDENCE_URL = "Url";
27
28
29
30 public IsolatedStoragePath() : this(false) { }
31 public IsolatedStoragePath(bool UseCallingAssembly) : this(UseCallingAssembly ? Assembly.GetCallingAssembly() : Assembly.GetExecutingAssembly()) { }
32 public IsolatedStoragePath(Assembly assembly) { CreatePath(assembly); }
33
34 #region IIsolatedStorageHash Members
35 private Assembly _AssemblyInfo;
36 public Assembly AssemblyInfo { get { return _AssemblyInfo; } private set { _AssemblyInfo = value; } }
37
38 private string _ConfigFilePath;
39 public string ConfigFilePath { get { return _ConfigFilePath; } private set { _ConfigFilePath = value; } }
40 #endregion
41
42
43 private void CreatePath(Assembly asm)
44 {
45 this.AssemblyInfo = asm;
46 this.ConfigFilePath = string.Empty;
47 //string path = string.Empty;
48 //string profile_dir = Environment.GetEnvironmentVariable("LocalAppData");
49 //string company_name = ((AssemblyCompanyAttribute)Attribute.GetCustomAttribute(this.AssemblyInfo, typeof(AssemblyCompanyAttribute), false)).Company;
50 //string app_fullname = new FileInfo(this.AssemblyInfo.Location).Name;
51 //string evidence_type = this.AssemblyInfo.GetName().GetPublicKey().Length == 0 ? EVIDENCE_URL : EVIDENCE_STRONGNAME;
52 //string evidence_hash = CompureEvidenceHashForAssembly(this.AssemblyInfo);
53 //string version = this.AssemblyInfo.GetName().Version.ToString();
54 //string config = "user.config";
55 //StringBuilder builder = new StringBuilder();
56 //builder.AppendFormat(@"{0}", profile_dir);
57 //if (company_name != string.Empty)
58 //{
59 // builder.AppendFormat(@"\{0}", company_name.Replace(" ", "_"));
60 //}
61 //builder.AppendFormat(@"\{0}", app_fullname);
62 //builder.AppendFormat(@"_{0}", evidence_type);
63 //builder.AppendFormat(@"_{0}", evidence_hash);
64 //builder.AppendFormat(@"\{0}", version);
65 //builder.AppendFormat(@"\{0}", config);
66 //path = builder.ToString();
67 //this.ConfigFilePath = path;
68
69 //var t = ClientConfigPaths.GetPaths(;
70
71
72 }
73
74
75 #region ClientConfigPaths
76 class ClientConfigPaths
77 {
78 internal const string UserConfigFilename = "user.config";
79
80 const string ClickOnceDataDirectory = "DataDirectory";
81 const string ConfigExtension = ".config";
82 const int MAX_PATH = 260;
83 const int MAX_LENGTH_TO_USE = 25;
84 const string FILE_URI_LOCAL = "file:///";
85 const string FILE_URI_UNC = "file://";
86 const string FILE_URI = "file:";
87 const string HTTP_URI = "http://";
88 const string StrongNameDesc = "StrongName";
89 const string UrlDesc = "Url";
90 const string PathDesc = "Path";
91
92 static Char[] s_Base32Char = {
93 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
94 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
95 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
96 'y', 'z', '0', '1', '2', '3', '4', '5'};
97
98 static volatile ClientConfigPaths s_current;
99 static volatile bool s_currentIncludesUserConfig;
100 static SecurityPermission s_serializationPerm;
101 static SecurityPermission s_controlEvidencePerm;
102
103 bool _hasEntryAssembly;
104 bool _includesUserConfig;
105 string _applicationUri;
106 string _applicationConfigUri;
107 string _roamingConfigDirectory;
108 string _roamingConfigFilename;
109 string _localConfigDirectory;
110 string _localConfigFilename;
111 string _companyName;
112 string _productName;
113 string _productVersion;
114
115
116 [FileIOPermission(SecurityAction.Assert, AllFiles = FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read)]
117 [SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
118 public ClientConfigPaths(string exePath, bool includeUserConfig)
119 {
120
121 _includesUserConfig = includeUserConfig;
122
123 Assembly exeAssembly = null;
124 string applicationUri = null;
125 string applicationFilename = null;
126
127 // get the assembly and applicationUri for the file
128 if (exePath == null)
129 {
130 // First check if a configuration file has been set for this app domain. If so, we will use that.
131 // The CLR would already have normalized this, so no further processing necessary.
132 AppDomain domain = AppDomain.CurrentDomain;
133 AppDomainSetup setup = domain.SetupInformation;
134 _applicationConfigUri = setup.ConfigurationFile;
135
136 // Now figure out the application path.
137 exeAssembly = Assembly.GetEntryAssembly();
138 if (exeAssembly != null)
139 {
140 _hasEntryAssembly = true;
141 applicationUri = exeAssembly.CodeBase;
142
143 bool isFile = false;
144
145 // If it is a local file URI, convert it to its filename, without invoking Uri class.
146 // example: "file:///C:/WINNT/Microsoft.NET/Framework/v2.0.x86fre/csc.exe"
147 if (StringUtil.StartsWithIgnoreCase(applicationUri, FILE_URI_LOCAL))
148 {
149 isFile = true;
150 applicationUri = applicationUri.Substring(FILE_URI_LOCAL.Length);
151 }
152 // If it is a UNC file URI, convert it to its filename, without invoking Uri class.
153 // example: "file://server/share/csc.exe"
154 else if (StringUtil.StartsWithIgnoreCase(applicationUri, FILE_URI_UNC))
155 {
156 isFile = true;
157 applicationUri = applicationUri.Substring(FILE_URI.Length);
158 }
159
160 if (isFile)
161 {
162 applicationUri = applicationUri.Replace('/', '\\');
163 applicationFilename = applicationUri;
164 }
165 else
166 {
167 applicationUri = exeAssembly.EscapedCodeBase;
168 }
169 }
170 else
171 {
172 StringBuilder sb = new StringBuilder(MAX_PATH);
173 UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, IntPtr.Zero), sb, sb.Capacity);
174 applicationUri = Path.GetFullPath(sb.ToString());
175 applicationFilename = applicationUri;
176 }
177 }
178 else
179 {
180 applicationUri = Path.GetFullPath(exePath);
181 if (!FileUtil.FileExists(applicationUri, false))
182 throw ExceptionUtil.ParameterInvalid("exePath");
183
184 applicationFilename = applicationUri;
185 }
186
187 // Fallback if we haven't set the app config file path yet.
188 if (_applicationConfigUri == null)
189 {
190 _applicationConfigUri = applicationUri + ConfigExtension;
191 }
192
193 // Set application path
194 _applicationUri = applicationUri;
195
196 // In the case when exePath was explicitly supplied, we will not be able to
197 // construct user.config paths, so quit here.
198 if (exePath != null)
199 {
200 return;
201 }
202
203 // Skip expensive initialization of user config file information if requested.
204 if (!_includesUserConfig)
205 {
206 return;
207 }
208
209 bool isHttp = StringUtil.StartsWithIgnoreCase(_applicationConfigUri, HTTP_URI);
210
211 SetNamesAndVersion(applicationFilename, exeAssembly, isHttp);
212
213 // Check if this is a clickonce deployed application. If so, point the user config
214 // files to the clickonce data directory.
215 if (this.IsClickOnceDeployed(AppDomain.CurrentDomain))
216 {
217 string dataPath = AppDomain.CurrentDomain.GetData(ClickOnceDataDirectory) as string;
218 string versionSuffix = Validate(_productVersion, false);
219
220 // NOTE: No roaming config for clickonce - not supported.
221 if (Path.IsPathRooted(dataPath))
222 {
223 _localConfigDirectory = CombineIfValid(dataPath, versionSuffix);
224 _localConfigFilename = CombineIfValid(_localConfigDirectory, UserConfigFilename);
225 }
226
227 }
228 else if (!isHttp)
229 {
230 // If we get the config from http, we do not have a roaming or local config directory,
231 // as it cannot be edited by the app in those cases because it does not have Full Trust.
232
233 // suffix for user config paths
234
235 string part1 = Validate(_companyName, true);
236
237 string validAppDomainName = Validate(AppDomain.CurrentDomain.FriendlyName, true);
238 string applicationUriLower = !String.IsNullOrEmpty(_applicationUri) ? _applicationUri.ToLower(CultureInfo.InvariantCulture) : null;
239 string namePrefix = !String.IsNullOrEmpty(validAppDomainName) ? validAppDomainName : Validate(_productName, true);
240 string hashSuffix = GetTypeAndHashSuffix(AppDomain.CurrentDomain, applicationUriLower);
241
242 string part2 = (!String.IsNullOrEmpty(namePrefix) && !String.IsNullOrEmpty(hashSuffix)) ? namePrefix + hashSuffix : null;
243
244 string part3 = Validate(_productVersion, false);
245
246 string dirSuffix = CombineIfValid(CombineIfValid(part1, part2), part3);
247
248 string roamingFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
249 if (Path.IsPathRooted(roamingFolderPath))
250 {
251 _roamingConfigDirectory = CombineIfValid(roamingFolderPath, dirSuffix);
252 _roamingConfigFilename = CombineIfValid(_roamingConfigDirectory, UserConfigFilename);
253 }
254
255 string localFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
256 if (Path.IsPathRooted(localFolderPath))
257 {
258 _localConfigDirectory = CombineIfValid(localFolderPath, dirSuffix);
259 _localConfigFilename = CombineIfValid(_localConfigDirectory, UserConfigFilename);
260 }
261 }
262 }
263
264 internal static ClientConfigPaths GetPaths(string exePath, bool includeUserConfig)
265 {
266 ClientConfigPaths result = null;
267
268 if (exePath == null)
269 {
270 if (s_current == null || (includeUserConfig && !s_currentIncludesUserConfig))
271 {
272 s_current = new ClientConfigPaths(null, includeUserConfig);
273 s_currentIncludesUserConfig = includeUserConfig;
274 }
275
276 result = s_current;
277 }
278 else
279 {
280 result = new ClientConfigPaths(exePath, includeUserConfig);
281 }
282
283 return result;
284 }
285
286 internal static void RefreshCurrent()
287 {
288 s_currentIncludesUserConfig = false;
289 s_current = null;
290 }
291
292 internal static ClientConfigPaths Current
293 {
294 get
295 {
296 return GetPaths(null, true);
297 }
298 }
299
300 internal bool HasEntryAssembly
301 {
302 get
303 {
304 return _hasEntryAssembly;
305 }
306 }
307
308 internal string ApplicationUri
309 {
310 get
311 {
312 return _applicationUri;
313 }
314 }
315
316 internal string ApplicationConfigUri
317 {
318 get
319 {
320 return _applicationConfigUri;
321 }
322 }
323
324 internal string RoamingConfigFilename
325 {
326 get
327 {
328 return _roamingConfigFilename;
329 }
330 }
331
332 internal string RoamingConfigDirectory
333 {
334 get
335 {
336 return _roamingConfigDirectory;
337 }
338 }
339
340 internal bool HasRoamingConfig
341 {
342 get
343 {
344 // Assume we have roaming config if we haven't loaded user config file information.
345 return RoamingConfigFilename != null || !_includesUserConfig;
346 }
347 }
348
349 internal string LocalConfigFilename
350 {
351 get
352 {
353 return _localConfigFilename;
354 }
355 }
356
357 internal string LocalConfigDirectory
358 {
359 get
360 {
361 return _localConfigDirectory;
362 }
363 }
364
365 internal bool HasLocalConfig
366 {
367 get
368 {
369 // Assume we have roaming config if we haven't loaded user config file information.
370 return LocalConfigFilename != null || !_includesUserConfig;
371 }
372 }
373
374 internal string ProductName
375 {
376 get
377 {
378 return _productName;
379 }
380 }
381
382 internal string ProductVersion
383 {
384 get
385 {
386 return _productVersion;
387 }
388 }
389
390 private static SecurityPermission ControlEvidencePermission
391 {
392 get
393 {
394 if (s_controlEvidencePerm == null)
395 {
396 s_controlEvidencePerm = new SecurityPermission(SecurityPermissionFlag.ControlEvidence);
397 }
398 return s_controlEvidencePerm;
399 }
400 }
401
402 private static SecurityPermission SerializationFormatterPermission
403 {
404 get
405 {
406 if (s_serializationPerm == null)
407 {
408 s_serializationPerm = new SecurityPermission(SecurityPermissionFlag.SerializationFormatter);
409 }
410 return s_serializationPerm;
411 }
412 }
413
414 // Combines path2 with path1 if possible, else returns null.
415 private string CombineIfValid(string path1, string path2)
416 {
417 string returnPath = null;
418
419 if (path1 != null && path2 != null)
420 {
421 try
422 {
423 string combinedPath = Path.Combine(path1, path2);
424 if (combinedPath.Length < MAX_PATH)
425 {
426 returnPath = combinedPath;
427 }
428 }
429 catch
430 {
431 }
432 }
433
434 return returnPath;
435 }
436
437 // Returns a type and hash suffix based on app domain evidence. The evidence we use, in
438 // priority order, is Strong Name, Url and Exe Path. If one of these is found, we compute a
439 // SHA1 hash of it and return a suffix based on that. If none is found, we return null.
440 private string GetTypeAndHashSuffix(AppDomain appDomain, string exePath)
441 {
442 string suffix = null;
443 string typeName = null;
444 object evidenceObj = null;
445
446 evidenceObj = GetEvidenceInfo(appDomain, exePath, out typeName);
447
448 if (evidenceObj != null && !String.IsNullOrEmpty(typeName))
449 {
450 MemoryStream ms = new MemoryStream();
451 BinaryFormatter bSer = new BinaryFormatter();
452 SerializationFormatterPermission.Assert();
453 bSer.Serialize(ms, evidenceObj);
454 ms.Position = 0;
455 string evidenceHash = GetHash(ms);
456
457 if (!String.IsNullOrEmpty(evidenceHash))
458 {
459 suffix = "_" + typeName + "_" + evidenceHash;
460 }
461 }
462
463 return suffix;
464 }
465
466 // Mostly borrowed from IsolatedStorage, with some modifications
467 private static object GetEvidenceInfo(AppDomain appDomain, string exePath, out string typeName)
468 {
469 ControlEvidencePermission.Assert();
470 Evidence evidence = appDomain.Evidence;
471 StrongName sn = null;
472 Url url = null;
473
474 if (evidence != null)
475 {
476 IEnumerator e = evidence.GetHostEnumerator();
477 object temp = null;
478
479 while (e.MoveNext())
480 {
481 temp = e.Current;
482
483 if (temp is StrongName)
484 {
485 sn = (StrongName)temp;
486 break;
487 }
488 else if (temp is Url)
489 {
490 url = (Url)temp;
491 }
492 }
493 }
494
495 object o = null;
496
497 // The order of preference is StrongName, Url, ExePath.
498 if (sn != null)
499 {
500 o = MakeVersionIndependent(sn);
501 typeName = StrongNameDesc;
502 }
503 else if (url != null)
504 {
505 // Extract the url string and normalize it to use as evidence
506 o = url.Value.ToUpperInvariant();
507 typeName = UrlDesc;
508 }
509 else if (exePath != null)
510 {
511 o = exePath;
512 typeName = PathDesc;
513 }
514 else
515 {
516 typeName = null;
517 }
518
519 return o;
520 }
521
522 private static String GetHash(Stream s)
523 {
524 byte[] hash;
525
526 using (SHA1 sha1 = new SHA1CryptoServiceProvider())
527 {
528 hash = sha1.ComputeHash(s);
529 }
530
531 return ToBase32StringSuitableForDirName(hash);
532 }
533
534 private bool IsClickOnceDeployed(AppDomain appDomain)
535 {
536 // NOTE: For perf & servicing reasons, we don't want to introduce a dependency on
537 // System.Deployment.dll here. The following code is an alternative to calling
538 // ApplicationDeployment.IsNetworkDeployed.
539
540 ActivationContext actCtx = appDomain.ActivationContext;
541
542 // Ensures the app is running with a context from the store.
543 if (actCtx != null && actCtx.Form == ActivationContext.ContextForm.StoreBounded)
544 {
545 string fullAppId = actCtx.Identity.FullName;
546 if (!String.IsNullOrEmpty(fullAppId))
547 {
548 return true;
549 }
550 }
551
552 return false;
553 }
554
555 private static StrongName MakeVersionIndependent(StrongName sn)
556 {
557 return new StrongName(sn.PublicKey, sn.Name, new Version(0, 0, 0, 0));
558 }
559
560 private void SetNamesAndVersion(string applicationFilename, Assembly exeAssembly, bool isHttp)
561 {
562 Type mainType = null;
563
564 //
565 // Get CompanyName, ProductName, and ProductVersion
566 // First try custom attributes on the assembly.
567 //
568 if (exeAssembly != null)
569 {
570 object[] attrs = exeAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
571 if (attrs != null && attrs.Length > 0)
572 {
573 _companyName = ((AssemblyCompanyAttribute)attrs[0]).Company;
574 if (_companyName != null)
575 {
576 _companyName = _companyName.Trim();
577 }
578 }
579
580 attrs = exeAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);
581 if (attrs != null && attrs.Length > 0)
582 {
583 _productName = ((AssemblyProductAttribute)attrs[0]).Product;
584 if (_productName != null)
585 {
586 _productName = _productName.Trim();
587 }
588 }
589
590 _productVersion = exeAssembly.GetName().Version.ToString();
591 if (_productVersion != null)
592 {
593 _productVersion = _productVersion.Trim();
594 }
595 }
596
597 //
598 // If we couldn't get custom attributes, try the Win32 file version
599 //
600 if (!isHttp && (String.IsNullOrEmpty(_companyName) || String.IsNullOrEmpty(_productName) || String.IsNullOrEmpty(_productVersion)))
601 {
602 string versionInfoFileName = null;
603
604 if (exeAssembly != null)
605 {
606 MethodInfo entryPoint = exeAssembly.EntryPoint;
607 if (entryPoint != null)
608 {
609 mainType = entryPoint.ReflectedType;
610 if (mainType != null)
611 {
612 versionInfoFileName = mainType.Module.FullyQualifiedName;
613 }
614 }
615 }
616
617 if (versionInfoFileName == null)
618 {
619 versionInfoFileName = applicationFilename;
620 }
621
622 if (versionInfoFileName != null)
623 {
624 System.Diagnostics.FileVersionInfo version = System.Diagnostics.FileVersionInfo.GetVersionInfo(versionInfoFileName);
625 if (version != null)
626 {
627 if (String.IsNullOrEmpty(_companyName))
628 {
629 _companyName = version.CompanyName;
630 if (_companyName != null)
631 {
632 _companyName = _companyName.Trim();
633 }
634 }
635
636 if (String.IsNullOrEmpty(_productName))
637 {
638 _productName = version.ProductName;
639 if (_productName != null)
640 {
641 _productName = _productName.Trim();
642 }
643 }
644
645 if (String.IsNullOrEmpty(_productVersion))
646 {
647 _productVersion = version.ProductVersion;
648 if (_productVersion != null)
649 {
650 _productVersion = _productVersion.Trim();
651 }
652 }
653 }
654 }
655 }
656
657 if (String.IsNullOrEmpty(_companyName) || String.IsNullOrEmpty(_productName))
658 {
659 string ns = null;
660 if (mainType != null)
661 {
662 ns = mainType.Namespace;
663 }
664
665 // Desperate measures for product name
666 if (String.IsNullOrEmpty(_productName))
667 {
668 // Try the remainder of the namespace
669 if (ns != null)
670 {
671 int lastDot = ns.LastIndexOf(".", StringComparison.Ordinal);
672 if (lastDot != -1 && lastDot < ns.Length - 1)
673 {
674 _productName = ns.Substring(lastDot + 1);
675 }
676 else
677 {
678 _productName = ns;
679 }
680
681 _productName = _productName.Trim();
682 }
683
684 // Try the type of the entry assembly
685 if (String.IsNullOrEmpty(_productName) && mainType != null)
686 {
687 _productName = mainType.Name.Trim();
688 }
689
690 // give up, return empty string
691 if (_productName == null)
692 {
693 _productName = string.Empty;
694 }
695 }
696
697 // Desperate measures for company name
698 if (String.IsNullOrEmpty(_companyName))
699 {
700 // Try the first part of the namespace
701 if (ns != null)
702 {
703 int firstDot = ns.IndexOf(".", StringComparison.Ordinal);
704 if (firstDot != -1)
705 {
706 _companyName = ns.Substring(0, firstDot);
707 }
708 else
709 {
710 _companyName = ns;
711 }
712
713 _companyName = _companyName.Trim();
714 }
715
716 // If that doesn't work, use the product name
717 if (String.IsNullOrEmpty(_companyName))
718 {
719 _companyName = _productName;
720 }
721 }
722 }
723
724 // Desperate measures for product version - assume 1.0
725 if (String.IsNullOrEmpty(_productVersion))
726 {
727 _productVersion = "1.0.0.0";
728 }
729 }
730
731 // Borrowed from IsolatedStorage
732 private static string ToBase32StringSuitableForDirName(byte[] buff)
733 {
734 StringBuilder sb = new StringBuilder();
735 byte b0, b1, b2, b3, b4;
736 int l, i;
737
738 l = buff.Length;
739 i = 0;
740
741 // Create l chars using the last 5 bits of each byte.
742 // Consume 3 MSB bits 5 bytes at a time.
743
744 do
745 {
746 b0 = (i < l) ? buff[i++] : (byte)0;
747 b1 = (i < l) ? buff[i++] : (byte)0;
748 b2 = (i < l) ? buff[i++] : (byte)0;
749 b3 = (i < l) ? buff[i++] : (byte)0;
750 b4 = (i < l) ? buff[i++] : (byte)0;
751
752 // Consume the 5 Least significant bits of each byte
753 sb.Append(s_Base32Char[b0 & 0x1F]);
754 sb.Append(s_Base32Char[b1 & 0x1F]);
755 sb.Append(s_Base32Char[b2 & 0x1F]);
756 sb.Append(s_Base32Char[b3 & 0x1F]);
757 sb.Append(s_Base32Char[b4 & 0x1F]);
758
759 // Consume 3 MSB of b0, b1, MSB bits 6, 7 of b3, b4
760 sb.Append(s_Base32Char[(
761 ((b0 & 0xE0) >> 5) |
762 ((b3 & 0x60) >> 2))]);
763
764 sb.Append(s_Base32Char[(
765 ((b1 & 0xE0) >> 5) |
766 ((b4 & 0x60) >> 2))]);
767
768 // Consume 3 MSB bits of b2, 1 MSB bit of b3, b4
769
770 b2 >>= 5;
771
772 if ((b3 & 0x80) != 0)
773 b2 |= 0x08;
774 if ((b4 & 0x80) != 0)
775 b2 |= 0x10;
776
777 sb.Append(s_Base32Char[b2]);
778
779 } while (i < l);
780
781 return sb.ToString();
782 }
783
784 // Makes the passed in string suitable to use as a path name by replacing illegal characters
785 // with underscores. Additionally, we do two things - replace spaces too with underscores and
786 // limit the resultant string's length to MAX_LENGTH_TO_USE if limitSize is true.
787 private string Validate(string str, bool limitSize)
788 {
789 string validated = str;
790
791 if (!String.IsNullOrEmpty(validated))
792 {
793 // First replace all illegal characters with underscores
794 foreach (char c in Path.GetInvalidFileNameChars())
795 {
796 validated = validated.Replace(c, '_');
797 }
798
799 // Replace all spaces with underscores
800 validated = validated.Replace(' ', '_');
801
802 if (limitSize)
803 {
804 validated = (validated.Length > MAX_LENGTH_TO_USE) ? validated.Substring(0, MAX_LENGTH_TO_USE) : validated;
805 }
806 }
807
808 return validated;
809 }
810 }
811 #endregion
812 }
813 }