diff --git a/WDBFontOverwrite.xcodeproj/project.pbxproj b/WDBFontOverwrite.xcodeproj/project.pbxproj index 48c4322..05bba98 100644 --- a/WDBFontOverwrite.xcodeproj/project.pbxproj +++ b/WDBFontOverwrite.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 4FE5EF3529653188003384EC /* FontMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF3429653188003384EC /* FontMap.swift */; }; 4FE5EF38296561A5003384EC /* FileEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF37296561A5003384EC /* FileEditorView.swift */; }; 4FE5EF3A296561B2003384EC /* FileEditorView.ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF39296561B2003384EC /* FileEditorView.ViewModel.swift */; }; + 4FE5EF3E29664537003384EC /* ProgressManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF3D29664537003384EC /* ProgressManager.swift */; }; C55CF774295BA37D000DE71C /* woff2_wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C55CF772295BA37D000DE71C /* woff2_wrapper.cpp */; }; C55CF776295BA9B1000DE71C /* BrotliPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55CF775295BA9B1000DE71C /* BrotliPadding.swift */; }; C55CF778295BAF42000DE71C /* libwoff2enc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C55CF76E295BA346000DE71C /* libwoff2enc.a */; }; @@ -36,6 +37,7 @@ 4FE5EF3429653188003384EC /* FontMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontMap.swift; sourceTree = ""; }; 4FE5EF37296561A5003384EC /* FileEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileEditorView.swift; sourceTree = ""; }; 4FE5EF39296561B2003384EC /* FileEditorView.ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileEditorView.ViewModel.swift; sourceTree = ""; }; + 4FE5EF3D29664537003384EC /* ProgressManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressManager.swift; sourceTree = ""; }; C55CF76E295BA346000DE71C /* libwoff2enc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libwoff2enc.a; sourceTree = ""; }; C55CF76F295BA346000DE71C /* libwoff2common.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libwoff2common.a; sourceTree = ""; }; C55CF772295BA37D000DE71C /* woff2_wrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = woff2_wrapper.cpp; sourceTree = ""; }; @@ -81,6 +83,14 @@ path = FileEditor; sourceTree = ""; }; + 4FE5EF3C2966452A003384EC /* Progress */ = { + isa = PBXGroup; + children = ( + 4FE5EF3D29664537003384EC /* ProgressManager.swift */, + ); + path = Progress; + sourceTree = ""; + }; C55CF777295BAF42000DE71C /* Frameworks */ = { isa = PBXGroup; children = ( @@ -111,6 +121,7 @@ C5C9A7A72959351A00466D87 /* Info.plist */, C5A95F45295964AE00C58FDB /* PreviewFonts */, C5C9A7A22959341600466D87 /* RepackedFonts */, + 4FE5EF3C2966452A003384EC /* Progress */, 4FE5EF362965617D003384EC /* FileEditor */, C55CF775295BA9B1000DE71C /* BrotliPadding.swift */, C5C9A7942959261000466D87 /* ContentView.swift */, @@ -222,6 +233,7 @@ 4FE5EF3A296561B2003384EC /* FileEditorView.ViewModel.swift in Sources */, C5C9A7952959261000466D87 /* ContentView.swift in Sources */, C55CF776295BA9B1000DE71C /* BrotliPadding.swift in Sources */, + 4FE5EF3E29664537003384EC /* ProgressManager.swift in Sources */, C5C9A7932959261000466D87 /* WDBFontOverwriteApp.swift in Sources */, 4FE5EF38296561A5003384EC /* FileEditorView.swift in Sources */, C5C9A7AA2959417100466D87 /* vm_unaligned_copy_switch_race.c in Sources */, diff --git a/WDBFontOverwrite/ContentView.ViewModel.swift b/WDBFontOverwrite/ContentView.ViewModel.swift index 81faf0a..6067c19 100644 --- a/WDBFontOverwrite/ContentView.ViewModel.swift +++ b/WDBFontOverwrite/ContentView.ViewModel.swift @@ -42,7 +42,6 @@ extension ContentView { @Published var fontListSelection: Int = 0 @Published var customFontPickerSelection: Int = 0 @Published var message = "Choose a font." - @Published var progress: Progress! @Published var importPresented: Bool = false @Published var isPresentedFileEditor: Bool = false @Published var importTTCRepackMode: TTCRepackMode = .woff2 @@ -105,14 +104,13 @@ extension ContentView { guard selectedCustomFontType == .font else { // Overwrite emoji let emojiFont = FontMap.emojiCustomFont - overwriteWithCustomFont( + await overwriteWithCustomFont( name: emojiFont.localPath, - targetPath: emojiFont.targetPath, - progress: progress + targetPath: emojiFont.targetPath ) { - self.progress = nil self.message = $0 } + ProgressManager.shared.isBusy = false return } @@ -126,16 +124,15 @@ extension ContentView { for font in fonts { let key = FontMap.key(forFont: font) if let customFont = FontMap.fontMap[key] { - overwriteWithCustomFont( + await overwriteWithCustomFont( name: customFont.localPath, - targetPath: customFont.targetPath, - progress: progress + targetPath: customFont.targetPath ) { - self.progress = nil self.message = $0 } } } + ProgressManager.shared.isBusy = false } catch { print(error) message = "Failed to read imported fonts." diff --git a/WDBFontOverwrite/ContentView.swift b/WDBFontOverwrite/ContentView.swift index 53c0a5e..8f83cab 100644 --- a/WDBFontOverwrite/ContentView.swift +++ b/WDBFontOverwrite/ContentView.swift @@ -10,6 +10,7 @@ import UniformTypeIdentifiers struct ContentView: View { @StateObject private var viewModel = ViewModel() + @StateObject private var progressManager = ProgressManager.shared @Environment(\.openURL) private var openURL var body: some View { @@ -68,8 +69,12 @@ struct ContentView: View { } else { Text(viewModel.message) } - if let progress = viewModel.progress { - ProgressView(progress) + if progressManager.isBusy { + ProgressView( + value: progressManager.completedProgress, + total: progressManager.totalProgress + ) + .progressViewStyle(.linear) } } @@ -78,13 +83,10 @@ struct ContentView: View { ForEach(viewModel.fonts, id: \.name) { font in Button { viewModel.message = "Running" - viewModel.progress = Progress(totalUnitCount: 1) - overwriteWithFont( - name: font.repackedPath, - progress: viewModel.progress - ) { - viewModel.message = $0 - viewModel.progress = nil + Task { + await overwriteWithFont(name: font.repackedPath) { + viewModel.message = $0 + } } } label: { Text(font.name) @@ -142,8 +144,8 @@ struct ContentView: View { } } Button { + progressManager.isBusy = true viewModel.message = "Running" - viewModel.progress = Progress(totalUnitCount: 1) Task { await viewModel.batchOverwriteFonts() } diff --git a/WDBFontOverwrite/OverwriteFontImpl.swift b/WDBFontOverwrite/OverwriteFontImpl.swift index 2b9ca94..b770b57 100644 --- a/WDBFontOverwrite/OverwriteFontImpl.swift +++ b/WDBFontOverwrite/OverwriteFontImpl.swift @@ -8,16 +8,16 @@ import UIKit import UniformTypeIdentifiers -func overwriteWithFont(name: String, progress: Progress, completion: @escaping (String) -> Void) { +func overwriteWithFont(name: String, completion: @escaping (String) -> Void) async { let fontURL = Bundle.main.url( forResource: name, withExtension: nil, subdirectory: "RepackedFonts" )! - overwriteWithFont( + + await overwriteWithFont( fontURL: fontURL, pathToTargetFont: "/System/Library/Fonts/CoreUI/SFUI.ttf", - progress: progress, completion: completion ) } @@ -25,33 +25,29 @@ func overwriteWithFont(name: String, progress: Progress, completion: @escaping ( func overwriteWithFont( fontURL: URL, pathToTargetFont: String, - progress: Progress, completion: ((String) -> Void)? -) { - DispatchQueue.global(qos: .userInteractive).async { - let succeeded = overwriteWithFontImpl( - fontURL: fontURL, - pathToTargetFont: pathToTargetFont, - progress: progress - ) - - print("done") - - DispatchQueue.main.async { - completion?(succeeded ? "Success: force close an app to see results" : "Failed") - } - } +) async { + let succeeded = overwriteWithFontImpl( + fontURL: fontURL, + pathToTargetFont: pathToTargetFont + ) + + await MainActor.run(body: { + completion?(succeeded ? "Success: force close an app to see results" : "Failed") + }) } /// Overwrite the system font with the given font using CVE-2022-46689. /// The font must be specially prepared so that it skips past the last byte in every 16KB page. /// See BrotliPadding.swift for an implementation that adds this padding to WOFF2 fonts. -func overwriteWithFontImpl(fontURL: URL, pathToTargetFont: String, progress: Progress) -> Bool { +func overwriteWithFontImpl(fontURL: URL, pathToTargetFont: String) -> Bool { var fontData = try! Data(contentsOf: fontURL) #if false - let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[ - 0 - ].path + let documentDirectory = FileManager.default.urls( + for: .documentDirectory, + in: .userDomainMask + )[0].path + let pathToTargetFont = documentDirectory + "/SFUI.ttf" let pathToRealTargetFont = "/System/Library/Fonts/CoreUI/SFUI.ttf" let origData = try! Data(contentsOf: URL(fileURLWithPath: pathToRealTargetFont)) @@ -103,16 +99,18 @@ func overwriteWithFontImpl(fontURL: URL, pathToTargetFont: String, progress: Pro return false } - // TODO(zhuowei): probably not the right way to use NSProgress... - let overwriteProgress = Progress(totalUnitCount: Int64(fontData.count)) - progress.addChild(overwriteProgress, withPendingUnitCount: Int64(1)) + DispatchQueue.main.async { + ProgressManager.shared.totalProgress = Double(fontData.count) + } // for every 16k chunk, rewrite print(Date()) for chunkOff in stride(from: 0, to: fontData.count, by: 0x4000) { print(String(format: "%lx", chunkOff)) if chunkOff % 0x40000 == 0 { - overwriteProgress.completedUnitCount = Int64(chunkOff) + DispatchQueue.main.async { + ProgressManager.shared.completedProgress = Double(chunkOff) + } } // we only rewrite 16383 bytes out of every 16384 bytes. let dataChunk = fontData[chunkOff.. Void)? = nil -) { +) async { let documentDirectory = FileManager.default.urls( for: .documentDirectory, in: .userDomainMask @@ -165,24 +164,20 @@ func overwriteWithCustomFont( completion?("No custom font imported") return } - - print("b4 switch") switch targetPath { case .single(let path): - overwriteWithFont( + await overwriteWithFont( fontURL: fontURL, pathToTargetFont: path, - progress: progress, completion: completion ) case .many(let paths): for path in paths { if (access(path, F_OK) == 0) { - overwriteWithFont( + await overwriteWithFont( fontURL: fontURL, pathToTargetFont: path, - progress: progress, completion: completion ) } diff --git a/WDBFontOverwrite/Progress/ProgressManager.swift b/WDBFontOverwrite/Progress/ProgressManager.swift new file mode 100644 index 0000000..f5f71a4 --- /dev/null +++ b/WDBFontOverwrite/Progress/ProgressManager.swift @@ -0,0 +1,15 @@ +// +// ProgressManager.swift +// WDBFontOverwrite +// +// Created by Noah Little on 5/1/2023. +// + +import Foundation + +final class ProgressManager: ObservableObject { + static let shared = ProgressManager() + var isBusy: Bool = false + @Published var completedProgress: Double = 0 + @Published var totalProgress: Double = 0 +}