Browse code

Add parser for ALZ archives

Andy Ragusa authored on 2024/01/25 05:03:16
Showing 21 changed files
... ...
@@ -9,10 +9,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
9 9
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
10 10
 
11 11
 [[package]]
12
+name = "adler32"
13
+version = "1.2.0"
14
+source = "registry+https://github.com/rust-lang/crates.io-index"
15
+checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
16
+
17
+[[package]]
12 18
 name = "aho-corasick"
13
-version = "1.1.2"
19
+version = "1.1.3"
14 20
 source = "registry+https://github.com/rust-lang/crates.io-index"
15
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
21
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
16 22
 dependencies = [
17 23
  "memchr",
18 24
 ]
... ...
@@ -34,9 +40,9 @@ dependencies = [
34 34
 
35 35
 [[package]]
36 36
 name = "autocfg"
37
-version = "1.1.0"
37
+version = "1.2.0"
38 38
 source = "registry+https://github.com/rust-lang/crates.io-index"
39
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
39
+checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
40 40
 
41 41
 [[package]]
42 42
 name = "base64"
... ...
@@ -63,7 +69,7 @@ dependencies = [
63 63
  "regex",
64 64
  "rustc-hash",
65 65
  "shlex",
66
- "syn 2.0.52",
66
+ "syn 2.0.58",
67 67
  "which",
68 68
 ]
69 69
 
... ...
@@ -81,9 +87,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
81 81
 
82 82
 [[package]]
83 83
 name = "bitflags"
84
-version = "2.4.2"
84
+version = "2.5.0"
85 85
 source = "registry+https://github.com/rust-lang/crates.io-index"
86
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
86
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
87 87
 
88 88
 [[package]]
89 89
 name = "block-buffer"
... ...
@@ -96,15 +102,15 @@ dependencies = [
96 96
 
97 97
 [[package]]
98 98
 name = "bumpalo"
99
-version = "3.15.3"
99
+version = "3.16.0"
100 100
 source = "registry+https://github.com/rust-lang/crates.io-index"
101
-checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
101
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
102 102
 
103 103
 [[package]]
104 104
 name = "bytemuck"
105
-version = "1.14.3"
105
+version = "1.15.0"
106 106
 source = "registry+https://github.com/rust-lang/crates.io-index"
107
-checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
107
+checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
108 108
 
109 109
 [[package]]
110 110
 name = "byteorder"
... ...
@@ -114,9 +120,19 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
114 114
 
115 115
 [[package]]
116 116
 name = "bytes"
117
-version = "1.5.0"
117
+version = "1.6.0"
118 118
 source = "registry+https://github.com/rust-lang/crates.io-index"
119
-checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
119
+checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
120
+
121
+[[package]]
122
+name = "bzip2-rs"
123
+version = "0.1.2"
124
+source = "registry+https://github.com/rust-lang/crates.io-index"
125
+checksum = "beeb59e7e4c811ab37cc73680c798c7a5da77fc9989c62b09138e31ee740f735"
126
+dependencies = [
127
+ "crc32fast",
128
+ "tinyvec",
129
+]
120 130
 
121 131
 [[package]]
122 132
 name = "cbindgen"
... ...
@@ -138,9 +154,9 @@ dependencies = [
138 138
 
139 139
 [[package]]
140 140
 name = "cc"
141
-version = "1.0.88"
141
+version = "1.0.94"
142 142
 source = "registry+https://github.com/rust-lang/crates.io-index"
143
-checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
143
+checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
144 144
 
145 145
 [[package]]
146 146
 name = "cexpr"
... ...
@@ -159,16 +175,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
159 159
 
160 160
 [[package]]
161 161
 name = "chrono"
162
-version = "0.4.34"
162
+version = "0.4.37"
163 163
 source = "registry+https://github.com/rust-lang/crates.io-index"
164
-checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
164
+checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
165 165
 dependencies = [
166 166
  "android-tzdata",
167 167
  "iana-time-zone",
168 168
  "js-sys",
169 169
  "num-traits",
170 170
  "wasm-bindgen",
171
- "windows-targets 0.52.4",
171
+ "windows-targets",
172 172
 ]
173 173
 
174 174
 [[package]]
... ...
@@ -177,12 +193,15 @@ version = "0.0.1"
177 177
 dependencies = [
178 178
  "base64",
179 179
  "bindgen",
180
+ "byteorder",
181
+ "bzip2-rs",
180 182
  "cbindgen",
181 183
  "delharc",
182 184
  "flate2",
183 185
  "hex",
184 186
  "hex-literal",
185 187
  "image",
188
+ "inflate",
186 189
  "libc",
187 190
  "log",
188 191
  "num-traits",
... ...
@@ -284,7 +303,7 @@ version = "0.5.0"
284 284
 source = "registry+https://github.com/rust-lang/crates.io-index"
285 285
 checksum = "f420b1ede12094758715adaee221d93cb2af86dc499cef368ef81a23fea96029"
286 286
 dependencies = [
287
- "bitflags 2.4.2",
287
+ "bitflags 2.5.0",
288 288
  "chrono",
289 289
  "memchr",
290 290
 ]
... ...
@@ -301,15 +320,15 @@ dependencies = [
301 301
 
302 302
 [[package]]
303 303
 name = "either"
304
-version = "1.10.0"
304
+version = "1.11.0"
305 305
 source = "registry+https://github.com/rust-lang/crates.io-index"
306
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
306
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
307 307
 
308 308
 [[package]]
309 309
 name = "encoding_rs"
310
-version = "0.8.33"
310
+version = "0.8.34"
311 311
 source = "registry+https://github.com/rust-lang/crates.io-index"
312
-checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
312
+checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
313 313
 dependencies = [
314 314
  "cfg-if",
315 315
 ]
... ...
@@ -332,7 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
332 332
 checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
333 333
 dependencies = [
334 334
  "libc",
335
- "windows-sys 0.52.0",
335
+ "windows-sys",
336 336
 ]
337 337
 
338 338
 [[package]]
... ...
@@ -353,9 +372,9 @@ dependencies = [
353 353
 
354 354
 [[package]]
355 355
 name = "fastrand"
356
-version = "2.0.1"
356
+version = "2.0.2"
357 357
 source = "registry+https://github.com/rust-lang/crates.io-index"
358
-checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
358
+checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
359 359
 
360 360
 [[package]]
361 361
 name = "fdeflate"
... ...
@@ -413,9 +432,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
413 413
 
414 414
 [[package]]
415 415
 name = "half"
416
-version = "2.4.0"
416
+version = "2.4.1"
417 417
 source = "registry+https://github.com/rust-lang/crates.io-index"
418
-checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e"
418
+checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
419 419
 dependencies = [
420 420
  "cfg-if",
421 421
  "crunchy",
... ...
@@ -451,7 +470,7 @@ version = "0.5.9"
451 451
 source = "registry+https://github.com/rust-lang/crates.io-index"
452 452
 checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
453 453
 dependencies = [
454
- "windows-sys 0.52.0",
454
+ "windows-sys",
455 455
 ]
456 456
 
457 457
 [[package]]
... ...
@@ -506,6 +525,15 @@ dependencies = [
506 506
 ]
507 507
 
508 508
 [[package]]
509
+name = "inflate"
510
+version = "0.4.5"
511
+source = "registry+https://github.com/rust-lang/crates.io-index"
512
+checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
513
+dependencies = [
514
+ "adler32",
515
+]
516
+
517
+[[package]]
509 518
 name = "itertools"
510 519
 version = "0.10.5"
511 520
 source = "registry+https://github.com/rust-lang/crates.io-index"
... ...
@@ -516,9 +544,9 @@ dependencies = [
516 516
 
517 517
 [[package]]
518 518
 name = "itoa"
519
-version = "1.0.10"
519
+version = "1.0.11"
520 520
 source = "registry+https://github.com/rust-lang/crates.io-index"
521
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
521
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
522 522
 
523 523
 [[package]]
524 524
 name = "jpeg-decoder"
... ...
@@ -531,9 +559,9 @@ dependencies = [
531 531
 
532 532
 [[package]]
533 533
 name = "js-sys"
534
-version = "0.3.68"
534
+version = "0.3.69"
535 535
 source = "registry+https://github.com/rust-lang/crates.io-index"
536
-checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
536
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
537 537
 dependencies = [
538 538
  "wasm-bindgen",
539 539
 ]
... ...
@@ -564,12 +592,12 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
564 564
 
565 565
 [[package]]
566 566
 name = "libloading"
567
-version = "0.8.1"
567
+version = "0.8.3"
568 568
 source = "registry+https://github.com/rust-lang/crates.io-index"
569
-checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
569
+checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
570 570
 dependencies = [
571 571
  "cfg-if",
572
- "windows-sys 0.48.0",
572
+ "windows-targets",
573 573
 ]
574 574
 
575 575
 [[package]]
... ...
@@ -596,9 +624,9 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
596 596
 
597 597
 [[package]]
598 598
 name = "memchr"
599
-version = "2.7.1"
599
+version = "2.7.2"
600 600
 source = "registry+https://github.com/rust-lang/crates.io-index"
601
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
601
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
602 602
 
603 603
 [[package]]
604 604
 name = "minimal-lexical"
... ...
@@ -702,12 +730,12 @@ dependencies = [
702 702
 
703 703
 [[package]]
704 704
 name = "prettyplease"
705
-version = "0.2.16"
705
+version = "0.2.17"
706 706
 source = "registry+https://github.com/rust-lang/crates.io-index"
707
-checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
707
+checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7"
708 708
 dependencies = [
709 709
  "proc-macro2",
710
- "syn 2.0.52",
710
+ "syn 2.0.58",
711 711
 ]
712 712
 
713 713
 [[package]]
... ...
@@ -721,9 +749,9 @@ dependencies = [
721 721
 
722 722
 [[package]]
723 723
 name = "proc-macro2"
724
-version = "1.0.78"
724
+version = "1.0.79"
725 725
 source = "registry+https://github.com/rust-lang/crates.io-index"
726
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
726
+checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
727 727
 dependencies = [
728 728
  "unicode-ident",
729 729
 ]
... ...
@@ -739,18 +767,18 @@ dependencies = [
739 739
 
740 740
 [[package]]
741 741
 name = "quote"
742
-version = "1.0.35"
742
+version = "1.0.36"
743 743
 source = "registry+https://github.com/rust-lang/crates.io-index"
744
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
744
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
745 745
 dependencies = [
746 746
  "proc-macro2",
747 747
 ]
748 748
 
749 749
 [[package]]
750 750
 name = "rayon"
751
-version = "1.9.0"
751
+version = "1.10.0"
752 752
 source = "registry+https://github.com/rust-lang/crates.io-index"
753
-checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
753
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
754 754
 dependencies = [
755 755
  "either",
756 756
  "rayon-core",
... ...
@@ -768,9 +796,9 @@ dependencies = [
768 768
 
769 769
 [[package]]
770 770
 name = "regex"
771
-version = "1.10.3"
771
+version = "1.10.4"
772 772
 source = "registry+https://github.com/rust-lang/crates.io-index"
773
-checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
773
+checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
774 774
 dependencies = [
775 775
  "aho-corasick",
776 776
  "memchr",
... ...
@@ -780,9 +808,9 @@ dependencies = [
780 780
 
781 781
 [[package]]
782 782
 name = "regex-automata"
783
-version = "0.4.5"
783
+version = "0.4.6"
784 784
 source = "registry+https://github.com/rust-lang/crates.io-index"
785
-checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
785
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
786 786
 dependencies = [
787 787
  "aho-corasick",
788 788
  "memchr",
... ...
@@ -791,9 +819,9 @@ dependencies = [
791 791
 
792 792
 [[package]]
793 793
 name = "regex-syntax"
794
-version = "0.8.2"
794
+version = "0.8.3"
795 795
 source = "registry+https://github.com/rust-lang/crates.io-index"
796
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
796
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
797 797
 
798 798
 [[package]]
799 799
 name = "rustc-hash"
... ...
@@ -827,15 +855,15 @@ dependencies = [
827 827
 
828 828
 [[package]]
829 829
 name = "rustix"
830
-version = "0.38.31"
830
+version = "0.38.32"
831 831
 source = "registry+https://github.com/rust-lang/crates.io-index"
832
-checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
832
+checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
833 833
 dependencies = [
834
- "bitflags 2.4.2",
834
+ "bitflags 2.5.0",
835 835
  "errno",
836 836
  "libc",
837 837
  "linux-raw-sys",
838
- "windows-sys 0.52.0",
838
+ "windows-sys",
839 839
 ]
840 840
 
841 841
 [[package]]
... ...
@@ -867,14 +895,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
867 867
 dependencies = [
868 868
  "proc-macro2",
869 869
  "quote",
870
- "syn 2.0.52",
870
+ "syn 2.0.58",
871 871
 ]
872 872
 
873 873
 [[package]]
874 874
 name = "serde_json"
875
-version = "1.0.114"
875
+version = "1.0.115"
876 876
 source = "registry+https://github.com/rust-lang/crates.io-index"
877
-checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
877
+checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
878 878
 dependencies = [
879 879
  "itoa",
880 880
  "ryu",
... ...
@@ -917,9 +945,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
917 917
 
918 918
 [[package]]
919 919
 name = "smallvec"
920
-version = "1.13.1"
920
+version = "1.13.2"
921 921
 source = "registry+https://github.com/rust-lang/crates.io-index"
922
-checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
922
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
923 923
 
924 924
 [[package]]
925 925
 name = "spin"
... ...
@@ -949,9 +977,9 @@ dependencies = [
949 949
 
950 950
 [[package]]
951 951
 name = "syn"
952
-version = "2.0.52"
952
+version = "2.0.58"
953 953
 source = "registry+https://github.com/rust-lang/crates.io-index"
954
-checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
954
+checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
955 955
 dependencies = [
956 956
  "proc-macro2",
957 957
  "quote",
... ...
@@ -967,27 +995,27 @@ dependencies = [
967 967
  "cfg-if",
968 968
  "fastrand",
969 969
  "rustix",
970
- "windows-sys 0.52.0",
970
+ "windows-sys",
971 971
 ]
972 972
 
973 973
 [[package]]
974 974
 name = "thiserror"
975
-version = "1.0.57"
975
+version = "1.0.58"
976 976
 source = "registry+https://github.com/rust-lang/crates.io-index"
977
-checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
977
+checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
978 978
 dependencies = [
979 979
  "thiserror-impl",
980 980
 ]
981 981
 
982 982
 [[package]]
983 983
 name = "thiserror-impl"
984
-version = "1.0.57"
984
+version = "1.0.58"
985 985
 source = "registry+https://github.com/rust-lang/crates.io-index"
986
-checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
986
+checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
987 987
 dependencies = [
988 988
  "proc-macro2",
989 989
  "quote",
990
- "syn 2.0.52",
990
+ "syn 2.0.58",
991 991
 ]
992 992
 
993 993
 [[package]]
... ...
@@ -1002,6 +1030,12 @@ dependencies = [
1002 1002
 ]
1003 1003
 
1004 1004
 [[package]]
1005
+name = "tinyvec"
1006
+version = "1.6.0"
1007
+source = "registry+https://github.com/rust-lang/crates.io-index"
1008
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
1009
+
1010
+[[package]]
1005 1011
 name = "toml"
1006 1012
 version = "0.5.11"
1007 1013
 source = "registry+https://github.com/rust-lang/crates.io-index"
... ...
@@ -1040,9 +1074,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
1040 1040
 
1041 1041
 [[package]]
1042 1042
 name = "uuid"
1043
-version = "1.7.0"
1043
+version = "1.8.0"
1044 1044
 source = "registry+https://github.com/rust-lang/crates.io-index"
1045
-checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
1045
+checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
1046 1046
 
1047 1047
 [[package]]
1048 1048
 name = "version_check"
... ...
@@ -1052,9 +1086,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
1052 1052
 
1053 1053
 [[package]]
1054 1054
 name = "wasm-bindgen"
1055
-version = "0.2.91"
1055
+version = "0.2.92"
1056 1056
 source = "registry+https://github.com/rust-lang/crates.io-index"
1057
-checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
1057
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
1058 1058
 dependencies = [
1059 1059
  "cfg-if",
1060 1060
  "wasm-bindgen-macro",
... ...
@@ -1062,24 +1096,24 @@ dependencies = [
1062 1062
 
1063 1063
 [[package]]
1064 1064
 name = "wasm-bindgen-backend"
1065
-version = "0.2.91"
1065
+version = "0.2.92"
1066 1066
 source = "registry+https://github.com/rust-lang/crates.io-index"
1067
-checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
1067
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
1068 1068
 dependencies = [
1069 1069
  "bumpalo",
1070 1070
  "log",
1071 1071
  "once_cell",
1072 1072
  "proc-macro2",
1073 1073
  "quote",
1074
- "syn 2.0.52",
1074
+ "syn 2.0.58",
1075 1075
  "wasm-bindgen-shared",
1076 1076
 ]
1077 1077
 
1078 1078
 [[package]]
1079 1079
 name = "wasm-bindgen-macro"
1080
-version = "0.2.91"
1080
+version = "0.2.92"
1081 1081
 source = "registry+https://github.com/rust-lang/crates.io-index"
1082
-checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
1082
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
1083 1083
 dependencies = [
1084 1084
  "quote",
1085 1085
  "wasm-bindgen-macro-support",
... ...
@@ -1087,22 +1121,22 @@ dependencies = [
1087 1087
 
1088 1088
 [[package]]
1089 1089
 name = "wasm-bindgen-macro-support"
1090
-version = "0.2.91"
1090
+version = "0.2.92"
1091 1091
 source = "registry+https://github.com/rust-lang/crates.io-index"
1092
-checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
1092
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
1093 1093
 dependencies = [
1094 1094
  "proc-macro2",
1095 1095
  "quote",
1096
- "syn 2.0.52",
1096
+ "syn 2.0.58",
1097 1097
  "wasm-bindgen-backend",
1098 1098
  "wasm-bindgen-shared",
1099 1099
 ]
1100 1100
 
1101 1101
 [[package]]
1102 1102
 name = "wasm-bindgen-shared"
1103
-version = "0.2.91"
1103
+version = "0.2.92"
1104 1104
 source = "registry+https://github.com/rust-lang/crates.io-index"
1105
-checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
1105
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
1106 1106
 
1107 1107
 [[package]]
1108 1108
 name = "weezl"
... ...
@@ -1124,9 +1158,9 @@ dependencies = [
1124 1124
 
1125 1125
 [[package]]
1126 1126
 name = "widestring"
1127
-version = "1.0.2"
1127
+version = "1.1.0"
1128 1128
 source = "registry+https://github.com/rust-lang/crates.io-index"
1129
-checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
1129
+checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
1130 1130
 
1131 1131
 [[package]]
1132 1132
 name = "windows-core"
... ...
@@ -1134,16 +1168,7 @@ version = "0.52.0"
1134 1134
 source = "registry+https://github.com/rust-lang/crates.io-index"
1135 1135
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
1136 1136
 dependencies = [
1137
- "windows-targets 0.52.4",
1138
-]
1139
-
1140
-[[package]]
1141
-name = "windows-sys"
1142
-version = "0.48.0"
1143
-source = "registry+https://github.com/rust-lang/crates.io-index"
1144
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
1145
-dependencies = [
1146
- "windows-targets 0.48.5",
1137
+ "windows-targets",
1147 1138
 ]
1148 1139
 
1149 1140
 [[package]]
... ...
@@ -1152,122 +1177,72 @@ version = "0.52.0"
1152 1152
 source = "registry+https://github.com/rust-lang/crates.io-index"
1153 1153
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
1154 1154
 dependencies = [
1155
- "windows-targets 0.52.4",
1156
-]
1157
-
1158
-[[package]]
1159
-name = "windows-targets"
1160
-version = "0.48.5"
1161
-source = "registry+https://github.com/rust-lang/crates.io-index"
1162
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
1163
-dependencies = [
1164
- "windows_aarch64_gnullvm 0.48.5",
1165
- "windows_aarch64_msvc 0.48.5",
1166
- "windows_i686_gnu 0.48.5",
1167
- "windows_i686_msvc 0.48.5",
1168
- "windows_x86_64_gnu 0.48.5",
1169
- "windows_x86_64_gnullvm 0.48.5",
1170
- "windows_x86_64_msvc 0.48.5",
1155
+ "windows-targets",
1171 1156
 ]
1172 1157
 
1173 1158
 [[package]]
1174 1159
 name = "windows-targets"
1175
-version = "0.52.4"
1160
+version = "0.52.5"
1176 1161
 source = "registry+https://github.com/rust-lang/crates.io-index"
1177
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
1162
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
1178 1163
 dependencies = [
1179
- "windows_aarch64_gnullvm 0.52.4",
1180
- "windows_aarch64_msvc 0.52.4",
1181
- "windows_i686_gnu 0.52.4",
1182
- "windows_i686_msvc 0.52.4",
1183
- "windows_x86_64_gnu 0.52.4",
1184
- "windows_x86_64_gnullvm 0.52.4",
1185
- "windows_x86_64_msvc 0.52.4",
1164
+ "windows_aarch64_gnullvm",
1165
+ "windows_aarch64_msvc",
1166
+ "windows_i686_gnu",
1167
+ "windows_i686_gnullvm",
1168
+ "windows_i686_msvc",
1169
+ "windows_x86_64_gnu",
1170
+ "windows_x86_64_gnullvm",
1171
+ "windows_x86_64_msvc",
1186 1172
 ]
1187 1173
 
1188 1174
 [[package]]
1189 1175
 name = "windows_aarch64_gnullvm"
1190
-version = "0.48.5"
1191
-source = "registry+https://github.com/rust-lang/crates.io-index"
1192
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
1193
-
1194
-[[package]]
1195
-name = "windows_aarch64_gnullvm"
1196
-version = "0.52.4"
1197
-source = "registry+https://github.com/rust-lang/crates.io-index"
1198
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
1199
-
1200
-[[package]]
1201
-name = "windows_aarch64_msvc"
1202
-version = "0.48.5"
1176
+version = "0.52.5"
1203 1177
 source = "registry+https://github.com/rust-lang/crates.io-index"
1204
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
1178
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
1205 1179
 
1206 1180
 [[package]]
1207 1181
 name = "windows_aarch64_msvc"
1208
-version = "0.52.4"
1182
+version = "0.52.5"
1209 1183
 source = "registry+https://github.com/rust-lang/crates.io-index"
1210
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
1184
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
1211 1185
 
1212 1186
 [[package]]
1213 1187
 name = "windows_i686_gnu"
1214
-version = "0.48.5"
1188
+version = "0.52.5"
1215 1189
 source = "registry+https://github.com/rust-lang/crates.io-index"
1216
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
1190
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
1217 1191
 
1218 1192
 [[package]]
1219
-name = "windows_i686_gnu"
1220
-version = "0.52.4"
1221
-source = "registry+https://github.com/rust-lang/crates.io-index"
1222
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
1223
-
1224
-[[package]]
1225
-name = "windows_i686_msvc"
1226
-version = "0.48.5"
1193
+name = "windows_i686_gnullvm"
1194
+version = "0.52.5"
1227 1195
 source = "registry+https://github.com/rust-lang/crates.io-index"
1228
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
1196
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
1229 1197
 
1230 1198
 [[package]]
1231 1199
 name = "windows_i686_msvc"
1232
-version = "0.52.4"
1233
-source = "registry+https://github.com/rust-lang/crates.io-index"
1234
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
1235
-
1236
-[[package]]
1237
-name = "windows_x86_64_gnu"
1238
-version = "0.48.5"
1200
+version = "0.52.5"
1239 1201
 source = "registry+https://github.com/rust-lang/crates.io-index"
1240
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
1202
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
1241 1203
 
1242 1204
 [[package]]
1243 1205
 name = "windows_x86_64_gnu"
1244
-version = "0.52.4"
1206
+version = "0.52.5"
1245 1207
 source = "registry+https://github.com/rust-lang/crates.io-index"
1246
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
1208
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
1247 1209
 
1248 1210
 [[package]]
1249 1211
 name = "windows_x86_64_gnullvm"
1250
-version = "0.48.5"
1251
-source = "registry+https://github.com/rust-lang/crates.io-index"
1252
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
1253
-
1254
-[[package]]
1255
-name = "windows_x86_64_gnullvm"
1256
-version = "0.52.4"
1257
-source = "registry+https://github.com/rust-lang/crates.io-index"
1258
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
1259
-
1260
-[[package]]
1261
-name = "windows_x86_64_msvc"
1262
-version = "0.48.5"
1212
+version = "0.52.5"
1263 1213
 source = "registry+https://github.com/rust-lang/crates.io-index"
1264
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
1214
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
1265 1215
 
1266 1216
 [[package]]
1267 1217
 name = "windows_x86_64_msvc"
1268
-version = "0.52.4"
1218
+version = "0.52.5"
1269 1219
 source = "registry+https://github.com/rust-lang/crates.io-index"
1270
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
1220
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
1271 1221
 
1272 1222
 [[package]]
1273 1223
 name = "zune-inflate"
... ...
@@ -108,6 +108,7 @@ static struct dconf_module modules[] = {
108 108
     {"ARCHIVE", "EGG", ARCH_CONF_EGG, 1},
109 109
     {"ARCHIVE", "UDF", ARCH_CONF_UDF, 1},
110 110
     {"ARCHIVE", "LHA", ARCH_CONF_LHA_LZH, 1},
111
+    {"ARCHIVE", "ALZ", ARCH_CONF_ALZ, 1},
111 112
 
112 113
     {"DOCUMENT", "HTML", DOC_CONF_HTML, 1},
113 114
     {"DOCUMENT", "RTF", DOC_CONF_RTF, 1},
... ...
@@ -98,6 +98,7 @@ struct cli_dconf {
98 98
 #define ARCH_CONF_EGG     0x4000000
99 99
 #define ARCH_CONF_UDF     0x8000000
100 100
 #define ARCH_CONF_LHA_LZH 0x10000000
101
+#define ARCH_CONF_ALZ     0x20000000
101 102
 
102 103
 /* Document flags */
103 104
 #define DOC_CONF_HTML         0x1
... ...
@@ -138,6 +138,7 @@ static const struct ftmap_s {
138 138
     { "CL_TYPE_EGG",                CL_TYPE_EGG             },
139 139
     { "CL_TYPE_EGGSFX",             CL_TYPE_EGGSFX          },
140 140
     { "CL_TYPE_UDF",                CL_TYPE_UDF             },
141
+    { "CL_TYPE_ALZ",                CL_TYPE_ALZ             },
141 142
     { "CL_TYPE_ONENOTE",            CL_TYPE_ONENOTE         },
142 143
     { "CL_TYPE_PYTHON_COMPILED",    CL_TYPE_PYTHON_COMPILED },
143 144
     { "CL_TYPE_LHA_LZH",            CL_TYPE_LHA_LZH         },
... ...
@@ -126,6 +126,7 @@ typedef enum cli_file {
126 126
     CL_TYPE_MHTML,
127 127
     CL_TYPE_LNK,
128 128
     CL_TYPE_UDF,
129
+    CL_TYPE_ALZ,
129 130
     CL_TYPE_OTHER,  /* on-the-fly, used for target 14 (OTHER) */
130 131
     CL_TYPE_IGNORED /* please don't add anything below */
131 132
 } cli_file_t;
... ...
@@ -301,5 +301,6 @@ static const char *ftypes_int[] = {
301 301
     "1:2:2d6c68(30|31|32|33|34|35|36|37|64|78)2d:LHA or LZH archive:CL_TYPE_ANY:CL_TYPE_LHA_LZH:210",
302 302
     "1:2:2d6c7a(73|34|35)2d:LHA archive using .LZS extension:CL_TYPE_ANY:CL_TYPE_LHA_LZH:210",
303 303
     "1:2:2d706d302d:LHA archive using PMarc (.PMA) extension:CL_TYPE_ANY:CL_TYPE_LHA_LZH:210",
304
+    "0:0:414c5a01:ALZ:CL_TYPE_ANY:CL_TYPE_ALZ:210", 
304 305
     NULL};
305 306
 #endif
... ...
@@ -4550,6 +4550,11 @@ cl_error_t cli_magic_scan(cli_ctx *ctx, cli_file_t type)
4550 4550
             if (SCAN_PARSE_ONENOTE && (DCONF_ARCH & DOC_CONF_ONENOTE))
4551 4551
                 ret = scan_onenote(ctx);
4552 4552
             break;
4553
+        case CL_TYPE_ALZ:
4554
+            if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ALZ)) {
4555
+                ret = cli_scanalz(ctx);
4556
+            }
4557
+            break;
4553 4558
 
4554 4559
         case CL_TYPE_LHA_LZH:
4555 4560
             if (SCAN_PARSE_ARCHIVE && (DCONF_ARCH & ARCH_CONF_LHA_LZH))
... ...
@@ -22,6 +22,9 @@ unicode-segmentation = "1.10"
22 22
 bindgen = "0.65"
23 23
 onenote_parser = { git = "https://github.com/Cisco-Talos/onenote.rs.git", branch = "CLAM-2329-new-from-slice" }
24 24
 hex-literal = "0.4"
25
+inflate = "0.4"
26
+bzip2-rs = "0.1"
27
+byteorder = "1.5"
25 28
 delharc = "0.5"
26 29
 
27 30
 [lib]
... ...
@@ -37,6 +37,7 @@ include = [
37 37
   "evidence::evidence_add_indicator",
38 38
   "evidence::IndicatorType",
39 39
   "scanners::scan_onenote",
40
+  "scanners::cli_scanalz",
40 41
 ]
41 42
 
42 43
 # prefix = "CAPI_"
43 44
new file mode 100644
... ...
@@ -0,0 +1,552 @@
0
+/*
1
+ *  ALZ archive extraction. 
2
+ *
3
+ *  Copyright (C) 2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4
+ *
5
+ *  Authors: Andy Ragusa
6
+ *
7
+ *  This program is free software; you can redistribute it and/or modify
8
+ *  it under the terms of the GNU General Public License version 2 as
9
+ *  published by the Free Software Foundation.
10
+ *
11
+ *  This program is distributed in the hope that it will be useful,
12
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ *  GNU General Public License for more details.
15
+ *
16
+ *  You should have received a copy of the GNU General Public License
17
+ *  along with this program; if not, write to the Free Software
18
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
+ *  MA 02110-1301, USA.
20
+ */
21
+
22
+/*
23
+#![warn(
24
+    clippy::all,
25
+    clippy::restriction,
26
+    clippy::pedantic,
27
+    clippy::nursery,
28
+    clippy::cargo,
29
+)]
30
+*/
31
+
32
+use std::io::{Cursor, Read};
33
+
34
+use byteorder::{LittleEndian, ReadBytesExt};
35
+use bzip2_rs::DecoderReader;
36
+use inflate::InflateStream;
37
+use log::debug;
38
+
39
+/// File header
40
+const ALZ_FILE_HEADER: u32 = 0x015a_4c41;
41
+/// Local file header
42
+const ALZ_LOCAL_FILE_HEADER: u32 = 0x015a_4c42;
43
+/// Central directory header
44
+const ALZ_CENTRAL_DIRECTORY_HEADER: u32 = 0x015a_4c43;
45
+/// End of Central directory header
46
+const ALZ_END_OF_CENTRAL_DIRECTORY_HEADER: u32 = 0x025a_4c43;
47
+
48
+/// Error enumerates all possible errors returned by this library.
49
+#[derive(thiserror::Error, Debug)]
50
+pub enum Error {
51
+    #[error("Error parsing ALZ archive: {0}")]
52
+    Parse(&'static str),
53
+
54
+    #[error("Unrecognized sig: '{0}'")]
55
+    UnrecognizedSig(String),
56
+
57
+    #[error("Unsupported ALZ feature: {0}")]
58
+    UnsupportedFeature(&'static str),
59
+
60
+    #[error("Failed to extract file")]
61
+    Extract,
62
+
63
+    #[error("Failed to read field: {0}")]
64
+    Read(&'static str),
65
+}
66
+
67
+struct AlzLocalFileHeaderHead {
68
+    file_name_length: u16,
69
+
70
+    file_attribute: u8,
71
+
72
+    file_time_date: u32,
73
+
74
+    file_descriptor: u8,
75
+
76
+    unknown: u8,
77
+}
78
+
79
+const ALZ_ENCR_HEADER_LEN: u32 = 12;
80
+
81
+struct AlzLocalFileHeader {
82
+    head: AlzLocalFileHeaderHead,
83
+
84
+    compression_method: u8,
85
+    unknown: u8,
86
+    file_crc: u32,
87
+
88
+    /* Can be smaller sizes, depending on file_descriptor/0x10 .*/
89
+    compressed_size: u64,
90
+    uncompressed_size: u64,
91
+
92
+    file_name: String,
93
+
94
+    enc_chk: [u8; ALZ_ENCR_HEADER_LEN as usize],
95
+
96
+    start_of_compressed_data: u64,
97
+}
98
+
99
+#[allow(dead_code)]
100
+enum AlzFileAttribute {
101
+    Readonly = 0x1,
102
+    Hidden = 0x2,
103
+    Directory = 0x10,
104
+    File = 0x20,
105
+}
106
+
107
+impl AlzLocalFileHeader {
108
+    const fn is_encrypted(&self) -> bool {
109
+        0 != (self.head.file_descriptor & 0x1)
110
+    }
111
+
112
+    const fn is_data_descriptor(&self) -> bool {
113
+        0 != (self.head.file_descriptor & 0x8)
114
+    }
115
+
116
+    const fn is_directory(&self) -> bool {
117
+        0 != ((AlzFileAttribute::Directory as u8) & self.head.file_attribute)
118
+    }
119
+
120
+    const fn _is_file(&self) -> bool {
121
+        0 != ((AlzFileAttribute::File as u8) & self.head.file_attribute)
122
+    }
123
+
124
+    const fn _is_readonly(&self) -> bool {
125
+        0 != ((AlzFileAttribute::Readonly as u8) & self.head.file_attribute)
126
+    }
127
+
128
+    const fn _is_hidden(&self) -> bool {
129
+        0 != ((AlzFileAttribute::Hidden as u8) & self.head.file_attribute)
130
+    }
131
+
132
+    fn _dump(&self) {
133
+        println!(
134
+            "self.start_of_compressed_data = {}",
135
+            self.start_of_compressed_data
136
+        );
137
+
138
+        println!(
139
+            "self.head.file_name_length = {:x}",
140
+            self.head.file_name_length
141
+        );
142
+        println!(
143
+            "self.head.file_attribute = {:02x}",
144
+            self.head.file_attribute
145
+        );
146
+        println!("self.head.file_time_date = {:x}", self.head.file_time_date);
147
+        println!(
148
+            "self.head.file_descriptor = {:x}",
149
+            self.head.file_descriptor
150
+        );
151
+        println!("self.head.unknown = {:x}", self.head.unknown);
152
+
153
+        println!("self.compression_method = {:x}", self.compression_method);
154
+        println!("self.unknown = {:x}", self.unknown);
155
+        println!("self.file_crc = {:x}", self.file_crc);
156
+        println!("self.compressed_size = {:x}", self.compressed_size);
157
+        println!("self.uncompressed_size = {:x}", self.uncompressed_size);
158
+
159
+        println!("self.file_name = {}", self.file_name);
160
+
161
+        print!("self.enc_chk = ");
162
+        for i in 0..ALZ_ENCR_HEADER_LEN {
163
+            if 0 != i {
164
+                print!(" ");
165
+            }
166
+            print!("{}", self.enc_chk[i as usize]);
167
+        }
168
+        println!();
169
+
170
+        println!("is_encrypted = {}", self.is_encrypted());
171
+        println!("is_data_descriptor = {}", self.is_data_descriptor());
172
+
173
+        println!();
174
+    }
175
+
176
+    pub const fn new() -> Self {
177
+        Self {
178
+            head: AlzLocalFileHeaderHead {
179
+                file_name_length: 0,
180
+                file_attribute: 0,
181
+                file_time_date: 0,
182
+                file_descriptor: 0,
183
+                unknown: 0,
184
+            },
185
+
186
+            compression_method: 0,
187
+            unknown: 0,
188
+            file_crc: 0,
189
+            compressed_size: 0,
190
+            uncompressed_size: 0,
191
+            file_name: String::new(),
192
+            enc_chk: [0; ALZ_ENCR_HEADER_LEN as usize],
193
+            start_of_compressed_data: 0,
194
+        }
195
+    }
196
+
197
+    pub fn parse(&mut self, cursor: &mut std::io::Cursor<&Vec<u8>>) -> Result<(), Error> {
198
+        self.head.file_name_length = cursor
199
+            .read_u16::<LittleEndian>()
200
+            .map_err(|_| Error::Read("file_name_length"))?;
201
+        self.head.file_attribute = cursor
202
+            .read_u8()
203
+            .map_err(|_| Error::Read("file_attribute"))?;
204
+        self.head.file_time_date = cursor
205
+            .read_u32::<LittleEndian>()
206
+            .map_err(|_| Error::Read("file_time_date"))?;
207
+        self.head.file_descriptor = cursor
208
+            .read_u8()
209
+            .map_err(|_| Error::Read("file_descriptor"))?;
210
+        self.head.unknown = cursor.read_u8().map_err(|_| Error::Read("unknown u8"))?;
211
+
212
+        if 0 == self.head.file_name_length {
213
+            return Err(Error::Parse("File Name Length is zero"));
214
+        }
215
+
216
+        let byte_len = self.head.file_descriptor / 0x10;
217
+        if byte_len > 0 {
218
+            self.compression_method = cursor
219
+                .read_u8()
220
+                .map_err(|_| Error::Read("compression_method"))?;
221
+            self.unknown = cursor.read_u8().map_err(|_| Error::Read("unknown u8"))?;
222
+            self.file_crc = cursor
223
+                .read_u32::<LittleEndian>()
224
+                .map_err(|_| Error::Read("file_crc"))?;
225
+
226
+            match byte_len {
227
+                1 => {
228
+                    self.compressed_size = u64::from(
229
+                        cursor
230
+                            .read_u8()
231
+                            .map_err(|_| Error::Read("compressed_size"))?,
232
+                    );
233
+                    self.uncompressed_size = u64::from(
234
+                        cursor
235
+                            .read_u8()
236
+                            .map_err(|_| Error::Read("uncompressed_size"))?,
237
+                    );
238
+                }
239
+                2 => {
240
+                    self.compressed_size = u64::from(
241
+                        cursor
242
+                            .read_u16::<LittleEndian>()
243
+                            .map_err(|_| Error::Read("compressed_size"))?,
244
+                    );
245
+                    self.uncompressed_size = u64::from(
246
+                        cursor
247
+                            .read_u16::<LittleEndian>()
248
+                            .map_err(|_| Error::Read("uncompressed_size"))?,
249
+                    );
250
+                }
251
+                4 => {
252
+                    self.compressed_size = u64::from(
253
+                        cursor
254
+                            .read_u32::<LittleEndian>()
255
+                            .map_err(|_| Error::Read("compressed_size"))?,
256
+                    );
257
+                    self.uncompressed_size = u64::from(
258
+                        cursor
259
+                            .read_u32::<LittleEndian>()
260
+                            .map_err(|_| Error::Read("uncompressed_size"))?,
261
+                    );
262
+                }
263
+                8 => {
264
+                    self.compressed_size = cursor
265
+                        .read_u64::<LittleEndian>()
266
+                        .map_err(|_| Error::Read("compressed_size"))?;
267
+                    self.uncompressed_size = cursor
268
+                        .read_u64::<LittleEndian>()
269
+                        .map_err(|_| Error::Read("uncompressed_size"))?;
270
+                }
271
+                _ => return Err(Error::Parse("Unsupported File Descriptor")),
272
+            }
273
+        }
274
+
275
+        #[allow(clippy::cast_possible_truncation)]
276
+        let idx0: usize = cursor.position() as usize;
277
+        let idx1: usize = idx0 + self.head.file_name_length as usize;
278
+
279
+        if idx1 > cursor.get_ref().len() {
280
+            return Err(Error::Parse("Invalid file name length"));
281
+        }
282
+
283
+        let filename = &cursor.get_ref().as_slice()[idx0..idx1];
284
+        cursor.set_position(idx1 as u64);
285
+
286
+        self.file_name = String::from_utf8_lossy(filename).into_owned();
287
+
288
+        if self.is_encrypted() {
289
+            cursor
290
+                .read_exact(&mut self.enc_chk)
291
+                .map_err(|_| Error::Read("encrypted buffer"))?;
292
+        }
293
+
294
+        self.start_of_compressed_data = cursor.position();
295
+        cursor.set_position(self.start_of_compressed_data + self.compressed_size);
296
+
297
+        if self.start_of_compressed_data + self.compressed_size > cursor.get_ref().len() as u64 {
298
+            return Err(Error::Parse("Invalid compressed data length"));
299
+        }
300
+
301
+        Ok(())
302
+    }
303
+
304
+    pub fn is_supported(&self) -> Result<(), Error> {
305
+        if self.is_encrypted() {
306
+            return Err(Error::UnsupportedFeature("Encryption Unsupported"));
307
+        }
308
+
309
+        if self.is_data_descriptor() {
310
+            return Err(Error::UnsupportedFeature("Data Descriptors are Unsupported"));
311
+        }
312
+
313
+        Ok(())
314
+    }
315
+
316
+    /*
317
+     * This has no header/checksum validation.
318
+     */
319
+    fn extract_file_deflate(
320
+        &mut self,
321
+        cursor: &std::io::Cursor<&Vec<u8>>,
322
+        files: &mut Vec<ExtractedFile>,
323
+    ) -> Result<(), Error> {
324
+        #[allow(clippy::cast_possible_truncation)]
325
+        let start: usize = self.start_of_compressed_data as usize;
326
+        #[allow(clippy::cast_possible_truncation)]
327
+        let end: usize = start + self.compressed_size as usize;
328
+        if end >= cursor.get_ref().len() {
329
+            return Err(Error::Extract);
330
+        }
331
+        let data: &[u8] = &cursor.get_ref().as_slice()[start..end];
332
+
333
+        let mut inflater = InflateStream::new();
334
+        let mut out: Vec<u8> = Vec::<u8>::new();
335
+        let mut n: usize = 0;
336
+
337
+        while n < data.len() {
338
+            let res = inflater.update(&data[n..]);
339
+            if let Ok((num_bytes_read, result)) = res {
340
+                n += num_bytes_read;
341
+                out.extend(result.iter().copied());
342
+            } else {
343
+                return Err(Error::Extract);
344
+            }
345
+        }
346
+
347
+        self.write_file(&out, files);
348
+
349
+        Ok(())
350
+    }
351
+
352
+    fn write_file(&mut self, buffer: &[u8], files: &mut Vec<ExtractedFile>) {
353
+        let extracted_file: ExtractedFile = ExtractedFile {
354
+            name: Some(self.file_name.to_string()),
355
+            data: buffer.to_vec(),
356
+        };
357
+
358
+        files.push(extracted_file);
359
+    }
360
+
361
+    fn extract_file_nocomp(
362
+        &mut self,
363
+        cursor: &mut std::io::Cursor<&Vec<u8>>,
364
+        files: &mut Vec<ExtractedFile>,
365
+    ) -> Result<(), Error> {
366
+        #[allow(clippy::cast_possible_truncation)]
367
+        let idx0: usize = self.start_of_compressed_data as usize;
368
+
369
+        let mut len = self.compressed_size;
370
+        if self.compressed_size != self.uncompressed_size {
371
+            debug!("Uncompressed file has different lengths for compressed vs uncompressed, using the shorter");
372
+            if self.compressed_size > self.uncompressed_size {
373
+                len = self.uncompressed_size;
374
+            }
375
+        }
376
+
377
+        #[allow(clippy::cast_possible_truncation)]
378
+        let idx1: usize = idx0 + len as usize;
379
+        if idx1 > cursor.get_ref().len() {
380
+            debug!("Invalid data length");
381
+            return Err(Error::Extract);
382
+        }
383
+
384
+        let contents = &cursor.get_ref().as_slice()[idx0..idx1];
385
+        cursor.set_position(idx1 as u64);
386
+
387
+        self.write_file(contents, files);
388
+        Ok(())
389
+    }
390
+
391
+    fn extract_file_bzip2(
392
+        &mut self,
393
+        cursor: &std::io::Cursor<&Vec<u8>>,
394
+        files: &mut Vec<ExtractedFile>,
395
+    ) -> Result<(), Error> {
396
+        #[allow(clippy::cast_possible_truncation)]
397
+        let idx0: usize = self.start_of_compressed_data as usize;
398
+        #[allow(clippy::cast_possible_truncation)]
399
+        let idx1: usize = idx0 + self.compressed_size as usize;
400
+
401
+        let contents = &cursor.get_ref().as_slice()[idx0..idx1];
402
+
403
+        /*
404
+         * Create vector of the needed capacity.
405
+         */
406
+        let mut out: Vec<u8> = Vec::new();
407
+        for _i in 0..self.uncompressed_size {
408
+            out.push(0);
409
+        }
410
+
411
+        let mut decompressor = DecoderReader::new(contents);
412
+        let ret = decompressor.read_exact(&mut out);
413
+        if ret.is_err() {
414
+            debug!("Unable to decompress bz2 data");
415
+            return Err(Error::Extract);
416
+        }
417
+
418
+        self.write_file(&out, files);
419
+        Ok(())
420
+    }
421
+
422
+    fn extract_file(
423
+        &mut self,
424
+        cursor: &mut std::io::Cursor<&Vec<u8>>,
425
+        files: &mut Vec<ExtractedFile>,
426
+    ) -> Result<(), Error> {
427
+        const ALZ_COMP_NOCOMP: u8 = 0;
428
+        const ALZ_COMP_BZIP2: u8 = 1;
429
+        const ALZ_COMP_DEFLATE: u8 = 2;
430
+
431
+        match self.compression_method {
432
+            ALZ_COMP_NOCOMP => self.extract_file_nocomp(cursor, files),
433
+            ALZ_COMP_BZIP2 => self.extract_file_bzip2(cursor, files),
434
+            ALZ_COMP_DEFLATE => self.extract_file_deflate(cursor, files),
435
+            _ => Err(Error::Extract),
436
+        }
437
+    }
438
+}
439
+
440
+/*TODO: Merge this with the onenote extracted_file struct, and use the same one everywhere.*/
441
+pub struct ExtractedFile {
442
+    pub name: Option<String>,
443
+    pub data: Vec<u8>,
444
+}
445
+
446
+#[derive(Default)]
447
+pub struct Alz {
448
+    pub embedded_files: Vec<ExtractedFile>,
449
+}
450
+
451
+impl<'aa> Alz {
452
+    /* Check for the ALZ file header. */
453
+    #[allow(clippy::unused_self)]
454
+    fn is_alz(&self, cursor: &mut std::io::Cursor<&Vec<u8>>) -> bool {
455
+        cursor
456
+            .read_u32::<LittleEndian>()
457
+            .map_or(false, |n| ALZ_FILE_HEADER == n)
458
+    }
459
+
460
+    fn parse_local_fileheader(&mut self, cursor: &mut std::io::Cursor<&Vec<u8>>) -> bool {
461
+        let mut local_fileheader = AlzLocalFileHeader::new();
462
+
463
+        if let Err(err) = local_fileheader.parse(cursor) {
464
+            debug!("{err}");
465
+            return false;
466
+        }
467
+
468
+        if let Err(err) = local_fileheader.is_supported() {
469
+            debug!("{err}");
470
+            return false;
471
+        }
472
+
473
+        if !local_fileheader.is_directory() {
474
+            /* The is_file flag doesn't appear to always be set, so we'll just assume it's a file if
475
+             * it's not marked as a directory.*/
476
+            let res2 = local_fileheader.extract_file(cursor, &mut self.embedded_files);
477
+            if res2.is_err() {
478
+                return false;
479
+            }
480
+        }
481
+
482
+        true
483
+    }
484
+
485
+    #[allow(clippy::unused_self)]
486
+    fn parse_central_directoryheader(&self, cursor: &mut std::io::Cursor<&Vec<u8>>) -> bool {
487
+        /*
488
+         * This is ignored in unalz (UnAlz.cpp ReadCentralDirectoryStructure).
489
+         *
490
+         * It actually reads 12 bytes, and I think it happens to work because EOF is hit on the next
491
+         * read, which it does not consider an error.
492
+         */
493
+        let ret = cursor.read_u64::<LittleEndian>();
494
+        ret.is_ok()
495
+    }
496
+
497
+    #[must_use]
498
+    pub const fn new() -> Self {
499
+        Self {
500
+            embedded_files: Vec::new(),
501
+        }
502
+    }
503
+
504
+    /// # Errors
505
+    /// Will return `Error::Parse` if file headers are not correct or are inconsistent.
506
+    pub fn from_bytes(bytes: &'aa [u8]) -> Result<Self, Error> {
507
+        let binding = bytes.to_vec();
508
+        let mut cursor = Cursor::new(&binding);
509
+
510
+        let mut alz: Self = Self::new();
511
+
512
+        if !alz.is_alz(&mut cursor) {
513
+            return Err(Error::Parse("No ALZ file header"));
514
+        }
515
+
516
+        //What these bytes are supposed to be in unspecified, but they need to be there.
517
+        let ret = cursor.read_u32::<LittleEndian>();
518
+        if ret.is_err() {
519
+            return Err(Error::Parse("Error reading uint32 from file"));
520
+        }
521
+
522
+        loop {
523
+            let Ok(sig) = cursor.read_u32::<LittleEndian>() else {
524
+                break;
525
+            };
526
+
527
+            match sig {
528
+                ALZ_LOCAL_FILE_HEADER => {
529
+                    if alz.parse_local_fileheader(&mut cursor) {
530
+                        continue;
531
+                    }
532
+                }
533
+                ALZ_CENTRAL_DIRECTORY_HEADER => {
534
+                    if alz.parse_central_directoryheader(&mut cursor) {
535
+                        continue;
536
+                    }
537
+                }
538
+                ALZ_END_OF_CENTRAL_DIRECTORY_HEADER => {
539
+                    break;
540
+                    /*This is the end, nothing really to do here.*/
541
+                }
542
+                _ => {
543
+                    #[allow(clippy::uninlined_format_args)]
544
+                    return Err(Error::UnrecognizedSig(format!("{:x}", sig)));
545
+                }
546
+            }
547
+        }
548
+
549
+        Ok(alz)
550
+    }
551
+}
... ...
@@ -244,17 +244,11 @@ impl Evidence {
244 244
 
245 245
         match indicator_type {
246 246
             IndicatorType::Strong => {
247
-                self.strong
248
-                    .entry(name.to_string())
249
-                    .or_default()
250
-                    .push(meta);
247
+                self.strong.entry(name.to_string()).or_default().push(meta);
251 248
             }
252 249
 
253 250
             IndicatorType::PotentiallyUnwanted => {
254
-                self.pua
255
-                    .entry(name.to_string())
256
-                    .or_default()
257
-                    .push(meta);
251
+                self.pua.entry(name.to_string()).or_default().push(meta);
258 252
             }
259 253
 
260 254
             #[cfg(feature = "not_ready")]
... ...
@@ -262,10 +256,7 @@ impl Evidence {
262 262
             // match the archive/extraction level at which each was found.
263 263
             // This will be required for alerting signatures to depend on weak-indicators for embedded content.
264 264
             IndicatorType::Weak => {
265
-                self.weak
266
-                    .entry(name.to_string())
267
-                    .or_default()
268
-                    .push(meta);
265
+                self.weak.entry(name.to_string()).or_default().push(meta);
269 266
             }
270 267
         }
271 268
 
... ...
@@ -26,8 +26,7 @@ use std::{
26 26
     ffi::CStr,
27 27
     mem::ManuallyDrop,
28 28
     os::raw::c_char,
29
-    panic,
30
-    slice,
29
+    panic, slice,
31 30
 };
32 31
 
33 32
 use image::{imageops::FilterType::Lanczos3, DynamicImage, ImageBuffer, Luma, Pixel, Rgb};
... ...
@@ -308,10 +307,7 @@ impl FuzzyHashMap {
308 308
 
309 309
                 // If the hash key does not exist in the hashmap, insert an empty vec.
310 310
                 // Then add the current meta struct to the entry.
311
-                self.hashmap
312
-                    .entry(fuzzy_hash)
313
-                    .or_default()
314
-                    .push(meta);
311
+                self.hashmap.entry(fuzzy_hash).or_default().push(meta);
315 312
 
316 313
                 Ok(())
317 314
             }
... ...
@@ -415,7 +411,6 @@ impl FuzzyHashMap {
415 415
 /// param: hash_out is an output variable
416 416
 /// param: hash_out_len indicates the size of the hash_out buffer
417 417
 pub fn fuzzy_hash_calculate_image(buffer: &[u8]) -> Result<Vec<u8>, Error> {
418
-
419 418
     // Load image and attempt to catch panics in case the decoders encounter unexpected issues
420 419
     let result = panic::catch_unwind(|| -> Result<DynamicImage, Error> {
421 420
         let image = image::load_from_memory(buffer).map_err(Error::ImageLoad)?;
... ...
@@ -34,3 +34,4 @@ pub mod logging;
34 34
 pub mod onenote;
35 35
 pub mod scanners;
36 36
 pub mod util;
37
+pub mod alz;
... ...
@@ -33,6 +33,7 @@ use libc::c_void;
33 33
 use log::{debug, error, warn};
34 34
 
35 35
 use crate::{
36
+    alz::Alz,
36 37
     ctx,
37 38
     onenote::OneNote,
38 39
     sys::{
... ...
@@ -295,3 +296,51 @@ pub unsafe extern "C" fn scan_lha_lzh(ctx: *mut cli_ctx) -> cl_error_t {
295 295
 
296 296
     cl_error_t_CL_SUCCESS
297 297
 }
298
+
299
+/// Scan an Alz file for attachments
300
+///
301
+/// # Safety
302
+///
303
+/// Must be a valid ctx pointer.
304
+#[no_mangle]
305
+pub unsafe extern "C" fn cli_scanalz(ctx: *mut cli_ctx) -> cl_error_t {
306
+    let fmap = match ctx::current_fmap(ctx) {
307
+        Ok(fmap) => fmap,
308
+        Err(e) => {
309
+            warn!("Error getting FMap from ctx: {e}");
310
+            return cl_error_t_CL_ERROR;
311
+        }
312
+    };
313
+
314
+    let file_bytes = match fmap.need_off(0, fmap.len()) {
315
+        Ok(bytes) => bytes,
316
+        Err(err) => {
317
+            error!(
318
+                "Failed to get file bytes for fmap of size {}: {err}",
319
+                fmap.len()
320
+            );
321
+            return cl_error_t_CL_ERROR;
322
+        }
323
+    };
324
+
325
+    let alz = match Alz::from_bytes(file_bytes) {
326
+        Ok(x) => x,
327
+        Err(err) => {
328
+            error!("Failed to parse Alz file: {}", err.to_string());
329
+            return cl_error_t_CL_ERROR;
330
+        }
331
+    };
332
+
333
+    for i in 0..alz.embedded_files.len() {
334
+        let ret = magic_scan(
335
+            ctx,
336
+            &alz.embedded_files[i].data,
337
+            alz.embedded_files[i].name.clone(),
338
+        );
339
+        if ret != cl_error_t_CL_SUCCESS {
340
+            return ret;
341
+        }
342
+    }
343
+
344
+    cl_error_t_CL_SUCCESS
345
+}
298 346
new file mode 100644
... ...
@@ -0,0 +1,121 @@
0
+# Copyright (C) 2020-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
1
+
2
+"""
3
+Run clamscan tests.
4
+"""
5
+
6
+import sys
7
+
8
+sys.path.append('../unit_tests')
9
+import testcase
10
+
11
+
12
+class TC(testcase.TestCase):
13
+    @classmethod
14
+    def setUpClass(cls):
15
+        super(TC, cls).setUpClass()
16
+
17
+    @classmethod
18
+    def tearDownClass(cls):
19
+        super(TC, cls).tearDownClass()
20
+
21
+    def setUp(self):
22
+        super(TC, self).setUp()
23
+
24
+    def tearDown(self):
25
+        super(TC, self).tearDown()
26
+        self.verify_valgrind_log()
27
+
28
+    def test_deflate(self):
29
+        self.step_name('Test alz files compressed with deflate (gzip)')
30
+
31
+        testfile = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'alz' / 'deflate.alz'
32
+        command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfile}'.format(
33
+            valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
34
+            path_db=TC.path_source / 'unit_tests' / 'input' / 'other_sigs' / 'alz.hdb',
35
+            testfile=testfile,
36
+        )
37
+        output = self.execute_command(command)
38
+
39
+        assert output.ec == 1  # virus
40
+
41
+        expected_results = [
42
+            'ALZ_TEST_FILE.UNOFFICIAL FOUND',
43
+        ]
44
+        self.verify_output(output.out, expected=expected_results)
45
+
46
+    def test_bzip2(self):
47
+        self.step_name('Test alz files compressed with bzip2')
48
+
49
+        testfile = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'alz' / 'bzip2.alz'
50
+        command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfile}'.format(
51
+            valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
52
+            path_db=TC.path_source / 'unit_tests' / 'input' / 'other_sigs' / 'alz.hdb',
53
+            testfile=testfile,
54
+        )
55
+        output = self.execute_command(command)
56
+
57
+        assert output.ec == 1  # virus
58
+
59
+        expected_results = [
60
+            'ALZ_TEST_FILE.UNOFFICIAL FOUND',
61
+        ]
62
+        self.verify_output(output.out, expected=expected_results)
63
+
64
+    def test_bzip2_with_binary(self):
65
+        self.step_name('Test alz files compressed with bzip2')
66
+
67
+        testfile = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'alz' / 'bzip2.bin.alz'
68
+        command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfile}'.format(
69
+            valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
70
+            path_db=TC.path_source / 'unit_tests' / 'input' / 'other_sigs' / 'alz.hdb',
71
+            testfile=testfile,
72
+        )
73
+        output = self.execute_command(command)
74
+
75
+        assert output.ec == 1  # virus
76
+
77
+        expected_results = [
78
+            'ALZ_TEST_FILE_EXECUTABLE.UNOFFICIAL FOUND',
79
+        ]
80
+        self.verify_output(output.out, expected=expected_results)
81
+
82
+    def test_uncompressed(self):
83
+        self.step_name('Test alz files with no compression')
84
+
85
+        testfile = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'alz' / 'uncompressed.alz'
86
+        command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfile}'.format(
87
+            valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
88
+            path_db=TC.path_source / 'unit_tests' / 'input' / 'other_sigs' / 'alz.hdb',
89
+            testfile=testfile,
90
+        )
91
+        output = self.execute_command(command)
92
+
93
+        assert output.ec == 1  # virus
94
+
95
+        expected_results = [
96
+            'ALZ_TEST_FILE.UNOFFICIAL FOUND',
97
+        ]
98
+        self.verify_output(output.out, expected=expected_results)
99
+
100
+    def test_uncompressed_with_binary(self):
101
+        self.step_name('Test alz files with no compression with binary data')
102
+
103
+        testfile = TC.path_source / 'unit_tests' / 'input' / 'other_scanfiles' / 'alz' / 'uncompressed.bin.alz'
104
+        command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfile}'.format(
105
+            valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
106
+            path_db=TC.path_source / 'unit_tests' / 'input' / 'other_sigs' / 'alz.hdb',
107
+            testfile=testfile,
108
+        )
109
+        output = self.execute_command(command)
110
+
111
+        assert output.ec == 1  # virus
112
+
113
+        expected_results = [
114
+            'ALZ_TEST_FILE_EXECUTABLE.UNOFFICIAL FOUND',
115
+        ]
116
+        self.verify_output(output.out, expected=expected_results)
117
+
118
+
119
+
120
+
0 121
new file mode 100644
1 122
Binary files /dev/null and b/unit_tests/input/other_scanfiles/alz/bzip2.alz differ
2 123
new file mode 100644
3 124
Binary files /dev/null and b/unit_tests/input/other_scanfiles/alz/bzip2.bin.alz differ
4 125
new file mode 100644
5 126
Binary files /dev/null and b/unit_tests/input/other_scanfiles/alz/deflate.alz differ
6 127
new file mode 100644
7 128
Binary files /dev/null and b/unit_tests/input/other_scanfiles/alz/uncompressed.alz differ
8 129
new file mode 100644
9 130
Binary files /dev/null and b/unit_tests/input/other_scanfiles/alz/uncompressed.bin.alz differ
10 131
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+03d4c70e6aa3832fa51959137b6a3fc55d8b9f55:16:ALZ_TEST_FILE
1
+05cf0585be97d8f544f034c7e46cf98778925c66:13:ALZ_TEST_FILE
2
+12f41f69d25d0ba9b73da429e0d69b27c95522db:16:ALZ_TEST_FILE
3
+24578375a0454c0657bac54084b50fdda1efaa21:11:ALZ_TEST_FILE
4
+26c0e077ad49260d416dbf449569efbc7ce02448:16:ALZ_TEST_FILE
5
+33ab5639bfd8e7b95eb1d8d0b87781d4ffea4d5d:12:ALZ_TEST_FILE
6
+67b33eebc1e4537d839bc6b04affd6b06074c746:13:ALZ_TEST_FILE
7
+6847c9c6e9218691910a0d7e36ac544149e3ce7d:13:ALZ_TEST_FILE
8
+9645df16bc733a92129563ad2e5f1f6a9ed483c9:16:ALZ_TEST_FILE
9
+9ac5483905f6c4b72c314c901ceb5eca2fee95c3:13:ALZ_TEST_FILE
10
+cb9431a94ca1d5c64d9a1e467c543905f592f351:13:ALZ_TEST_FILE
11
+ce5cec9fef4940d0d1fe2bc5004b14d7f8fc290c:77:ALZ_TEST_FILE
12
+edf6cd48d7b44a6cc0a96a6139cfe020865f8c4c:16712:ALZ_TEST_FILE_EXECUTABLE