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

# User Rev Content
1 william 722 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     }