Data.swift 2.8 KB

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