ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/RomCheater/trunk/RomCheater.UserSettingsSupport/IsolatedStoragePath.cs
Revision: 723
Committed: Tue Jun 18 19:32:24 2013 UTC (10 years, 5 months ago) by william
File size: 33233 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 william 723 ClientConfigPaths t = new ClientConfigPaths(this.AssemblyInfo, true);
70 william 722
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 william 723 public ClientConfigPaths(Assembly assembly, bool includeUserConfig)
119 william 722 {
120    
121 william 723 //_includesUserConfig = includeUserConfig;
122 william 722
123 william 723 Assembly exeAssembly = assembly;
124     //string applicationUri = null;
125     //string applicationFilename = null;
126 william 722
127 william 723 //// 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 william 722
136 william 723 // // Now figure out the application path.
137     // exeAssembly = Assembly.GetEntryAssembly();
138     // if (exeAssembly != null)
139     // {
140     // _hasEntryAssembly = true;
141     // applicationUri = exeAssembly.CodeBase;
142 william 722
143 william 723 // bool isFile = false;
144 william 722
145 william 723 // // 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 william 722
160 william 723 // 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 william 722
184 william 723 //// applicationFilename = applicationUri;
185     ////}
186 william 722
187 william 723 //// Fallback if we haven't set the app config file path yet.
188     //if (_applicationConfigUri == null)
189     //{
190     // _applicationConfigUri = applicationUri + ConfigExtension;
191     //}
192 william 722
193 william 723 //// Set application path
194     //_applicationUri = applicationUri;
195 william 722
196 william 723 //// 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 william 722
203 william 723 //// Skip expensive initialization of user config file information if requested.
204     //if (!_includesUserConfig)
205     //{
206     // return;
207     //}
208 william 722
209 william 723 ////bool isHttp = StringUtil.StartsWithIgnoreCase(_applicationConfigUri, HTTP_URI);
210 william 722
211 william 723 //SetNamesAndVersion(applicationFilename, exeAssembly, false);
212     SetNamesAndVersion(exeAssembly, false);
213 william 722
214 william 723 //// Check if this is a clickonce deployed application. If so, point the user config
215     //// files to the clickonce data directory.
216     //if (this.IsClickOnceDeployed(AppDomain.CurrentDomain))
217     //{
218     // string dataPath = AppDomain.CurrentDomain.GetData(ClickOnceDataDirectory) as string;
219     // string versionSuffix = Validate(_productVersion, false);
220 william 722
221 william 723 // // NOTE: No roaming config for clickonce - not supported.
222     // if (Path.IsPathRooted(dataPath))
223     // {
224     // _localConfigDirectory = CombineIfValid(dataPath, versionSuffix);
225     // _localConfigFilename = CombineIfValid(_localConfigDirectory, UserConfigFilename);
226     // }
227 william 722
228 william 723 //}
229     //else if (!isHttp)
230     //{
231 william 722 // If we get the config from http, we do not have a roaming or local config directory,
232     // as it cannot be edited by the app in those cases because it does not have Full Trust.
233    
234     // suffix for user config paths
235    
236     string part1 = Validate(_companyName, true);
237    
238 william 723 //string validAppDomainName = Validate(AppDomain.CurrentDomain.FriendlyName, true);
239     string friendlyName = new FileInfo(exeAssembly.Location).Name;
240     string validAppDomainName = Validate(friendlyName, true);
241 william 722 string applicationUriLower = !String.IsNullOrEmpty(_applicationUri) ? _applicationUri.ToLower(CultureInfo.InvariantCulture) : null;
242     string namePrefix = !String.IsNullOrEmpty(validAppDomainName) ? validAppDomainName : Validate(_productName, true);
243 william 723 //string hashSuffix = GetTypeAndHashSuffix(AppDomain.CurrentDomain, applicationUriLower);
244     string hashSuffix = GetTypeAndHashSuffix(exeAssembly, applicationUriLower);
245 william 722
246     string part2 = (!String.IsNullOrEmpty(namePrefix) && !String.IsNullOrEmpty(hashSuffix)) ? namePrefix + hashSuffix : null;
247    
248     string part3 = Validate(_productVersion, false);
249    
250     string dirSuffix = CombineIfValid(CombineIfValid(part1, part2), part3);
251    
252     string roamingFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
253     if (Path.IsPathRooted(roamingFolderPath))
254     {
255     _roamingConfigDirectory = CombineIfValid(roamingFolderPath, dirSuffix);
256     _roamingConfigFilename = CombineIfValid(_roamingConfigDirectory, UserConfigFilename);
257     }
258    
259     string localFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
260     if (Path.IsPathRooted(localFolderPath))
261     {
262     _localConfigDirectory = CombineIfValid(localFolderPath, dirSuffix);
263     _localConfigFilename = CombineIfValid(_localConfigDirectory, UserConfigFilename);
264     }
265 william 723 //}
266 william 722 }
267    
268 william 723 //internal static ClientConfigPaths GetPaths(string exePath, bool includeUserConfig)
269     //{
270     // ClientConfigPaths result = null;
271 william 722
272 william 723 // if (exePath == null)
273     // {
274     // if (s_current == null || (includeUserConfig && !s_currentIncludesUserConfig))
275     // {
276     // s_current = new ClientConfigPaths(null, includeUserConfig);
277     // s_currentIncludesUserConfig = includeUserConfig;
278     // }
279 william 722
280 william 723 // result = s_current;
281     // }
282     // else
283     // {
284     // result = new ClientConfigPaths(exePath, includeUserConfig);
285     // }
286 william 722
287 william 723 // return result;
288     //}
289 william 722
290     internal static void RefreshCurrent()
291     {
292     s_currentIncludesUserConfig = false;
293     s_current = null;
294     }
295    
296 william 723 //internal static ClientConfigPaths Current
297     //{
298     // get
299     // {
300     // return GetPaths(null, true);
301     // }
302     //}
303 william 722
304     internal bool HasEntryAssembly
305     {
306     get
307     {
308     return _hasEntryAssembly;
309     }
310     }
311    
312     internal string ApplicationUri
313     {
314     get
315     {
316     return _applicationUri;
317     }
318     }
319    
320     internal string ApplicationConfigUri
321     {
322     get
323     {
324     return _applicationConfigUri;
325     }
326     }
327    
328     internal string RoamingConfigFilename
329     {
330     get
331     {
332     return _roamingConfigFilename;
333     }
334     }
335    
336     internal string RoamingConfigDirectory
337     {
338     get
339     {
340     return _roamingConfigDirectory;
341     }
342     }
343    
344     internal bool HasRoamingConfig
345     {
346     get
347     {
348     // Assume we have roaming config if we haven't loaded user config file information.
349     return RoamingConfigFilename != null || !_includesUserConfig;
350     }
351     }
352    
353     internal string LocalConfigFilename
354     {
355     get
356     {
357     return _localConfigFilename;
358     }
359     }
360    
361     internal string LocalConfigDirectory
362     {
363     get
364     {
365     return _localConfigDirectory;
366     }
367     }
368    
369     internal bool HasLocalConfig
370     {
371     get
372     {
373     // Assume we have roaming config if we haven't loaded user config file information.
374     return LocalConfigFilename != null || !_includesUserConfig;
375     }
376     }
377    
378     internal string ProductName
379     {
380     get
381     {
382     return _productName;
383     }
384     }
385    
386     internal string ProductVersion
387     {
388     get
389     {
390     return _productVersion;
391     }
392     }
393    
394     private static SecurityPermission ControlEvidencePermission
395     {
396     get
397     {
398     if (s_controlEvidencePerm == null)
399     {
400     s_controlEvidencePerm = new SecurityPermission(SecurityPermissionFlag.ControlEvidence);
401     }
402     return s_controlEvidencePerm;
403     }
404     }
405    
406     private static SecurityPermission SerializationFormatterPermission
407     {
408     get
409     {
410     if (s_serializationPerm == null)
411     {
412     s_serializationPerm = new SecurityPermission(SecurityPermissionFlag.SerializationFormatter);
413     }
414     return s_serializationPerm;
415     }
416     }
417    
418     // Combines path2 with path1 if possible, else returns null.
419     private string CombineIfValid(string path1, string path2)
420     {
421     string returnPath = null;
422    
423     if (path1 != null && path2 != null)
424     {
425     try
426     {
427     string combinedPath = Path.Combine(path1, path2);
428     if (combinedPath.Length < MAX_PATH)
429     {
430     returnPath = combinedPath;
431     }
432     }
433     catch
434     {
435     }
436     }
437    
438     return returnPath;
439     }
440    
441     // Returns a type and hash suffix based on app domain evidence. The evidence we use, in
442     // priority order, is Strong Name, Url and Exe Path. If one of these is found, we compute a
443     // SHA1 hash of it and return a suffix based on that. If none is found, we return null.
444 william 723 //private string GetTypeAndHashSuffix(AppDomain appDomain, string exePath)
445     private string GetTypeAndHashSuffix(Assembly appDomain, string exePath)
446 william 722 {
447     string suffix = null;
448     string typeName = null;
449     object evidenceObj = null;
450    
451     evidenceObj = GetEvidenceInfo(appDomain, exePath, out typeName);
452    
453     if (evidenceObj != null && !String.IsNullOrEmpty(typeName))
454     {
455     MemoryStream ms = new MemoryStream();
456     BinaryFormatter bSer = new BinaryFormatter();
457     SerializationFormatterPermission.Assert();
458     bSer.Serialize(ms, evidenceObj);
459     ms.Position = 0;
460     string evidenceHash = GetHash(ms);
461    
462     if (!String.IsNullOrEmpty(evidenceHash))
463     {
464     suffix = "_" + typeName + "_" + evidenceHash;
465     }
466     }
467    
468     return suffix;
469     }
470    
471     // Mostly borrowed from IsolatedStorage, with some modifications
472 william 723 //private static object GetEvidenceInfo(AppDomain appDomain, string exePath, out string typeName)
473     private static object GetEvidenceInfo(Assembly appDomain, string exePath, out string typeName)
474 william 722 {
475     ControlEvidencePermission.Assert();
476     Evidence evidence = appDomain.Evidence;
477     StrongName sn = null;
478     Url url = null;
479    
480     if (evidence != null)
481     {
482     IEnumerator e = evidence.GetHostEnumerator();
483     object temp = null;
484    
485     while (e.MoveNext())
486     {
487     temp = e.Current;
488    
489     if (temp is StrongName)
490     {
491     sn = (StrongName)temp;
492     break;
493     }
494     else if (temp is Url)
495     {
496     url = (Url)temp;
497     }
498     }
499     }
500    
501     object o = null;
502    
503     // The order of preference is StrongName, Url, ExePath.
504     if (sn != null)
505     {
506     o = MakeVersionIndependent(sn);
507     typeName = StrongNameDesc;
508     }
509     else if (url != null)
510     {
511     // Extract the url string and normalize it to use as evidence
512     o = url.Value.ToUpperInvariant();
513     typeName = UrlDesc;
514     }
515     else if (exePath != null)
516     {
517     o = exePath;
518     typeName = PathDesc;
519     }
520     else
521     {
522     typeName = null;
523     }
524    
525     return o;
526     }
527    
528     private static String GetHash(Stream s)
529     {
530     byte[] hash;
531    
532     using (SHA1 sha1 = new SHA1CryptoServiceProvider())
533     {
534     hash = sha1.ComputeHash(s);
535     }
536    
537     return ToBase32StringSuitableForDirName(hash);
538     }
539    
540     private bool IsClickOnceDeployed(AppDomain appDomain)
541     {
542     // NOTE: For perf & servicing reasons, we don't want to introduce a dependency on
543     // System.Deployment.dll here. The following code is an alternative to calling
544     // ApplicationDeployment.IsNetworkDeployed.
545    
546     ActivationContext actCtx = appDomain.ActivationContext;
547    
548     // Ensures the app is running with a context from the store.
549     if (actCtx != null && actCtx.Form == ActivationContext.ContextForm.StoreBounded)
550     {
551     string fullAppId = actCtx.Identity.FullName;
552     if (!String.IsNullOrEmpty(fullAppId))
553     {
554     return true;
555     }
556     }
557    
558     return false;
559     }
560    
561     private static StrongName MakeVersionIndependent(StrongName sn)
562     {
563     return new StrongName(sn.PublicKey, sn.Name, new Version(0, 0, 0, 0));
564     }
565    
566 william 723 //private void SetNamesAndVersion(string applicationFilename, Assembly exeAssembly, bool isHttp)
567     private void SetNamesAndVersion(Assembly exeAssembly, bool isHttp)
568 william 722 {
569     Type mainType = null;
570    
571     //
572     // Get CompanyName, ProductName, and ProductVersion
573     // First try custom attributes on the assembly.
574     //
575     if (exeAssembly != null)
576     {
577     object[] attrs = exeAssembly.GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
578     if (attrs != null && attrs.Length > 0)
579     {
580     _companyName = ((AssemblyCompanyAttribute)attrs[0]).Company;
581     if (_companyName != null)
582     {
583     _companyName = _companyName.Trim();
584     }
585     }
586    
587     attrs = exeAssembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);
588     if (attrs != null && attrs.Length > 0)
589     {
590     _productName = ((AssemblyProductAttribute)attrs[0]).Product;
591     if (_productName != null)
592     {
593     _productName = _productName.Trim();
594     }
595     }
596    
597     _productVersion = exeAssembly.GetName().Version.ToString();
598     if (_productVersion != null)
599     {
600     _productVersion = _productVersion.Trim();
601     }
602     }
603    
604     //
605     // If we couldn't get custom attributes, try the Win32 file version
606     //
607     if (!isHttp && (String.IsNullOrEmpty(_companyName) || String.IsNullOrEmpty(_productName) || String.IsNullOrEmpty(_productVersion)))
608     {
609     string versionInfoFileName = null;
610    
611     if (exeAssembly != null)
612     {
613     MethodInfo entryPoint = exeAssembly.EntryPoint;
614     if (entryPoint != null)
615     {
616     mainType = entryPoint.ReflectedType;
617     if (mainType != null)
618     {
619     versionInfoFileName = mainType.Module.FullyQualifiedName;
620     }
621     }
622     }
623    
624 william 723 //if (versionInfoFileName == null)
625     //{
626     // versionInfoFileName = applicationFilename;
627     //}
628 william 722
629     if (versionInfoFileName != null)
630     {
631     System.Diagnostics.FileVersionInfo version = System.Diagnostics.FileVersionInfo.GetVersionInfo(versionInfoFileName);
632     if (version != null)
633     {
634     if (String.IsNullOrEmpty(_companyName))
635     {
636     _companyName = version.CompanyName;
637     if (_companyName != null)
638     {
639     _companyName = _companyName.Trim();
640     }
641     }
642    
643     if (String.IsNullOrEmpty(_productName))
644     {
645     _productName = version.ProductName;
646     if (_productName != null)
647     {
648     _productName = _productName.Trim();
649     }
650     }
651    
652     if (String.IsNullOrEmpty(_productVersion))
653     {
654     _productVersion = version.ProductVersion;
655     if (_productVersion != null)
656     {
657     _productVersion = _productVersion.Trim();
658     }
659     }
660     }
661     }
662     }
663    
664     if (String.IsNullOrEmpty(_companyName) || String.IsNullOrEmpty(_productName))
665     {
666     string ns = null;
667     if (mainType != null)
668     {
669     ns = mainType.Namespace;
670     }
671    
672     // Desperate measures for product name
673     if (String.IsNullOrEmpty(_productName))
674     {
675     // Try the remainder of the namespace
676     if (ns != null)
677     {
678     int lastDot = ns.LastIndexOf(".", StringComparison.Ordinal);
679     if (lastDot != -1 && lastDot < ns.Length - 1)
680     {
681     _productName = ns.Substring(lastDot + 1);
682     }
683     else
684     {
685     _productName = ns;
686     }
687    
688     _productName = _productName.Trim();
689     }
690    
691     // Try the type of the entry assembly
692     if (String.IsNullOrEmpty(_productName) && mainType != null)
693     {
694     _productName = mainType.Name.Trim();
695     }
696    
697     // give up, return empty string
698     if (_productName == null)
699     {
700     _productName = string.Empty;
701     }
702     }
703    
704     // Desperate measures for company name
705     if (String.IsNullOrEmpty(_companyName))
706     {
707     // Try the first part of the namespace
708     if (ns != null)
709     {
710     int firstDot = ns.IndexOf(".", StringComparison.Ordinal);
711     if (firstDot != -1)
712     {
713     _companyName = ns.Substring(0, firstDot);
714     }
715     else
716     {
717     _companyName = ns;
718     }
719    
720     _companyName = _companyName.Trim();
721     }
722    
723     // If that doesn't work, use the product name
724     if (String.IsNullOrEmpty(_companyName))
725     {
726     _companyName = _productName;
727     }
728     }
729     }
730    
731     // Desperate measures for product version - assume 1.0
732     if (String.IsNullOrEmpty(_productVersion))
733     {
734     _productVersion = "1.0.0.0";
735     }
736     }
737    
738     // Borrowed from IsolatedStorage
739     private static string ToBase32StringSuitableForDirName(byte[] buff)
740     {
741     StringBuilder sb = new StringBuilder();
742     byte b0, b1, b2, b3, b4;
743     int l, i;
744    
745     l = buff.Length;
746     i = 0;
747    
748     // Create l chars using the last 5 bits of each byte.
749     // Consume 3 MSB bits 5 bytes at a time.
750    
751     do
752     {
753     b0 = (i < l) ? buff[i++] : (byte)0;
754     b1 = (i < l) ? buff[i++] : (byte)0;
755     b2 = (i < l) ? buff[i++] : (byte)0;
756     b3 = (i < l) ? buff[i++] : (byte)0;
757     b4 = (i < l) ? buff[i++] : (byte)0;
758    
759     // Consume the 5 Least significant bits of each byte
760     sb.Append(s_Base32Char[b0 & 0x1F]);
761     sb.Append(s_Base32Char[b1 & 0x1F]);
762     sb.Append(s_Base32Char[b2 & 0x1F]);
763     sb.Append(s_Base32Char[b3 & 0x1F]);
764     sb.Append(s_Base32Char[b4 & 0x1F]);
765    
766     // Consume 3 MSB of b0, b1, MSB bits 6, 7 of b3, b4
767     sb.Append(s_Base32Char[(
768     ((b0 & 0xE0) >> 5) |
769     ((b3 & 0x60) >> 2))]);
770    
771     sb.Append(s_Base32Char[(
772     ((b1 & 0xE0) >> 5) |
773     ((b4 & 0x60) >> 2))]);
774    
775     // Consume 3 MSB bits of b2, 1 MSB bit of b3, b4
776    
777     b2 >>= 5;
778    
779     if ((b3 & 0x80) != 0)
780     b2 |= 0x08;
781     if ((b4 & 0x80) != 0)
782     b2 |= 0x10;
783    
784     sb.Append(s_Base32Char[b2]);
785    
786     } while (i < l);
787    
788     return sb.ToString();
789     }
790    
791     // Makes the passed in string suitable to use as a path name by replacing illegal characters
792     // with underscores. Additionally, we do two things - replace spaces too with underscores and
793     // limit the resultant string's length to MAX_LENGTH_TO_USE if limitSize is true.
794     private string Validate(string str, bool limitSize)
795     {
796     string validated = str;
797    
798     if (!String.IsNullOrEmpty(validated))
799     {
800     // First replace all illegal characters with underscores
801     foreach (char c in Path.GetInvalidFileNameChars())
802     {
803     validated = validated.Replace(c, '_');
804     }
805    
806     // Replace all spaces with underscores
807     validated = validated.Replace(' ', '_');
808    
809     if (limitSize)
810     {
811     validated = (validated.Length > MAX_LENGTH_TO_USE) ? validated.Substring(0, MAX_LENGTH_TO_USE) : validated;
812     }
813     }
814    
815     return validated;
816     }
817     }
818     #endregion
819     }
820     }