Загрузить двоичные структуры c из файла в структуры swift

Мне дали двоичный файл, созданный системой, предназначенной для поддержки встроенного оборудования. Файл был создан с использованием 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 в структуре и сохранить простоту, но я не знаю, как это лучше всего сделать.

Я застрял в использовании data [offset..length], что глупо, потому что оно создает копию данных, и я получаю странные исключения, которые заставили меня сделать копию, а затем другую копию: data.advanced (by : 0) [смещение..длина]. (Примечание: "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:). Должен быть способ получше, и зачем мне все это делать? Я знаю, что данные находятся в байтах, которые я пытаюсь выделить.

Объект Data - это то, что нужно для загрузки байтов с диска в память. Затем вы начинаете выбирать эти байты для инициализации ваших структур в соответствии со спецификациями.

Code Different 13.09.2018 21:41

Проблема XY. Определите чистый формат файла и запишите данные в этом формате. Не полагайтесь на представление и кодировку, зависящие от языка / машины. И не существует "формата данных C". Это исключительно зависит от вашей реализации и окружения.

too honest for this site 13.09.2018 22:47

@CodeDifferent - Как их выбрать? Не могли бы вы привести примеры синтаксиса? Я делал что-то вроде (см. Править).

Brandon M 13.09.2018 22:55

В Swift это считается неподходящим способом сохранения представления памяти в файл, поэтому нет современные соглашения и методы Swift для чтения такого файла. Пожалуйста, предоставьте достаточно подробностей. Показывать некоторую неуверенную структуру в Swift бесполезно. (Хотя я уверен, что ваш ContiguousArray никогда не заработает.)

OOPer 14.09.2018 02:33

Думаю, я собираюсь использовать изменяемый указатель данных.

Brandon M 14.09.2018 02:36

Чтобы уточнить, в конечном итоге моя цель - создать и записать файл. Я хотел начать с загрузки файла примера, который мне дали, чтобы я мог лучше понять формат. Я еще не уверен, но для меня может быть лучше просто использовать объект Mutable Data и просто добавлять к нему биты для создания структур в памяти, прежде чем выводить его как двоичный.

Brandon M 14.09.2018 16:27
2
6
231
0

Другие вопросы по теме