Skip to main content

windows_metadata/writer/file/
mod.rs

1use super::*;
2mod into_stream;
3
4mod rec;
5
6mod blobs;
7use blobs::*;
8
9mod strings;
10use strings::*;
11
12mod helpers;
13use helpers::*;
14
15/// Represents an ECMA-335 file in memory so that it can be built incrementally.
16#[derive(Default)]
17pub struct File {
18    strings: Strings,
19    blobs: Blobs,
20    records: rec::Records,
21    reference: Option<reader::Index>,
22
23    TypeRef: HashMap<String, HashMap<String, TypeRef>>,
24    TypeSpec: HashMap<BlobId, TypeSpec>,
25    AssemblyRef: HashMap<String, AssemblyRef>,
26    ModuleRef: HashMap<String, ModuleRef>,
27    MemberRef: HashMap<rec::MemberRef, MemberRef>,
28
29    // Sorted staging keeps deferred tables reproducible.
30    Constant: BTreeMap<HasConstant, rec::Constant>,
31    Attribute: BTreeMap<HasAttribute, Vec<rec::Attribute>>,
32    GenericParam: BTreeMap<TypeOrMethodDef, Vec<rec::GenericParam>>,
33}
34
35impl File {
36    pub fn new(name: &str) -> Self {
37        let mut file = Self::default();
38
39        file.records.Assembly.push(rec::Assembly {
40            Name: file.strings.insert(name),
41            HashAlgId: 0x00008004,
42            MajorVersion: 0xFF,
43            MinorVersion: 0xFF,
44            BuildNumber: 0xFF,
45            RevisionNumber: 0xFF,
46            Flags: AssemblyFlags::WindowsRuntime,
47            ..Default::default()
48        });
49
50        file.records.Module.push(rec::Module {
51            Name: file.strings.insert(name),
52            Mvid: 1,
53            ..Default::default()
54        });
55
56        // Some parsers require the `mscorlib` reference implied by "System" types.
57        file.AssemblyRef("System");
58
59        file.TypeDef("", "<Module>", TypeDefOrRef::default(), TypeAttributes(0));
60
61        file
62    }
63
64    /// Sets the reference index used to resolve external `TypeRef` scopes.
65    pub fn set_reference(&mut self, reference: reader::Index) {
66        self.reference = Some(reference);
67    }
68
69    pub fn reference(&self) -> Option<&reader::Index> {
70        self.reference.as_ref()
71    }
72
73    fn ModuleRef(&mut self, name: &str) -> ModuleRef {
74        if let Some(pos) = self.ModuleRef.get(name) {
75            return *pos;
76        }
77
78        let pos = ModuleRef(self.records.ModuleRef.push_pos(rec::ModuleRef {
79            Name: self.strings.insert(name),
80        }));
81
82        self.ModuleRef.insert(name.to_string(), pos);
83        pos
84    }
85
86    pub fn ImplMap(
87        &mut self,
88        method: MethodDef,
89        flags: PInvokeAttributes,
90        import_name: &str,
91        import_scope: &str,
92    ) {
93        let scope = self.ModuleRef(import_scope);
94
95        self.records.ImplMap.push(rec::ImplMap {
96            MappingFlags: flags,
97            MemberForwarded: MemberForwarded::MethodDef(method),
98            ImportName: self.strings.insert(import_name),
99            ImportScope: scope,
100        });
101    }
102
103    fn AssemblyRef(&mut self, assembly_name: &str) -> AssemblyRef {
104        if let Some(pos) = self.AssemblyRef.get(assembly_name) {
105            return *pos;
106        }
107
108        let pos = AssemblyRef(if assembly_name == "System" {
109            self.records.AssemblyRef.push_pos(rec::AssemblyRef {
110                Name: self.strings.insert("mscorlib"),
111                MajorVersion: 4,
112                PublicKeyOrToken: self
113                    .blobs
114                    .insert(&[0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89]),
115                ..Default::default()
116            })
117        } else {
118            self.records.AssemblyRef.push_pos(rec::AssemblyRef {
119                Name: self.strings.insert(assembly_name),
120                MajorVersion: 0xFF,
121                MinorVersion: 0xFF,
122                BuildNumber: 0xFF,
123                RevisionNumber: 0xFF,
124                Flags: AssemblyFlags::WindowsRuntime,
125                ..Default::default()
126            })
127        });
128
129        self.AssemblyRef.insert(assembly_name.to_string(), pos);
130        pos
131    }
132
133    pub fn TypeDef(
134        &mut self,
135        namespace: &str,
136        name: &str,
137        extends: TypeDefOrRef,
138        flags: TypeAttributes,
139    ) -> TypeDef {
140        TypeDef(self.records.TypeDef.push_pos(rec::TypeDef {
141            TypeName: self.strings.insert(name),
142            TypeNamespace: self.strings.insert(namespace),
143            Flags: flags,
144            Extends: extends,
145            FieldList: self.records.Field.len() as u32,
146            MethodList: self.records.MethodDef.len() as u32,
147        }))
148    }
149
150    pub fn TypeRef(&mut self, namespace: &str, name: &str) -> TypeRef {
151        if let Some(key) = self.TypeRef.get(namespace)
152            && let Some(pos) = key.get(name)
153        {
154            return *pos;
155        }
156
157        let pos = if let Some((parent, leaf)) = name.rsplit_once('/') {
158            let enclosing = self.TypeRef(namespace, parent);
159            TypeRef(self.records.TypeRef.push_pos(rec::TypeRef {
160                TypeName: self.strings.insert(leaf),
161                TypeNamespace: self.strings.insert(""),
162                ResolutionScope: ResolutionScope::TypeRef(enclosing),
163            }))
164        } else {
165            let assembly_name = self
166                .reference
167                .as_ref()
168                .and_then(|r| r.assembly_name(namespace, name))
169                .map(str::to_string);
170
171            let scope = if let Some(assembly_name) = assembly_name {
172                ResolutionScope::AssemblyRef(self.AssemblyRef(&assembly_name))
173            } else if namespace == "System" {
174                ResolutionScope::AssemblyRef(self.AssemblyRef("System"))
175            } else {
176                ResolutionScope::Module(Module(0))
177            };
178
179            TypeRef(self.records.TypeRef.push_pos(rec::TypeRef {
180                TypeName: self.strings.insert(name),
181                TypeNamespace: self.strings.insert(namespace),
182                ResolutionScope: scope,
183            }))
184        };
185
186        self.TypeRef
187            .entry(namespace.to_string())
188            .or_default()
189            .insert(name.to_string(), pos);
190
191        pos
192    }
193
194    pub fn TypeSpec(&mut self, namespace: &str, name: &str, generics: &[Type]) -> TypeSpec {
195        debug_assert!(!generics.is_empty());
196        // Avoid doubling an existing generic arity suffix read from a winmd.
197        let base = name.split_once('`').map_or(name, |(base, _)| base);
198        let name = format!("{base}`{}", generics.len());
199        let type_ref = self.TypeRef(namespace, &name);
200
201        let mut buffer = vec![];
202        buffer.push(ELEMENT_TYPE_GENERICINST);
203        buffer.push(ELEMENT_TYPE_CLASS);
204        buffer.write_compressed(TypeDefOrRef::TypeRef(type_ref).encode() as usize);
205        buffer.write_compressed(generics.len());
206
207        for ty in generics {
208            self.Type(ty, &mut buffer);
209        }
210
211        let signature = self.blobs.insert(&buffer);
212
213        if let Some(pos) = self.TypeSpec.get(&signature) {
214            return *pos;
215        }
216
217        let pos = TypeSpec(self.records.TypeSpec.push_pos(rec::TypeSpec {
218            Signature: signature,
219        }));
220        self.TypeSpec.insert(signature, pos);
221        pos
222    }
223
224    pub fn Field(&mut self, name: &str, ty: &Type, flags: FieldAttributes) -> Field {
225        let signature = self.FieldSig(ty);
226
227        Field(self.records.Field.push_pos(rec::Field {
228            Name: self.strings.insert(name),
229            Flags: flags,
230            Signature: signature,
231        }))
232    }
233
234    pub fn MethodDef(
235        &mut self,
236        name: &str,
237        signature: &Signature,
238        flags: MethodAttributes,
239        impl_flags: MethodImplAttributes,
240    ) -> MethodDef {
241        let signature = self.MethodDefSig(signature);
242
243        MethodDef(self.records.MethodDef.push_pos(rec::MethodDef {
244            RVA: 0,
245            ImplFlags: impl_flags,
246            Flags: flags,
247            Name: self.strings.insert(name),
248            Signature: signature,
249            ParamList: self.records.Param.len() as u32,
250        }))
251    }
252
253    pub fn MemberRef(
254        &mut self,
255        name: &str,
256        signature: &Signature,
257        parent: MemberRefParent,
258    ) -> MemberRef {
259        let signature = self.MethodDefSig(signature);
260
261        let record = rec::MemberRef {
262            Name: self.strings.insert(name),
263            Signature: signature,
264            Parent: parent,
265        };
266
267        if let Some(pos) = self.MemberRef.get(&record) {
268            return *pos;
269        }
270
271        let pos = MemberRef(self.records.MemberRef.push_pos(record));
272        self.MemberRef.insert(record, pos);
273        pos
274    }
275
276    /// Adds a `Param` row to the file, returning the row offset.
277    pub fn Param(&mut self, name: &str, sequence: u16, flags: ParamAttributes) -> Param {
278        Param(self.records.Param.push_pos(rec::Param {
279            Flags: flags,
280            Sequence: sequence,
281            Name: self.strings.insert(name),
282        }))
283    }
284
285    /// Adds a `Property` row to the file, returning the row offset.
286    pub fn Property(&mut self, name: &str, ty: &Type) -> Property {
287        let signature = self.PropertySig(ty);
288
289        Property(self.records.Property.push_pos(rec::Property {
290            Flags: 0,
291            Name: self.strings.insert(name),
292            Type: signature,
293        }))
294    }
295
296    /// Adds a `PropertyMap` row associating a type with its first property.
297    pub fn PropertyMap(&mut self, parent: TypeDef, property_list: Property) -> PropertyMap {
298        PropertyMap(self.records.PropertyMap.push_pos(rec::PropertyMap {
299            Parent: parent,
300            PropertyList: property_list,
301        }))
302    }
303
304    /// Adds an `Event` row to the file, returning the row offset. `ty` is the event's
305    /// handler delegate type.
306    pub fn Event(&mut self, name: &str, ty: &Type) -> Event {
307        let Type::ClassName(ty) = ty else {
308            panic!("invalid event type");
309        };
310        let event_type = TypeDefOrRef::TypeRef(self.TypeRef(&ty.namespace, &ty.name));
311
312        Event(self.records.Event.push_pos(rec::Event {
313            Flags: 0,
314            Name: self.strings.insert(name),
315            EventType: event_type,
316        }))
317    }
318
319    /// Adds an `EventMap` row associating a type with its first event.
320    pub fn EventMap(&mut self, parent: TypeDef, event_list: Event) -> EventMap {
321        EventMap(self.records.EventMap.push_pos(rec::EventMap {
322            Parent: parent,
323            EventList: event_list,
324        }))
325    }
326
327    /// Adds a `MethodSemantics` row linking an accessor method to a property or event.
328    pub fn MethodSemantics(
329        &mut self,
330        semantics: u16,
331        method: MethodDef,
332        association: HasSemantics,
333    ) -> MethodSemantics {
334        MethodSemantics(self.records.MethodSemantics.push_pos(rec::MethodSemantics {
335            Semantics: semantics,
336            Method: method,
337            Association: association,
338        }))
339    }
340
341    /// Adds an `Attribute` row without assigning its sorted row offset.
342    pub fn Attribute(
343        &mut self,
344        parent: HasAttribute,
345        ty: AttributeType,
346        value: &[(String, Value)],
347    ) {
348        let value = self.AttributeValue(value);
349
350        self.Attribute
351            .entry(parent)
352            .or_default()
353            .push(rec::Attribute {
354                Parent: parent,
355                Type: ty,
356                Value: value,
357            });
358    }
359
360    pub fn Constant(&mut self, parent: HasConstant, value: &Value) {
361        let ty = value.ty().code();
362        let value = self.ConstantValue(value);
363
364        self.Constant.insert(
365            parent,
366            rec::Constant {
367                Parent: parent,
368                Type: ty,
369                Value: value,
370            },
371        );
372    }
373
374    pub fn GenericParam(
375        &mut self,
376        name: &str,
377        owner: TypeOrMethodDef,
378        number: u16,
379        flags: GenericParamAttributes,
380    ) {
381        self.GenericParam
382            .entry(owner)
383            .or_default()
384            .push(rec::GenericParam {
385                Name: self.strings.insert(name),
386                Number: number,
387                Owner: owner,
388                Flags: flags,
389            });
390    }
391
392    pub fn ClassLayout(&mut self, parent: TypeDef, packing_size: u16, class_size: u32) {
393        self.records.ClassLayout.push(rec::ClassLayout {
394            PackingSize: packing_size,
395            ClassSize: class_size,
396            Parent: parent.0,
397        });
398    }
399
400    pub fn FieldLayout(&mut self, field: Field, offset: u32) {
401        self.records.FieldLayout.push(rec::FieldLayout {
402            Offset: offset,
403            Field: field.0,
404        });
405    }
406
407    pub fn NestedClass(&mut self, inner: TypeDef, outer: TypeDef) {
408        debug_assert!(inner.0 > outer.0);
409
410        self.records.NestedClass.push(rec::NestedClass {
411            NestedClass: inner.0,
412            EnclosingClass: outer.0,
413        });
414    }
415
416    pub fn InterfaceImpl(&mut self, class: TypeDef, interface: &Type) -> InterfaceImpl {
417        let Type::ClassName(interface) = interface else {
418            panic!("invalid interface type");
419        };
420
421        let interface = if interface.generics.is_empty() {
422            TypeDefOrRef::TypeRef(self.TypeRef(&interface.namespace, &interface.name))
423        } else {
424            TypeDefOrRef::TypeSpec(self.TypeSpec(
425                &interface.namespace,
426                &interface.name,
427                &interface.generics,
428            ))
429        };
430
431        InterfaceImpl(self.records.InterfaceImpl.push_pos(rec::InterfaceImpl {
432            Class: class,
433            Interface: interface,
434        }))
435    }
436
437    /// Encodes the `Type` into the buffer, adding any required `TypeRef` rows to the file.
438    fn Type(&mut self, ty: &Type, buffer: &mut Vec<u8>) {
439        match ty {
440            Type::Void => buffer.push(ELEMENT_TYPE_VOID),
441            Type::Bool => buffer.push(ELEMENT_TYPE_BOOLEAN),
442            Type::Char => buffer.push(ELEMENT_TYPE_CHAR),
443            Type::I8 => buffer.push(ELEMENT_TYPE_I1),
444            Type::U8 => buffer.push(ELEMENT_TYPE_U1),
445            Type::I16 => buffer.push(ELEMENT_TYPE_I2),
446            Type::U16 => buffer.push(ELEMENT_TYPE_U2),
447            Type::I32 => buffer.push(ELEMENT_TYPE_I4),
448            Type::U32 => buffer.push(ELEMENT_TYPE_U4),
449            Type::I64 => buffer.push(ELEMENT_TYPE_I8),
450            Type::U64 => buffer.push(ELEMENT_TYPE_U8),
451            Type::F32 => buffer.push(ELEMENT_TYPE_R4),
452            Type::F64 => buffer.push(ELEMENT_TYPE_R8),
453            Type::ISize => buffer.push(ELEMENT_TYPE_I),
454            Type::USize => buffer.push(ELEMENT_TYPE_U),
455            Type::String => buffer.push(ELEMENT_TYPE_STRING),
456            Type::Object => buffer.push(ELEMENT_TYPE_OBJECT),
457
458            Type::Array(ty) => {
459                buffer.push(ELEMENT_TYPE_SZARRAY);
460                self.Type(ty, buffer);
461            }
462
463            Type::RefMut(ty) => {
464                buffer.push(ELEMENT_TYPE_BYREF);
465                self.Type(ty, buffer);
466            }
467
468            Type::RefConst(ty) => {
469                buffer.write_compressed(ELEMENT_TYPE_CMOD_REQD as usize);
470                let pos = self.TypeRef("System.Runtime.CompilerServices", "IsConst");
471                buffer.write_compressed(TypeDefOrRef::TypeRef(pos).encode() as usize);
472                buffer.push(ELEMENT_TYPE_BYREF);
473                self.Type(ty, buffer);
474            }
475
476            Type::PtrMut(ty, pointers) => {
477                for _ in 0..*pointers {
478                    buffer.write_compressed(ELEMENT_TYPE_PTR as usize);
479                }
480
481                self.Type(ty, buffer);
482            }
483
484            Type::PtrConst(ty, pointers) => {
485                buffer.write_compressed(ELEMENT_TYPE_CMOD_REQD as usize);
486                let pos = self.TypeRef("System.Runtime.CompilerServices", "IsConst");
487                buffer.write_compressed(TypeDefOrRef::TypeRef(pos).encode() as usize);
488
489                for _ in 0..*pointers {
490                    buffer.write_compressed(ELEMENT_TYPE_PTR as usize);
491                }
492
493                self.Type(ty, buffer);
494            }
495
496            Type::ArrayFixed(ty, len) => {
497                // See II.23.2.13 ArrayShape
498                buffer.push(ELEMENT_TYPE_ARRAY);
499                self.Type(ty, buffer);
500                buffer.write_compressed(1); // rank
501                buffer.write_compressed(1); // num_sizes
502                buffer.write_compressed(*len); // size
503                buffer.write_compressed(0); // num_lo_bounds
504            }
505
506            Type::Generic(_, number) => {
507                buffer.push(ELEMENT_TYPE_VAR);
508                buffer.write_compressed((*number).into());
509            }
510
511            Type::ClassName(ty) => {
512                self.TypeName(false, &ty.namespace, &ty.name, &ty.generics, buffer);
513            }
514            Type::ValueName(ty) => {
515                self.TypeName(true, &ty.namespace, &ty.name, &ty.generics, buffer);
516            }
517        }
518    }
519
520    fn TypeName(
521        &mut self,
522        is_value_type: bool,
523        namespace: &str,
524        name: &str,
525        generics: &[Type],
526        buffer: &mut Vec<u8>,
527    ) {
528        let pos = if !generics.is_empty() {
529            buffer.push(ELEMENT_TYPE_GENERICINST);
530            // Strip any existing `N suffix before re-deriving it (see TypeSpec).
531            let base = name.split_once('`').map_or(name, |(base, _)| base);
532            let name = format!("{base}`{}", generics.len());
533            self.TypeRef(namespace, &name)
534        } else {
535            self.TypeRef(namespace, name)
536        };
537
538        buffer.push(if is_value_type {
539            ELEMENT_TYPE_VALUETYPE
540        } else {
541            ELEMENT_TYPE_CLASS
542        });
543        buffer.write_compressed(TypeDefOrRef::TypeRef(pos).encode() as usize);
544
545        if !generics.is_empty() {
546            buffer.write_compressed(generics.len());
547
548            for ty in generics {
549                self.Type(ty, buffer);
550            }
551        }
552    }
553
554    /// Writes the `Type` into a `FileSig` buffer and stores it in the file, returning the blob
555    /// offset.
556    fn FieldSig(&mut self, ty: &Type) -> BlobId {
557        let mut buffer = vec![0x6]; // FIELD
558        self.Type(ty, &mut buffer);
559        self.blobs.insert(&buffer)
560    }
561
562    fn PropertySig(&mut self, ty: &Type) -> BlobId {
563        let mut buffer = vec![0x28]; // HASTHIS | PROPERTY
564        buffer.write_compressed(0); // parameter count
565        self.Type(ty, &mut buffer);
566        self.blobs.insert(&buffer)
567    }
568
569    /// Stores a method signature and returns its blob offset.
570    fn MethodDefSig(&mut self, signature: &Signature) -> BlobId {
571        let mut buffer = vec![signature.flags.0];
572        buffer.write_compressed(signature.types.len());
573        self.Type(&signature.return_type, &mut buffer);
574
575        for ty in &signature.types {
576            self.Type(ty, &mut buffer);
577        }
578
579        self.blobs.insert(&buffer)
580    }
581
582    fn ConstantValue(&mut self, value: &Value) -> BlobId {
583        let mut buffer = vec![];
584        buffer.write_value(value);
585        self.blobs.insert(&buffer)
586    }
587
588    fn AttributeValue(&mut self, values: &[(String, Value)]) -> BlobId {
589        let mut buffer = vec![];
590        buffer.write_u16(1); // prolog
591
592        let mut count = 0;
593
594        for (name, value) in values {
595            if name.is_empty() {
596                count += 1;
597                buffer.write_value(value);
598            } else {
599                break;
600            }
601        }
602
603        buffer.write_u16((values.len() - count).try_into().unwrap());
604
605        for (name, value) in &values[count..] {
606            buffer.push(0x53); // field=0x53 property=0x54
607
608            if let Value::EnumValue(tn, _) = value {
609                // SERIALIZATION_TYPE_ENUM (ECMA-335 II.23.1.16): 0x55 followed by
610                // a SerString of the fully-qualified enum type name.
611                buffer.push(0x55);
612                let enum_name = if tn.namespace.is_empty() {
613                    tn.name.clone()
614                } else {
615                    format!("{}.{}", tn.namespace, tn.name)
616                };
617                buffer.write_compressed(enum_name.len());
618                buffer.extend_from_slice(enum_name.as_bytes());
619            } else {
620                buffer.push(value.ty().code());
621            }
622
623            buffer.write_compressed(name.len());
624            buffer.extend_from_slice(name.as_bytes());
625            buffer.write_value(value);
626        }
627
628        self.blobs.insert(&buffer)
629    }
630}