Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernised DFU Manifest #482

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 22 additions & 53 deletions iOSDFULibrary/Classes/Utilities/DFUPackage/Manifest/Manifest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,25 @@

import Foundation

class Manifest: NSObject {
// MARK: - ManifestJSONContainer

struct ManifestJSONContainer: Codable {

let manifest: Manifest
}

// MARK: - Manifest

struct Manifest: Codable {

// MARK: - Properties
// MARK: Properties

var application: ManifestFirmwareInfo?
var softdevice: ManifestFirmwareInfo?
var bootloader: ManifestFirmwareInfo?
var softdeviceBootloader: SoftdeviceBootloaderInfo?
let application: ManifestFirmwareInfo?
let softdevice: ManifestFirmwareInfo?
let bootloader: ManifestFirmwareInfo?
let softdeviceBootloader: SoftdeviceBootloaderInfo?

var valid: Bool {
var isValid: Bool {
// The manifest.json file may specify only:
// 1. a softdevice, a bootloader, or both combined (with, or without an app)
// 2. only the app
Expand All @@ -53,52 +62,12 @@ class Manifest: NSObject {
return count == 1 || (count == 0 && hasApplication)
}

// MARK: - Init
// MARK: Coding Keys

init(withJsonString aString: String) {
do {
guard let data = aString.data(using: String.Encoding.utf8),
let aDictionary = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? Dictionary<String, AnyObject> else {
throw Error.unableToParseJSON(description: "Unable to Decode root JSON Dictionary.")
}

guard let mainObject = aDictionary["manifest"] as? Dictionary<String, AnyObject> else {
throw Error.unableToParseJSON(description: "Manifest JSON Dictionary could not be found.")
}

if let applicationDictionary = mainObject["application"] as? Dictionary<String, AnyObject> {
self.application = ManifestFirmwareInfo(withDictionary: applicationDictionary)
}

if let bootloaderDictionary = mainObject["softdevice_bootloader"] as? Dictionary<String, AnyObject> {
self.softdeviceBootloader = SoftdeviceBootloaderInfo(withDictionary: bootloaderDictionary)
}

if let softDeviceDictionary = mainObject["softdevice"] as? Dictionary<String, AnyObject> {
self.softdevice = ManifestFirmwareInfo(withDictionary: softDeviceDictionary)
}

if let bootloaderDictionary = mainObject["bootloader"] as? Dictionary<String, AnyObject> {
self.bootloader = ManifestFirmwareInfo(withDictionary: bootloaderDictionary)
}
} catch {
print("Encountered an error while parsing manifest.json: \(error.localizedDescription)")
}
}
}

// MARK: - Manifest.Error

extension Manifest {

enum Error: Swift.Error, LocalizedError {
case unableToParseJSON(description: String)

var errorDescription: String? {
switch self {
case .unableToParseJSON(let description):
return description
}
}
enum CodingKeys: String, CodingKey {
case application = "application"
case softdeviceBootloader = "softdevice_bootloader"
case softdevice = "softdevice"
case bootloader = "bootloader"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,30 @@

import Foundation

class ManifestFirmwareInfo: NSObject {
var binFile: String? = nil
var datFile: String? = nil
// MARK: - ManifestFirmware

protocol ManifestFirmware {

var binFile: String? { get }
var datFile: String? { get }
}

extension ManifestFirmware {

var valid: Bool {
var isValid: Bool {
return binFile != nil // && datFile != nil The init packet was not required before SDK 7.1
dinesharjani marked this conversation as resolved.
Show resolved Hide resolved
}
}

// MARK: - ManifestFirmwareInfo

struct ManifestFirmwareInfo: ManifestFirmware, Codable {

let binFile: String?
let datFile: String?

init(withDictionary aDictionary : Dictionary<String, AnyObject>) {
if aDictionary.keys.contains("bin_file") {
binFile = String(describing: aDictionary["bin_file"]!)
}
if aDictionary.keys.contains("dat_file") {
datFile = String(describing: aDictionary["dat_file"]!)
}
enum CodingKeys: String, CodingKey {
case binFile = "bin_file"
case datFile = "dat_file"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,53 @@

import Foundation

class SoftdeviceBootloaderInfo: ManifestFirmwareInfo {
var blSize: UInt32 = 0
dinesharjani marked this conversation as resolved.
Show resolved Hide resolved
var sdSize: UInt32 = 0
// MARK: - SoftdeviceBootloaderInfo

struct SoftdeviceBootloaderInfo: ManifestFirmware, Codable {

override init(withDictionary aDictionary : Dictionary<String, AnyObject>) {
super.init(withDictionary: aDictionary)
if aDictionary.keys.contains("bl_size") {
blSize = (aDictionary["bl_size"]!).uint32Value
}
if aDictionary.keys.contains("sd_size") {
sdSize = (aDictionary["sd_size"]!).uint32Value
// MARK: Properties

let binFile: String?
let datFile: String?
let metadata: Metadata?
let _blSize: UInt32?
let _sdSize: UInt32?

// MARK: Computed Properties

var blSize: UInt32 {
return metadata?.blSize ?? _blSize ?? 0
}

var sdSize: UInt32 {
return metadata?.sdSize ?? _sdSize ?? 0
}

// MARK: CodingKeys

enum CodingKeys: String, CodingKey {
case binFile = "bin_file"
case datFile = "dat_file"
case metadata = "info_read_only_metadata"
dinesharjani marked this conversation as resolved.
Show resolved Hide resolved
case _blSize = "bl_size"
case _sdSize = "sd_size"
}
}

// MARK: - SoftdeviceBootloaderInfo.SecureMetadata

extension SoftdeviceBootloaderInfo {

struct Metadata: Codable {

let blSize: UInt32
let sdSize: UInt32

// MARK: CodingKeys

enum CodingKeys: String, CodingKey {
case blSize = "bl_size"
case sdSize = "sd_size"
}
}
}
26 changes: 14 additions & 12 deletions iOSDFULibrary/Classes/Utilities/Streams/DFUStreamZip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,20 +141,22 @@ internal class DFUStreamZip : DFUStream {
let manifestUrl = ZipArchive.findFile(DFUStreamZip.MANIFEST_FILE, inside: contentUrls)

if let url = manifestUrl {
// Read manifest content.
let json = try String(contentsOf: url)

// Deserialize json.
manifest = Manifest(withJsonString: json)
let jsonData = try Data(contentsOf: url)
if let debugJson = String(data: jsonData, encoding: .utf8) {
print("Manifest JSON: \(debugJson)")
}
manifest = try? JSONDecoder().decode(ManifestJSONContainer.self, from: jsonData).manifest
print(String(describing: manifest))

if manifest!.valid {
if let manifest = manifest, manifest.isValid {
// After validation we are sure that the manifest file contains at
// most one of: softdeviceBootloader, softdevice or bootloader.

// Look for and assign files specified in the manifest.
let softdeviceBootloaderType = FIRMWARE_TYPE_SOFTDEVICE | FIRMWARE_TYPE_BOOTLOADER
if type.rawValue & softdeviceBootloaderType == softdeviceBootloaderType {
if let softdeviceBootloader = manifest!.softdeviceBootloader {
if let softdeviceBootloader = manifest.softdeviceBootloader {
let (bin, dat) = try getContentOf(softdeviceBootloader, from: contentUrls)
systemBinaries = bin
systemInitPacket = dat
Expand All @@ -176,7 +178,7 @@ internal class DFUStreamZip : DFUStream {

let softdeviceType = FIRMWARE_TYPE_SOFTDEVICE
if type.rawValue & softdeviceType == softdeviceType {
if let softdevice = manifest!.softdevice {
if let softdevice = manifest.softdevice {
if systemBinaries != nil {
// It is not allowed to put both softdevice and softdeviceBootloader
// in the manifest.
Expand All @@ -192,7 +194,7 @@ internal class DFUStreamZip : DFUStream {

let bootloaderType = FIRMWARE_TYPE_BOOTLOADER
if type.rawValue & bootloaderType == bootloaderType {
if let bootloader = manifest!.bootloader {
if let bootloader = manifest.bootloader {
if systemBinaries != nil {
// It is not allowed to put both bootloader and softdeviceBootloader
// in the manifest.
Expand All @@ -208,7 +210,7 @@ internal class DFUStreamZip : DFUStream {

let applicationType = FIRMWARE_TYPE_APPLICATION
if type.rawValue & applicationType == applicationType {
if let application = manifest!.application {
if let application = manifest.application {
let (bin, dat) = try getContentOf(application, from: contentUrls)
appBinaries = bin
appInitPacket = dat
Expand Down Expand Up @@ -268,9 +270,9 @@ internal class DFUStreamZip : DFUStream {

- returns: Content bin and dat files.
*/
private func getContentOf(_ info: ManifestFirmwareInfo,
from contentUrls: [URL]) throws -> (Data, Data?) {
if !info.valid {
private func getContentOf<T: ManifestFirmware>(_ info: T,
from contentUrls: [URL]) throws -> (Data, Data?) {
guard info.isValid else {
throw DFUStreamZipError.invalidManifest
}

Expand Down