Data.swift 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //
  2. // NSData.swift
  3. // xDripG5
  4. //
  5. // Created by Nathan Racklyeft on 3/5/16.
  6. // Copyright © 2016 Nathan Racklyeft. 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 toInt<T: FixedWidthInteger>() -> T {
  23. return to(T.self)
  24. }
  25. func toBigEndian<T: FixedWidthInteger>(_ type: T.Type) -> T {
  26. return T(bigEndian: toDefaultEndian(type))
  27. }
  28. mutating func append<T: FixedWidthInteger>(_ newElement: T) {
  29. withUnsafePointer(to: newElement.littleEndian) { (ptr: UnsafePointer<T>) in
  30. append(UnsafeBufferPointer(start: ptr, count: 1))
  31. }
  32. }
  33. mutating func appendBigEndian<T: FixedWidthInteger>(_ newElement: T) {
  34. withUnsafePointer(to: newElement.bigEndian) { (ptr: UnsafePointer<T>) in
  35. append(UnsafeBufferPointer(start: ptr, count: 1))
  36. }
  37. }
  38. init<T: FixedWidthInteger>(_ value: T) {
  39. self = withUnsafePointer(to: value.littleEndian) { (ptr: UnsafePointer<T>) -> Data in
  40. return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1))
  41. }
  42. }
  43. init<T: FixedWidthInteger>(bigEndian value: T) {
  44. self = withUnsafePointer(to: value.bigEndian) { (ptr: UnsafePointer<T>) -> Data in
  45. return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1))
  46. }
  47. }
  48. }
  49. // String conversion methods, adapted from https://stackoverflow.com/questions/40276322/hex-binary-string-conversion-in-swift/40278391#40278391
  50. extension Data {
  51. init?(hexadecimalString: String) {
  52. self.init(capacity: hexadecimalString.utf16.count / 2)
  53. // Convert 0 ... 9, a ... f, A ...F to their decimal value,
  54. // return nil for all other input characters
  55. func decodeNibble(u: UInt16) -> UInt8? {
  56. switch u {
  57. case 0x30 ... 0x39: // '0'-'9'
  58. return UInt8(u - 0x30)
  59. case 0x41 ... 0x46: // 'A'-'F'
  60. return UInt8(u - 0x41 + 10) // 10 since 'A' is 10, not 0
  61. case 0x61 ... 0x66: // 'a'-'f'
  62. return UInt8(u - 0x61 + 10) // 10 since 'a' is 10, not 0
  63. default:
  64. return nil
  65. }
  66. }
  67. var even = true
  68. var byte: UInt8 = 0
  69. for c in hexadecimalString.utf16 {
  70. guard let val = decodeNibble(u: c) else { return nil }
  71. if even {
  72. byte = val << 4
  73. } else {
  74. byte += val
  75. self.append(byte)
  76. }
  77. even = !even
  78. }
  79. guard even else { return nil }
  80. }
  81. var hexadecimalString: String {
  82. return map { String(format: "%02hhx", $0) }.joined()
  83. }
  84. }