Skip to content

Commit 80eac12

Browse files
authored
Merge pull request #11 from RougeWare/feature/hardwareModelIdentifier-parsing
Hardware model identifiers
2 parents 6b32d5d + 285d7bb commit 80eac12

File tree

6 files changed

+117
-196
lines changed

6 files changed

+117
-196
lines changed

LICENSE.txt

Lines changed: 3 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,6 @@
1-
BLUE HUSKY LICENSE 1 - PUBLIC SHARE - OPUS 3
1+
Copyright waived in 2025 by the author, Ky.
22

3-
0: LAYMAN'S TERMS
4-
This section is meant to explain the purpose of this license in Layman's
5-
terms, and should thusly never be seen as legally binding. This disclaimer does
6-
not apply to further sections of this license.
3+
Usage of the works is permitted provided that this instrument is retained with the works, so that any entity that uses the works is notified of this instrument.
74

8-
If you made this:
5+
DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
96

10-
1. This is your product and you can do what you want with it
11-
a. You must make sure that if you use anyone else's stuff in it, you do so
12-
with their permission, or under Fair Use
13-
b. If you do include someone else's stuff, you can't claim you made that
14-
c. You guarantee you're providing this product for free
15-
2. You must let others do what they want with it
16-
a. They still have to say you made it in the first place
17-
b. You have to include this license along with your product for it to count
18-
c. They have to include this license when they redistribute your product
19-
3. This license is overridden by governmental laws
20-
4. You're not responsible for bad things that might happen because someone
21-
used your product
22-
23-
If you got this:
24-
25-
1. This is not your product, and you need to respect that
26-
a. If you see anyone else's stuff in it, that was put there with their
27-
permission, or under Fair Use
28-
b. You are guaranteed you're getting this product for free
29-
2. You can do what you want with this
30-
a. You still have to say who made it in the first place
31-
b. You get all the freedoms in this license along with this product
32-
c. You have to include this license when you redistribute this product,
33-
unless the creator says otherwise
34-
d. You can edit this license as long as you let other editors know,
35-
especially the original author
36-
e. You must make sure that if you use anyone else's stuff in it, you do so
37-
with their permission, or under Fair Use
38-
f. If you do include someone else's stuff, you can't claim you made that
39-
3. This license is overridden by governmental laws
40-
4. The original creator is not responsible for bad things that might happen
41-
because you used this product
42-
43-
44-
1: DECLARATION OF COPYRIGHT
45-
This Product is copyright Ben 'Ky' Leggiero (c) 2021 BH-1-PS
46-
47-
Ben 'Ky' Leggiero may be reached at KyLeggiero@Gmail.com
48-
49-
50-
2: DEFINITIONS
51-
- "License": this text.
52-
- "Product": the product with which this License was distributed, and any
53-
assets necessary for its use.
54-
- "Creator": any entity or entities who originally invented the Product,
55-
withstanding related and contributing parties.
56-
- "Licensee": any entity or entities involved in consumption of the Product.
57-
- "Licensor": any entity or entities involved in distribution of the Product
58-
and of this License. The Creator is always a Licensor, but a Licensor is not
59-
always the Creator.
60-
61-
62-
3: NOTICE OF PERMISSIONS
63-
Permission is hereby granted to any entity obtaining a copy of the Product,
64-
to use, copy, modify, host, redistribute, sublicense, sell copies of, and/or
65-
otherwise handle the Product, and to permit Licensees to also do so, given the
66-
following conditions are obeyed:
67-
68-
1. The above copyright notice and this permission notice shall be included in
69-
all copies and/or substantial portions of the Product.
70-
2. This License shall be blatantly provided, unmodified, along with the
71-
Product.
72-
3. Attribution to the Creator must be blatantly stated.
73-
74-
75-
4: DECLARATION OF OWNERSHIP
76-
The Creator hereby declares that everything which makes up the Product is
77-
the intellectual property solely of the Creator and of no other party,
78-
notwithstanding any intellectual property which is included under Fair Use Laws
79-
as described in § 5.4 of this License, or within the restrictions of the
80-
licenses thereof. Such intellectual property falls under § 5.1 of this License.
81-
82-
83-
5: THE RIGHTS OF THE CREATOR AND FURTHER LICENSORS
84-
1. The Creator reserves no rights to any previously-established intellectual
85-
property which is implicitly or explicitly owned by any other entity or
86-
entities.
87-
a. If any such intellectual property is contained within or bundled
88-
alongside the Product, or is otherwise distributed with or appears
89-
covered under this License, the Creator forfeits any and all claims on
90-
said property, and said property shall not be covered by this License and
91-
shall not be considered a part of the Product.
92-
2. The Creator will not gain any profit through the creation or distribution
93-
of the Product.
94-
a. The Creator forfeits the right to request compensation for any use of the
95-
Product which adheres to the restrictions described by this License.
96-
3. The Creator reserves the right to freely create, edit, distribute, destroy,
97-
or otherwise interact with the whole of, or any part of, the Product.
98-
4. In the case that any entity other than the Creator claims to own
99-
intellectual property contained within the Product and requests
100-
Compensation for the use of such intellectual property, the Creator
101-
reserves the right to refuse such Compensation as allowed by the following
102-
legal documents:
103-
a. Amendment I of the United States Constitution.
104-
b. Article 19 of the Universal Declaration of Human Rights.
105-
c. 17 USC § 107 - Limitations on exclusive rights: Fair use.
106-
5. In cases where all of the documents listed under § 5.4 of this
107-
License are not legally recognized, the Creator agrees to pay the owner of
108-
the disputed intellectual property a sum which equals the proportion of the
109-
prevalence that the disputed intellectual property maintains in the Product
110-
out of the total sum of profits garnered by the Creator for creating the
111-
Product.
112-
6. The Creator reserves the right to waive any conditions of this License at
113-
the Creator's discretion.
114-
7. The Licensor reserves the right to edit this License at any time under the
115-
terms of BH-1-PS.
116-
a. The Licensor agrees to increment the Opus number of this License to
117-
correspond with version changes.
118-
b. The Licensor agrees to never publish two or more versions of this License
119-
under the same Opus number.
120-
c. The Licensor agrees to notify the License's original author of any
121-
changes made to the License. If such author is not reasonably accessible,
122-
the Licensor agrees to notify any known authors which have previously
123-
contributed to the License.
124-
8. In no way are any of the Creator's moral rights affected by this License.
125-
126-
127-
6: RIGHTS AND RESTRICTIONS OF LICENSEES AND LICENSORS ("YOU")
128-
1. You maintain the following rights and restrictions:
129-
a. You are free to copy, distribute and transmit the Product.
130-
i. For any reuse or distribution, You must make clear to others the
131-
License terms of the License.
132-
b. You are free to adapt the Product.
133-
i. If You alter, transform, or build upon the Product, You may distribute
134-
the resulting Product only under this License.
135-
ii. If you alter, transform, or build upon this License, You must do so
136-
under the terms of § 5.7 of this License.
137-
c. You are free to make indirect commercial use of the Product.
138-
i. You may not directly profit from distribution of the Product.
139-
d. You must attribute the Product in the manner specified by the Creator (but
140-
not in any way that suggests that the Creator endorses You or such use of
141-
the Product).
142-
e. The Creator and any Licensors or Licensees previous to You are not
143-
responsible for any changes made to the Product by You, or any effects
144-
arising thereof.
145-
f. You can be granted special rights by the Creator as described in § 5.6 of
146-
this License.
147-
2. In no way are any of the following rights affected by the License:
148-
a. The fair dealing or fair use rights afforded to You, or other applicable
149-
copyright exceptions and limitations.
150-
b. Rights another entity may have, either in the Product itself or in how
151-
the Product is used, such as publicity, privacy, or repair rights.
152-
153-
154-
7: ACCORDANCE WITH THE LAW
155-
The terms that make up the whole and parts of this License shall not apply
156-
where local, state, provincial, federal, national, or any other law prohibits
157-
such terms.
158-
159-
160-
8: DISCLAIMER
161-
THE PRODUCT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
162-
IMPLIED. IN NO EVENT SHALL THE CREATORS, LICENSEES, OR LICENSORS BE LIABLE FOR
163-
ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT,
164-
OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE PRODUCT OR THE
165-
USE OR OTHER DEALINGS IN OR WITH THE PRODUCT.

Sources/Introspection/Bundle Reading.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// Bundle Reading.swift
33
// Swift-Introspection
44
//
5-
// Created by Ky Leggiero on 2021-07-24.
6-
// Copyright Ben 'Ky' Leggiero 2021 BH-1-PS
5+
// Created by Ky on 2021-07-24.
76
//
87

98
import Foundation

Sources/Introspection/Device Info.swift

Lines changed: 99 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// Device Info.swift
33
// Swift-Introspection
44
//
5-
// Created by Ky Leggiero on 2021-07-24.
6-
// Copyright Ben 'Ky' Leggiero 2021 BH-1-PS
5+
// Created by Ky on 2021-07-24.
76
//
87

98
import Foundation
@@ -25,6 +24,11 @@ public extension Introspection {
2524
@dynamicMemberLookup
2625
struct Device {
2726

27+
/// The device’s hardware model identifier, like `{"Mac", 14, 8}` or `{"iPhone", 18, 2}`.
28+
///
29+
/// `nil` signifies that it's unknown or unimportant to the current usecase.
30+
public let hardwareModelIdentifier: HardwareModelIdentifier?
31+
2832
/// The device's model type, like `.macPro` or `.iPhone`
2933
public let modelType: ModelType
3034

@@ -37,11 +41,13 @@ public extension Introspection {
3741
/// Creates a new `Device` value
3842
///
3943
/// - Parameters:
44+
/// - hardwareModelIdentifier: _optional_ - The device's hardware model identifier, like `{"Mac", 14, 8}` or `{"iPhone", 18, 2}`
4045
/// - modelType: The device's model type, like `.macBookPro` or `.iPad`
4146
/// - `class`: _optional_ - The device's class, like `.laptop` or `.tablet`. Defaults to inferring this from the model type.
42-
public init(modelType: ModelType, `class`: Class? = nil) {
47+
public init(hardwareModelIdentifier: HardwareModelIdentifier? = nil, modelType: ModelType, `class`: Class? = nil) {
48+
self.hardwareModelIdentifier = hardwareModelIdentifier
4349
self.modelType = modelType
44-
self.deviceClass = `class` ?? modelType.deviceClass
50+
self.deviceClass = `class` ?? modelType.deviceClass // FIXME: For some fuckin reason, Apple's latest Mac Pro isn't `"MacPro14,8"`; it's `"Mac14,8"` :/
4551
}
4652

4753

@@ -79,7 +85,7 @@ public extension Introspection.Device {
7985

8086
public extension Introspection.Device {
8187

82-
/// The current device's hardware model type, like `"MacBookPro"` or `"iPad"`
88+
/// The current device's hardware model type, like `"MacBookPro"` or `"iPad"`
8389
///
8490
/// - Note: This relies on the return value from `sysctl`. There is a chance that it will not return a value at all, in which case, the value returned from this will be `.unknown`
8591
@inline(__always)
@@ -94,14 +100,85 @@ public extension Introspection.Device {
94100
UIDevice.current.modelName
95101
#endif
96102
}
103+
104+
105+
/// The hardware model identifier of the current device, like `{"Mac", 14, 8}` or `{"iPhone", 18, 2}`
106+
static let hardwareModelIdentifier: HardwareModelIdentifier? = {
107+
guard let identifierString = hardwareModelIdentifierString else { return nil }
108+
let match = hardwareModelRegex
109+
.firstMatch(in: identifierString, options: .anchored, range: NSRange(location: 0, length: identifierString.count))
110+
111+
guard let typeRange = match?.range(withName: "Type"),
112+
let type = identifierString[orNil: typeRange],
113+
114+
let versionRange = match?.range(withName: "Version"),
115+
let version = identifierString[orNil: versionRange],
116+
117+
let majorVersionRange = match?.range(withName: "MajorVersion"),
118+
let majorVersionString = identifierString[orNil: majorVersionRange],
119+
let majorVersion = Int(majorVersionString),
120+
121+
let minorVersionRange = match?.range(withName: "MinorVersion"),
122+
let minorVersionString = identifierString[orNil: minorVersionRange],
123+
let minorVersion = Int(minorVersionString)
124+
else {
125+
print("malformed hardware model identifier: \(identifierString)")
126+
return nil
127+
}
128+
129+
return HardwareModelIdentifier(
130+
type: .init(String(type)),
131+
version: .init(full: String(version), major: majorVersion, minor: minorVersion)
132+
)
133+
}()
134+
135+
136+
/// Splits something like `"MacBookAir9,1"` into the groups `"Type"` (`"MacBookAir"`), `"Version"` (`"9,1"`), `"MajorVersion"` (`"9"`), and `"MinorVersion"` (`"1"`)
137+
fileprivate static let hardwareModelRegex = try! NSRegularExpression(pattern: #"^(?<Type>\w+?)(?<Version>(?<MajorVersion>\d+),(?<MinorVersion>\d+))$"#, options: [])
138+
139+
140+
141+
/// Models the components of a hardware model identifier. So `"MacBookAir9,1"` would split into `{type: "MacBookAir", version: {full: "9,1", major: 9, minor: 1}}`
142+
public struct HardwareModelIdentifier: Hashable {
143+
144+
/// The "type" portion of the hardware model identifier, like `"MacBookAir"` or `"iPhone"`
145+
public let type: ModelType
146+
147+
/// A breakdown of the "version" portion of the model identifier
148+
public let version: Version
149+
150+
151+
152+
/// A breakdown of the "version" portion of a model identifier. In `"MacBookAir9,1"`, this would be the `9,1` part
153+
public struct Version: Hashable {
154+
155+
/// The raw "version" portion of the model identifier. For `"MacBookAir9,1"`, this would be `"9,1"`
156+
public let full: String
157+
158+
/// The "major version" portion of the model identifier. For `"iPhone18,2"`, this would be `18`
159+
public let major: Int
160+
161+
/// The "minor version" portion of the model identifier. For `"iPad13,2"`, this would be `2`
162+
public let minor: Int
163+
}
164+
}
165+
}
166+
167+
168+
169+
public extension Introspection.Device.HardwareModelIdentifier {
170+
/// The hardware model identifier of the current device, like `{"Mac", 14, 8}` or `{"iPhone", 18, 2}`
171+
static var current: Self? {
172+
Introspection.Device.hardwareModelIdentifier
173+
}
97174
}
98175

99176

100177

101178
public extension Introspection.Device.ModelType {
102179

103180

104-
/// The current device's hardware model type, like `"MacBookPro"` or `"iPad"`
181+
/// The current device's hardware model type, like `"MacBookPro"` or `"iPad"`
105182
///
106183
/// - Note: This relies on the return value from `sysctl`. There is a chance that it will not return a value at all, in which case, the value returned from this will be `.unknown`
107184
static var current: Self {
@@ -110,21 +187,17 @@ public extension Introspection.Device.ModelType {
110187
}
111188

112189
guard
113-
let matchRange = hardwareModelRegex
190+
let typeRange = Introspection.Device.hardwareModelRegex
114191
.firstMatch(in: identifier, options: .anchored, range: NSRange(location: 0, length: identifier.count))?
115192
.range(withName: "Type"),
116-
let type = identifier[orNil: matchRange]
193+
let type = identifier[orNil: typeRange]
117194
else {
118195
// Not an Apple-format identifier; just return the string itself
119196
return .init(identifier)
120197
}
121198

122199
return .init(.init(type))
123200
}
124-
125-
126-
/// Splits something like `"MacBookAir9,1"` into the groups `"Type"` (`"MacBookAir"`), `"Version"` (`"9,1"`), `"MajorVersion"` (`"9"`), and `"MinorVersion"` (`"1"`)
127-
private static let hardwareModelRegex = try! NSRegularExpression(pattern: #"^(?<Type>\w+?)(?<Version>(?<MajorVersion>\d+),(?<MinorVersion>\d+))$"#, options: [])
128201
}
129202

130203

@@ -134,7 +207,12 @@ public extension Introspection.Device.ModelType {
134207
public extension Introspection.Device {
135208

136209
/// The current device
137-
static var current: Self { self.init(modelType: .current) }
210+
static var current: Self {
211+
self.init(
212+
hardwareModelIdentifier: .current,
213+
modelType: .current
214+
)
215+
}
138216

139217

140218
// There's a bug in the Swift compiler that makes this impossible, so I have to enumerate them by-hand:
@@ -377,21 +455,17 @@ public extension Introspection.Device.ModelType {
377455
private func sysctl(category: CInt, value: CInt) -> String? {
378456
var mib = [category, value]
379457

380-
var len = size_t()
381-
var rstring: String?
382-
383-
sysctl(&mib, 2, nil, &len, nil, 0 )
384-
let mallocated = malloc( len )
385-
defer {
386-
free(&rstring )
387-
rstring = nil
388-
}
458+
var len: size_t = 0
459+
let getSizeResult = sysctl(&mib, 2, nil, &len, nil, 0)
460+
guard getSizeResult == 0, len > 0 else { return nil }
389461

390-
rstring = mallocated?.load(as: String.self)
462+
let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: len)
463+
defer { buffer.deallocate() }
391464

392-
sysctl(&mib, 2, &rstring, &len, nil, 0 )
465+
let getResult = sysctl(&mib, 2, buffer, &len, nil, 0)
466+
guard getResult == 0 else { return nil }
393467

394-
return rstring
468+
return String(validatingUTF8: buffer)
395469
}
396470

397471

Sources/Introspection/Introspection.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// Introspection.swift
33
// Swift-Introspection
44
//
5-
// Created by Ky Leggiero on 2021-07-24.
6-
// Copyright Ben 'Ky' Leggiero 2021 BH-1-PS
5+
// Created by Ky on 2021-07-24.
76
//
87

98
import Foundation

0 commit comments

Comments
 (0)