Data.swift 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. //
  2. // Data.swift
  3. // MinimedKit
  4. //
  5. // Created by Pete Schwamb on 3/19/23.
  6. //
  7. import Foundation
  8. extension Data {
  9. private func toDefaultEndian<T: FixedWidthInteger>(_: T.Type) -> T {
  10. return self.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> T in
  11. let bufferPointer = rawBufferPointer.bindMemory(to: T.self)
  12. guard let pointer = bufferPointer.baseAddress else {
  13. return 0
  14. }
  15. return T(pointer.pointee)
  16. })
  17. }
  18. func to<T: FixedWidthInteger>(_ type: T.Type) -> T {
  19. return T(littleEndian: toDefaultEndian(type))
  20. }
  21. func toBigEndian<T: FixedWidthInteger>(_ type: T.Type) -> T {
  22. return T(bigEndian: toDefaultEndian(type))
  23. }
  24. mutating func append<T: FixedWidthInteger>(_ newElement: T) {
  25. var element = newElement.littleEndian
  26. append(Data(bytes: &element, count: element.bitWidth / 8))
  27. }
  28. mutating func appendBigEndian<T: FixedWidthInteger>(_ newElement: T) {
  29. var element = newElement.bigEndian
  30. append(Data(bytes: &element, count: element.bitWidth / 8))
  31. }
  32. init<T: FixedWidthInteger>(_ value: T) {
  33. var value = value.littleEndian
  34. self.init(bytes: &value, count: value.bitWidth / 8)
  35. }
  36. init<T: FixedWidthInteger>(bigEndian value: T) {
  37. var value = value.bigEndian
  38. self.init(bytes: &value, count: value.bitWidth / 8)
  39. }
  40. }
  41. // String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391
  42. extension Data {
  43. init?(hexadecimalString: String) {
  44. self.init(capacity: hexadecimalString.utf16.count / 2)
  45. // Convert 0 ... 9, a ... f, A ...F to their decimal value,
  46. // return nil for all other input characters
  47. func decodeNibble(u: UInt16) -> UInt8? {
  48. switch u {
  49. case 0x30 ... 0x39: // '0'-'9'
  50. return UInt8(u - 0x30)
  51. case 0x41 ... 0x46: // 'A'-'F'
  52. return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0
  53. case 0x61 ... 0x66: // 'a'-'f'
  54. return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0
  55. default:
  56. return nil
  57. }
  58. }
  59. var even = true
  60. var byte: UInt8 = 0
  61. for c in hexadecimalString.utf16 {
  62. guard let val = decodeNibble(u: c) else { return nil }
  63. if even {
  64. byte = val << 4
  65. } else {
  66. byte += val
  67. self.append(byte)
  68. }
  69. even = !even
  70. }
  71. guard even else { return nil }
  72. }
  73. var hexadecimalString: String {
  74. return map { String(format: "%02hhx", $0) }.joined()
  75. }
  76. }