atom_macho/load_command/
build_version.rs1use crate::io::{Endian, ReadExt as _, WriteExt as _};
2use num_derive::FromPrimitive;
3use num_traits::FromPrimitive;
4use std::io::{Read, Write};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct BuildVersionCommand {
11 pub cmd: u32,
12 pub cmdsize: u32,
14 pub platform: Platform,
15 pub minos: Version,
17 pub sdk: Version,
19 pub ntools: u32,
20}
21
22impl BuildVersionCommand {
23 pub const TYPE: u32 = 0x32;
24
25 pub const SIZE: u32 = 0x18; pub fn read_from_in<R: Read>(read: &mut R, endian: Endian) -> Self {
28 let cmd = read.read_u32_in(endian);
29 assert_eq!(cmd, Self::TYPE);
30
31 let cmdsize = read.read_u32_in(endian);
32
33 let platform_n = read.read_u32_in(endian);
34 let platform = Platform::from_u32(platform_n);
35
36 let minos_n = read.read_u32_in(endian);
37 let minos = Version::from_u32(minos_n);
38
39 let sdk_n = read.read_u32_in(endian);
40 let sdk = Version::from_u32(sdk_n);
41
42 let ntools = read.read_u32_in(endian);
43
44 assert_eq!(cmdsize, Self::SIZE + BuildToolVersion::SIZE * ntools);
45
46 BuildVersionCommand {
47 cmd,
48 cmdsize,
49 platform,
50 minos,
51 sdk,
52 ntools,
53 }
54 }
55
56 pub fn write_into<W: Write>(&self, write: &mut W) {
57 write.write_u32_native(self.cmd);
58 write.write_u32_native(self.cmdsize);
59 write.write_u32_native(self.platform.to_u32());
60 write.write_u32_native(self.minos.to_u32());
61 write.write_u32_native(self.sdk.to_u32());
62 write.write_u32_native(self.ntools);
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive)]
67pub enum Platform {
68 MacOS = 1,
69 IOS = 2,
70 TvOS = 3,
71 WatchOS = 4,
72 BridgeOS = 5,
73 MacCatalyst = 6,
74 IOSSimulator = 7,
75 TvOSSimulator = 8,
76 WatchOSSimulator = 9,
77 Driverkit = 10,
78}
79
80impl Platform {
81 pub fn from_u32(n: u32) -> Self {
82 FromPrimitive::from_u32(n).unwrap_or_else(|| panic!("Invalid platform number {}", n))
83 }
84
85 pub fn to_u32(self) -> u32 {
86 self as u32
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub struct Version {
92 pub major: u16,
93 pub minor: u8,
94 pub release: u8,
95}
96
97impl Version {
98 pub fn from_u32(n: u32) -> Self {
100 let major = ((n & 0xFFFF_0000) >> 16) as u16;
101 let minor = ((n & 0x0000_FF00) >> 8) as u8;
102 let release = (n & 0x0000_00FF) as u8;
103 Version {
104 major,
105 minor,
106 release,
107 }
108 }
109
110 pub fn to_u32(&self) -> u32 {
111 let mut n = 0;
112 n |= (self.major as u32) << 16;
113 n |= (self.minor as u32) << 8;
114 n |= self.release as u32;
115 n
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct BuildToolVersion {
121 pub tool: Tool,
122 pub version: u32,
123}
124
125impl BuildToolVersion {
126 pub const SIZE: u32 = 0x8;
127
128 pub fn read_from_in<R: Read>(read: &mut R, endian: Endian) -> Self {
129 let tool_n = read.read_u32_in(endian);
130 let tool = Tool::from_u32(tool_n);
131 let version = read.read_u32_in(endian);
132
133 BuildToolVersion { tool, version }
134 }
135
136 pub fn write_into<W: Write>(&self, write: &mut W) {
137 write.write_u32_native(self.tool.to_u32());
138 write.write_u32_native(self.version);
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive)]
143pub enum Tool {
144 Clang = 1,
145 Swift = 2,
146 LD = 3,
147}
148
149impl Tool {
150 pub fn from_u32(n: u32) -> Self {
151 FromPrimitive::from_u32(n).unwrap_or_else(|| panic!("Unsupported tool number {}", n))
152 }
153
154 pub fn to_u32(self) -> u32 {
155 self as u32
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn write_and_read_build_version_command() {
165 let cmd = BuildVersionCommand {
166 cmd: BuildVersionCommand::TYPE,
167 cmdsize: BuildVersionCommand::SIZE,
168 platform: Platform::MacOS,
169 minos: Version {
170 major: 3,
171 minor: 10,
172 release: 42,
173 },
174 sdk: Version {
175 major: 1,
176 minor: 11,
177 release: 13,
178 },
179 ntools: 0,
180 };
181
182 let mut buf = Vec::new();
183
184 cmd.write_into(&mut buf);
185
186 assert_eq!(buf.len(), BuildVersionCommand::SIZE as usize);
187
188 let read_cmd = BuildVersionCommand::read_from_in(&mut buf.as_slice(), Endian::NATIVE);
189
190 assert_eq!(read_cmd, cmd);
191 }
192
193 #[test]
194 fn write_and_read_build_tool_version() {
195 let version = BuildToolVersion {
196 tool: Tool::Clang,
197 version: 42,
198 };
199
200 let mut buf = Vec::new();
201
202 version.write_into(&mut buf);
203
204 assert_eq!(buf.len(), BuildToolVersion::SIZE as usize);
205
206 let read_version = BuildToolVersion::read_from_in(&mut buf.as_slice(), Endian::NATIVE);
207
208 assert_eq!(read_version, version);
209 }
210}