2.7.0
This commit is contained in:
@@ -869,7 +869,7 @@ NextAni:
|
||||
Loop
|
||||
|
||||
'如果当前动画组都执行完毕则删除
|
||||
If Entry.Data.Count = 0 Then
|
||||
If Not Entry.Data.Any() Then
|
||||
'为了避免新添加的动画影响顺序,不能 RemoveAt(i)
|
||||
'为了允许动画在执行中添加同名动画组,不能按名字移除
|
||||
For Current = 0 To AniGroups.Count - 1
|
||||
|
||||
@@ -11,12 +11,12 @@ Public Module ModBase
|
||||
#Region "声明"
|
||||
|
||||
'下列版本信息由更新器自动修改
|
||||
Public Const VersionBaseName As String = "2.6.15" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.6.15." & VersionBranchCode '标准格式的四段式版本号
|
||||
Public Const VersionBaseName As String = "2.7.0" '不含分支前缀的显示用版本名
|
||||
Public Const VersionStandardCode As String = "2.7.0." & VersionBranchCode '标准格式的四段式版本号
|
||||
#If BETA Then
|
||||
Public Const VersionCode As Integer = 317 'Release
|
||||
Public Const VersionCode As Integer = 319 'Release
|
||||
#Else
|
||||
Public Const VersionCode As Integer = 316 'Snapshot
|
||||
Public Const VersionCode As Integer = 318 'Snapshot
|
||||
#End If
|
||||
'自动生成的版本信息
|
||||
Public Const VersionDisplayName As String = VersionBranchName & " " & VersionBaseName
|
||||
@@ -110,6 +110,14 @@ Public Module ModBase
|
||||
''' </summary>
|
||||
Public Const IconButtonDelete As String = "M520.192 0C408.43 0 317.44 82.87 313.563 186.734H52.736c-29.038 0-52.663 21.943-52.663 49.079s23.625 49.152 52.663 49.152h58.075v550.473c0 103.35 75.118 187.757 167.717 187.757h472.43c92.599 0 167.716-83.894 167.716-187.757V285.477h52.59c29.038 0 52.59-21.943 52.663-49.08-0.073-27.135-23.625-49.151-52.663-49.151H726.235C723.237 83.017 631.955 0 520.192 0zM404.846 177.957c3.803-50.03 50.176-89.015 107.447-89.015 57.197 0 103.57 38.985 106.788 89.015H404.92zM284.379 933.669c-33.353 0-69.997-39.351-69.997-95.525v-549.01H833.39v549.522c0 56.247-36.645 95.525-69.998 95.525H284.379v-0.512z M357.23 800.695a48.274 48.274 0 0 0 47.616-49.006V471.7a48.274 48.274 0 0 0-47.543-49.08 48.274 48.274 0 0 0-47.69 49.006V751.69c0 27.282 20.846 49.006 47.617 49.006z m166.62 0a48.274 48.274 0 0 0 47.688-49.006V471.7a48.274 48.274 0 0 0-47.689-49.08 48.274 48.274 0 0 0-47.543 49.006V751.69c0 27.282 21.431 49.006 47.543 49.006z m142.92 0a48.274 48.274 0 0 0 47.543-49.006V471.7a48.274 48.274 0 0 0-47.543-49.08 48.274 48.274 0 0 0-47.616 49.006V751.69c0 27.282 20.773 49.006 47.543 49.006z"
|
||||
''' <summary>
|
||||
''' 图标按钮,禁止,1x
|
||||
''' </summary>
|
||||
Public Const IconButtonStop As String = "M508 990.4c-261.6 0-474.4-212-474.4-474.4S246.4 41.6 508 41.6s474.4 212 474.4 474.4S769.6 990.4 508 990.4zM508 136.8c-209.6 0-379.2 169.6-379.2 379.2 0 209.6 169.6 379.2 379.2 379.2s379.2-169.6 379.2-379.2C887.2 306.4 717.6 136.8 508 136.8zM697.6 563.2 318.4 563.2c-26.4 0-47.2-21.6-47.2-47.2 0-26.4 21.6-47.2 47.2-47.2l379.2 0c26.4 0 47.2 21.6 47.2 47.2C744.8 542.4 724 563.2 697.6 563.2z"
|
||||
''' <summary>
|
||||
''' 图标按钮,勾选,1x
|
||||
''' </summary>
|
||||
Public Const IconButtonCheck As String = "M512 0a512 512 0 1 0 512 512A512 512 0 0 0 512 0z m0 921.6a409.6 409.6 0 1 1 409.6-409.6 409.6 409.6 0 0 1-409.6 409.6z M716.8 339.968l-256 253.44L328.192 460.8A51.2 51.2 0 0 0 256 532.992l168.448 168.96a51.2 51.2 0 0 0 72.704 0l289.28-289.792A51.2 51.2 0 0 0 716.8 339.968z"
|
||||
''' <summary>
|
||||
''' 图标按钮,笔,1x
|
||||
''' </summary>
|
||||
Public Const IconButtonEdit As String = "M732.64 64.32C688.576 21.216 613.696 21.216 569.6 64.32L120.128 499.52c-17.6 12.896-26.432 30.144-30.848 51.68L32 870.048c0 25.856 8.8 56 26.432 73.248 17.632 17.216 17.632 48.704 88.64 48.704h13.248l326.08-56c22.016-4.32 39.68-12.928 52.864-30.176l449.472-435.2c22.048-21.536 35.264-47.36 35.264-77.536 0-30.176-13.216-56-35.264-77.568l-256.096-251.2zM139.712 903.776l56-326.912 311.04-295.136 267.104 269.44-310.976 295.168-323.168 57.44zM844.576 467.84l-273.984-260.672 61.856-59.84c8.832-8.512 26.528-8.512 39.776 0l234.24 226.496c4.384 4.288 8.832 12.8 8.832 17.088s-4.416 8.544-8.864 12.8l-61.856 64.128z"
|
||||
@@ -471,11 +479,11 @@ Public Module ModBase
|
||||
Const Digits As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/+="
|
||||
'零与负数的处理
|
||||
If String.IsNullOrEmpty(Input) Then Return "0"
|
||||
Dim IsNegative As Boolean = Input.StartsWith("-")
|
||||
Dim IsNegative As Boolean = Input.StartsWithF("-")
|
||||
If IsNegative Then Input = Input.TrimStart("-")
|
||||
'转换为十进制
|
||||
Dim RealNum As Long = 0, Scale As Long = 1
|
||||
For Each Digit In Input.Reverse.Select(Function(l) Digits.IndexOf(l))
|
||||
For Each Digit In Input.Reverse.Select(Function(l) Digits.IndexOfF(l))
|
||||
RealNum += Digit * Scale
|
||||
Scale *= FromRadix
|
||||
Next
|
||||
@@ -614,82 +622,53 @@ Public Module ModBase
|
||||
End Sub
|
||||
|
||||
'Ini 文件
|
||||
Private Class IniCache
|
||||
Public FileContent As String = ""
|
||||
Public KVCache As New Dictionary(Of String, String)
|
||||
End Class
|
||||
Private ReadOnly IniCacheList As New Dictionary(Of String, IniCache)
|
||||
Private ReadOnly IniCache As New Dictionary(Of String, Dictionary(Of String, String))
|
||||
''' <summary>
|
||||
''' 清除某 Ini 文件的运行时缓存。
|
||||
''' 清除某 ini 文件的运行时缓存。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
|
||||
Public Sub IniClearCache(FileName As String)
|
||||
'还原文件路径
|
||||
If Not FileName.Contains(":\") Then FileName = Path & "PCL\" & FileName & ".ini"
|
||||
'检索缓存
|
||||
If IniCacheList.ContainsKey(FileName) Then IniCacheList.Remove(FileName)
|
||||
If Not FileName.Contains(":\") Then FileName = $"{Path}PCL\{FileName}.ini"
|
||||
If IniCache.ContainsKey(FileName) Then IniCache.Remove(FileName)
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 获取 Ini 文件内容,这可能会使用到缓存。
|
||||
''' 获取 ini 文件缓存。如果没有,则新读取 ini 文件内容。
|
||||
''' 在文件不存在或读取失败时返回 Nothing。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
|
||||
Private Function IniGetContent(FileName As String) As IniCache
|
||||
Private Function IniGetContent(FileName As String) As Dictionary(Of String, String)
|
||||
Try
|
||||
'还原文件路径
|
||||
If Not FileName.Contains(":\") Then FileName = Path & "PCL\" & FileName & ".ini"
|
||||
If Not FileName.Contains(":\") Then FileName = $"{Path}PCL\{FileName}.ini"
|
||||
'检索缓存
|
||||
If IniCacheList.ContainsKey(FileName) Then
|
||||
'返回缓存中的信息
|
||||
Dim Cache As New IniCache
|
||||
IniCacheList.TryGetValue(FileName, Cache)
|
||||
Return Cache '防止ByRef导致缓存变更
|
||||
Else
|
||||
Dim Ini As IniCache
|
||||
If File.Exists(FileName) Then
|
||||
'返回文件信息并且记入缓存
|
||||
Dim Cache As String = (vbCrLf & ReadFile(FileName) & vbCrLf).Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, vbCrLf).Replace(vbCrLf & vbCrLf, vbCrLf).Replace(vbNullChar, "")
|
||||
Ini = New IniCache With {.FileContent = Cache}
|
||||
Else
|
||||
'返回空文件信息
|
||||
Ini = New IniCache With {.FileContent = ""}
|
||||
End If
|
||||
If Not IniCacheList.ContainsKey(FileName) Then IniCacheList.Add(FileName, Ini) '避免多线程异步执行此方法时造成多次添加项
|
||||
Return Ini
|
||||
End If
|
||||
If IniCache.ContainsKey(FileName) Then Return IniCache(FileName)
|
||||
'读取文件
|
||||
If Not File.Exists(FileName) Then Return Nothing
|
||||
Dim Ini As New Dictionary(Of String, String)
|
||||
For Each Line In ReadFile(FileName).Split(vbCrLf.ToArray(), StringSplitOptions.RemoveEmptyEntries)
|
||||
Dim Index As Integer = Line.IndexOfF(":")
|
||||
If Index > 0 Then Ini.Add(Line.Substring(0, Index), Line.Substring(Index + 1))
|
||||
Next
|
||||
IniCache(FileName) = Ini
|
||||
Return Ini
|
||||
Catch ex As Exception
|
||||
Log(ex, "读取文件失败:" & FileName, LogLevel.Hint)
|
||||
Return New IniCache With {.FileContent = ""}
|
||||
Log(ex, $"生成 ini 文件缓存失败({FileName})", LogLevel.Hint)
|
||||
Return Nothing
|
||||
End Try
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 读取Ini文件,这可能会使用到缓存。
|
||||
''' 读取 ini 文件。这可能会使用到缓存。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
|
||||
''' <param name="Key">键。</param>
|
||||
''' <param name="DefaultValue">没有找到键时返回的默认值。</param>
|
||||
Public Function ReadIni(FileName As String, Key As String, Optional DefaultValue As String = "") As String
|
||||
Try
|
||||
'获取目前文件
|
||||
Dim NowIni As IniCache = IniGetContent(FileName)
|
||||
If IsNothing(NowIni) Then Return DefaultValue
|
||||
'使用缓存
|
||||
If NowIni.KVCache.ContainsKey(Key) Then Return If(NowIni.KVCache(Key), DefaultValue)
|
||||
'没有缓存,读取文件
|
||||
If NowIni.FileContent.Contains(vbCrLf & Key & ":") Then
|
||||
Dim Ret As String = Mid(NowIni.FileContent, NowIni.FileContent.IndexOf(vbCrLf & Key & ":") + 3)
|
||||
Ret = If(Ret.Contains(vbCrLf), Mid(Ret, 1, Ret.IndexOf(vbCrLf)), Ret).Replace(Key & ":", "")
|
||||
NowIni.KVCache.Add(Key, If(Ret = vbLf, "", Ret))
|
||||
Return If(Ret = vbLf, "", Ret)
|
||||
Else
|
||||
Return DefaultValue
|
||||
End If
|
||||
Catch ex As Exception
|
||||
'读取失败
|
||||
Return DefaultValue
|
||||
End Try
|
||||
Dim Content = IniGetContent(FileName)
|
||||
If Content Is Nothing OrElse Not Content.ContainsKey(Key) Then Return DefaultValue
|
||||
Return Content(Key)
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 写入ini文件,这会更新缓存。
|
||||
''' 写入 ini 文件,这会更新缓存。
|
||||
''' </summary>
|
||||
''' <param name="FileName">文件完整路径或简写文件名。简写将会使用“ApplicationName\文件名.ini”作为路径。</param>
|
||||
''' <param name="Key">键。</param>
|
||||
@@ -697,47 +676,41 @@ Public Module ModBase
|
||||
''' <remarks></remarks>
|
||||
Public Sub WriteIni(FileName As String, Key As String, Value As String)
|
||||
Try
|
||||
|
||||
'还原文件路径
|
||||
If Not FileName.Contains(":\") Then FileName = Path & "PCL\" & FileName & ".ini"
|
||||
If IsNothing(Value) Then Value = ""
|
||||
Value = Value.Replace(vbCrLf, "")
|
||||
'创建文件夹
|
||||
If Not Directory.Exists(GetPathFromFullPath(FileName)) Then Directory.CreateDirectory(GetPathFromFullPath(FileName))
|
||||
'预处理
|
||||
Key = Key.Replace(vbCr, "").Replace(vbLf, "").Replace(":", "")
|
||||
Value = Value.Replace(vbCr, "").Replace(vbLf, "") '允许 Value 中包含冒号
|
||||
'获取目前文件
|
||||
Dim NowFile As String = IniGetContent(FileName).FileContent
|
||||
If Not NowFile.EndsWith(vbCrLf) Then NowFile += vbCrLf
|
||||
'如果值一样就不处理
|
||||
If NowFile.Contains(vbCrLf & Key & ":" & Value & vbCrLf) Then Exit Sub
|
||||
'处理文件
|
||||
Dim FindResult As String = ReadIni(FileName, Key)
|
||||
If FindResult = "" AndAlso Not NowFile.Contains(vbCrLf & Key & ":") Then
|
||||
'不存在这个键
|
||||
NowFile = NowFile & vbCrLf & Key & ":" & Value & vbCrLf
|
||||
Else
|
||||
'存在这个键
|
||||
NowFile = NowFile.Replace(vbCrLf & Key & ":" & FindResult & vbCrLf, vbCrLf & Key & ":" & Value & vbCrLf)
|
||||
End If
|
||||
WriteFile(FileName, NowFile)
|
||||
'刷新目前缓存
|
||||
IniCacheList(FileName).FileContent = NowFile
|
||||
IniCacheList(FileName).KVCache.Remove(Key)
|
||||
IniCacheList(FileName).KVCache.Add(Key, Value)
|
||||
|
||||
Dim Content As Dictionary(Of String, String) = IniGetContent(FileName)
|
||||
If Content Is Nothing Then Content = New Dictionary(Of String, String)
|
||||
If Content.ContainsKey(Key) AndAlso Content(Key) = Value Then Exit Sub '如果值一样就不处理
|
||||
'更新缓存
|
||||
Content(Key) = Value
|
||||
'写入文件
|
||||
Dim FileContent As New StringBuilder
|
||||
For Each Pair In Content
|
||||
FileContent.Append(Pair.Key)
|
||||
FileContent.Append(":")
|
||||
FileContent.Append(Pair.Value)
|
||||
FileContent.Append(vbCrLf)
|
||||
Next
|
||||
If Not FileName.Contains(":\") Then FileName = $"{Path}PCL\{FileName}.ini"
|
||||
WriteFile(FileName, FileContent.ToString)
|
||||
Catch ex As Exception
|
||||
Log(ex, "写入文件失败:" & FileName & "/" & Key & ": " & Value)
|
||||
Log(ex, $"写入文件失败({FileName} -> {Key}:{Value})")
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
'路径处理
|
||||
''' <summary>
|
||||
''' 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。不包含路径将会抛出异常。
|
||||
''' 从文件路径或者 Url 获取不包含文件名的路径,或获取文件夹的父文件夹路径。
|
||||
''' 取决于原路径格式,路径以 / 或 \ 结尾。
|
||||
''' 不包含路径将会抛出异常。
|
||||
''' </summary>
|
||||
Public Function GetPathFromFullPath(FilePath As String) As String
|
||||
If Not (FilePath.Contains("\") OrElse FilePath.Contains("/")) Then Throw New Exception("不包含路径:" & FilePath)
|
||||
If FilePath.EndsWith("\") OrElse FilePath.EndsWith("/") Then
|
||||
If FilePath.EndsWithF("\") OrElse FilePath.EndsWithF("/") Then
|
||||
'是文件夹路径
|
||||
Dim IsRight As Boolean = FilePath.EndsWith("\")
|
||||
Dim IsRight As Boolean = FilePath.EndsWithF("\")
|
||||
FilePath = Left(FilePath, Len(FilePath) - 1)
|
||||
GetPathFromFullPath = Left(FilePath, FilePath.LastIndexOfAny({"\", "/"})) & If(IsRight, "\", "/")
|
||||
If GetPathFromFullPath = "" Then Throw New Exception("不包含路径:" & FilePath)
|
||||
@@ -752,11 +725,13 @@ Public Module ModBase
|
||||
''' </summary>
|
||||
Public Function GetFileNameFromPath(FilePath As String) As String
|
||||
FilePath = FilePath.Replace("/", "\")
|
||||
If FilePath.EndsWith("\") Then Throw New Exception("不包含文件名:" & FilePath)
|
||||
Dim FileName As String = FilePath.Split("\").Last.Split("?").First '去掉网络参数后的 ?
|
||||
If FileName.Length = 0 Then Throw New Exception("不包含文件名:" & FilePath)
|
||||
If FileName.Length > 250 Then Throw New PathTooLongException("文件名过长:" & FilePath)
|
||||
Return FileName
|
||||
If FilePath.EndsWithF("\") Then Throw New Exception("不包含文件名:" & FilePath)
|
||||
If FilePath.Contains("\") Then FilePath = FilePath.Substring(FilePath.LastIndexOfF("\") + 1)
|
||||
If FilePath.Contains("?") Then FilePath = FilePath.Substring(0, FilePath.IndexOfF("?")) '去掉网络参数后的 ?
|
||||
Dim length As Integer = FilePath.Length
|
||||
If length = 0 Then Throw New Exception("不包含文件名:" & FilePath)
|
||||
If length > 250 Then Throw New PathTooLongException("文件名过长:" & FilePath)
|
||||
Return FilePath
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 从文件路径或者 Url 获取不包含路径与扩展名的文件名。不包含文件名将会抛出异常。
|
||||
@@ -764,7 +739,7 @@ Public Module ModBase
|
||||
Public Function GetFileNameWithoutExtentionFromPath(FilePath As String) As String
|
||||
Dim Name As String = GetFileNameFromPath(FilePath)
|
||||
If Name.Contains(".") Then
|
||||
Return Name.Substring(0, Name.LastIndexOf("."))
|
||||
Return Name.Substring(0, Name.LastIndexOfF("."))
|
||||
Else
|
||||
Return Name
|
||||
End If
|
||||
@@ -773,8 +748,8 @@ Public Module ModBase
|
||||
''' 从文件夹路径获取文件夹名。
|
||||
''' </summary>
|
||||
Public Function GetFolderNameFromPath(FolderPath As String) As String
|
||||
If FolderPath.EndsWith(":\") OrElse FolderPath.EndsWith(":\\") Then Return FolderPath.Substring(0, 1)
|
||||
If FolderPath.EndsWith("\") OrElse FolderPath.EndsWith("/") Then FolderPath = Left(FolderPath, FolderPath.Length - 1)
|
||||
If FolderPath.EndsWithF(":\") OrElse FolderPath.EndsWithF(":\\") Then Return FolderPath.Substring(0, 1)
|
||||
If FolderPath.EndsWithF("\") OrElse FolderPath.EndsWithF("/") Then FolderPath = Left(FolderPath, FolderPath.Length - 1)
|
||||
Return GetFileNameFromPath(FolderPath)
|
||||
End Function
|
||||
|
||||
@@ -1027,7 +1002,7 @@ Public Module ModBase
|
||||
Public Function SelectFolder(Optional Title As String = "选择文件夹") As String
|
||||
Dim folderDialog As New Ookii.Dialogs.Wpf.VistaFolderBrowserDialog With {.ShowNewFolderButton = True, .RootFolder = Environment.SpecialFolder.Desktop, .Description = Title, .UseDescriptionForTitle = True}
|
||||
folderDialog.ShowDialog()
|
||||
SelectFolder = If(String.IsNullOrEmpty(folderDialog.SelectedPath), "", folderDialog.SelectedPath & If(folderDialog.SelectedPath.EndsWith("\"), "", "\"))
|
||||
SelectFolder = If(String.IsNullOrEmpty(folderDialog.SelectedPath), "", folderDialog.SelectedPath & If(folderDialog.SelectedPath.EndsWithF("\"), "", "\"))
|
||||
Log("[UI] 选择文件夹返回:" & SelectFolder)
|
||||
End Function
|
||||
|
||||
@@ -1038,8 +1013,8 @@ Public Module ModBase
|
||||
Public Function CheckPermission(Path As String) As Boolean
|
||||
Try
|
||||
If Path = "" Then Return False
|
||||
If Not Path.EndsWith("\") Then Path += "\"
|
||||
If Path.EndsWith(":\System Volume Information\") OrElse Path.EndsWith(":\$RECYCLE.BIN\") Then Return False
|
||||
If Not Path.EndsWithF("\") Then Path += "\"
|
||||
If Path.EndsWithF(":\System Volume Information\") OrElse Path.EndsWithF(":\$RECYCLE.BIN\") Then Return False
|
||||
If Not Directory.Exists(Path) Then Return False
|
||||
Dim FileName As String = "CheckPermission" & GetUuid()
|
||||
If File.Exists(Path & FileName) Then File.Delete(Path & FileName)
|
||||
@@ -1056,7 +1031,7 @@ Public Module ModBase
|
||||
''' </summary>
|
||||
Public Sub CheckPermissionWithException(Path As String)
|
||||
If String.IsNullOrWhiteSpace(Path) Then Throw New ArgumentNullException("文件夹名不能为空!")
|
||||
If Not Path.EndsWith("\") Then Path += "\"
|
||||
If Not Path.EndsWithF("\") Then Path += "\"
|
||||
If Not Directory.Exists(Path) Then Throw New DirectoryNotFoundException("文件夹不存在!")
|
||||
If File.Exists(Path & "CheckPermission") Then File.Delete(Path & "CheckPermission")
|
||||
File.Create(Path & "CheckPermission").Dispose()
|
||||
@@ -1245,7 +1220,7 @@ Re:
|
||||
Public Function ExtractFile(CompressFilePath As String, DestDirectory As String, Optional Encode As Encoding = Nothing) As Boolean
|
||||
Try
|
||||
Directory.CreateDirectory(DestDirectory)
|
||||
If CompressFilePath.EndsWith(".gz") Then
|
||||
If CompressFilePath.EndsWithF(".gz", True) Then
|
||||
'以 gz 方式解压
|
||||
Dim stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.ReadWrite), CompressionMode.Decompress)
|
||||
Dim decompressedFile As New FileStream(DestDirectory & GetFileNameFromPath(CompressFilePath).ToLower.Replace(".tar", "").Replace(".gz", ""), FileMode.OpenOrCreate, FileAccess.Write)
|
||||
@@ -1262,7 +1237,7 @@ Re:
|
||||
Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, If(Encode, Encoding.GetEncoding("GB18030")))
|
||||
For Each Entry As ZipArchiveEntry In Archive.Entries
|
||||
Dim DestinationPath As String = IO.Path.Combine(DestDirectory, Entry.FullName)
|
||||
If DestinationPath.EndsWith("\") OrElse DestinationPath.EndsWith("/") Then
|
||||
If DestinationPath.EndsWithF("\") OrElse DestinationPath.EndsWithF("/") Then
|
||||
Continue For '不创建空文件夹
|
||||
Else
|
||||
Directory.CreateDirectory(GetPathFromFullPath(DestinationPath))
|
||||
@@ -1318,9 +1293,9 @@ Re:
|
||||
''' </summary>
|
||||
Public Sub CopyDirectory(FromPath As String, ToPath As String)
|
||||
FromPath = FromPath.Replace("/", "\")
|
||||
If Not FromPath.EndsWith("\") Then FromPath &= "\"
|
||||
If Not FromPath.EndsWithF("\") Then FromPath &= "\"
|
||||
ToPath = ToPath.Replace("/", "\")
|
||||
If Not ToPath.EndsWith("\") Then ToPath &= "\"
|
||||
If Not ToPath.EndsWithF("\") Then ToPath &= "\"
|
||||
For Each File In EnumerateFiles(FromPath)
|
||||
CopyFile(File.FullName, File.FullName.Replace(FromPath, ToPath))
|
||||
Next
|
||||
@@ -1567,6 +1542,42 @@ Re:
|
||||
Return tmp.ToString()
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 高速的 StartsWith。
|
||||
''' </summary>
|
||||
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
|
||||
Public Function StartsWithF(Str As String, Prefix As String, Optional IgnoreCase As Boolean = False) As Boolean
|
||||
Return Str.StartsWith(Prefix, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 高速的 EndsWith。
|
||||
''' </summary>
|
||||
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
|
||||
Public Function EndsWithF(Str As String, Suffix As String, Optional IgnoreCase As Boolean = False) As Boolean
|
||||
Return Str.EndsWith(Suffix, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 支持可变大小写判断的 Contains。
|
||||
''' </summary>
|
||||
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
|
||||
Public Function ContainsF(Str As String, SubStr As String, Optional IgnoreCase As Boolean = False) As Boolean
|
||||
Return Str.IndexOf(SubStr, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal)) >= 0
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 高速的 IndexOf。
|
||||
''' </summary>
|
||||
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
|
||||
Public Function IndexOfF(Str As String, SubStr As String, Optional IgnoreCase As Boolean = False) As Integer
|
||||
Return Str.IndexOf(SubStr, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
|
||||
End Function
|
||||
''' <summary>
|
||||
''' 高速的 LastIndexOf。
|
||||
''' </summary>
|
||||
<Extension> <MethodImpl(MethodImplOptions.AggressiveInlining)>
|
||||
Public Function LastIndexOfF(Str As String, SubStr As String, Optional IgnoreCase As Boolean = False) As Integer
|
||||
Return Str.LastIndexOf(SubStr, If(IgnoreCase, StringComparison.OrdinalIgnoreCase, StringComparison.Ordinal))
|
||||
End Function
|
||||
|
||||
''' <summary>
|
||||
''' 输入 And 字符不会报错的 Val。
|
||||
''' </summary>
|
||||
@@ -1649,14 +1660,14 @@ Re:
|
||||
Source = Source.ToLower.Replace(" ", "")
|
||||
Query = Query.ToLower.Replace(" ", "")
|
||||
Dim sourceLength As Integer = Source.Length, queryLength As Integer = Query.Length '用于计算最后因数的长度缓存
|
||||
Do While qp < Query.Length
|
||||
Do While qp < queryLength
|
||||
'对 qp 作为开始位置计算
|
||||
Dim sp As Integer = 0, lenMax As Integer = 0, spMax As Integer = 0
|
||||
'查找以 qp 为头的最大子串
|
||||
Do While sp < Source.Length
|
||||
'对每个 sp 作为开始位置计算最大子串
|
||||
Dim len As Integer = 0
|
||||
Do While (qp + len) < Query.Length AndAlso (sp + len) < Source.Length AndAlso Source(sp + len) = Query(qp + len)
|
||||
Do While (qp + len) < queryLength AndAlso (sp + len) < Source.Length AndAlso Source(sp + len) = Query(qp + len)
|
||||
len += 1
|
||||
Loop
|
||||
'存储 len
|
||||
@@ -1671,7 +1682,7 @@ Re:
|
||||
Source = Source.Substring(0, spMax) & If(Source.Count > spMax + lenMax, Source.Substring(spMax + lenMax), String.Empty) '将源中的对应字段替换空
|
||||
'存储 lenSum
|
||||
Dim IncWeight = (Math.Pow(1.4, 3 + lenMax) - 3.6) '根据长度加成
|
||||
IncWeight *= (1 + 0.3 * Math.Max(0, 3 - Math.Abs(qp - spMax))) '根据位置加成
|
||||
IncWeight *= 1 + 0.3 * Math.Max(0, 3 - Math.Abs(qp - spMax)) '根据位置加成
|
||||
lenSum += IncWeight
|
||||
End If
|
||||
'根据结果增加 qp
|
||||
@@ -1721,23 +1732,24 @@ Re:
|
||||
Public Function Search(Of T)(Entries As List(Of SearchEntry(Of T)), Query As String, Optional MaxBlurCount As Integer = 5, Optional MinBlurSimilarity As Double = 0.1) As List(Of SearchEntry(Of T))
|
||||
'初始化
|
||||
Dim ResultList As New List(Of SearchEntry(Of T))
|
||||
If Entries.Count = 0 Then Return ResultList
|
||||
If Not Entries.Any() Then Return ResultList
|
||||
'进行搜索,获取相似信息
|
||||
For Each Entry In Entries
|
||||
Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query)
|
||||
Entry.AbsoluteRight = False
|
||||
For Each Pair In Entry.SearchSource
|
||||
If Pair.Key.ToLower.Replace(" ", "").Contains(Query.ToLower.Replace(" ", "")) Then Entry.AbsoluteRight = True
|
||||
If Pair.Key.Replace(" ", "").ContainsF(Query.Replace(" ", ""), True) Then Entry.AbsoluteRight = True
|
||||
Next
|
||||
Next
|
||||
'按照相似度进行排序
|
||||
Entries = Sort(Entries, Function(Left As SearchEntry(Of T), Right As SearchEntry(Of T)) As Boolean
|
||||
If Left.AbsoluteRight Xor Right.AbsoluteRight Then
|
||||
Return Left.AbsoluteRight
|
||||
Else
|
||||
Return Left.Similarity > Right.Similarity
|
||||
End If
|
||||
End Function)
|
||||
Entries = Sort(Entries,
|
||||
Function(Left, Right) As Boolean
|
||||
If Left.AbsoluteRight Xor Right.AbsoluteRight Then
|
||||
Return Left.AbsoluteRight
|
||||
Else
|
||||
Return Left.Similarity > Right.Similarity
|
||||
End If
|
||||
End Function)
|
||||
'返回结果
|
||||
Dim BlurCount As Integer = 0
|
||||
For Each Entry In Entries
|
||||
@@ -2089,7 +2101,7 @@ NextElement:
|
||||
Dim AllArguments() As String = Command.Split(" ")
|
||||
For i = 0 To AllArguments.Length - 1
|
||||
If AllArguments(i) = "-" & Name Then
|
||||
If AllArguments.Length = i + 1 OrElse AllArguments(i + 1).StartsWith("-") Then Return True
|
||||
If AllArguments.Length = i + 1 OrElse AllArguments(i + 1).StartsWithF("-") Then Return True
|
||||
Return AllArguments(i + 1)
|
||||
End If
|
||||
Next
|
||||
@@ -2116,7 +2128,7 @@ NextElement:
|
||||
''' </summary>
|
||||
Public Sub OpenWebsite(Url As String)
|
||||
Try
|
||||
If Not Url.ToLower.StartsWith("http") Then Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
|
||||
If Not Url.StartsWithF("http", True) Then Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!")
|
||||
Log("[System] 正在打开网页:" & Url)
|
||||
Process.Start(Url)
|
||||
Catch ex As Exception
|
||||
|
||||
@@ -490,7 +490,7 @@
|
||||
Select Case Loader.State
|
||||
Case LoadState.Finished
|
||||
'检查是否需要重启
|
||||
If Loader.GetType.Name.StartsWith("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
|
||||
If Loader.GetType.Name.StartsWithF("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
|
||||
If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
|
||||
If ModeDebug Then Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name)
|
||||
GoTo Restart
|
||||
@@ -500,7 +500,7 @@
|
||||
End If
|
||||
Case LoadState.Loading
|
||||
'检查是否需要重启
|
||||
If Loader.GetType.Name.StartsWith("LoaderTask") Then
|
||||
If Loader.GetType.Name.StartsWithF("LoaderTask") Then
|
||||
If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
|
||||
If ModeDebug Then Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, LogLevel.Developer)
|
||||
GoTo Restart
|
||||
@@ -517,9 +517,9 @@ Restart:
|
||||
If Input IsNot Nothing Then
|
||||
'若输入类型与下一个加载器相同才继续
|
||||
Dim LoaderType As String = Loader.GetType.Name
|
||||
If LoaderType.StartsWith("LoaderTask") OrElse LoaderType.StartsWith("LoaderCombo") Then
|
||||
If LoaderType.StartsWithF("LoaderTask") OrElse LoaderType.StartsWithF("LoaderCombo") Then
|
||||
Loader.Start(If(Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IsForceRestarting)
|
||||
ElseIf LoaderType.StartsWith("LoaderDownload") Then
|
||||
ElseIf LoaderType.StartsWithF("LoaderDownload") Then
|
||||
Loader.Start(If(TypeOf Input Is List(Of NetFile), Input, Nothing), IsForceRestarting)
|
||||
Else
|
||||
Throw New Exception("未知的加载器类型(" & LoaderType & ")")
|
||||
@@ -545,7 +545,7 @@ Restart:
|
||||
Public Shared Sub GetLoaderList(Loader As Object, ByRef List As List(Of LoaderBase), Optional RequireShow As Boolean = True)
|
||||
For Each SubLoader In Loader.Loaders
|
||||
If SubLoader.Show OrElse Not RequireShow Then List.Add(SubLoader)
|
||||
If SubLoader.GetType.Name.StartsWith("LoaderCombo") Then GetLoaderList(SubLoader, List)
|
||||
If SubLoader.GetType.Name.StartsWithF("LoaderCombo") Then GetLoaderList(SubLoader, List)
|
||||
Next
|
||||
End Sub
|
||||
''' <summary>
|
||||
@@ -606,7 +606,7 @@ Restart:
|
||||
End If
|
||||
RunInUi(Sub() FrmMain.BtnExtraDownload.Progress = LoaderTaskbarProgress)
|
||||
'更新任务栏信息
|
||||
If LoaderTaskbar.Count = 0 OrElse LoaderTaskbarProgress = 1 Then
|
||||
If Not LoaderTaskbar.Any() OrElse LoaderTaskbarProgress = 1 Then
|
||||
NewState = Shell.TaskbarItemProgressState.None
|
||||
ElseIf LoaderTaskbarProgress < 0.015 Then
|
||||
NewState = Shell.TaskbarItemProgressState.Indeterminate
|
||||
|
||||
@@ -189,7 +189,7 @@ RequestFinished:
|
||||
Dim Request As HttpWebRequest = WebRequest.Create(Url)
|
||||
Dim Result As New List(Of Byte)
|
||||
Try
|
||||
If Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then Request.ProtocolVersion = HttpVersion.Version11
|
||||
If Url.StartsWithF("https", True) Then Request.ProtocolVersion = HttpVersion.Version11
|
||||
Request.Timeout = Timeout
|
||||
Request.Accept = Accept
|
||||
SecretHeadersSign(Url, Request, UseBrowserUserAgent)
|
||||
@@ -397,7 +397,7 @@ RequestFinished:
|
||||
Req.ContentType = ContentType
|
||||
Req.Timeout = Timeout
|
||||
SecretHeadersSign(Url, Req, UseBrowserUserAgent)
|
||||
If Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then Req.ProtocolVersion = HttpVersion.Version11
|
||||
If Url.StartsWithF("https", True) Then Req.ProtocolVersion = HttpVersion.Version11
|
||||
If Method = "POST" OrElse Method = "PUT" Then
|
||||
Req.ContentLength = SendData.Length
|
||||
DataStream = Req.GetRequestStream()
|
||||
@@ -897,7 +897,7 @@ RequestFinished:
|
||||
''' 新建一个需要下载的文件。
|
||||
''' </summary>
|
||||
''' <param name="LocalPath">包含文件名的本地地址。</param>
|
||||
Public Sub New(Urls As String(), LocalPath As String, Optional Check As FileChecker = Nothing, Optional UseBrowserUserAgent As Boolean = False)
|
||||
Public Sub New(Urls As IEnumerable(Of String), LocalPath As String, Optional Check As FileChecker = Nothing, Optional UseBrowserUserAgent As Boolean = False)
|
||||
Dim Sources As New List(Of NetSource)
|
||||
Dim Count As Integer = 0
|
||||
Urls = Urls.Distinct.ToArray
|
||||
@@ -987,7 +987,7 @@ StartThread:
|
||||
'构建线程
|
||||
Dim ThreadUuid As Integer = GetUuid()
|
||||
SyncLock LockTasks
|
||||
If Tasks.Count = 0 Then Return False '由于中断,已没有可用任务
|
||||
If Not Tasks.Any() Then Return False '由于中断,已没有可用任务
|
||||
Th = New Thread(AddressOf Thread) With {.Name = "NetTask " & Tasks(0).Uuid & "/" & Uuid & " Download " & ThreadUuid & "#", .Priority = ThreadPriority.BelowNormal}
|
||||
End SyncLock
|
||||
ThreadInfo = New NetThread With {.Uuid = ThreadUuid, .DownloadStart = StartPosition, .Thread = Th, .Source = StartSource, .Task = Me, .State = NetState.WaitForDownload}
|
||||
@@ -1035,7 +1035,7 @@ StartThread:
|
||||
If SourcesOnce.Contains(Info.Source) AndAlso Not Info.Equals(Info.Source.Thread) Then GoTo SourceBreak
|
||||
'请求头
|
||||
HttpRequest = WebRequest.Create(Info.Source.Url)
|
||||
If Info.Source.Url.StartsWith("https", StringComparison.OrdinalIgnoreCase) Then HttpRequest.ProtocolVersion = HttpVersion.Version11
|
||||
If Info.Source.Url.StartsWithF("https", True) Then HttpRequest.ProtocolVersion = HttpVersion.Version11
|
||||
'HttpRequest.Proxy = Nothing 'new WebProxy(Ip, Port)
|
||||
HttpRequest.Timeout = Timeout
|
||||
HttpRequest.AddRange(Info.DownloadStart)
|
||||
@@ -1067,11 +1067,11 @@ StartThread:
|
||||
If ThreadFileSize > 50 * 1024 * 1024 Then
|
||||
For Each Drive As DriveInfo In DriveInfo.GetDrives
|
||||
Dim DriveName As String = Drive.Name.First.ToString
|
||||
Dim RequiredSpace = If(PathTemp.StartsWith(DriveName), ThreadFileSize * 1.1, 0) +
|
||||
If(LocalPath.StartsWith(DriveName), ThreadFileSize + 5 * 1024 * 1024, 0)
|
||||
Dim RequiredSpace = If(PathTemp.StartsWithF(DriveName), ThreadFileSize * 1.1, 0) +
|
||||
If(LocalPath.StartsWithF(DriveName), ThreadFileSize + 5 * 1024 * 1024, 0)
|
||||
If Drive.TotalFreeSpace < RequiredSpace Then
|
||||
Throw New Exception(DriveName & " 盘空间不足,无法进行下载。" & vbCrLf & "需要至少 " & GetString(RequiredSpace) & " 空间,但当前仅剩余 " & GetString(Drive.TotalFreeSpace) & "。" &
|
||||
If(PathTemp.StartsWith(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
|
||||
If(PathTemp.StartsWithF(DriveName), vbCrLf & vbCrLf & "下载时需要与文件同等大小的空间存放缓存,你可以在设置中调整缓存文件夹的位置。", ""))
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
@@ -1465,7 +1465,7 @@ Retry:
|
||||
Public Overrides Property Progress As Double
|
||||
Get
|
||||
If State >= LoadState.Finished Then Return 1
|
||||
If Files.Count = 0 Then Return 0 '必须返回 0,否则在获取列表的时候会错觉已经下载完了
|
||||
If Not Files.Any() Then Return 0 '必须返回 0,否则在获取列表的时候会错觉已经下载完了
|
||||
Return _Progress
|
||||
End Get
|
||||
Set(value As Double)
|
||||
@@ -1559,21 +1559,21 @@ NextElement:
|
||||
RunInNewThread(Sub()
|
||||
Try
|
||||
'输入检测
|
||||
If Files.Count = 0 Then
|
||||
If Not Files.Any() Then
|
||||
OnFinish()
|
||||
Exit Sub
|
||||
End If
|
||||
For Each File As NetFile In Files
|
||||
If File Is Nothing Then Throw New ArgumentException("存在空文件请求!")
|
||||
For Each Source As NetSource In File.Sources
|
||||
If Not (Source.Url.ToLower.StartsWith("https://") OrElse Source.Url.ToLower.StartsWith("http://")) Then
|
||||
If Not (Source.Url.StartsWithF("https://", True) OrElse Source.Url.StartsWithF("http://", True)) Then
|
||||
Source.Ex = New ArgumentException("输入的下载链接不正确!")
|
||||
Source.IsFailed = True
|
||||
End If
|
||||
Next
|
||||
If File.IsSourceFailed() Then Throw New ArgumentException("输入的下载链接不正确!")
|
||||
If Not File.LocalPath.ToLower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确!")
|
||||
If File.LocalPath.EndsWith("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径!")
|
||||
If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径!")
|
||||
'文件夹检测
|
||||
Dim DirPath As String = New FileInfo(File.LocalPath).Directory.FullName
|
||||
If Not Directory.Exists(DirPath) Then Directory.CreateDirectory(DirPath)
|
||||
@@ -1626,7 +1626,7 @@ NextElement:
|
||||
For Each File As NetFile In Files
|
||||
Dim ExistFilePath As String = Nothing
|
||||
'判断是否有已存在的文件
|
||||
If File.Check IsNot Nothing AndAlso McFolderList IsNot Nothing AndAlso PathMcFolder IsNot Nothing AndAlso File.Check.CanUseExistsFile AndAlso File.LocalPath.StartsWith(PathMcFolder) Then
|
||||
If File.Check IsNot Nothing AndAlso McFolderList IsNot Nothing AndAlso PathMcFolder IsNot Nothing AndAlso File.Check.CanUseExistsFile AndAlso File.LocalPath.StartsWithF(PathMcFolder) Then
|
||||
Dim Relative = File.LocalPath.Replace(PathMcFolder, "")
|
||||
For Each Folder In FolderList
|
||||
Dim Target = Folder & Relative
|
||||
@@ -1699,7 +1699,7 @@ Retry:
|
||||
Public Sub OnFail(ExList As List(Of Exception))
|
||||
SyncLock LockState
|
||||
If State > LoadState.Loading Then Exit Sub
|
||||
If ExList Is Nothing OrElse ExList.Count = 0 Then ExList = New List(Of Exception) From {New Exception("未知错误!")}
|
||||
If ExList Is Nothing OrElse Not ExList.Any() Then ExList = New List(Of Exception) From {New Exception("未知错误!")}
|
||||
'寻找第一个不是 404 的下载源
|
||||
Dim UsefulExs = ExList.Where(Function(e) Not e.Message.Contains("(404)")).ToList
|
||||
[Error] = If(UsefulExs.Count > 0, UsefulExs(0), ExList(0))
|
||||
|
||||
@@ -76,7 +76,7 @@ Public Class ValidateHttp
|
||||
Public Sub New()
|
||||
End Sub '用于 XAML 初始化
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
If Str.EndsWith("/") Then Str = Str.Substring(0, Str.Length - 1)
|
||||
If Str.EndsWithF("/") Then Str = Str.Substring(0, Str.Length - 1)
|
||||
If Not RegexCheck(Str, "^(http[s]?)\://") Then Return "输入的网址无效!"
|
||||
Return ""
|
||||
End Function
|
||||
@@ -149,7 +149,7 @@ Public Class ValidateExcept
|
||||
End Sub
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
For Each Ch As String In Excepts
|
||||
If Str.IndexOf(Ch, StringComparison.OrdinalIgnoreCase) >= 0 Then
|
||||
If Str.IndexOfF(Ch, StringComparison.OrdinalIgnoreCase) >= 0 Then
|
||||
If IsNothing(ErrorMessage) Then ErrorMessage = ""
|
||||
Return ErrorMessage.Replace("%", Ch)
|
||||
End If
|
||||
@@ -220,13 +220,13 @@ Public Class ValidateFolderName
|
||||
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查空格
|
||||
If Str.StartsWith(" ") Then Return "文件夹名不能以空格开头!"
|
||||
If Str.EndsWith(" ") Then Return "文件夹名不能以空格结尾!"
|
||||
If Str.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
|
||||
If Str.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
|
||||
'检查长度
|
||||
LengthCheck = New ValidateLength(1, 100).Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查尾部小数点
|
||||
If Str.EndsWith(".") Then Return "文件夹名不能以小数点结尾!"
|
||||
If Str.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
|
||||
'检查特殊字符
|
||||
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件夹名不可包含 % 字符!").Validate(Str)
|
||||
If Not CharactCheck = "" Then Return CharactCheck
|
||||
@@ -273,13 +273,13 @@ Public Class ValidateFileName
|
||||
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查空格
|
||||
If Str.StartsWith(" ") Then Return "文件名不能以空格开头!"
|
||||
If Str.EndsWith(" ") Then Return "文件名不能以空格结尾!"
|
||||
If Str.StartsWithF(" ") Then Return "文件名不能以空格开头!"
|
||||
If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
|
||||
'检查长度
|
||||
LengthCheck = New ValidateLength(1, 253).Validate(Str & If(ParentFolder, ""))
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查尾部小数点
|
||||
If Str.EndsWith(".") Then Return "文件名不能以小数点结尾!"
|
||||
If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
|
||||
'检查特殊字符
|
||||
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件名不可包含 % 字符!").Validate(Str)
|
||||
If Not CharactCheck = "" Then Return CharactCheck
|
||||
@@ -319,7 +319,7 @@ Public Class ValidateFolderPath
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
'去除尾部斜线,统一为 \
|
||||
Str = Str.Replace("/", "\")
|
||||
If Not Str.TrimEnd("\").EndsWith(":") Then Str = Str.TrimEnd("\")
|
||||
If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
|
||||
'检查是否为空
|
||||
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
@@ -327,15 +327,15 @@ Public Class ValidateFolderPath
|
||||
LengthCheck = New ValidateLength(1, 254).Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查开头
|
||||
If Str.StartsWith("\\Mac\") Then GoTo Fin
|
||||
If Str.StartsWithF("\\Mac\") Then GoTo Fin
|
||||
For Each Drive As DriveInfo In My.Computer.FileSystem.Drives
|
||||
If Str.ToUpper = Drive.Name Then Return ""
|
||||
If Str.ToUpper.StartsWith(Drive.Name) Then GoTo Fin
|
||||
If Str.StartsWithF(Drive.Name, True) Then GoTo Fin
|
||||
Next
|
||||
Return "文件夹路径头存在错误!"
|
||||
Fin:
|
||||
'对首层以外的路径检查
|
||||
For i = If(Str.StartsWith("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
|
||||
For i = If(Str.StartsWithF("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
|
||||
Dim SubStr As String = Str.Split("\")(i)
|
||||
'检查是否为空
|
||||
Dim SubLengthCheck As String = New ValidateNullOrWhiteSpace().Validate(SubStr)
|
||||
@@ -344,10 +344,10 @@ Fin:
|
||||
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "路径中存在无效字符!").Validate(SubStr)
|
||||
If Not CharactCheck = "" Then Return CharactCheck
|
||||
'检查头部空格
|
||||
If SubStr.StartsWith(" ") Then Return "文件夹名不能以空格开头!"
|
||||
If SubStr.EndsWith(" ") Then Return "文件夹名不能以空格结尾!"
|
||||
If SubStr.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
|
||||
If SubStr.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
|
||||
'检查尾部小数点
|
||||
If SubStr.EndsWith(".") Then Return "文件夹名不能以小数点结尾!"
|
||||
If SubStr.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
|
||||
'检查特殊字符串
|
||||
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr)
|
||||
If Not InvalidStrCheck = "" Then Return InvalidStrCheck
|
||||
|
||||
@@ -55,7 +55,7 @@ Public Class MyBitmap
|
||||
Public Sub New(FilePathOrResourceName As String)
|
||||
Try
|
||||
FilePathOrResourceName = FilePathOrResourceName.Replace("pack://application:,,,/images/", PathImage)
|
||||
If FilePathOrResourceName.StartsWith(PathImage) Then
|
||||
If FilePathOrResourceName.StartsWithF(PathImage) Then
|
||||
'使用缓存
|
||||
If BitmapCache.ContainsKey(FilePathOrResourceName) Then
|
||||
Pic = BitmapCache(FilePathOrResourceName).Pic
|
||||
|
||||
Reference in New Issue
Block a user