2020-05-26 22:43:56 +08:00
|
|
|
import Foundation
|
|
|
|
|
|
|
|
public class Decoder {
|
|
|
|
|
2020-05-27 14:58:55 +08:00
|
|
|
typealias Output = (
|
2020-05-26 22:43:56 +08:00
|
|
|
payload: Payload,
|
2020-05-27 14:58:55 +08:00
|
|
|
controlRange: Range<Data.Index>,
|
|
|
|
payloadRange: Range<Data.Index>
|
2020-05-26 22:43:56 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
private let data: Data
|
|
|
|
private let controlByteInterpreter: ControlByteInterpreter
|
|
|
|
private let payloadInterpreter: PayloadInterpreter
|
2020-05-28 20:23:26 +08:00
|
|
|
private let sourceEndianness: Endianness = .big
|
2020-05-26 22:43:56 +08:00
|
|
|
|
|
|
|
init(
|
|
|
|
data: Data,
|
|
|
|
controlByteInterpreter: ControlByteInterpreter,
|
|
|
|
payloadInterpreter: PayloadInterpreter
|
|
|
|
) {
|
|
|
|
precondition(!data.isEmpty, "Can't decode an empty binary.")
|
|
|
|
self.data = data
|
|
|
|
self.controlByteInterpreter = controlByteInterpreter
|
|
|
|
self.payloadInterpreter = payloadInterpreter
|
|
|
|
}
|
|
|
|
|
2020-05-28 20:23:26 +08:00
|
|
|
public convenience init(_ data: Data) {
|
|
|
|
self.init(
|
|
|
|
data: data,
|
|
|
|
controlByteInterpreter: ControlByteInterpreter(
|
|
|
|
typeResolver: resolveType,
|
|
|
|
payloadSizeResolver: resolvePayloadSize,
|
|
|
|
definitionSizeResolver: resolveDefinitionSize
|
|
|
|
),
|
|
|
|
payloadInterpreter: PayloadInterpreter(
|
|
|
|
interpretArray: interpretArray,
|
|
|
|
interpretDataCacheContainer: interpretDataCacheContainer,
|
|
|
|
interpretDouble: interpretDouble,
|
|
|
|
interpretFloat: interpretFloat,
|
|
|
|
interpretInt32: interpretInt32,
|
|
|
|
interpretMap: interpretMap,
|
|
|
|
interpretPointer: interpretPointer,
|
|
|
|
interpretUInt16: interpretUInt16,
|
|
|
|
interpretUInt32: interpretUInt32,
|
|
|
|
interpretUInt64: interpretUInt64,
|
|
|
|
interpretUtf8String: interpretUtf8String
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-05-28 02:07:25 +08:00
|
|
|
private func rangeOfData(offset: Int, count: Int) -> Range<Data.Index> {
|
2020-05-26 22:43:56 +08:00
|
|
|
let sliceStart = data.index(
|
|
|
|
data.startIndex,
|
|
|
|
offsetBy: offset,
|
|
|
|
limitedBy: data.index(before: data.endIndex)
|
|
|
|
) ?? data.index(before: data.endIndex)
|
|
|
|
|
|
|
|
let sliceEnd = data.index(
|
|
|
|
sliceStart,
|
2020-05-28 02:07:25 +08:00
|
|
|
offsetBy: count,
|
|
|
|
limitedBy: data.endIndex
|
|
|
|
) ?? data.endIndex
|
2020-05-26 22:43:56 +08:00
|
|
|
|
2020-05-28 02:07:25 +08:00
|
|
|
return Range(uncheckedBounds: (lower: sliceStart, upper: sliceEnd))
|
2020-05-26 22:43:56 +08:00
|
|
|
}
|
|
|
|
|
2020-05-28 20:23:26 +08:00
|
|
|
internal func read(at controlByteOffset: Int, resolvePointers: Bool = true) -> Output? {
|
2020-05-26 22:43:56 +08:00
|
|
|
if controlByteOffset >= data.count { return nil }
|
2020-05-28 02:07:25 +08:00
|
|
|
let controlByteCandidate = data.subdata(in: rangeOfData(offset: controlByteOffset, count: 5))
|
2020-05-26 22:43:56 +08:00
|
|
|
guard let controlByteResult = controlByteInterpreter.interpret(
|
|
|
|
bytes: controlByteCandidate,
|
2020-05-28 20:23:26 +08:00
|
|
|
sourceEndianness: sourceEndianness
|
2020-05-26 22:43:56 +08:00
|
|
|
) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
let payloadStart = controlByteOffset + controlByteResult.definition.count
|
|
|
|
let payloadBytes: Data
|
|
|
|
if let controlByteCount = controlByteResult.controlByte.byteCount {
|
|
|
|
let payloadEnd = payloadStart + Int(controlByteCount)
|
2020-05-28 02:07:25 +08:00
|
|
|
if payloadEnd > data.endIndex { return nil }
|
|
|
|
// if !data.indices.contains(payloadEnd) { return nil }
|
|
|
|
payloadBytes = data.subdata(in: rangeOfData(offset: payloadStart, count: Int(controlByteCount)))
|
2020-05-26 22:43:56 +08:00
|
|
|
} else {
|
|
|
|
payloadBytes = Data()
|
|
|
|
}
|
|
|
|
|
2020-05-28 02:07:25 +08:00
|
|
|
guard let payloadResult = payloadInterpreter.interpret(
|
2020-05-26 22:43:56 +08:00
|
|
|
input: (
|
|
|
|
bytes: payloadBytes,
|
|
|
|
controlByte: controlByteResult.controlByte,
|
2020-05-28 20:23:26 +08:00
|
|
|
sourceEndianness: sourceEndianness,
|
2020-05-26 22:43:56 +08:00
|
|
|
controlStart: controlByteOffset,
|
|
|
|
payloadStart: payloadStart
|
|
|
|
),
|
|
|
|
using: self,
|
2020-05-27 14:58:55 +08:00
|
|
|
resolvePointers: resolvePointers
|
2020-05-28 02:07:25 +08:00
|
|
|
) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
let controlRange = Range(
|
|
|
|
uncheckedBounds: (
|
|
|
|
lower: controlByteOffset,
|
|
|
|
upper: controlByteOffset + controlByteResult.definition.count
|
|
|
|
)
|
|
|
|
)
|
|
|
|
let payloadRange = Range(
|
|
|
|
uncheckedBounds: (
|
|
|
|
lower: controlRange.upperBound,
|
|
|
|
upper: controlRange.upperBound + Int(payloadResult.definitionSize)
|
|
|
|
)
|
2020-05-26 22:43:56 +08:00
|
|
|
)
|
2020-05-28 02:07:25 +08:00
|
|
|
return (payloadResult.payload, controlRange, payloadRange)
|
2020-05-26 22:43:56 +08:00
|
|
|
}
|
|
|
|
|
2020-05-27 14:58:55 +08:00
|
|
|
public func read(at controlByteOffset: Int, resolvePointers: Bool = true) -> Payload? {
|
|
|
|
guard let output: Output = read(at: controlByteOffset, resolvePointers: resolvePointers) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return output.payload
|
|
|
|
}
|
|
|
|
|
2020-05-26 22:43:56 +08:00
|
|
|
}
|