Parcourir la source

添加项目文件。

龙腾猫跃 il y a 6 mois
Parent
commit
95fb4203b5
5 fichiers modifiés avec 222 ajouts et 0 suppressions
  1. 67 0
      General/Extensions.cs
  2. 52 0
      General/MsDelta.cs
  3. 43 0
      General/PathUtils.cs
  4. 29 0
      MeloongCore.csproj
  5. 31 0
      MeloongCore.sln

+ 67 - 0
General/Extensions.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace PCLCS {
+    public static class Extensions {
+
+        #region String
+
+        /// <summary>
+        /// 高速的 StartsWith。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool StartsWithF(this string value, string prefix, bool ignoreCase = false) {
+            if (value == null) return false;
+            return value.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+        }
+        /// <summary>
+        /// 高速的 EndsWith。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool EndsWithF(this string value, string suffix, bool ignoreCase = false) {
+            if (value == null) return false;
+            return value.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+        }
+
+        /// <summary>
+        /// 忽略大小写的 Contains。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool ContainsIgnoreCase(this string value, string subString) {
+            return value.IndexOf(subString,StringComparison.OrdinalIgnoreCase) >= 0;
+        }
+
+        /// <summary>
+        /// 高速的 IndexOf。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int IndexOfF(this string value, string subString, bool ignoreCase = false) {
+            return value.IndexOf(subString, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+        }
+        /// <summary>
+        /// 高速的 IndexOf。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int IndexOfF(this string value, string subString, int startIndex, bool ignoreCase = false) {
+            return value.IndexOf(subString, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+        }
+
+        /// <summary>
+        /// 高速的 LastIndexOf。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int LastIndexOfF(this string value, string subString, bool ignoreCase = false) {
+            return value.LastIndexOf(subString, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+        }
+        /// <summary>
+        /// 高速的 LastIndexOf。
+        /// </summary>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int LastIndexOfF(this string value, string subString, int startIndex, bool ignoreCase = false) {
+            return value.LastIndexOf(subString, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
+        }
+
+        #endregion
+
+    }
+}

+ 52 - 0
General/MsDelta.cs

@@ -0,0 +1,52 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+
+namespace PCLCS {
+
+    /// <summary>
+    /// 使用 Windows MsDelta API 生成、应用增量补丁文件。
+    /// </summary>
+    public static class MsDelta {
+
+        /// <summary>
+        /// 生成增量补丁文件:比较 <paramref name="oldFilePath"/> 和 <paramref name="newFilePath"/>,将补丁写入 <paramref name="deltaFilePath"/>。
+        /// </summary>
+        public static void Create(string oldFilePath, string newFilePath, string deltaFilePath) {
+            // fileTypeSet:https://learn.microsoft.com/en-us/previous-versions/bb417345(v=msdn.10)?redirectedfrom=MSDN#file-type-sets (15L: DELTA_FILE_TYPE_SET_EXECUTABLES)
+            // 131072L: IgnoreFileSizeLimit, 32u: Crc32
+            if (!CreateDelta(15L, 131072L, 0L, 
+                PathUtils.Shorten(oldFilePath), PathUtils.Shorten(newFilePath), null, null, new DeltaInput(), IntPtr.Zero, 32u, PathUtils.Shorten(deltaFilePath)))
+                throw new Win32Exception();
+        }
+
+        /// <summary>
+        /// 应用增量补丁文件:将 <paramref name="deltaFilePath"/> 补丁应用到 <paramref name="oldFilePath"/>,将结果写入 <paramref name="newFilePath"/>。
+        /// </summary>
+        public static void Apply(string oldFilePath, string deltaFilePath, string newFilePath) {
+            // 1L: AllowLegacy
+            if (!ApplyDelta(1L, PathUtils.Shorten(oldFilePath), PathUtils.Shorten(deltaFilePath), PathUtils.Shorten(newFilePath)))
+                throw new Win32Exception();
+        }
+
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct DeltaInput {
+            public IntPtr Start;
+            public IntPtr Size;
+            [MarshalAs(UnmanagedType.Bool)] public bool Editable;
+        }
+        [DllImport("msdelta.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        private static extern bool CreateDelta(
+            long fileTypeSet, long setFlags, long resetFlags,
+            string sourceName, string targetName, string sourceOptionsName,
+            string targetOptionsName, DeltaInput globalOptions,
+            IntPtr targetFileTime, uint hashAlgId, string deltaName);
+        [DllImport("msdelta.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        private static extern bool ApplyDelta(long applyFlags, string sourceName, string deltaName, string targetName);
+
+    }
+
+}

+ 43 - 0
General/PathUtils.cs

@@ -0,0 +1,43 @@
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace PCLCS {
+    public static class PathUtils {
+
+        /// <summary>
+        /// 若路径较长,则尽量将其转换为短路径。
+        /// 若输入的是文件夹路径,不保证其结尾是否有 \ 。
+        /// </summary>
+        public static string Shorten(string fullName, bool keepFileName = false) {
+            if (string.IsNullOrEmpty(fullName) || fullName.Length <= 200) return fullName;
+            fullName = fullName.Replace('/', '\\');
+
+            // 保留文件名
+            string pathToKeep = "";
+            string pathToShorten = fullName;
+            if (fullName.EndsWithF(".jar", true)) keepFileName = true; // jar 文件的文件名需要保留原样,否则会导致 Forge 1.20.1 无法通过文件名识别模块名
+            if (keepFileName && File.Exists(fullName)) {
+                pathToKeep = Path.GetFileName(fullName);
+                pathToShorten = Path.GetDirectoryName(fullName);
+            }
+
+            // 逐级向上寻找已存在的文件夹,将不存在的部分挪到 suffix,不再缩短
+            while (!Directory.Exists(pathToShorten) && !File.Exists(pathToShorten)) { // 如果路径不存在
+                string parentPath = Path.GetDirectoryName(pathToShorten);
+                if (string.IsNullOrEmpty(parentPath) || parentPath == pathToShorten) return fullName; // 已经到达根目录,全都不存在,直接返回
+                pathToKeep = Path.Combine(Path.GetFileName(pathToShorten), pathToKeep);
+                pathToShorten = parentPath;
+            }
+            if (pathToShorten.Length <= 10) return fullName;
+
+            // 缩短路径
+            StringBuilder buffer = new StringBuilder(260);
+            if (GetShortPathNameW(pathToShorten, buffer, buffer.Capacity) == 0) return fullName;
+            return Path.Combine(buffer.ToString(), pathToKeep);
+        }
+        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
+        private static extern int GetShortPathNameW(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer);
+
+    }
+}

+ 29 - 0
MeloongCore.csproj

@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net462</TargetFramework>
+    <OutputType>Library</OutputType>
+    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+	<OutDir>bin\</OutDir>
+	<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+	<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
+	<Configurations>Debug;Release;Snapshot;SnapshotUpdate</Configurations>
+	<Deterministic>true</Deterministic>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <DefineConstants>$(DefineConstants);SNAPSHOT</DefineConstants>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'" />
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='SnapshotUpdate|AnyCPU'">
+    <DefineConstants>$(DefineConstants);SNAPSHOT;UPDATE</DefineConstants>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Snapshot|AnyCPU'">
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+
+</Project>

+ 31 - 0
MeloongCore.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.14.36401.2 d17.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeloongCore", "MeloongCore.csproj", "{182EE415-8FA1-28AC-F015-94632CC53589}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+		Snapshot|Any CPU = Snapshot|Any CPU
+		SnapshotUpdate|Any CPU = SnapshotUpdate|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{182EE415-8FA1-28AC-F015-94632CC53589}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.Release|Any CPU.Build.0 = Release|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.Snapshot|Any CPU.ActiveCfg = Snapshot|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.Snapshot|Any CPU.Build.0 = Snapshot|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.SnapshotUpdate|Any CPU.ActiveCfg = SnapshotUpdate|Any CPU
+		{182EE415-8FA1-28AC-F015-94632CC53589}.SnapshotUpdate|Any CPU.Build.0 = SnapshotUpdate|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {B303EB9D-4553-4E41-810D-7803E31EF4C3}
+	EndGlobalSection
+EndGlobal