@@ -2,6 +2,7 @@ mod entry;
2
2
mod first_header;
3
3
mod header;
4
4
mod language;
5
+ mod state;
5
6
mod strings;
6
7
mod version;
7
8
@@ -10,8 +11,6 @@ use crate::installers::nsis::entry::Entry;
10
11
use crate :: installers:: nsis:: first_header:: FirstHeader ;
11
12
use crate :: installers:: nsis:: header:: compression:: Compression ;
12
13
use crate :: installers:: nsis:: header:: { Decompressed , Header } ;
13
- use crate :: installers:: nsis:: language:: table:: LanguageTable ;
14
- use crate :: installers:: nsis:: version:: NsisVersion ;
15
14
use crate :: installers:: traits:: InstallSpec ;
16
15
use crate :: installers:: utils:: { read_lzma_stream_header, RELATIVE_PROGRAM_FILES_64 } ;
17
16
use crate :: manifests:: installer_manifest:: Scope ;
@@ -26,11 +25,11 @@ use header::block::BlockType;
26
25
use liblzma:: read:: XzDecoder ;
27
26
use msi:: Language ;
28
27
use protobuf:: Enum ;
28
+ use state:: NsisState ;
29
29
use std:: borrow:: Cow ;
30
30
use std:: io;
31
31
use std:: io:: Read ;
32
32
use std:: str:: FromStr ;
33
- use strings:: encoding:: nsis_string;
34
33
use strsim:: levenshtein;
35
34
use thiserror:: Error ;
36
35
use versions:: Versioning ;
@@ -86,41 +85,33 @@ impl Nsis {
86
85
let ( header, _) = Header :: ref_from_prefix ( & decompressed_data)
87
86
. map_err ( |error| NsisError :: ZeroCopy ( error. to_string ( ) ) ) ?;
88
87
89
- let strings_block = BlockType :: Strings . get ( & decompressed_data, & header. blocks ) ;
90
-
91
- let language_table = LanguageTable :: get_main ( & decompressed_data, header) ?;
92
-
93
- let nsis_version = NsisVersion :: from_manifest ( data, pe)
94
- . or_else ( || NsisVersion :: from_branding_text ( strings_block, language_table) )
95
- . unwrap_or_else ( || NsisVersion :: detect ( strings_block) ) ;
88
+ let mut state = NsisState :: new ( pe, & decompressed_data, header) ?;
96
89
97
90
let entries = <[ Entry ] >:: try_ref_from_bytes (
98
91
BlockType :: Entries . get ( & decompressed_data, & header. blocks ) ,
99
92
)
100
93
. map_err ( |error| NsisError :: ZeroCopy ( error. to_string ( ) ) ) ?;
101
94
102
- let mut user_vars = [ const { Cow :: Borrowed ( "" ) } ; 9 ] ;
103
-
104
95
let mut architecture = None ;
105
96
106
97
let mut display_name = None ;
107
98
let mut display_version = None ;
108
99
let mut display_publisher = None ;
109
100
for entry in entries {
110
- entry. update_vars ( strings_block , & mut user_vars , nsis_version ) ;
101
+ entry. update_vars ( & mut state ) ;
111
102
if let Entry :: WriteReg {
112
103
value_name, value, ..
113
104
} = entry
114
105
{
115
- let value = nsis_string ( strings_block , value. get ( ) , & user_vars , nsis_version ) ;
116
- match & * nsis_string ( strings_block , value_name. get ( ) , & user_vars , nsis_version ) {
106
+ let value = state . get_string ( value. get ( ) ) ;
107
+ match & * state . get_string ( value_name. get ( ) ) {
117
108
"DisplayName" => display_name = Some ( value) ,
118
109
"DisplayVersion" => display_version = Some ( value) ,
119
110
"Publisher" => display_publisher = Some ( value) ,
120
111
_ => { }
121
112
}
122
113
} else if let Entry :: ExtractFile { name, .. } = entry {
123
- let name = nsis_string ( strings_block , name. get ( ) , & user_vars , nsis_version ) ;
114
+ let name = state . get_string ( name. get ( ) ) ;
124
115
let file_stem = Utf8Path :: new ( & name) . file_stem ( ) ;
125
116
// If there is an app-64 file, the app is x64.
126
117
// If there is an app-32 file or both files are present, the app is x86
@@ -133,113 +124,94 @@ impl Nsis {
133
124
} ;
134
125
}
135
126
136
- let install_dir = ( header. install_directory_ptr != U32 :: ZERO ) . then ( || {
137
- nsis_string (
138
- strings_block,
139
- header. install_directory_ptr . get ( ) ,
140
- & user_vars,
141
- nsis_version,
142
- )
143
- } ) ;
144
-
145
- let app_name = nsis_string (
146
- strings_block,
147
- language_table. language_string_offsets [ 2 ] . get ( ) ,
148
- & user_vars,
149
- nsis_version,
150
- ) ;
127
+ let install_dir = ( header. install_directory_ptr != U32 :: ZERO )
128
+ . then ( || state. get_string ( header. install_directory_ptr . get ( ) ) ) ;
151
129
152
- architecture = architecture. or_else ( || {
153
- install_dir
154
- . as_deref ( )
155
- . is_some_and ( |dir| dir. contains ( RELATIVE_PROGRAM_FILES_64 ) )
156
- . then_some ( Architecture :: X64 )
157
- . or_else ( || {
158
- entries
159
- . iter ( )
160
- . filter_map ( |entry| {
161
- if let Entry :: ExtractFile { name, position, .. } = entry {
162
- Some ( (
163
- nsis_string (
164
- strings_block,
165
- name. get ( ) ,
166
- & user_vars,
167
- nsis_version,
168
- ) ,
169
- position. get ( ) as usize + size_of :: < u32 > ( ) ,
170
- ) )
171
- } else {
172
- None
173
- }
174
- } )
175
- . filter ( |( name, _) | {
176
- Utf8Path :: new ( name)
177
- . extension ( )
178
- . is_some_and ( |extension| extension. eq_ignore_ascii_case ( EXE ) )
179
- } )
180
- . min_by_key ( |( name, _) | levenshtein ( name, & app_name) )
181
- . map ( |( _, mut position) | {
182
- if !is_solid {
183
- position += data_offset
184
- + non_solid_start_offset as usize
185
- + size_of :: < u32 > ( ) ;
186
- }
187
- position
188
- } )
189
- . and_then ( |position| {
190
- let mut decoder: Box < dyn Read > = if is_solid {
191
- solid_decoder
192
- } else {
193
- match compression {
194
- Compression :: Lzma ( filter_flag) => {
195
- let mut data = & data[ position + usize:: from ( filter_flag) ..] ;
196
- let stream = read_lzma_stream_header ( & mut data) . ok ( ) ?;
197
- Box :: new ( XzDecoder :: new_stream ( data, stream) )
198
- }
199
- Compression :: BZip2 => {
200
- Box :: new ( BzDecoder :: new ( & data[ position..] ) )
201
- }
202
- Compression :: Zlib => {
203
- Box :: new ( DeflateDecoder :: new ( & data[ position..] ) )
204
- }
205
- Compression :: None => Box :: new ( & data[ position..] ) ,
130
+ architecture = architecture
131
+ . or_else ( || {
132
+ install_dir
133
+ . as_deref ( )
134
+ . is_some_and ( |dir| dir. contains ( RELATIVE_PROGRAM_FILES_64 ) )
135
+ . then_some ( Architecture :: X64 )
136
+ } )
137
+ . or_else ( || {
138
+ let app_name = state. get_string ( state. language_table . string_offsets [ 2 ] . get ( ) ) ;
139
+ entries
140
+ . iter ( )
141
+ . filter_map ( |entry| {
142
+ if let Entry :: ExtractFile { name, position, .. } = entry {
143
+ Some ( (
144
+ state. get_string ( name. get ( ) ) ,
145
+ position. get ( ) . unsigned_abs ( ) as usize + size_of :: < u32 > ( ) ,
146
+ ) )
147
+ } else {
148
+ None
149
+ }
150
+ } )
151
+ . filter ( |( name, _) | {
152
+ Utf8Path :: new ( name)
153
+ . extension ( )
154
+ . is_some_and ( |extension| extension. eq_ignore_ascii_case ( EXE ) )
155
+ } )
156
+ . min_by_key ( |( name, _) | levenshtein ( name, & app_name) )
157
+ . map ( |( _, mut position) | {
158
+ if !is_solid {
159
+ position +=
160
+ data_offset + non_solid_start_offset as usize + size_of :: < u32 > ( ) ;
161
+ }
162
+ position
163
+ } )
164
+ . and_then ( |position| {
165
+ let mut decoder: Box < dyn Read > = if is_solid {
166
+ solid_decoder
167
+ } else {
168
+ match compression {
169
+ Compression :: Lzma ( filter_flag) => {
170
+ let mut data = & data[ position + usize:: from ( filter_flag) ..] ;
171
+ let stream = read_lzma_stream_header ( & mut data) . ok ( ) ?;
172
+ Box :: new ( XzDecoder :: new_stream ( data, stream) )
206
173
}
207
- } ;
208
- let mut void = io:: sink ( ) ;
209
-
210
- if is_solid {
211
- // Seek to file
212
- io:: copy ( & mut decoder. by_ref ( ) . take ( position as u64 ) , & mut void)
213
- . ok ( ) ?;
174
+ Compression :: BZip2 => Box :: new ( BzDecoder :: new ( & data[ position..] ) ) ,
175
+ Compression :: Zlib => {
176
+ Box :: new ( DeflateDecoder :: new ( & data[ position..] ) )
177
+ }
178
+ Compression :: None => Box :: new ( & data[ position..] ) ,
214
179
}
180
+ } ;
181
+ let mut void = io:: sink ( ) ;
182
+
183
+ if is_solid {
184
+ // Seek to file
185
+ io:: copy ( & mut decoder. by_ref ( ) . take ( position as u64 ) , & mut void)
186
+ . ok ( ) ?;
187
+ }
215
188
216
- // Seek to COFF header offset inside exe
217
- io:: copy ( & mut decoder. by_ref ( ) . take ( 0x3C ) , & mut void) . ok ( ) ?;
189
+ // Seek to COFF header offset inside exe
190
+ io:: copy ( & mut decoder. by_ref ( ) . take ( 0x3C ) , & mut void) . ok ( ) ?;
218
191
219
- let coff_offset = decoder. read_u32 :: < LE > ( ) . ok ( ) ?;
192
+ let coff_offset = decoder. read_u32 :: < LE > ( ) . ok ( ) ?;
220
193
221
- // Seek to machine value
222
- io:: copy (
223
- & mut decoder
224
- . by_ref ( )
225
- . take ( u64:: from ( coff_offset. checked_sub ( 0x3C ) ?) ) ,
226
- & mut void,
227
- )
228
- . ok ( ) ?;
194
+ // Seek to machine value
195
+ io:: copy (
196
+ & mut decoder
197
+ . by_ref ( )
198
+ . take ( u64:: from ( coff_offset. checked_sub ( 0x3C ) ?) ) ,
199
+ & mut void,
200
+ )
201
+ . ok ( ) ?;
229
202
230
- let machine_value = decoder. read_u16 :: < LE > ( ) . ok ( ) ?;
231
- Machine :: from_i32 ( i32:: from ( machine_value) )
232
- } )
233
- . and_then ( |machine| Architecture :: from_machine ( machine) . ok ( ) )
234
- } )
235
- } ) ;
203
+ let machine_value = decoder. read_u16 :: < LE > ( ) . ok ( ) ?;
204
+ Machine :: from_i32 ( i32:: from ( machine_value) )
205
+ } )
206
+ . and_then ( |machine| Architecture :: from_machine ( machine) . ok ( ) )
207
+ } ) ;
236
208
237
209
Ok ( Self {
238
210
architecture,
239
211
scope : install_dir. as_deref ( ) . and_then ( Scope :: from_install_dir) ,
240
212
install_dir : install_dir. as_deref ( ) . map ( Utf8PathBuf :: from) ,
241
213
install_locale : LanguageTag :: from_str (
242
- Language :: from_code ( language_table. language_id . get ( ) ) . tag ( ) ,
214
+ Language :: from_code ( state . language_table . id . get ( ) ) . tag ( ) ,
243
215
)
244
216
. ok ( ) ,
245
217
display_name : display_name. map ( Cow :: into_owned) ,
0 commit comments