Skip to content

Commit 2bae26b

Browse files
authored
Merge pull request #9 from p-x9/feature/binary-parse-lib
Extract generic binary analysis utilities into a shared library
2 parents c373616 + 71364cd commit 2bae26b

13 files changed

+60
-797
lines changed

Package.resolved

Lines changed: 20 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,27 @@ let package = Package(
1111
),
1212
],
1313
dependencies: [
14-
.package(url: "https://github.com/p-x9/swift-fileio.git", from: "0.9.0")
14+
.package(
15+
url: "https://github.com/p-x9/swift-binary-parse-support.git",
16+
from: "0.2.1"
17+
),
18+
.package(
19+
url: "https://github.com/p-x9/swift-fileio.git",
20+
from: "0.9.0"
21+
),
22+
.package(
23+
url: "https://github.com/p-x9/swift-fileio-extra.git",
24+
from: "0.2.2"
25+
),
1526
],
1627
targets: [
1728
.target(
1829
name: "ELFKit",
1930
dependencies: [
2031
"ELFKitC",
21-
.product(name: "FileIO", package: "swift-fileio")
32+
.product(name: "BinaryParseSupport", package: "swift-binary-parse-support"),
33+
.product(name: "FileIO", package: "swift-fileio"),
34+
.product(name: "FileIOBinary", package: "swift-fileio-extra")
2235
]
2336
),
2437
.target(

Sources/ELFKit/ELFFile+Strings.swift

Lines changed: 2 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,9 @@ internal import FileIO
1313
@_implementationOnly import FileIO
1414
#endif
1515

16-
public protocol StringTable<Encoding>: Sequence<StringTableEntry> {
17-
associatedtype Encoding: _UnicodeEncoding
18-
}
19-
2016
extension ELFFile {
17+
public typealias UnicodeStrings = BinaryParseSupport.UnicodeStrings
2118
public typealias Strings = UnicodeStrings<UTF8>
22-
23-
public struct UnicodeStrings<Encoding: _UnicodeEncoding>: StringTable {
24-
typealias FileSlice = File.FileSlice
25-
26-
private let fileSlice: FileSlice
27-
28-
/// file offset of string table start
29-
public let offset: Int
30-
31-
/// size of string table
32-
public let size: Int
33-
34-
public let isSwapped: Bool
35-
36-
public func makeIterator() -> Iterator {
37-
.init(fileSlice: fileSlice, isSwapped: isSwapped)
38-
}
39-
}
4019
}
4120

4221
extension ELFFile.UnicodeStrings {
@@ -51,95 +30,10 @@ extension ELFFile.UnicodeStrings {
5130
length: size
5231
)
5332
self.init(
54-
fileSlice: fileSlice,
33+
source: fileSlice,
5534
offset: offset,
5635
size: size,
5736
isSwapped: isSwapped
5837
)
5938
}
6039
}
61-
62-
extension ELFFile.UnicodeStrings {
63-
public var data: Data? {
64-
try? fileSlice.readAllData()
65-
}
66-
}
67-
68-
extension ELFFile.UnicodeStrings {
69-
public struct Iterator: IteratorProtocol {
70-
public typealias Element = StringTableEntry
71-
72-
private let fileSice: FileSlice
73-
private let tableSize: Int
74-
private let isSwapped: Bool
75-
76-
private var nextOffset: Int
77-
78-
init(fileSlice: FileSlice, isSwapped: Bool) {
79-
self.fileSice = fileSlice
80-
self.tableSize = fileSlice.size
81-
self.nextOffset = 0
82-
self.isSwapped = isSwapped
83-
}
84-
85-
public mutating func next() -> Element? {
86-
guard nextOffset < tableSize else { return nil }
87-
88-
let ptr = UnsafeRawPointer(fileSice.ptr)
89-
.advanced(by: nextOffset)
90-
.assumingMemoryBound(to: Encoding.CodeUnit.self)
91-
var (string, offset) = ptr.readString(as: Encoding.self)
92-
93-
defer {
94-
nextOffset += offset
95-
}
96-
97-
if isSwapped || shouldSwap(ptr) {
98-
let data = Data(bytes: ptr, count: offset)
99-
.byteSwapped(Encoding.CodeUnit.self)
100-
string = data.withUnsafeBytes {
101-
let baseAddress = $0.baseAddress!
102-
.assumingMemoryBound(to: Encoding.CodeUnit.self)
103-
return .init(
104-
decodingCString: baseAddress,
105-
as: Encoding.self
106-
)
107-
}
108-
}
109-
110-
return .init(
111-
string: string,
112-
offset: nextOffset
113-
)
114-
}
115-
}
116-
}
117-
118-
extension ELFFile.Strings {
119-
func string(at offset: Int) -> Element? {
120-
guard fileSlice.size >= offset else { return nil }
121-
let string = String(
122-
cString: fileSlice.ptr
123-
.advanced(by: offset)
124-
.assumingMemoryBound(to: CChar.self)
125-
)
126-
return .init(string: string, offset: offset)
127-
}
128-
}
129-
130-
extension ELFFile.UnicodeStrings.Iterator {
131-
// https://github.com/swiftlang/swift-corelibs-foundation/blob/4a9694d396b34fb198f4c6dd865702f7dc0b0dcf/Sources/Foundation/NSString.swift#L1390
132-
func shouldSwap(_ ptr: UnsafePointer<Encoding.CodeUnit>) -> Bool {
133-
let size = MemoryLayout<Encoding.CodeUnit>.size
134-
switch size {
135-
case 1:
136-
return false
137-
case 2:
138-
return ptr.pointee == 0xFFFE /* ZERO WIDTH NO-BREAK SPACE (swapped) */
139-
case 4:
140-
return ptr.pointee == UInt32(0xFFFE0000) // avoid overflows in 32bit env
141-
default:
142-
return false
143-
}
144-
}
145-
}

Sources/ELFKit/ELFImage+Strings.swift

Lines changed: 15 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -9,93 +9,25 @@
99
import Foundation
1010

1111
extension ELFImage {
12+
public typealias UnicodeStrings = BinaryParseSupport.UnicodeStrings
1213
public typealias Strings = UnicodeStrings<UTF8>
13-
14-
public struct UnicodeStrings<Encoding: _UnicodeEncoding>: StringTable {
15-
public let basePointer: UnsafePointer<Encoding.CodeUnit>
16-
public let tableSize: Int
17-
18-
public let isLittleEndian: Bool
19-
20-
init(
21-
basePointer: UnsafePointer<Encoding.CodeUnit>,
22-
tableSize: Int,
23-
isLittleEndian: Bool = false
24-
) {
25-
self.basePointer = basePointer
26-
self.tableSize = tableSize
27-
self.isLittleEndian = isLittleEndian
28-
}
29-
30-
public func makeIterator() -> Iterator {
31-
Iterator(
32-
basePointer: basePointer,
33-
tableSize: tableSize,
34-
isLittleEndian: isLittleEndian
35-
)
36-
}
37-
}
3814
}
3915

4016
extension ELFImage.UnicodeStrings {
41-
public struct Iterator: IteratorProtocol {
42-
public typealias Element = StringTableEntry
43-
44-
private let basePointer: UnsafePointer<Encoding.CodeUnit>
45-
private let tableSize: Int
46-
private let isLittleEndian: Bool
47-
48-
private var nextPointer: UnsafePointer<Encoding.CodeUnit>
49-
50-
init(
51-
basePointer: UnsafePointer<Encoding.CodeUnit>,
52-
tableSize: Int,
53-
isLittleEndian: Bool
54-
) {
55-
self.basePointer = basePointer
56-
self.tableSize = tableSize
57-
self.isLittleEndian = isLittleEndian
58-
self.nextPointer = basePointer
59-
}
60-
61-
public mutating func next() -> Element? {
62-
let offset = Int(bitPattern: nextPointer) - Int(bitPattern: basePointer)
63-
if offset >= tableSize {
64-
return nil
65-
}
66-
var (string, nextOffset) = nextPointer.readString(
67-
as: Encoding.self
68-
)
69-
70-
if isLittleEndian {
71-
let data = Data(bytes: nextPointer, count: offset)
72-
string = data.withUnsafeBytes {
73-
let baseAddress = $0.baseAddress!
74-
.assumingMemoryBound(to: Encoding.CodeUnit.self)
75-
return .init(
76-
decodingCString: baseAddress,
77-
as: Encoding.self
78-
)
79-
}
80-
}
81-
82-
nextPointer = nextPointer.advanced(
83-
by: nextOffset / MemoryLayout<Encoding.CodeUnit>.size
84-
)
85-
86-
return .init(string: string, offset: offset)
87-
}
88-
}
89-
}
90-
91-
extension ELFImage.Strings {
92-
func string(at offset: Int) -> Element? {
93-
guard tableSize >= offset else { return nil }
94-
let string = String(
95-
cString: UnsafeRawPointer(basePointer)
96-
.advanced(by: offset)
97-
.assumingMemoryBound(to: CChar.self)
17+
init(
18+
basePointer: UnsafePointer<Encoding.CodeUnit>,
19+
offset: Int,
20+
tableSize: Int,
21+
isLittleEndian: Bool = false
22+
) {
23+
self.init(
24+
source: MemoryUnicodeStringsSource(
25+
ptr: .init(basePointer),
26+
size: tableSize
27+
),
28+
offset: offset,
29+
size: tableSize,
30+
isSwapped: !isLittleEndian
9831
)
99-
return .init(string: string, offset: offset)
10032
}
10133
}

0 commit comments

Comments
 (0)