179 lines
5.1 KiB
Swift
179 lines
5.1 KiB
Swift
//
|
|
// Data+Manipulation.swift
|
|
// TunnelKit
|
|
//
|
|
// Created by Davide De Rosa on 2/3/17.
|
|
// Copyright © 2018 London Trust Media. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
// hex -> Data conversion code from: http://stackoverflow.com/questions/32231926/nsdata-from-hex-string
|
|
// Data -> hex conversion code from: http://stackoverflow.com/questions/39075043/how-to-convert-data-to-hex-string-in-swift
|
|
|
|
extension UnicodeScalar {
|
|
var hexNibble: UInt8 {
|
|
let value = self.value
|
|
if 48 <= value && value <= 57 {
|
|
return UInt8(value - 48)
|
|
}
|
|
else if 65 <= value && value <= 70 {
|
|
return UInt8(value - 55)
|
|
}
|
|
else if 97 <= value && value <= 102 {
|
|
return UInt8(value - 87)
|
|
}
|
|
fatalError("\(self) not a legal hex nibble")
|
|
}
|
|
}
|
|
|
|
extension Data {
|
|
init(hex: String) {
|
|
let scalars = hex.unicodeScalars
|
|
var bytes = Array<UInt8>(repeating: 0, count: (scalars.count + 1) >> 1)
|
|
for (index, scalar) in scalars.enumerated() {
|
|
var nibble = scalar.hexNibble
|
|
if index & 1 == 0 {
|
|
nibble <<= 4
|
|
}
|
|
bytes[index >> 1] |= nibble
|
|
}
|
|
self = Data(bytes: bytes)
|
|
}
|
|
|
|
func toHex() -> String {
|
|
return map { String(format: "%02hhx", $0) }.joined()
|
|
}
|
|
|
|
mutating func zero() {
|
|
resetBytes(in: 0..<count)
|
|
}
|
|
|
|
mutating func zero(from: Int, to: Int) {
|
|
resetBytes(in: from..<to)
|
|
}
|
|
}
|
|
|
|
extension Data {
|
|
mutating func append(_ value: UInt16) {
|
|
var localValue = value
|
|
let buffer = UnsafeBufferPointer(start: &localValue, count: 1)
|
|
append(buffer)
|
|
}
|
|
|
|
mutating func append(_ value: UInt32) {
|
|
var localValue = value
|
|
let buffer = UnsafeBufferPointer(start: &localValue, count: 1)
|
|
append(buffer)
|
|
}
|
|
|
|
mutating func append(_ value: UInt64) {
|
|
var localValue = value
|
|
let buffer = UnsafeBufferPointer(start: &localValue, count: 1)
|
|
append(buffer)
|
|
}
|
|
|
|
mutating func append(nullTerminatedString: String) {
|
|
append(nullTerminatedString.data(using: .ascii)!)
|
|
append(UInt8(0))
|
|
}
|
|
|
|
func nullTerminatedString(from: Int) -> String? {
|
|
var nullOffset: Int?
|
|
for i in from..<count {
|
|
if (self[i] == 0) {
|
|
nullOffset = i
|
|
break
|
|
}
|
|
}
|
|
guard let to = nullOffset else {
|
|
return nil
|
|
}
|
|
return String(data: subdata(in: from..<to), encoding: .ascii)
|
|
}
|
|
|
|
// best
|
|
func UInt16Value(from: Int) -> UInt16 {
|
|
var value: UInt16 = 0
|
|
for i in 0..<2 {
|
|
let byte = self[from + i]
|
|
// print("byte: \(String(format: "%x", byte))")
|
|
value |= (UInt16(byte) << UInt16(8 * i))
|
|
}
|
|
// print("value: \(String(format: "%x", value))")
|
|
return value
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
func UInt16ValueFromPointers(from: Int) -> UInt16 {
|
|
return subdata(in: from..<(from + 2)).withUnsafeBytes { $0.pointee }
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
func UInt16ValueFromReboundPointers(from: Int) -> UInt16 {
|
|
let data = subdata(in: from..<(from + 2))
|
|
// print("data: \(data.toHex())")
|
|
let value = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UInt16 in
|
|
bytes.withMemoryRebound(to: UInt16.self, capacity: 1) {
|
|
$0.pointee
|
|
}
|
|
}
|
|
// print("value: \(String(format: "%x", value))")
|
|
return value
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
func UInt32ValueFromBuffer(from: Int) -> UInt32 {
|
|
var value: UInt32 = 0
|
|
for i in 0..<4 {
|
|
let byte = self[from + i]
|
|
// print("byte: \(String(format: "%x", byte))")
|
|
value |= (UInt32(byte) << UInt32(8 * i))
|
|
}
|
|
// print("value: \(String(format: "%x", value))")
|
|
return value
|
|
}
|
|
|
|
// best
|
|
func UInt32Value(from: Int) -> UInt32 {
|
|
return subdata(in: from..<(from + 4)).withUnsafeBytes { $0.pointee }
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
func UInt32ValueFromReboundPointers(from: Int) -> UInt32 {
|
|
let data = subdata(in: from..<(from + 4))
|
|
// print("data: \(data.toHex())")
|
|
let value = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> UInt32 in
|
|
bytes.withMemoryRebound(to: UInt32.self, capacity: 1) {
|
|
$0.pointee
|
|
}
|
|
}
|
|
// print("value: \(String(format: "%x", value))")
|
|
return value
|
|
}
|
|
|
|
func networkUInt16Value(from: Int) -> UInt16 {
|
|
return UInt16(bigEndian: subdata(in: from..<(from + 2)).withUnsafeBytes {
|
|
$0.pointee
|
|
})
|
|
}
|
|
|
|
func networkUInt32Value(from: Int) -> UInt32 {
|
|
return UInt32(bigEndian: subdata(in: from..<(from + 4)).withUnsafeBytes {
|
|
$0.pointee
|
|
})
|
|
}
|
|
}
|
|
|
|
extension Data {
|
|
func subdata(offset: Int, count: Int) -> Data {
|
|
return subdata(in: offset..<(offset + count))
|
|
}
|
|
}
|
|
|
|
extension Array where Element == Data {
|
|
var flatCount: Int {
|
|
return map { $0.count }.reduce(0) { $0 + $1 }
|
|
}
|
|
}
|