Skip to content

Commit cbf3b9e

Browse files
authoredFeb 2, 2025··
Merge pull request #98 from sorairolake/feature/archives
Add bzip3 and LZ4 support
2 parents 644cf90 + f591327 commit cbf3b9e

File tree

6 files changed

+68
-1
lines changed

6 files changed

+68
-1
lines changed
 

‎README.md

+2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ assert_eq!(kind.extension(), "foo");
157157
- **rar** - `application/vnd.rar`
158158
- **gz** - `application/gzip`
159159
- **bz2** - `application/x-bzip2`
160+
- **bz3** - `application/vnd.bzip3`
160161
- **7z** - `application/x-7z-compressed`
161162
- **xz** - `application/x-xz`
162163
- **pdf** - `application/pdf`
@@ -175,6 +176,7 @@ assert_eq!(kind.extension(), "foo");
175176
- **rpm** - `application/x-rpm`
176177
- **dcm** - `application/dicom`
177178
- **zst** - `application/zstd`
179+
- **lz4** - `application/x-lz4`
178180
- **msi** - `application/x-ole-storage`
179181
- **cpio** - `application/x-cpio`
180182

‎src/map.rs

+12
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,12 @@ matcher_map!(
462462
"bz2",
463463
matchers::archive::is_bz2
464464
),
465+
(
466+
MatcherType::Archive,
467+
"application/vnd.bzip3",
468+
"bz3",
469+
matchers::archive::is_bz3
470+
),
465471
(
466472
MatcherType::Archive,
467473
"application/x-7z-compressed",
@@ -570,6 +576,12 @@ matcher_map!(
570576
"zst",
571577
matchers::archive::is_zst
572578
),
579+
(
580+
MatcherType::Archive,
581+
"application/x-lz4",
582+
"lz4",
583+
matchers::archive::is_lz4
584+
),
573585
(
574586
MatcherType::Archive,
575587
"application/x-ole-storage",

‎src/matchers/archive.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,21 @@ pub fn is_gz(buf: &[u8]) -> bool {
5252
buf.len() > 2 && buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x8
5353
}
5454

55-
/// Returns whether a buffer is a bzip archive.
55+
/// Returns whether a buffer is a bzip2 archive.
5656
pub fn is_bz2(buf: &[u8]) -> bool {
5757
buf.len() > 2 && buf[0] == 0x42 && buf[1] == 0x5A && buf[2] == 0x68
5858
}
5959

60+
/// Returns whether a buffer is a bzip3 archive.
61+
pub fn is_bz3(buf: &[u8]) -> bool {
62+
buf.len() > 4
63+
&& buf[0] == b'B'
64+
&& buf[1] == b'Z'
65+
&& buf[2] == b'3'
66+
&& buf[3] == b'v'
67+
&& buf[4] == b'1'
68+
}
69+
6070
/// Returns whether a buffer is a 7z archive.
6171
pub fn is_7z(buf: &[u8]) -> bool {
6272
buf.len() > 5
@@ -239,6 +249,41 @@ pub fn is_zst(buf: &[u8]) -> bool {
239249
is_zst(next_frame)
240250
}
241251

252+
/// Returns whether a buffer is a LZ4 archive.
253+
// LZ4 compressed data is made of one or more frames.
254+
// There are two frame formats defined by LZ4: LZ4 Frame format and Skippable frames.
255+
// See more details from https://github.com/lz4/lz4/blob/v1.9.4/doc/lz4_Frame_format.md
256+
pub fn is_lz4(buf: &[u8]) -> bool {
257+
if buf.len() > 3 && buf[0] == 0x04 && buf[1] == 0x22 && buf[2] == 0x4D && buf[3] == 0x18 {
258+
return true;
259+
}
260+
261+
if buf.len() < 8 {
262+
return false;
263+
}
264+
265+
let magic = u32::from_le_bytes(buf[0..4].try_into().unwrap());
266+
let Ok(magic) = usize::try_from(magic) else {
267+
return false;
268+
};
269+
270+
if magic & ZSTD_SKIP_MASK != ZSTD_SKIP_START {
271+
return false;
272+
}
273+
274+
let data_len = u32::from_le_bytes(buf[4..8].try_into().unwrap());
275+
let Ok(data_len) = usize::try_from(data_len) else {
276+
return false;
277+
};
278+
279+
if buf.len() < 8 + data_len {
280+
return false;
281+
}
282+
283+
let next_frame = &buf[8 + data_len..];
284+
is_lz4(next_frame)
285+
}
286+
242287
/// Returns whether a buffer is a MSI Windows Installer archive.
243288
pub fn is_msi(buf: &[u8]) -> bool {
244289
buf.len() > 7

‎testdata/sample.tar.bz3

127 Bytes
Binary file not shown.

‎testdata/sample.tar.lz4

119 Bytes
Binary file not shown.

‎tests/archive.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
mod common;
22

3+
test_format!(
4+
Archive,
5+
"application/vnd.bzip3",
6+
"bz3",
7+
bz3,
8+
"sample.tar.bz3"
9+
);
310
test_format!(
411
Archive,
512
"application/vnd.sqlite3",
@@ -9,6 +16,7 @@ test_format!(
916
);
1017

1118
test_format!(Archive, "application/zstd", "zst", zst, "sample.tar.zst");
19+
test_format!(Archive, "application/x-lz4", "lz4", lz4, "sample.tar.lz4");
1220
test_format!(Archive, "application/x-cpio", "cpio", cpio, "sample.cpio");
1321
test_format!(
1422
Archive,

0 commit comments

Comments
 (0)
Please sign in to comment.