-
Notifications
You must be signed in to change notification settings - Fork 406
/
BinaryDataScanner.swift
93 lines (71 loc) · 2 KB
/
BinaryDataScanner.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//
// BinaryDataScanner.swift
// Murphy
//
// Created by Dave Peck on 7/20/14.
// Copyright (c) 2014 Dave Peck. All rights reserved.
//
import Foundation
/*
Toying with tools to help read binary formats.
I've seen lots of approaches in swift that create
an intermediate object per-read (usually another NSData)
but even if these are lightweight under the hood,
it seems like overkill. Plus this taught me about <()> aka <Void>
And it would be nice to have an extension to
NSFileHandle too that does much the same.
*/
public protocol BinaryReadable {
var littleEndian: Self { get }
var bigEndian: Self { get }
}
extension UInt8: BinaryReadable {
public var littleEndian: UInt8 { return self }
public var bigEndian: UInt8 { return self }
}
extension UInt16: BinaryReadable {}
extension UInt32: BinaryReadable {}
extension UInt64: BinaryReadable {}
open class BinaryDataScanner {
let data: Data
let littleEndian: Bool
// let encoding: NSStringEncoding
var remaining: Int {
return data.count - position
}
var position: Int = 0
public init(data: Data, littleEndian: Bool) {
self.data = data
self.littleEndian = littleEndian
}
open func read<T: BinaryReadable>() -> T? {
if remaining < MemoryLayout<T>.size {
return nil
}
let v = data.withUnsafeBytes {
$0.baseAddress!.advanced(by: position).assumingMemoryBound(to: T.self).pointee
}
position += MemoryLayout<T>.size
return littleEndian ? v.littleEndian : v.bigEndian
}
// swiftlint:disable variable_name
open func skip(to n: Int) {
position = n
}
open func advance(by n: Int) {
position += n
}
/* convenience read funcs */
open func readByte() -> UInt8? {
return read()
}
open func read16() -> UInt16? {
return read()
}
open func read32() -> UInt32? {
return read()
}
open func read64() -> UInt64? {
return read()
}
}