1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . IO ;
4
+ using System . Linq ;
4
5
using System . Windows . Forms ;
5
6
using bytepress . Compresison ;
6
7
using bytepress . Compresison . LZMA ;
7
8
using bytepress . Extensions ;
9
+ using bytepress . Properties ;
8
10
9
11
namespace bytepress . Engine
10
12
{
@@ -15,8 +17,9 @@ public class Presser
15
17
private byte [ ] _fileBytes ;
16
18
private byte [ ] _fileBytesCompressed ;
17
19
private AssemblyCloner _cloner ;
18
- private static List < ICompressor > _compressors ;
19
-
20
+ private ICompressor _compressor ;
21
+ private List < ICompressor > _compressors ;
22
+ private List < string > _libraries ;
20
23
public UpdateHandler UpdateStatus = delegate { } ;
21
24
public delegate void UpdateHandler ( string status , StatusType type ) ;
22
25
@@ -31,7 +34,7 @@ public enum StatusType
31
34
public Presser ( string file )
32
35
{
33
36
_file = file ;
34
- _source = Properties . Resources . source ;
37
+ _source = Resources . source ;
35
38
_cloner = new AssemblyCloner ( _file ) ;
36
39
_compressors = new List < ICompressor > ( ) ;
37
40
LoadCompressors ( ) ;
@@ -42,13 +45,65 @@ public Presser(string file, byte[] data)
42
45
{
43
46
_file = file ;
44
47
_fileBytes = data ;
45
- _source = Properties . Resources . source ;
48
+ _source = Resources . source ;
46
49
_cloner = new AssemblyCloner ( _file ) ;
47
50
_compressors = new List < ICompressor > ( ) ;
48
51
LoadCompressors ( ) ;
49
52
CleanWorkspace ( ) ;
50
53
}
51
54
55
+ /// <summary>
56
+ /// Set which compression algorithm to use.
57
+ /// </summary>
58
+ public void SetCompressor ( string algorithm )
59
+ {
60
+ algorithm = algorithm . ToLower ( ) . Trim ( ) ;
61
+ switch ( algorithm )
62
+ {
63
+ case "gzip" :
64
+ _compressor = _compressors [ 0 ] ;
65
+ break ;
66
+ case "quicklz" :
67
+ _compressor = _compressors [ 1 ] ;
68
+ break ;
69
+ case "lzma" :
70
+ _compressor = _compressors [ 2 ] ;
71
+ break ;
72
+ default :
73
+ UpdateStatus ( $ "Invalid compression algorithm '{ algorithm } '. Defaulting to automatic calculation...", StatusType . Warning ) ;
74
+ break ;
75
+ }
76
+
77
+ }
78
+
79
+ /// <summary>
80
+ /// Verifies and sets the libraries to be merged with the main assembly.
81
+ /// </summary>
82
+ /// <param name="libraries"></param>
83
+ public void MergeLibraries ( List < string > libraries )
84
+ {
85
+ foreach ( string lib in libraries )
86
+ {
87
+ byte [ ] temp = File . ReadAllBytes ( lib ) ;
88
+ if ( ! IsManagedAssembly ( temp ) )
89
+ throw new Exception ( "Libraries to merge must be valid .NET assemblies." ) ;
90
+ Array . Clear ( temp , 0 , temp . Length ) ;
91
+ }
92
+ _libraries = libraries ;
93
+ }
94
+
95
+ /// <summary>
96
+ /// Checks the .NET header conventions to determine if assembly is managed (.NET).
97
+ /// </summary>
98
+ private bool IsManagedAssembly ( byte [ ] payloadBuffer )
99
+ {
100
+ int e_lfanew = BitConverter . ToInt32 ( payloadBuffer , 0x3c ) ;
101
+ int magicNumber = BitConverter . ToInt16 ( payloadBuffer , e_lfanew + 0x18 ) ;
102
+ int isManagedOffset = magicNumber == 0x10B ? 0xE8 : 0xF8 ;
103
+ int isManaged = BitConverter . ToInt32 ( payloadBuffer , e_lfanew + isManagedOffset ) ;
104
+ return isManaged != 0 ;
105
+ }
106
+
52
107
/// <summary>
53
108
/// Loads the available compression algorithms.
54
109
/// </summary>
@@ -67,22 +122,35 @@ public void Process()
67
122
if ( _fileBytes == null )
68
123
_fileBytes = File . ReadAllBytes ( _file ) ;
69
124
125
+ UpdateStatus ( "Verifying file is .NET assembly..." , Presser . StatusType . Normal ) ;
126
+ if ( ! IsManagedAssembly ( _fileBytes ) )
127
+ throw new Exception ( "Only .NET executable files are supported" ) ;
128
+
70
129
FileInfo f = new FileInfo ( _file ) ;
71
130
72
- UpdateStatus ( $ "Calculating the best compression algorithm..." , StatusType . Normal ) ;
73
- PickCompressor ( ) ;
131
+ if ( _compressor == null )
132
+ UpdateStatus ( "Calculating the best compression algorithm..." , StatusType . Normal ) ;
74
133
75
- UpdateStatus ( $ "Writing compressed payload to %temp%...", StatusType . Normal ) ;
134
+ Compress ( ) ;
135
+
136
+ UpdateStatus ( "Writing compressed payload to %temp%..." , StatusType . Normal ) ;
76
137
File . WriteAllBytes ( Path . GetTempPath ( ) + "\\ data" , _fileBytesCompressed ) ;
77
138
78
139
UpdateStatus ( "Copying assembly information and icon..." , StatusType . Normal ) ;
79
140
CopyAssembly ( ) ;
80
141
81
142
UpdateStatus ( "Compiling..." , StatusType . Normal ) ;
143
+
144
+ string outLocation = String . Empty ;
145
+ if ( _libraries != null && _libraries . Count > 0 )
146
+ outLocation = Path . GetTempPath ( ) + f . Name . Replace ( ".exe" , "_bytepressed.exe" ) ;
147
+
148
+ else
149
+ outLocation = f . DirectoryName + "\\ " + f . Name . Replace ( ".exe" , "_bytepressed.exe" ) ;
150
+
82
151
Compiler comp = new Compiler
83
152
{
84
- // add option to save as same name
85
- CompileLocation = f . DirectoryName + "\\ " + f . Name . Replace ( ".exe" , "_bytepressed.exe" ) ,
153
+ CompileLocation = outLocation ,
86
154
ResourceFiles = new [ ] { Path . GetTempPath ( ) + "\\ data" , Application . StartupPath + "\\ bytepress.lib.dll" } ,
87
155
SourceCodes = new [ ] { _source } ,
88
156
References = new [ ] {
@@ -98,10 +166,18 @@ public void Process()
98
166
CleanWorkspace ( ) ;
99
167
throw new Exception ( comp . CompileError ) ;
100
168
}
101
-
169
+ if ( _libraries != null && _libraries . Count > 0 )
170
+ {
171
+ UpdateStatus ( "Merging additional libraries..." , StatusType . Normal ) ;
172
+ Merger m = new Merger ( _libraries ) ;
173
+ if ( ! m . Merge ( outLocation , f . DirectoryName + "\\ " + f . Name . Replace ( ".exe" , "_bytepressed.exe" ) ) )
174
+ throw new Exception ( "Failed to merge libraries" ) ;
175
+ }
176
+
177
+
102
178
Console . WriteLine ( ) ;
103
179
104
- byte [ ] compiled = File . ReadAllBytes ( comp . CompileLocation ) ;
180
+ byte [ ] compiled = File . ReadAllBytes ( f . DirectoryName + " \\ " + f . Name . Replace ( ".exe" , "_bytepressed.exe" ) ) ;
105
181
double compressionRatio = 100 - ( double ) compiled . Length / _fileBytes . Length * 100.0 ;
106
182
UpdateStatus ( "Compression Results" , StatusType . Normal ) ;
107
183
UpdateStatus ( "--------------------------------------------" , StatusType . Normal ) ;
@@ -122,38 +198,50 @@ public void Process()
122
198
/// <summary>
123
199
/// Tests and chooses the best compression algorithm.
124
200
/// </summary>
125
- private void PickCompressor ( )
201
+ private void Compress ( )
126
202
{
127
- ICompressor best = null ;
128
- long bestLength = long . MaxValue ;
129
- foreach ( ICompressor c in _compressors )
203
+ if ( _compressor == null )
130
204
{
131
- UpdateStatus ( "--------------------------------------------" , StatusType . Normal ) ;
132
- UpdateStatus ( $ "Testing algorithm: { c . Name } ...", StatusType . Normal ) ;
133
- byte [ ] tmp = c . Compress ( _fileBytes ) ;
134
- double cR = 100 - ( double ) tmp . Length / _fileBytes . Length * 100.0 ;
135
- UpdateStatus ( $ "{ c . Name } Compression Ratio: { cR : F} %", StatusType . Normal ) ;
136
- if ( tmp . Length < bestLength )
205
+ long bestLength = Int64 . MaxValue ;
206
+ foreach ( ICompressor c in _compressors )
137
207
{
138
- best = c ;
139
- bestLength = tmp . Length ;
140
- _fileBytesCompressed = tmp ;
208
+ UpdateStatus ( "--------------------------------------------" , StatusType . Normal ) ;
209
+ UpdateStatus ( $ "Testing algorithm: { c . Name } ...", StatusType . Normal ) ;
210
+ byte [ ] tmp = c . Compress ( _fileBytes ) ;
211
+ double cR = 100 - ( double ) tmp . Length / _fileBytes . Length * 100.0 ;
212
+ UpdateStatus ( $ "{ c . Name } Compression Ratio: { cR : F} %", StatusType . Normal ) ;
213
+ if ( tmp . Length < bestLength )
214
+ {
215
+ _compressor = c ;
216
+ bestLength = tmp . Length ;
217
+ _fileBytesCompressed = tmp ;
218
+ }
141
219
}
142
220
}
221
+ else
222
+ {
223
+ UpdateStatus ( $ "Using algorithm: { _compressor . Name } ...", StatusType . Normal ) ;
224
+ _fileBytesCompressed = _compressor . Compress ( _fileBytes ) ;
225
+ double cR = 100 - ( double ) _fileBytesCompressed . Length / _fileBytes . Length * 100.0 ;
226
+ UpdateStatus ( $ "{ _compressor . Name } Compression Ratio: { cR : F} %", StatusType . Normal ) ;
227
+ _source = _source . Replace ( "*type*" , _compressors . IndexOf ( _compressor ) . ToString ( ) ) ;
228
+ return ;
229
+ }
143
230
144
- UpdateStatus ( "--------------------------------------------" , StatusType . Normal ) ;
145
231
146
- if ( best . GetType ( ) == typeof ( GZIP ) )
232
+ UpdateStatus ( "--------------------------------------------" , StatusType . Normal ) ;
233
+
234
+ if ( _compressor . GetType ( ) == typeof ( GZIP ) )
147
235
{
148
236
_source = _source . Replace ( "*type*" , "0" ) ;
149
237
UpdateStatus ( "Chosen algorithm: GZIP" , StatusType . Normal ) ;
150
238
}
151
- if ( best . GetType ( ) == typeof ( QuickLZ ) )
239
+ if ( _compressor . GetType ( ) == typeof ( QuickLZ ) )
152
240
{
153
241
_source = _source . Replace ( "*type*" , "1" ) ;
154
242
UpdateStatus ( "Chosen algorithm: QuickLZ" , StatusType . Normal ) ;
155
243
}
156
- if ( best . GetType ( ) == typeof ( LZMAez ) )
244
+ if ( _compressor . GetType ( ) == typeof ( LZMAez ) )
157
245
{
158
246
_source = _source . Replace ( "*type*" , "2" ) ;
159
247
UpdateStatus ( "Chosen algorithm: LZMA" , StatusType . Normal ) ;
@@ -187,7 +275,7 @@ private void CleanWorkspace()
187
275
string [ ] tempFiles =
188
276
{
189
277
"data" ,
190
- "icon.ico"
278
+ "icon.ico" ,
191
279
} ;
192
280
foreach ( string file in tempFiles )
193
281
{
0 commit comments