parselnk/extra_data/
mod.rs

1//! Types defining the
2//! [ExtraData](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-shllink/c41e062d-f764-4f13-bd4f-ea812ab9a4d1)
3//! type.
4//!
5
6mod console_data_block;
7mod console_fe_data_block;
8mod darwin_data_block;
9mod environment_variable_data_block;
10mod icon_environment_data_block;
11mod known_folder_data_block;
12mod property_store_data_block;
13mod shim_data_block;
14mod special_folder_data_block;
15mod tracker_data_block;
16mod vista_and_above_id_list_data_block;
17
18use crate::{error::ExtraDataError, header::ShellLinkHeader};
19use byteorder::{ReadBytesExt, LE};
20pub use console_data_block::*;
21pub use console_data_block::*;
22pub use console_fe_data_block::*;
23pub use darwin_data_block::*;
24pub use environment_variable_data_block::*;
25pub use icon_environment_data_block::*;
26pub use known_folder_data_block::*;
27pub use property_store_data_block::*;
28pub use shim_data_block::*;
29pub use special_folder_data_block::*;
30use std::io::Cursor;
31pub use tracker_data_block::*;
32pub use vista_and_above_id_list_data_block::*;
33
34/// Result for parsing `ExtraData` blocks
35type Result<T> = std::result::Result<T, ExtraDataError>;
36
37#[derive(Clone, Debug, Default)]
38/// ExtraData refers to a set of structures that convey additional information about a link target. These optional structures can be present in an extra data section that is appended to the basic Shell Link Binary File Format.
39/// The ExtraData structures conform to the following ABNF rules [RFC5234]:
40pub struct ExtraData {
41    /// The DarwinDataBlock structure specifies an application identifier that can be used instead of a link target IDList to install an application when a shell link is activated.
42    darwin_props: Option<DarwinDataBlock>,
43
44    /// The SpecialFolderDataBlock structure specifies the location of a special folder. This data can be used when a link target is a special folder to keep track of the folder, so that the link target IDList can be translated when the link is loaded.
45    special_folder_props: Option<SpecialFolderDataBlock>,
46
47    /// The ConsoleDataBlock structure specifies the display settings to use when a link target specifies an application that is run in a console window.
48    pub console_props: Option<ConsoleDataBlock>,
49
50    /// The ConsoleFEDataBlock structure specifies the code page to use for displaying text when a link target specifies an application that is run in a console window.
51    pub console_fe_props: Option<ConsoleFEDataBlock>,
52
53    /// The EnvironmentVariableDataBlock structure specifies a path to environment variable information when the link target refers to a location that has a corresponding environment variable.
54    environment_props: Option<EnvironmentVariableDataBlock>,
55
56    /// The IconEnvironmentDataBlock structure specifies the path to an icon. The path is encoded using environment variables, which makes it possible to find the icon across machines where the locations vary but are expressed using environment variables.
57    icon_environment_props: Option<IconEnvironmentDataBlock>,
58
59    /// The KnownFolderDataBlock structure specifies the location of a known folder. This data can be used when a link target is a known folder to keep track of the folder so that the link target IDList can be translated when the link is loaded.
60    known_folder_props: Option<KnownFolderDataBlock>,
61
62    /// A PropertyStoreDataBlock structure specifies a set of properties that can be used by applications to store extra data in the shell link.
63    property_store_props: Option<PropertyStoreDataBlock>,
64
65    /// The ShimDataBlock structure specifies the name of a shim that can be applied when activating a link target.
66    pub shim_props: Option<ShimDataBlock>,
67
68    /// The TrackerDataBlock structure specifies data that can be used to resolve a link target if it is not found in its original location when the link is resolved. This data is passed to the Link Tracking service [MS-DLTW] to find the link target.
69    tracker_props: Option<TrackerDataBlock>,
70
71    /// The VistaAndAboveIDListDataBlock structure specifies an alternate IDList that can be used instead of the LinkTargetIDList structure (section 2.2) on platforms that support it.
72    vista_and_above_idlist_props: Option<VistaAndAboveIDListDataBlock>,
73}
74
75impl ExtraData {
76    /// Construct a new `ExtraData` instance from the data in `cursor`
77    pub fn new(cursor: &mut Cursor<Vec<u8>>, _header: &ShellLinkHeader) -> Result<Self> {
78        let mut this = Self::default();
79
80        while {
81            match this.parse_next_block(cursor) {
82                Err(ExtraDataError::UnknownBlock(a, b)) => Err(ExtraDataError::UnknownBlock(a, b)),
83                Err(_) => Ok(false),
84                Ok(_) => Ok(true),
85            }?
86        } {}
87
88        Ok(this)
89    }
90
91    fn parse_next_block(
92        &mut self,
93        cursor: &mut Cursor<Vec<u8>>,
94    ) -> std::result::Result<(), ExtraDataError> {
95        let block_size = cursor.read_u32::<LE>().map_err(ExtraDataError::Read)?;
96        let block_signature = cursor.read_u32::<LE>().map_err(ExtraDataError::Read)?;
97
98        match (block_size, block_signature) {
99            (0x0000_0314, 0xa000_0001) => {
100                self.environment_props =
101                    EnvironmentVariableDataBlock::new(block_size, block_signature, cursor)
102                        .map(Some)?;
103                Ok(())
104            }
105            (0x0000_00cc, 0xa000_0002) => {
106                self.console_props =
107                    ConsoleDataBlock::new(block_size, block_signature, cursor).map(Some)?;
108                Ok(())
109            }
110            (0x0000_0060, 0xa000_0003) => {
111                self.tracker_props =
112                    TrackerDataBlock::new(block_size, block_signature, cursor).map(Some)?;
113                Ok(())
114            }
115            (0x0000_000c, 0xa000_0004) => {
116                self.console_fe_props =
117                    ConsoleFEDataBlock::new(block_size, block_signature, cursor).map(Some)?;
118                Ok(())
119            }
120            (0x0000_0010, 0xa000_0005) => {
121                self.special_folder_props =
122                    SpecialFolderDataBlock::new(block_size, block_signature, cursor).map(Some)?;
123                Ok(())
124            }
125            (0x0000_0314, 0xa000_0006) => {
126                self.darwin_props =
127                    DarwinDataBlock::new(block_size, block_signature, cursor).map(Some)?;
128                Ok(())
129            }
130            (0x0000_0314, 0xa000_0007) => {
131                self.icon_environment_props =
132                    IconEnvironmentDataBlock::new(block_size, block_signature, cursor).map(Some)?;
133                Ok(())
134            }
135            (_, 0xa000_0008) => {
136                self.shim_props =
137                    ShimDataBlock::new(block_size, block_signature, cursor).map(Some)?;
138                Ok(())
139            }
140            (_, 0xa000_0009) => {
141                self.property_store_props =
142                    PropertyStoreDataBlock::new(block_size, block_signature, cursor).map(Some)?;
143                Ok(())
144            }
145            (0x0000_001c, 0xa000_000b) => {
146                self.known_folder_props =
147                    KnownFolderDataBlock::new(block_size, block_signature, cursor).map(Some)?;
148                Ok(())
149            }
150            (_, 0xa000_000c) => {
151                self.vista_and_above_idlist_props =
152                    VistaAndAboveIDListDataBlock::new(block_size, block_signature, cursor)
153                        .map(Some)?;
154                Ok(())
155            }
156            (size, signature) => Err(ExtraDataError::UnknownBlock(size, signature)),
157        }
158    }
159}