Skip to content

Commit f591327

Browse files
committedJul 13, 2024
feat(archive): Add LZ4 support
1 parent 51d4a37 commit f591327

File tree

5 files changed

+43
-0
lines changed

5 files changed

+43
-0
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ assert_eq!(kind.extension(), "foo");
176176
- **rpm** - `application/x-rpm`
177177
- **dcm** - `application/dicom`
178178
- **zst** - `application/zstd`
179+
- **lz4** - `application/x-lz4`
179180
- **msi** - `application/x-ole-storage`
180181
- **cpio** - `application/x-cpio`
181182

‎src/map.rs

+6
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,12 @@ matcher_map!(
576576
"zst",
577577
matchers::archive::is_zst
578578
),
579+
(
580+
MatcherType::Archive,
581+
"application/x-lz4",
582+
"lz4",
583+
matchers::archive::is_lz4
584+
),
579585
(
580586
MatcherType::Archive,
581587
"application/x-ole-storage",

‎src/matchers/archive.rs

+35
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,41 @@ pub fn is_zst(buf: &[u8]) -> bool {
249249
is_zst(next_frame)
250250
}
251251

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+
252287
/// Returns whether a buffer is a MSI Windows Installer archive.
253288
pub fn is_msi(buf: &[u8]) -> bool {
254289
buf.len() > 7

‎testdata/sample.tar.lz4

119 Bytes
Binary file not shown.

‎tests/archive.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ test_format!(
1616
);
1717

1818
test_format!(Archive, "application/zstd", "zst", zst, "sample.tar.zst");
19+
test_format!(Archive, "application/x-lz4", "lz4", lz4, "sample.tar.lz4");
1920
test_format!(Archive, "application/x-cpio", "cpio", cpio, "sample.cpio");
2021
test_format!(
2122
Archive,

0 commit comments

Comments
 (0)
Please sign in to comment.