将二进制C结构从文件加载到Swift结构

时间:2018-09-13 19:31:22

标签: swift struct binaryfiles binary-data

已给我提供了一个二进制文件,该文件是由旨在支持嵌入式硬件的系统生成的。该文件是使用C生成的。我有一个电子表格,概述了该文件的格式。

我可能可以使用C加载该文件,尽管自从接触C以来已经有一段时间了,但是我真的很想坚持使用纯粹的Swift(4)并将该文件加载到正确的位置使用现代Swift约定和技术的各个Swift结构。

我找到了一些有关如何使用“不安全”指针的教程以及其他各种可能的解决方案,但是还不能完全以一种可以解决该文件复杂性的方式将它们放在一起。

以下是一些示例结构,以匹配我所面临的相似性,而为了简单起见,使其不变得非常复杂:

基本文件头

struct FileHeader {
  let index: Int32
  let id: UInt16
  let headerCRC: UInt16
}

具有多种值类型的结构

struct MiscRecord {
  let lengthOfRecordData: UInt16
  let crcOfRecordData: UInt16
  let resetCause: UInt8
  let disable: Bool
  let ratio: Float
}

带有数组的结构

struct AccessoryRecord {
  struct AccessoryConfiguration {
    let type: UInt8
    let startupTime: UInt32
    let shutoffTime: UInt32
  }

  let lengthOfRecordData: UInt16
  let crcOfRecordData: UInt16
  // Not even sure if ContiguousArray is the right thing or necessary.
  // I know that there will be a static number of 5 records present in the file.
  let accessoryConfigurations: ContiguousArray<AccessoryConfiguration>
}

布局

struct ConfigLayout {
  let fileHeader: FileHeader
  let miscRecord: MiscRecord
  let accessoryRecord: AccessoryRecord
}

总共,实际上总共有大约12个结构写入此文件。我知道每个结构开始的偏移量。我能够从磁盘加载文件并拥有一个数据对象。

数据对象正确吗?我应该以某种方式使用UnsafeMutableRawPointer吗?怎么样?

我可以想象,如果我知道数据的长度,我应该能够对结构进行类似于memcpy的操作并使它简单,但是我不知道这样做的最佳方法是什么。 / p>

我坚持使用data [offset..length],这很愚蠢,因为它创建了数据的副本,并且我遇到了怪异的异常,这些异常迫使我进行复制,然后再进行复制:data。先进的(by:0)[offset..length]。 (请注意:本段中的“ offset..length”应为[点点小于”,但小于字符会使文本显示混乱。)

总而言之,问题是:

将从C结构写入的二进制文件加载到一系列各自的Swift结构中的最佳方法是什么?

编辑:

这就是我一直试图做的事情:

init(withData: Data) {
    // fileHeader
    var offset = 0
    var length = MemoryLayout<FileHeader>.size + offset
    fileHeader = FileHeader(withData: withData[offset..<length])

    // miscRecord
    offset = length
    length = MemoryLayout<MiscRecord>.size + offset
    miscRecord = MiscRecord(withData: withData[offset..<length])

    // accessoryRecord
    offset = length
    length = MemoryLayout<AccessoryRecord>.size + offset
    accessoryRecord = AccessoryRecord(withData: withData[offset..<length])
}

...但是,我一直在withData[offset..<length](EXC_BAD_INSTRUCTION)看到运行时崩溃。

我能够通过以下方法解决它:

    init(withData: Data) {
      let unneccessaryDataCopy = withData.advanced(by: 0)

      // fileHeader
      var offset = 0
      var length = MemoryLayout<FileHeader>.size + offset
      fileHeader = FileHeader(withData: unneccessaryDataCopy[offset..<length])

      // miscRecord
      offset = length
      length = MemoryLayout<MiscRecord>.size + offset
      miscRecord = MiscRecord(withData: unneccessaryDataCopy[offset..<length])

      // accessoryRecord
      offset = length
      length = MemoryLayout<AccessoryRecord>.size + offset
      accessoryRecord = AccessoryRecord(withData: unneccessaryDataCopy[offset..<length])
    }

..但这很不好,因为数据被复制了两次。 (一次使用subset,一次使用advanced(by:)。必须有一个更好的方法,为什么我必须做所有这些事情?我知道数据位于我尝试分配的字节处。

0 个答案:

没有答案