windows_metadata/writer/file/
into_stream.rs1use super::*;
2
3const SECTION_ALIGNMENT: u32 = 4096;
4
5#[repr(C)]
6#[derive(Default)]
7struct METADATA_HEADER {
8 signature: u32,
9 major_version: u16,
10 minor_version: u16,
11 reserved: u32,
12 length: u32,
13 version: [u8; 20],
14 flags: u16,
15 streams: u16,
16}
17
18const METADATA_SIGNATURE: u32 = 0x424A_5342;
19
20#[repr(C)]
21struct STREAM_HEADER<const LEN: usize> {
22 offset: u32,
23 size: u32,
24 name: [u8; LEN],
25}
26
27impl<const LEN: usize> STREAM_HEADER<LEN> {
28 fn new(offset: u32, size: u32, name: &[u8; LEN]) -> Self {
29 Self {
30 offset,
31 size,
32 name: *name,
33 }
34 }
35 fn next_offset(&self) -> u32 {
36 self.offset + self.size
37 }
38}
39
40impl File {
41 pub fn into_stream(mut self) -> Vec<u8> {
42 self.records.Constant.extend(self.Constant.values());
45
46 self.records
47 .Attribute
48 .extend(self.Attribute.values().flatten());
49
50 self.records
51 .GenericParam
52 .extend(self.GenericParam.values().flatten());
53
54 debug_assert!(self
57 .records
58 .ClassLayout
59 .iter()
60 .map(|r| r.Parent)
61 .is_sorted());
62
63 debug_assert!(self.records.Constant.iter().map(|r| r.Parent).is_sorted());
64 debug_assert!(self.records.Attribute.iter().map(|r| r.Parent).is_sorted());
65
66 debug_assert!(self
67 .records
68 .GenericParam
69 .iter()
70 .map(|r| r.Owner)
71 .is_sorted());
72
73 debug_assert!(self
74 .records
75 .ImplMap
76 .iter()
77 .map(|r| r.MemberForwarded)
78 .is_sorted());
79
80 debug_assert!(self
81 .records
82 .NestedClass
83 .iter()
84 .map(|r| r.NestedClass)
85 .is_sorted());
86
87 let mut strings = self.strings.into_stream();
90 let mut blobs = self.blobs.into_stream();
91 let mut records = self.records.into_stream();
92
93 if [records.len(), strings.len(), blobs.len()]
94 .iter()
95 .any(|len| *len > u32::MAX as usize)
96 {
97 panic!("heap too large");
98 }
99
100 unsafe {
101 let mut guids = vec![0; 16]; let size_of_streams = records.len() + guids.len() + strings.len() + blobs.len();
103
104 let mut dos: IMAGE_DOS_HEADER = core::mem::zeroed();
105 dos.e_magic = IMAGE_DOS_SIGNATURE;
106 dos.e_lfarlc = 64;
107 dos.e_lfanew = core::mem::size_of::<IMAGE_DOS_HEADER>() as i32;
108
109 let mut file: IMAGE_FILE_HEADER = core::mem::zeroed();
110 file.Machine = IMAGE_FILE_MACHINE_I386;
111 file.NumberOfSections = 1;
112 file.SizeOfOptionalHeader = core::mem::size_of::<IMAGE_OPTIONAL_HEADER32>() as u16;
113 file.Characteristics =
114 IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE;
115
116 let mut optional: IMAGE_OPTIONAL_HEADER32 = core::mem::zeroed();
117 optional.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
118 optional.MajorLinkerVersion = 11;
119 optional.SizeOfInitializedData = 1024;
120 optional.ImageBase = 0x400000;
121 optional.SectionAlignment = SECTION_ALIGNMENT;
122 optional.FileAlignment = 512;
123 optional.MajorOperatingSystemVersion = 6;
124 optional.MinorOperatingSystemVersion = 2;
125 optional.MajorSubsystemVersion = 6;
126 optional.MinorSubsystemVersion = 2;
127 optional.SizeOfHeaders = 512;
128 optional.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
129 optional.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT
130 | IMAGE_DLLCHARACTERISTICS_NO_SEH
131 | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE;
132 optional.SizeOfStackReserve = 0x100000;
133 optional.SizeOfHeapReserve = 4096;
134 optional.LoaderFlags = 0x100000;
135 optional.NumberOfRvaAndSizes = 16;
136
137 let mut section: IMAGE_SECTION_HEADER = core::mem::zeroed();
138 section.Name = *b".text\0\0\0";
139 section.Characteristics = 0x4000_0020;
140 section.VirtualAddress = SECTION_ALIGNMENT;
141
142 let mut clr: IMAGE_COR20_HEADER = core::mem::zeroed();
143 clr.cb = core::mem::size_of::<IMAGE_COR20_HEADER>() as u32;
144 clr.MajorRuntimeVersion = 2;
145 clr.MinorRuntimeVersion = 5;
146 clr.Flags = 1;
147
148 let metadata = METADATA_HEADER {
149 signature: METADATA_SIGNATURE,
150 major_version: 1,
151 minor_version: 1,
152 length: 20,
153 version: *b"WindowsRuntime 1.4\0\0",
154 streams: 4,
155 ..Default::default()
156 };
157
158 type TablesHeader = STREAM_HEADER<4>;
159 type StringsHeader = STREAM_HEADER<12>;
160 type GuidsHeader = STREAM_HEADER<8>;
161 type BlobsHeader = STREAM_HEADER<8>;
162
163 let size_of_stream_headers = core::mem::size_of::<TablesHeader>()
164 + core::mem::size_of::<StringsHeader>()
165 + core::mem::size_of::<GuidsHeader>()
166 + core::mem::size_of::<BlobsHeader>();
167
168 let size_of_image = optional.FileAlignment as usize
169 + core::mem::size_of::<IMAGE_COR20_HEADER>()
170 + core::mem::size_of::<METADATA_HEADER>()
171 + size_of_stream_headers
172 + size_of_streams;
173
174 optional.SizeOfImage = round(size_of_image, optional.SectionAlignment as usize) as u32;
175 section.Misc.VirtualSize = size_of_image as u32 - optional.FileAlignment;
176
177 section.SizeOfRawData = round(
178 section.Misc.VirtualSize as usize,
179 optional.FileAlignment as usize,
180 ) as u32;
181
182 optional.DataDirectory[14] = IMAGE_DATA_DIRECTORY {
183 VirtualAddress: SECTION_ALIGNMENT,
184 Size: core::mem::size_of::<IMAGE_COR20_HEADER>() as u32,
185 };
186
187 section.PointerToRawData = optional.FileAlignment;
188
189 clr.MetaData.VirtualAddress =
190 SECTION_ALIGNMENT + core::mem::size_of::<IMAGE_COR20_HEADER>() as u32;
191
192 clr.MetaData.Size =
193 section.Misc.VirtualSize - core::mem::size_of::<IMAGE_COR20_HEADER>() as u32;
194
195 let mut buffer = Vec::<u8>::new();
196 buffer.write_header(&dos);
197 buffer.write_u32(IMAGE_NT_SIGNATURE);
198 buffer.write_header(&file);
199 buffer.write_header(&optional);
200 buffer.write_header(§ion);
201 debug_assert!(buffer.len() < optional.FileAlignment as usize);
202 buffer.resize(optional.FileAlignment as usize, 0);
203 buffer.write_header(&clr);
204 let metadata_offset = buffer.len();
205 buffer.write_header(&metadata);
206
207 let stream_offset = buffer.len() - metadata_offset + size_of_stream_headers;
208
209 let tables_header =
210 TablesHeader::new(stream_offset as u32, records.len() as u32, b"#~\0\0");
211
212 let strings_header = StringsHeader::new(
213 tables_header.next_offset(),
214 strings.len() as u32,
215 b"#Strings\0\0\0\0",
216 );
217
218 let guids_header = GuidsHeader::new(
219 strings_header.next_offset(),
220 guids.len() as u32,
221 b"#GUID\0\0\0",
222 );
223
224 let blobs_header = BlobsHeader::new(
225 guids_header.next_offset(),
226 blobs.len() as u32,
227 b"#Blob\0\0\0",
228 );
229
230 buffer.write_header(&tables_header);
231 buffer.write_header(&strings_header);
232 buffer.write_header(&guids_header);
233 buffer.write_header(&blobs_header);
234
235 buffer.append(&mut records);
236 buffer.append(&mut strings);
237 buffer.append(&mut guids);
238 buffer.append(&mut blobs);
239
240 assert_eq!(clr.MetaData.Size as usize, buffer.len() - metadata_offset);
241 assert_eq!(size_of_image, buffer.len());
242
243 buffer
244 }
245 }
246}