7
7
import sys
8
8
import multiprocessing
9
9
import queue
10
+ from pathlib import Path
10
11
from functools import partial
11
12
from .__version__ import __version__ , __description__ , __title__ , __date__ , __repo__ , __author__
12
13
13
14
14
-
15
15
class Color :
16
16
RED = '\033 [31m'
17
17
GREEN = '\033 [32m'
@@ -48,7 +48,7 @@ def __init__(self, original_size, compressed_size, crc32, type_val):
48
48
self .type = type_val
49
49
50
50
51
- def createDVPLFooter (input_size , compressed_size , crc32_val , type_val ):
51
+ def create_dvpl_footer (input_size , compressed_size , crc32_val , type_val ):
52
52
result = bytearray (DVPL_FOOTER_SIZE )
53
53
result [:4 ] = input_size .to_bytes (4 , 'little' )
54
54
result [4 :8 ] = compressed_size .to_bytes (4 , 'little' )
@@ -58,7 +58,7 @@ def createDVPLFooter(input_size, compressed_size, crc32_val, type_val):
58
58
return result
59
59
60
60
61
- def readDVPLFooter (buffer ):
61
+ def read_dvpl_footer (buffer ):
62
62
if len (buffer ) < DVPL_FOOTER_SIZE :
63
63
raise ValueError (Color .RED + "InvalidDVPLFooter: Buffer size is smaller than expected" + Color .RESET )
64
64
@@ -75,14 +75,21 @@ def readDVPLFooter(buffer):
75
75
return DVPLFooter (original_size , compressed_size , crc32_val , type_val )
76
76
77
77
78
- def CompressDVPL (buffer ):
79
- compressed_block = lz4 .block .compress (buffer , store_size = False )
80
- footer_buffer = createDVPLFooter (len (buffer ), len (compressed_block ), zlib .crc32 (compressed_block ), DVPL_TYPE_LZ4 )
78
+ def compress_dvpl (buffer , compression_type = "default" ):
79
+ if compression_type == "fast" :
80
+ mode = "fast"
81
+ elif compression_type == "hc" :
82
+ mode = "high_compression"
83
+ else :
84
+ mode = "default"
85
+
86
+ compressed_block = lz4 .block .compress (buffer , store_size = False , mode = mode )
87
+ footer_buffer = create_dvpl_footer (len (buffer ), len (compressed_block ), zlib .crc32 (compressed_block ), DVPL_TYPE_LZ4 )
81
88
return compressed_block + footer_buffer
82
89
83
90
84
- def DecompressDVPL (buffer ):
85
- footer_data = readDVPLFooter (buffer )
91
+ def decompress_dvpl (buffer ):
92
+ footer_data = read_dvpl_footer (buffer )
86
93
target_block = buffer [:- DVPL_FOOTER_SIZE ]
87
94
88
95
if len (target_block ) != footer_data .compressed_size :
@@ -96,10 +103,10 @@ def DecompressDVPL(buffer):
96
103
raise ValueError (Color .RED + "DVPLTypeSizeMismatch" + Color .RESET )
97
104
return target_block
98
105
elif footer_data .type == DVPL_TYPE_LZ4 :
99
- deDVPL_block = lz4 .block .decompress (target_block , uncompressed_size = footer_data .original_size )
100
- if len (deDVPL_block ) != footer_data .original_size :
106
+ de_dvpl_block = lz4 .block .decompress (target_block , uncompressed_size = footer_data .original_size )
107
+ if len (de_dvpl_block ) != footer_data .original_size :
101
108
raise ValueError (Color .RED + "DVPLDecodeSizeMismatch" + Color .RESET )
102
- return deDVPL_block
109
+ return de_dvpl_block
103
110
else :
104
111
raise ValueError (Color .RED + "UNKNOWN DVPL FORMAT" + Color .RESET )
105
112
@@ -115,16 +122,15 @@ def print_progress_bar(processed_files, total_files):
115
122
sys .stdout .flush ()
116
123
117
124
118
- from pathlib import Path
119
-
120
125
def count_total_files (directory ):
121
126
total_files = 0
122
127
for path in Path (directory ).rglob ('*' ):
123
128
if path .is_file ():
124
129
total_files += 1
125
130
return total_files
126
131
127
- def ConvertDVPLFiles (directory_or_file , config , total_files = None , processed_files = None ):
132
+
133
+ def convert_dvpl (directory_or_file , config , total_files = None , processed_files = None ):
128
134
if total_files is None :
129
135
total_files = count_total_files (directory_or_file )
130
136
if processed_files is None :
@@ -134,10 +140,13 @@ def ConvertDVPLFiles(directory_or_file, config, total_files=None, processed_file
134
140
failure_count = 0
135
141
ignored_count = 0
136
142
143
+ if not os .path .exists (directory_or_file ):
144
+ raise FileNotFoundError (f"File or directory '{ directory_or_file } ' not found." )
145
+
137
146
if Path (directory_or_file ).is_dir ():
138
147
for file_path in Path (directory_or_file ).rglob ('*' ):
139
148
if file_path .is_file ():
140
- succ , fail , ignored = ConvertDVPLFiles (str (file_path ), config , total_files , processed_files )
149
+ succ , fail , ignored = convert_dvpl (str (file_path ), config , total_files , processed_files )
141
150
success_count += succ
142
151
failure_count += fail
143
152
ignored_count += ignored
@@ -154,26 +163,38 @@ def ConvertDVPLFiles(directory_or_file, config, total_files=None, processed_file
154
163
if not should_ignore and (is_decompression or is_compression ):
155
164
file_path = directory_or_file
156
165
try :
157
- with open (file_path , "rb" ) as f :
158
- file_data = f .read ()
159
-
160
- if is_compression :
161
- processed_block = CompressDVPL (file_data )
162
- new_name = file_path + ".dvpl"
166
+ # Check if the file exists before attempting to open it
167
+ if os .path .exists (file_path ):
168
+ with open (file_path , "rb" ) as f :
169
+ file_data = f .read ()
170
+
171
+ if is_compression :
172
+ if config .compression == "fast" :
173
+ processed_block = compress_dvpl (file_data , "fast" )
174
+ elif config .compression == "hc" :
175
+ processed_block = compress_dvpl (file_data , "hc" )
176
+ else :
177
+ processed_block = compress_dvpl (file_data )
178
+ new_name = file_path + ".dvpl"
179
+ else :
180
+ processed_block = decompress_dvpl (file_data )
181
+ new_name = os .path .splitext (file_path )[0 ]
182
+
183
+ with open (new_name , "wb" ) as f :
184
+ f .write (processed_block )
185
+
186
+ if not config .keep_originals :
187
+ os .remove (file_path )
188
+
189
+ success_count += 1
190
+ if config .verbose :
191
+ with output_lock :
192
+ print (f"{ Color .GREEN } \n File{ Color .RESET } { file_path } has been successfully { Color .GREEN } { 'compressed' if is_compression else 'decompressed' } { Color .RESET } into { Color .GREEN } { new_name } { Color .RESET } " )
163
193
else :
164
- processed_block = DecompressDVPL (file_data )
165
- new_name = os .path .splitext (file_path )[0 ]
166
-
167
- with open (new_name , "wb" ) as f :
168
- f .write (processed_block )
169
-
170
- if not config .keep_originals :
171
- os .remove (file_path )
172
-
173
- success_count += 1
174
- if config .verbose :
175
- with output_lock :
176
- print (f"{ Color .GREEN } \n File{ Color .RESET } { file_path } has been successfully { Color .GREEN } { 'compressed' if is_compression else 'decompressed' } { Color .RESET } into { Color .GREEN } { new_name } { Color .RESET } " )
194
+ if config .verbose :
195
+ with output_lock :
196
+ print (f"{ Color .RED } \n Error{ Color .RESET } : File { file_path } does not exist." )
197
+ failure_count += 1
177
198
except Exception as e :
178
199
failure_count += 1
179
200
if config .verbose :
@@ -187,7 +208,8 @@ def ConvertDVPLFiles(directory_or_file, config, total_files=None, processed_file
187
208
188
209
return success_count , failure_count , ignored_count
189
210
190
- def VerifyDVPLFiles (directory_or_file , config , total_files = None , processed_files = None ):
211
+
212
+ def verify_dvpl (directory_or_file , config , total_files = None , processed_files = None ):
191
213
if total_files is None :
192
214
total_files = count_total_files (directory_or_file )
193
215
if processed_files is None :
@@ -197,10 +219,13 @@ def VerifyDVPLFiles(directory_or_file, config, total_files=None, processed_files
197
219
failure_count = 0
198
220
ignored_count = 0
199
221
222
+ if not os .path .exists (directory_or_file ):
223
+ raise FileNotFoundError (f"File or directory '{ directory_or_file } ' not found." )
224
+
200
225
if Path (directory_or_file ).is_dir ():
201
226
for file_path in Path (directory_or_file ).rglob ('*' ):
202
227
if file_path .is_file () and file_path .suffix == '.dvpl' :
203
- succ , fail , ignored = VerifyDVPLFiles (str (file_path ), config , total_files , processed_files )
228
+ succ , fail , ignored = verify_dvpl (str (file_path ), config , total_files , processed_files )
204
229
success_count += succ
205
230
failure_count += fail
206
231
ignored_count += ignored
@@ -219,7 +244,7 @@ def VerifyDVPLFiles(directory_or_file, config, total_files=None, processed_files
219
244
with open (file_path , "rb" ) as f :
220
245
file_data = f .read ()
221
246
222
- footer_data = readDVPLFooter (file_data )
247
+ footer_data = read_dvpl_footer (file_data )
223
248
224
249
target_block = file_data [:- DVPL_FOOTER_SIZE ]
225
250
@@ -233,8 +258,8 @@ def VerifyDVPLFiles(directory_or_file, config, total_files=None, processed_files
233
258
if footer_data .original_size != footer_data .compressed_size or footer_data .type != DVPL_TYPE_NONE :
234
259
raise ValueError (Color .RED + "DVPLTypeSizeMismatch" + Color .RESET )
235
260
elif footer_data .type == DVPL_TYPE_LZ4 :
236
- deDVPL_block = lz4 .block .decompress (target_block , uncompressed_size = footer_data .original_size )
237
- if len (deDVPL_block ) != footer_data .original_size :
261
+ de_dvpl_block = lz4 .block .decompress (target_block , uncompressed_size = footer_data .original_size )
262
+ if len (de_dvpl_block ) != footer_data .original_size :
238
263
raise ValueError (Color .RED + "DVPLDecodeSizeMismatch" + Color .RESET )
239
264
else :
240
265
raise ValueError (Color .RED + "UNKNOWN DVPL FORMAT" + Color .RESET )
@@ -259,19 +284,20 @@ def VerifyDVPLFiles(directory_or_file, config, total_files=None, processed_files
259
284
return success_count , failure_count , ignored_count
260
285
261
286
262
- def process_func (directory_or_file , config , total_files , processed_files ):
287
+
288
+ def process_mode (directory_or_file , config ):
263
289
if config .mode in ["compress" , "decompress" ]:
264
- return ConvertDVPLFiles (directory_or_file , config )
290
+ return convert_dvpl (directory_or_file , config )
265
291
elif config .mode == "verify" :
266
- return VerifyDVPLFiles (directory_or_file , config )
292
+ return verify_dvpl (directory_or_file , config )
267
293
elif config .mode == "help" :
268
- PrintHelpMessage ()
269
- return ( 0 , 0 , 0 ) # Return (0, 0, 0) when in help mode
294
+ print_help_message ()
295
+ return 0 , 0 , 0
270
296
else :
271
297
raise ValueError ("Incorrect mode selected. Use '--help' for information." )
272
298
273
299
274
- def ParseCommandLineArgs ():
300
+ def parse_command_line_args ():
275
301
parser = argparse .ArgumentParser ()
276
302
parser .add_argument ("-m" , "--mode" ,
277
303
help = "mode can be 'c' or 'compress' / 'd' or 'decompress' / 'v' or 'verify' / 'h' or 'help' (for an extended help guide)." )
@@ -284,6 +310,8 @@ def ParseCommandLineArgs():
284
310
help = "Comma-separated list of file extensions to ignore during compression." )
285
311
parser .add_argument ("-t" , "--threads" , type = int , default = 1 ,
286
312
help = "Number of threads to use for processing. Default is 1." )
313
+ parser .add_argument ("-c" , "--compression" , choices = ['default' , 'fast' , 'hc' ],
314
+ help = "Select compression level: 'default' for default compression, 'fast' for fast compression, 'hc' for high compression." )
287
315
args = parser .parse_args ()
288
316
289
317
if not args .mode :
@@ -300,14 +328,14 @@ def ParseCommandLineArgs():
300
328
'h' : 'help'
301
329
}
302
330
303
- # If mode argument is provided and it matches a short form, replace it with the full mode name
331
+ # If mode argument is provided, and it matches a short form, replace it with the full mode name
304
332
if args .mode in mode_mapping :
305
333
args .mode = mode_mapping [args .mode ]
306
334
307
335
return args
308
336
309
337
310
- def PrintHelpMessage ():
338
+ def print_help_message ():
311
339
print ('''$ pydvpl [--mode] [--keep-originals] [--path] [--verbose] [--ignore] [--threads]
312
340
313
341
• flags can be one of the following:
@@ -344,7 +372,7 @@ def PrintHelpMessage():
344
372
345
373
$ pydvpl --mode decompress --keep-originals --path /path/to/decompress/compress.yaml.dvpl
346
374
347
- $ pydvpl --mode dcompress --keep-originals --path /path/to/decompress/compress.yaml
375
+ $ pydvpl --mode decompress --keep-originals --path /path/to/decompress/compress.yaml
348
376
349
377
$ pydvpl --mode compress --path /path/to/decompress --ignore .exe,.dll
350
378
@@ -359,10 +387,14 @@ def PrintHelpMessage():
359
387
$ pydvpl --mode decompress --path /path/to/decompress/compress.yaml.dvpl --threads 10
360
388
361
389
$ pydvpl --mode compress --path /path/to/decompress/compress.yaml --threads 10
390
+
391
+ $ pydvpl --mode compress --path /path/to/decompress/compress.yaml --compression hc
392
+
393
+ $ pydvpl --mode compress --path /path/to/decompress/ --compression fast
362
394
''' )
363
395
364
396
365
- def PrintElapsedTime (elapsed_time ):
397
+ def print_elapsed_time (elapsed_time ):
366
398
if elapsed_time < 1 :
367
399
print (f"\n Processing took { Color .GREEN } { int (elapsed_time * 1000 )} ms{ Color .RESET } \n " )
368
400
elif elapsed_time < 60 :
@@ -380,19 +412,14 @@ def main():
380
412
print (f"{ Color .BLUE } • Info:{ Color .RESET } { Meta .INFO } \n " )
381
413
382
414
start_time = time .time ()
383
- config = ParseCommandLineArgs ()
415
+ config = parse_command_line_args ()
384
416
385
417
if config .threads <= 0 :
386
418
print (f"\n { Color .YELLOW } No threads specified.{ Color .RESET } No processing will be done.\n " )
387
419
return
388
420
389
- total_files = count_total_files (config .path )
390
- manager = multiprocessing .Manager ()
391
- processed_files = manager .Value ('i' , 0 ) # Define processed_files using a Manager
392
-
393
421
try :
394
- process_func_partial = partial (process_func , config = config , total_files = total_files ,
395
- processed_files = processed_files )
422
+ process_func_partial = partial (process_mode , config = config )
396
423
397
424
if config .threads > 1 :
398
425
with multiprocessing .Pool (config .threads ) as pool :
@@ -414,8 +441,8 @@ def main():
414
441
print (f"\n \n { Color .RED } { config .mode .upper ()} FAILED{ Color .RESET } : { e } \n " )
415
442
416
443
elapsed_time = time .time () - start_time
417
- PrintElapsedTime (elapsed_time )
444
+ print_elapsed_time (elapsed_time )
418
445
419
446
420
447
if __name__ == "__main__" :
421
- main ()
448
+ main ()
0 commit comments