⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dompersistence.cs

📁 SharpDevelop2.0.0 c#开发免费工具
💻 CS
📖 第 1 页 / 共 2 页
字号:
// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
//     <version>$Revision: 1307 $</version>
// </file>

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.IO;
using ICSharpCode.Core;

namespace ICSharpCode.SharpDevelop.Dom
{
	/// <summary>
	/// This class can write Dom entity into a binary file for fast loading.
	/// </summary>
	public static class DomPersistence
	{
		public const long FileMagic = 0x11635233ED2F428C;
		public const long IndexFileMagic = 0x11635233ED2F427D;
		public const short FileVersion = 6;
		
		#region Cache management
		#if DEBUG
		const string tempPathName = "SharpDevelop/DomCacheDebug";
		#else
		const string tempPathName = "SharpDevelop/DomCache";
		#endif
		
		static string MakeTempPath()
		{
			string tempPath = Path.Combine(Path.GetTempPath(), tempPathName);
			if (!Directory.Exists(tempPath))
				Directory.CreateDirectory(tempPath);
			return tempPath;
		}
		
		public static string SaveProjectContent(ReflectionProjectContent pc)
		{
			string assemblyFullName = pc.AssemblyFullName;
			int pos = assemblyFullName.IndexOf(',');
			string fileName = Path.Combine(MakeTempPath(),
			                               assemblyFullName.Substring(0, pos)
			                               + "." + assemblyFullName.GetHashCode().ToString("x", CultureInfo.InvariantCulture)
			                               + "." + pc.AssemblyLocation.GetHashCode().ToString("x", CultureInfo.InvariantCulture)
			                               + ".dat");
			AddFileNameToCacheIndex(Path.GetFileName(fileName), pc);
			using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) {
				using (BinaryWriter writer = new BinaryWriter(fs)) {
					new ReadWriteHelper(writer).WriteProjectContent(pc);
				}
			}
			return fileName;
		}
		
		public static ReflectionProjectContent LoadProjectContentByAssemblyName(string assemblyName)
		{
			string cacheFileName;
			if (CacheIndex.TryGetValue(assemblyName, out cacheFileName)) {
				cacheFileName = Path.Combine(MakeTempPath(), cacheFileName);
				if (File.Exists(cacheFileName)) {
					return LoadProjectContent(cacheFileName);
				}
			}
			return null;
		}
		
		public static ReflectionProjectContent LoadProjectContent(string cacheFileName)
		{
			ReflectionProjectContent pc;
			using (FileStream fs = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read)) {
				using (BinaryReader reader = new BinaryReader(fs)) {
					try {
						pc = new ReadWriteHelper(reader).ReadProjectContent();
					} catch (EndOfStreamException) {
						LoggingService.Warn("Read dom: EndOfStreamException");
						return null;
					}
				}
			}
			if (pc != null) {
				pc.InitializeSpecialClasses();
			}
			return pc;
		}
		#endregion
		
		#region Cache index
		static string GetIndexFileName() { return Path.Combine(MakeTempPath(), "index.dat"); }
		
		static Dictionary<string, string> cacheIndex;
		
		static Dictionary<string, string> CacheIndex {
			get {
				if (cacheIndex == null) {
					cacheIndex = LoadCacheIndex();
				}
				return cacheIndex;
			}
		}
		
		static Dictionary<string, string> LoadCacheIndex()
		{
			string indexFile = GetIndexFileName();
			Dictionary<string, string> list = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
			if (File.Exists(indexFile)) {
				try {
					using (FileStream fs = new FileStream(indexFile, FileMode.Open, FileAccess.Read)) {
						using (BinaryReader reader = new BinaryReader(fs)) {
							if (reader.ReadInt64() != IndexFileMagic) {
								LoggingService.Warn("Index cache has wrong file magic");
								return list;
							}
							if (reader.ReadInt16() != FileVersion) {
								LoggingService.Warn("Index cache has wrong file version");
								return list;
							}
							int count = reader.ReadInt32();
							for (int i = 0; i < count; i++) {
								string key = reader.ReadString();
								list[key] = reader.ReadString();
							}
						}
					}
				} catch (IOException ex) {
					LoggingService.Warn("Error reading DomPersistance cache index", ex);
				}
			}
			return list;
		}
		
		static void SaveCacheIndex(Dictionary<string, string> cacheIndex)
		{
			string indexFile = GetIndexFileName();
			using (FileStream fs = new FileStream(indexFile, FileMode.Create, FileAccess.Write)) {
				using (BinaryWriter writer = new BinaryWriter(fs)) {
					writer.Write(IndexFileMagic);
					writer.Write(FileVersion);
					writer.Write(cacheIndex.Count);
					foreach (KeyValuePair<string, string> e in cacheIndex) {
						writer.Write(e.Key);
						writer.Write(e.Value);
					}
				}
			}
		}
		
		static void AddFileNameToCacheIndex(string cacheFile, ReflectionProjectContent pc)
		{
			Dictionary<string, string> l = LoadCacheIndex();
			l[pc.AssemblyLocation] = cacheFile;
			string txt = pc.AssemblyFullName;
			l[txt] = cacheFile;
			int pos = txt.LastIndexOf(',');
			do {
				txt = txt.Substring(0, pos);
				if (l.ContainsKey(txt))
					break;
				l[txt] = cacheFile;
				pos = txt.LastIndexOf(',');
			} while (pos >= 0);
			SaveCacheIndex(l);
			cacheIndex = l;
		}
		#endregion
		
		private struct ClassNameTypeCountPair {
			public readonly string ClassName;
			public readonly byte TypeParameterCount;
			
			public ClassNameTypeCountPair(IClass c) {
				this.ClassName = c.FullyQualifiedName;
				this.TypeParameterCount = (byte)c.TypeParameters.Count;
			}
			
			public ClassNameTypeCountPair(IReturnType rt) {
				this.ClassName = rt.FullyQualifiedName;
				this.TypeParameterCount = (byte)rt.TypeParameterCount;
			}
			
			public override bool Equals(object obj) {
				if (!(obj is ClassNameTypeCountPair)) return false;
				ClassNameTypeCountPair myClassNameTypeCountPair = (ClassNameTypeCountPair)obj;
				if (!ClassName.Equals(myClassNameTypeCountPair.ClassName, StringComparison.InvariantCultureIgnoreCase)) return false;
				if (TypeParameterCount != myClassNameTypeCountPair.TypeParameterCount) return false;
				return true;
			}
			
			public override int GetHashCode() {
				return StringComparer.InvariantCultureIgnoreCase.GetHashCode(ClassName) ^ ((int)TypeParameterCount * 5);
			}
		}
		
		public sealed class ReadWriteHelper
		{
			ReflectionProjectContent pc;
			
			readonly BinaryWriter writer;
			readonly Dictionary<ClassNameTypeCountPair, int> classIndices = new Dictionary<ClassNameTypeCountPair, int>();
			readonly Dictionary<string, int> stringDict = new Dictionary<string, int>();
			
			readonly BinaryReader reader;
			IReturnType[] types;
			string[] stringArray;
			
			#region Write/Read ProjectContent
			public ReadWriteHelper(BinaryWriter writer)
			{
				this.writer = writer;
			}
			
			public void WriteProjectContent(ReflectionProjectContent pc)
			{
				this.pc = pc;
				writer.Write(FileMagic);
				writer.Write(FileVersion);
				writer.Write(pc.AssemblyFullName);
				writer.Write(pc.AssemblyLocation);
				long time = 0;
				try {
					time = File.GetLastWriteTimeUtc(pc.AssemblyLocation).ToFileTime();
				} catch {}
				writer.Write(time);
				writer.Write(pc.ReferencedAssemblies.Length);
				foreach (AssemblyName name in pc.ReferencedAssemblies) {
					writer.Write(name.FullName);
				}
				WriteClasses();
			}
			
			public ReadWriteHelper(BinaryReader reader)
			{
				this.reader = reader;
			}
			
			public ReflectionProjectContent ReadProjectContent()
			{
				if (reader.ReadInt64() != FileMagic) {
					LoggingService.Warn("Read dom: wrong magic");
					return null;
				}
				if (reader.ReadInt16() != FileVersion) {
					LoggingService.Warn("Read dom: wrong version");
					return null;
				}
				string assemblyName = reader.ReadString();
				string assemblyLocation = reader.ReadString();
				long time = 0;
				try {
					time = File.GetLastWriteTimeUtc(assemblyLocation).ToFileTime();
				} catch {}
				if (reader.ReadInt64() != time) {
					LoggingService.Warn("Read dom: assembly changed since cache was created");
					return null;
				}
				AssemblyName[] referencedAssemblies = new AssemblyName[reader.ReadInt32()];
				for (int i = 0; i < referencedAssemblies.Length; i++) {
					referencedAssemblies[i] = new AssemblyName(reader.ReadString());
				}
				this.pc = new ReflectionProjectContent(assemblyName, assemblyLocation, referencedAssemblies);
				if (ReadClasses()) {
					return pc;
				} else {
					LoggingService.Warn("Read dom: error in file (invalid control mark)");
					return null;
				}
			}
			
			void WriteClasses()
			{
				ICollection<IClass> classes = pc.Classes;
				
				classIndices.Clear();
				stringDict.Clear();
				int i = 0;
				foreach (IClass c in classes) {
					classIndices[new ClassNameTypeCountPair(c)] = i;
					i += 1;
				}
				
				List<ClassNameTypeCountPair> externalTypes = new List<ClassNameTypeCountPair>();
				List<string> stringList = new List<string>();
				CreateExternalTypeList(externalTypes, stringList, classes.Count, classes);
				
				writer.Write(classes.Count);
				writer.Write(externalTypes.Count);
				foreach (IClass c in classes) {
					writer.Write(c.FullyQualifiedName);
				}
				foreach (ClassNameTypeCountPair type in externalTypes) {
					writer.Write(type.ClassName);
					writer.Write(type.TypeParameterCount);
				}
				writer.Write(stringList.Count);
				foreach (string text in stringList) {
					writer.Write(text);
				}
				foreach (IClass c in classes) {
					WriteClass(c);
					// BinaryReader easily reads junk data when the file does not have the
					// expected format, so we put a checking byte after each class.
					writer.Write((byte)64);
				}
			}
			
			bool ReadClasses()
			{
				int classCount = reader.ReadInt32();
				int externalTypeCount = reader.ReadInt32();
				types = new IReturnType[classCount + externalTypeCount];
				DefaultClass[] classes = new DefaultClass[classCount];
				for (int i = 0; i < classes.Length; i++) {
					DefaultClass c = new DefaultClass(pc.AssemblyCompilationUnit, reader.ReadString());
					classes[i] = c;
					types[i] = c.DefaultReturnType;
				}
				for (int i = classCount; i < types.Length; i++) {
					string name = reader.ReadString();
					types[i] = new GetClassReturnType(pc, name, reader.ReadByte());
				}
				stringArray = new string[reader.ReadInt32()];
				for (int i = 0; i < stringArray.Length; i++) {
					stringArray[i] = reader.ReadString();
				}
				for (int i = 0; i < classes.Length; i++) {
					ReadClass(classes[i]);
					pc.AddClassToNamespaceList(classes[i]);
					if (reader.ReadByte() != 64) {
						return false;
					}
				}
				return true;
			}
			#endregion
			
			#region Write/Read Class
			IClass currentClass;
			
			void WriteClass(IClass c)
			{
				this.currentClass = c;
				WriteTemplates(c.TypeParameters);
				writer.Write(c.BaseTypes.Count);
				foreach (IReturnType type in c.BaseTypes) {
					WriteType(type);
				}
				writer.Write((int)c.Modifiers);
				if (c is DefaultClass) {
					writer.Write(((DefaultClass)c).Flags);
				} else {
					writer.Write((byte)0);
				}
				writer.Write((byte)c.ClassType);
				WriteAttributes(c.Attributes);
				writer.Write(c.InnerClasses.Count);
				foreach (IClass innerClass in c.InnerClasses) {
					writer.Write(innerClass.FullyQualifiedName);
					WriteClass(innerClass);
				}
				this.currentClass = c;
				writer.Write(c.Methods.Count);
				foreach (IMethod method in c.Methods) {
					WriteMethod(method);
				}
				writer.Write(c.Properties.Count);
				foreach (IProperty property in c.Properties) {
					WriteProperty(property);
				}
				writer.Write(c.Events.Count);
				foreach (IEvent evt in c.Events) {
					WriteEvent(evt);
				}
				writer.Write(c.Fields.Count);
				foreach (IField field in c.Fields) {
					WriteField(field);
				}
				this.currentClass = null;
			}
			
			void WriteTemplates(IList<ITypeParameter> list)
			{
				// read code exists twice: in ReadClass and ReadMethod
				writer.Write((byte)list.Count);
				foreach (ITypeParameter typeParameter in list) {
					WriteString(typeParameter.Name);
				}
				foreach (ITypeParameter typeParameter in list) {
					writer.Write(typeParameter.Constraints.Count);
					foreach (IReturnType type in typeParameter.Constraints) {
						WriteType(type);
					}
				}
			}
			
			void ReadClass(DefaultClass c)
			{
				this.currentClass = c;
				int count;
				count = reader.ReadByte();
				for (int i = 0; i < count; i++) {
					c.TypeParameters.Add(new DefaultTypeParameter(c, ReadString(), i));
				}
				if (count > 0) {
					foreach (ITypeParameter typeParameter in c.TypeParameters) {
						count = reader.ReadInt32();
						for (int i = 0; i < count; i++) {
							typeParameter.Constraints.Add(ReadType());
						}
					}
				} else {
					c.TypeParameters = DefaultTypeParameter.EmptyTypeParameterList;
				}
				count = reader.ReadInt32();
				for (int i = 0; i < count; i++) {
					c.BaseTypes.Add(ReadType());
				}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -