From 67c633b2a3cc8afd94da16577f4abb04613ea417 Mon Sep 17 00:00:00 2001 From: TechUnRestricted <83237609+TechUnRestricted@users.noreply.github.com> Date: Thu, 26 May 2022 21:12:34 +0300 Subject: [PATCH] Safe [Data -> Int32] conversion --- PSDirectSender.xcodeproj/project.pbxproj | 6 ++- PSDirectSender/SFOExplorer.swift | 48 ++++++++++++--------- PSDirectSender/Screens/QueueView.swift | 45 +++++++++++-------- PSDirectSender/ru.lproj/Localizable.strings | 2 + README.md | 4 +- 5 files changed, 62 insertions(+), 43 deletions(-) diff --git a/PSDirectSender.xcodeproj/project.pbxproj b/PSDirectSender.xcodeproj/project.pbxproj index 52fcb0c..42d797c 100644 --- a/PSDirectSender.xcodeproj/project.pbxproj +++ b/PSDirectSender.xcodeproj/project.pbxproj @@ -455,12 +455,13 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PSDirectSender/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = com.techunrestricted.PSDirectSender; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -484,12 +485,13 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PSDirectSender/Info.plist; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1; PRODUCT_BUNDLE_IDENTIFIER = com.techunrestricted.PSDirectSender; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/PSDirectSender/SFOExplorer.swift b/PSDirectSender/SFOExplorer.swift index fc6124c..7270b63 100644 --- a/PSDirectSender/SFOExplorer.swift +++ b/PSDirectSender/SFOExplorer.swift @@ -8,12 +8,15 @@ import Foundation fileprivate extension Data { - var integerRepresentation: Int32 { - return self.withUnsafeBytes({(pointer: UnsafeRawBufferPointer) -> Int32 in - return pointer.load(as: Int32.self) - }) + var integerRepresentation: Int32? { + if self.count < MemoryLayout.size { + return nil + } else { + return self.withUnsafeBytes({(pointer: UnsafeRawBufferPointer) -> Int32 in + return pointer.load(as: Int32.self) + }) + } } - var stringRepresentation: String { return String(decoding: self, as: UTF8.self) } @@ -74,22 +77,24 @@ class SFOExplorer { } private func getParamSFOOffset(fileHandler: FileHandle) -> UInt32? { - let filesCount = loadFileDataBlocks(from: 0x00C, - bytesCount: 4, - fileHandler: fileHandler) - .integerRepresentation - .bigEndian + guard let filesCount = loadFileDataBlocks(from: 0x00C, + bytesCount: 4, + fileHandler: fileHandler) + .integerRepresentation? + .bigEndian + else { return nil } if filesCount >= 256 { print("[ERROR:] Files count >= 256 (current: \(filesCount)). It's can't be real.") return nil } - let tableOffset = loadFileDataBlocks(from: 0x018, - bytesCount: 4, - fileHandler: fileHandler) - .integerRepresentation - .bigEndian + guard let tableOffset = loadFileDataBlocks(from: 0x018, + bytesCount: 4, + fileHandler: fileHandler) + .integerRepresentation? + .bigEndian + else { return nil } let tableData = loadFileDataBlocks( from: UInt64(tableOffset), @@ -101,6 +106,7 @@ class SFOExplorer { for table in tableStruct where table.id == 1048576 { return table.offset } + return nil } @@ -116,11 +122,11 @@ class SFOExplorer { /// MAGIC /* let magic: Int32 = loadFileDataBlocks( - from: 0, - bytesCount: 4, - fileHandler: fileHandler - ).integerRepresentation - */ + from: 0, + bytesCount: 4, + fileHandler: fileHandler + ).integerRepresentation + */ /// PARAM.SFO guard let offset32: UInt32 = getParamSFOOffset(fileHandler: fileHandler) else { @@ -171,7 +177,7 @@ class SFOExplorer { values.append(entryData.stringRepresentation.replacingOccurrences(of: "\0", with: "")) case 1028: /* Integer */ - values.append(String(entryData.integerRepresentation)) + values.append(String(entryData.integerRepresentation ?? -1)) default: break } diff --git a/PSDirectSender/Screens/QueueView.swift b/PSDirectSender/Screens/QueueView.swift index 44d55da..d785cdd 100644 --- a/PSDirectSender/Screens/QueueView.swift +++ b/PSDirectSender/Screens/QueueView.swift @@ -63,7 +63,7 @@ struct QueueView: View { @EnvironmentObject var logsCollector: LogsCollector @State fileprivate var alert: AlertIdentifier? - @State var packageURLs: [Package] = [] + @State var packages: [Package] = [] @State private var selection: Set = [] @State var isInDropArea: Bool = false @@ -83,7 +83,7 @@ struct QueueView: View { }.padding() List(selection: $selection) { - ForEach(packageURLs, id: \.id) { package in + ForEach(packages, id: \.id) { package in HStack { Image(systemName: "shippingbox") Text("\(package.title_id ?? package.url.lastPathComponent)") @@ -106,10 +106,17 @@ struct QueueView: View { if let url = object, url.pathExtension == "pkg"{ let packageDetails = SFOExplorer().getParamSFOData(url: url) var title: String? + if let packageDetails = packageDetails { title = packageDetails["TITLE"] + if let title = title { + logsCollector.addLog("Package name defined: \"\(title)\" (\"\(url)\")") + } else { + logsCollector.addLog("Package name for (\"\(url)\") is undefined. Maybe the package is damaged or not compatible with the PS4 system.") + } } - packageURLs.append(Package(url: url, title_id: title)) + + packages.append(Package(url: url, title_id: title)) } } } @@ -123,7 +130,7 @@ struct QueueView: View { Image(systemName: "shippingbox") .resizable() .frame(width: 100, height: 100) - Text(#"Drop ".pkg" files"#) + Text("Drop .pkg files") .font(.title) } .opacity(0.5) @@ -172,21 +179,21 @@ struct QueueView: View { } private func deleteSelection() { - packageURLs.removeAll { selection.contains($0.id) } + packages.removeAll { selection.contains($0.id) } selection.removeAll() } fileprivate func AddButton() -> ColorButton { return ColorButton(text: "Add", color: .orange, image: Image(systemName: "plus.rectangle.on.rectangle"), action: { - let packages = selectPackages() - for package in packages { + let selectedPackages = selectPackages() + for package in selectedPackages { if let package = package { let packageDetails = SFOExplorer().getParamSFOData(url: package) var title: String? if let packageDetails = packageDetails { title = packageDetails["TITLE"] } - packageURLs.append(Package(url: package, title_id: title)) + packages.append(Package(url: package, title_id: title)) } } }) @@ -194,7 +201,7 @@ struct QueueView: View { fileprivate func SendButton() -> ColorButton { return ColorButton(text: "Send", color: .green, image: Image(systemName: "arrow.up.forward.app"), action: { - if packageURLs.isEmpty { return } + if packages.isEmpty { return } if connection.serverIP.isEmpty || connection.serverPort.isEmpty { connection.generateServerDetails() @@ -214,13 +221,13 @@ struct QueueView: View { loadingScreenIsShown = true DispatchQueue.global(qos: .background).async { - for index in packageURLs.indices { - if packageURLs[index].state == .sendSuccess { + for index in packages.indices { + if packages[index].state == .sendSuccess { continue } - let alias = createTempDirPackageAlias(package: packageURLs[index])! + let alias = createTempDirPackageAlias(package: packages[index])! - logsCollector.addLog("Creating package alias (\"\(packageURLs[index].url.path)\" -> \"\(tempDirectory.path)/\(alias)\").") + logsCollector.addLog("Creating package alias (\"\(packages[index].url.path)\" -> \"\(tempDirectory.path)/\(alias)\").") logsCollector.addLog("Sending package \"\(alias)\" to the console (IP: \(connection.consoleIP), Port: \(connection.consolePort))") let response = sendPackagesToConsole(packageFilename: alias, connection: connection) @@ -234,15 +241,15 @@ struct QueueView: View { } break } else if let response = response as? SendSuccess { - logsCollector.addLog("Successfully sent \(packageURLs[index].url) [Package Link: \"\(packageURLs[index].id).pkg\", id: \(response.taskID), title: \"\(response.title)\"]") + logsCollector.addLog("Successfully sent \(packages[index].url) [Package Link: \"\(packages[index].id).pkg\", id: \(response.taskID), title: \"\(response.title)\"]") DispatchQueue.main.async { - packageURLs[index].state = .sendSuccess - packageURLs[index].task_id = response.taskID + packages[index].state = .sendSuccess + packages[index].task_id = response.taskID } } else if let response = response as? SendFailure { - logsCollector.addLog("An error occurred while sending \(packageURLs[index].url) [\(packageURLs[index].id).pkg] {ERROR: \(response.error)}") + logsCollector.addLog("An error occurred while sending \(packages[index].url) [\(packages[index].id).pkg] {ERROR: \(response.error)}") DispatchQueue.main.async { - packageURLs[index].state = .sendFailure + packages[index].state = .sendFailure } break } @@ -267,7 +274,7 @@ struct QueueView_Previews: PreviewProvider { @EnvironmentObject var connection: ConnectionDetails static var previews: some View { - let view = QueueView(packageURLs: [ + let view = QueueView(packages: [ Package(url: URL(string: "https://example.com/game.pkg")!), Package(url: URL(string: "https://example.com/dlc.pkg")!, state: .sendSuccess), Package(url: URL(string: "https://example.com/dlc.pkg")!, state: .sendFailure) diff --git a/PSDirectSender/ru.lproj/Localizable.strings b/PSDirectSender/ru.lproj/Localizable.strings index fa092ec..86d0fd1 100644 --- a/PSDirectSender/ru.lproj/Localizable.strings +++ b/PSDirectSender/ru.lproj/Localizable.strings @@ -113,3 +113,5 @@ "Stopped" = "Остановлен"; "Invalid configuration data" = "Неверные данные конфигурации"; + +"Drop .pkg files" = "Перетащите файлы .pkg"; diff --git a/README.md b/README.md index 5862821..4801380 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,11 @@ ## Current features * Sending local .pkg files * Drag'n'drop support + * Automatic .pkg title detection * Creating aliases for files for correct sending .pkg containing spaces in the name. * Advanced logging system * Automatic appropriate data generation for the server (IP, Port) + * English / Russian language support image @@ -27,7 +29,7 @@ * Wired or wireless connection to the same network as PS4 * Local PS4-compatible .pkg files -# Usage +## Usage
  1. Open PSDirectSender
  2. Go to the Configuration section