Files
Leeksov 4647310322 GLEGram 12.5 — Initial public release
Based on Swiftgram 12.5 (Telegram iOS 12.5).
All GLEGram features ported and organized in GLEGram/ folder.

Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass,
Font Replacement, Fake Profile, Chat Export, Plugin System, and more.

See CHANGELOG_12.5.md for full details.
2026-04-06 09:48:12 +03:00

253 lines
8.7 KiB
Swift

//
// Created by Eric Firestone on 3/22/16.
// Copyright © 2016 Square, Inc. All rights reserved.
// Released under the Apache v2 License.
//
// Adapted from https://gist.github.com/blakemerryman/76312e1cbf8aec248167
// Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3
import Foundation
public let GlobBehaviorBashV3 = Glob.Behavior(
supportsGlobstar: false,
includesFilesFromRootOfGlobstar: false,
includesDirectoriesInResults: true,
includesFilesInResultsIfTrailingSlash: false
)
public let GlobBehaviorBashV4 = Glob.Behavior(
supportsGlobstar: true, // Matches Bash v4 with "shopt -s globstar" option
includesFilesFromRootOfGlobstar: true,
includesDirectoriesInResults: true,
includesFilesInResultsIfTrailingSlash: false
)
public let GlobBehaviorGradle = Glob.Behavior(
supportsGlobstar: true,
includesFilesFromRootOfGlobstar: true,
includesDirectoriesInResults: false,
includesFilesInResultsIfTrailingSlash: true
)
/**
Finds files on the file system using pattern matching.
*/
public class Glob: Collection {
/**
* Different glob implementations have different behaviors, so the behavior of this
* implementation is customizable.
*/
public struct Behavior {
// If true then a globstar ("**") causes matching to be done recursively in subdirectories.
// If false then "**" is treated the same as "*"
let supportsGlobstar: Bool
// If true the results from the directory where the globstar is declared will be included as well.
// For example, with the pattern "dir/**/*.ext" the fie "dir/file.ext" would be included if this
// property is true, and would be omitted if it's false.
let includesFilesFromRootOfGlobstar: Bool
// If false then the results will not include directory entries. This does not affect recursion depth.
let includesDirectoriesInResults: Bool
// If false and the last characters of the pattern are "**/" then only directories are returned in the results.
let includesFilesInResultsIfTrailingSlash: Bool
}
public static var defaultBehavior = GlobBehaviorBashV4
public static let defaultBlacklistedDirectories = ["node_modules", "Pods"]
@Atomic private var isDirectoryCache = [String: Bool]()
public let behavior: Behavior
public let blacklistedDirectories: [String]
var paths = [String]()
public var startIndex: Int { paths.startIndex }
public var endIndex: Int { paths.endIndex }
/// Initialize a glob
///
/// - Parameters:
/// - pattern: The pattern to use when building the list of matching directories.
/// - behavior: See individual descriptions on `Glob.Behavior` values.
/// - blacklistedDirectories: An array of directories to ignore at the root level of the project.
public init(pattern: String, behavior: Behavior = Glob.defaultBehavior, blacklistedDirectories: [String] = defaultBlacklistedDirectories) {
self.behavior = behavior
self.blacklistedDirectories = blacklistedDirectories
var adjustedPattern = pattern
let hasTrailingGlobstarSlash = pattern.hasSuffix("**/")
var includeFiles = !hasTrailingGlobstarSlash
if behavior.includesFilesInResultsIfTrailingSlash {
includeFiles = true
if hasTrailingGlobstarSlash {
// Grab the files too.
adjustedPattern += "*"
}
}
let patterns = behavior.supportsGlobstar ? expandGlobstar(pattern: adjustedPattern) : [adjustedPattern]
#if os(macOS)
paths = patterns.parallelMap { paths(usingPattern: $0, includeFiles: includeFiles) }.flatMap { $0 }
#else
// Parallel invocations of Glob on Linux seems to be causing unexpected crashes
paths = patterns.map { paths(usingPattern: $0, includeFiles: includeFiles) }.flatMap { $0 }
#endif
paths = Array(Set(paths)).sorted { lhs, rhs in
lhs.compare(rhs) != ComparisonResult.orderedDescending
}
clearCaches()
}
// MARK: Subscript Support
public subscript(i: Int) -> String {
paths[i]
}
// MARK: Protocol of IndexableBase
public func index(after i: Int) -> Int {
i + 1
}
// MARK: Private
private var globalFlags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK
private func executeGlob(pattern: UnsafePointer<CChar>, gt: UnsafeMutablePointer<glob_t>) -> Bool {
glob(pattern, globalFlags, nil, gt) == 0
}
private func expandGlobstar(pattern: String) -> [String] {
guard pattern.contains("**") else {
return [pattern]
}
var results = [String]()
var parts = pattern.components(separatedBy: "**")
let firstPart = parts.removeFirst()
var lastPart = parts.joined(separator: "**")
var directories: [URL]
if FileManager.default.fileExists(atPath: firstPart) {
do {
directories = try exploreDirectories(path: firstPart)
} catch {
directories = []
print("Error parsing file system item: \(error)")
}
} else {
directories = []
}
if behavior.includesFilesFromRootOfGlobstar {
// Check the base directory for the glob star as well.
directories.insert(URL(fileURLWithPath: firstPart), at: 0)
// Include the globstar root directory ("dir/") in a pattern like "dir/**" or "dir/**/"
if lastPart.isEmpty {
results.append(firstPart)
}
}
if lastPart.isEmpty {
lastPart = "*"
}
for directory in directories {
let partiallyResolvedPattern = directory.appendingPathComponent(lastPart)
let standardizedPattern = (partiallyResolvedPattern.relativePath as NSString).standardizingPath
results.append(contentsOf: expandGlobstar(pattern: standardizedPattern))
}
return results
}
private func exploreDirectories(path: String) throws -> [URL] {
try FileManager.default.contentsOfDirectory(atPath: path)
.compactMap { subpath -> [URL]? in
if blacklistedDirectories.contains(subpath) {
return nil
}
let firstLevel = URL(fileURLWithPath: path).appendingPathComponent(subpath, isDirectory: true)
guard isDirectory(path: firstLevel.path) else {
return nil
}
var subDirs: [URL] = try FileManager.default.subpathsOfDirectory(atPath: firstLevel.path)
.compactMap { subpath -> URL? in
let full = firstLevel.appendingPathComponent(subpath, isDirectory: true)
return isDirectory(path: full.path) ? full : nil
}
subDirs.append(firstLevel)
return subDirs
}
.joined()
.array()
}
private func isDirectory(path: String) -> Bool {
if let isDirectory = isDirectoryCache[path] {
return isDirectory
}
var isDirectoryBool = ObjCBool(false)
let isDirectory = FileManager.default.fileExists(atPath: path, isDirectory: &isDirectoryBool) && isDirectoryBool.boolValue
$isDirectoryCache.with { isDirectoryCache in
isDirectoryCache[path] = isDirectory
}
return isDirectory
}
private func clearCaches() {
$isDirectoryCache.with { isDirectoryCache in
isDirectoryCache.removeAll()
}
}
private func paths(usingPattern pattern: String, includeFiles: Bool) -> [String] {
var gt = glob_t()
defer { globfree(&gt) }
if executeGlob(pattern: pattern, gt: &gt) {
return populateFiles(gt: gt, includeFiles: includeFiles)
}
return []
}
private func populateFiles(gt: glob_t, includeFiles: Bool) -> [String] {
var paths = [String]()
let includeDirectories = behavior.includesDirectoriesInResults
#if os(macOS)
let matches = Int(gt.gl_matchc)
#else
let matches = Int(gt.gl_pathc)
#endif
for i in 0..<matches {
if let path = String(validatingUTF8: gt.gl_pathv[i]!) {
if !includeFiles || !includeDirectories {
let isDirectory = self.isDirectory(path: path)
if (!includeFiles && !isDirectory) || (!includeDirectories && isDirectory) {
continue
}
}
paths.append(path)
}
}
return paths
}
}
private extension Sequence {
func array() -> [Element] {
Array(self)
}
}