16namespace fs = std::filesystem;
26inline uint16_t
le16(
const unsigned char* p) {
27 return static_cast<uint16_t
>(p[0]) |
28 (
static_cast<uint16_t
>(p[1]) << 8);
30inline uint32_t
le32(
const unsigned char* p) {
31 return static_cast<uint32_t
>(p[0]) |
32 (
static_cast<uint32_t
>(p[1]) << 8) |
33 (
static_cast<uint32_t
>(p[2]) << 16) |
34 (
static_cast<uint32_t
>(p[3]) << 24);
36inline uint32_t
be32(
const unsigned char* p) {
37 return (
static_cast<uint32_t
>(p[0]) << 24) |
38 (
static_cast<uint32_t
>(p[1]) << 16) |
39 (
static_cast<uint32_t
>(p[2]) << 8) |
40 static_cast<uint32_t
>(p[3]);
42inline uint64_t
be64(
const unsigned char* p) {
43 return (
static_cast<uint64_t
>(p[0]) << 56) |
44 (
static_cast<uint64_t
>(p[1]) << 48) |
45 (
static_cast<uint64_t
>(p[2]) << 40) |
46 (
static_cast<uint64_t
>(p[3]) << 32) |
47 (
static_cast<uint64_t
>(p[4]) << 24) |
48 (
static_cast<uint64_t
>(p[5]) << 16) |
49 (
static_cast<uint64_t
>(p[6]) << 8) |
50 static_cast<uint64_t
>(p[7]);
56 const unsigned char* pat,
size_t pat_len,
58 if (pat_len == 0 || pat_len > buf_len)
return SIZE_MAX;
59 for (
size_t i = start; i + pat_len <= buf_len; ++i) {
60 if (std::memcmp(buf + i, pat, pat_len) == 0)
return i;
77using PeekMore = std::function<size_t(uint64_t abs_off,
unsigned char* dst,
89 std::vector<unsigned char>
magic;
101 uint64_t file_disk_off,
102 uint64_t max_file_size,
114 uint64_t file_disk_off,
115 uint64_t max_file_size,
118 if (window_len < 4)
return r;
121 const uint8_t b3 = window[3];
122 const bool good_marker =
123 (b3 >= 0xE0 && b3 <= 0xEF) ||
125 (b3 >= 0xC0 && b3 <= 0xCF) ||
127 if (!good_marker)
return r;
131 constexpr size_t SCAN_CHUNK = 1024 * 1024;
132 constexpr unsigned char footer[2] = { 0xFF, 0xD9 };
135 size_t hit =
find_pattern(window, window_len, footer, 2, 4);
136 if (hit != SIZE_MAX) {
143 std::vector<unsigned char> chunk(SCAN_CHUNK);
144 uint64_t cursor = file_disk_off + window_len;
145 uint64_t total = window_len;
147 bool have_carry = (window_len > 0 && window[window_len - 1] == 0xFF);
149 while (total < max_file_size) {
150 size_t got = peek_more(cursor, chunk.data(), SCAN_CHUNK);
154 if (have_carry && got >= 1 && chunk[0] == 0xD9) {
160 size_t local =
find_pattern(chunk.data(), got, footer, 2);
161 if (local != SIZE_MAX) {
163 r.size = total + local + 2;
166 have_carry = (got > 0 && chunk[got - 1] == 0xFF);
171 if (total >= max_file_size) {
173 r.size = max_file_size;
174 r.size_is_capped =
true;
188 uint64_t file_disk_off,
189 uint64_t max_file_size,
192 constexpr size_t HDR = 8;
193 if (window_len < HDR + 8)
return r;
196 const uint32_t first_len =
be32(window + HDR + 0);
197 if (first_len != 13)
return r;
198 if (std::memcmp(window + HDR + 4,
"IHDR", 4) != 0)
return r;
206 constexpr size_t SCAN_CHUNK = 256 * 1024;
207 std::vector<unsigned char> chunk_buf(SCAN_CHUNK);
209 auto read_at = [&](uint64_t off,
unsigned char* dst,
size_t want) ->
size_t {
211 if (off >= file_disk_off &&
212 off + want <= file_disk_off + window_len) {
213 std::memcpy(dst, window + (off - file_disk_off), want);
216 return peek_more(off, dst, want);
220 constexpr int MAX_CHUNKS = 100000;
221 for (
int n = 0; n < MAX_CHUNKS; ++n) {
222 if (pos + 12 > max_file_size) {
224 r.size = max_file_size;
225 r.size_is_capped =
true;
228 unsigned char hdr[12];
229 if (read_at(file_disk_off + pos, hdr, 12) != 12)
return r;
230 const uint32_t clen =
be32(hdr);
231 if (clen > 0x10000000u)
return r;
232 const bool is_iend = std::memcmp(hdr + 4,
"IEND", 4) == 0;
240 if (pos > max_file_size) {
242 r.size = max_file_size;
243 r.size_is_capped =
true;
259 uint64_t file_disk_off,
260 uint64_t max_file_size,
264 if (window_len < 13)
return r;
269 if (window[10] == window[11] && window[11] == window[12]
270 && (window[10] == 0x00 || window[10] == 0xFF))
return r;
273 constexpr size_t SCAN_CHUNK = 256 * 1024;
274 std::vector<unsigned char> chunk(SCAN_CHUNK);
275 constexpr unsigned char trailer = 0x3B;
278 for (
size_t i = 13; i < window_len; ++i) {
279 if (window[i] == trailer && i > 0 && window[i - 1] == 0x00) {
285 uint64_t total = window_len;
286 uint64_t cursor = file_disk_off + window_len;
287 unsigned char prev_last = window_len > 0 ? window[window_len - 1] : 0;
288 while (total < max_file_size) {
289 size_t got = peek_more(cursor, chunk.data(), SCAN_CHUNK);
291 for (
size_t i = 0; i < got; ++i) {
292 const unsigned char prev = (i == 0) ? prev_last : chunk[i - 1];
293 if (chunk[i] == trailer && prev == 0x00) {
295 r.size = total + i + 1;
299 prev_last = chunk[got - 1];
314 uint64_t file_disk_off,
315 uint64_t max_file_size,
319 if (window_len < 8)
return r;
320 if (window[5] !=
'1' && window[5] !=
'2')
return r;
321 if (window[6] !=
'.')
return r;
323 constexpr size_t SCAN_CHUNK = 1024 * 1024;
324 std::vector<unsigned char> chunk(SCAN_CHUNK);
325 constexpr unsigned char eof[5] = {
'%',
'%',
'E',
'O',
'F'};
328 uint64_t last_eof_end = 0;
331 for (
size_t i = 0; i + 5 <= window_len; ++i) {
332 if (std::memcmp(window + i, eof, 5) == 0) {
333 last_eof_end = i + 5;
336 uint64_t total = window_len;
337 uint64_t cursor = file_disk_off + window_len;
339 unsigned char carry[4] = {0, 0, 0, 0};
340 size_t carry_len = std::min<size_t>(4, window_len);
341 if (window_len > 0) {
342 std::memcpy(carry, window + window_len - carry_len, carry_len);
345 while (total < max_file_size) {
346 size_t got = peek_more(cursor, chunk.data(), SCAN_CHUNK);
350 std::vector<unsigned char> bnd(carry_len + std::min<size_t>(got, 4));
351 std::memcpy(bnd.data(), carry, carry_len);
352 std::memcpy(bnd.data() + carry_len, chunk.data(),
353 std::min<size_t>(got, 4));
354 for (
size_t i = 0; i + 5 <= bnd.size(); ++i) {
355 if (std::memcmp(bnd.data() + i, eof, 5) == 0) {
357 last_eof_end = total - carry_len + i + 5;
361 for (
size_t i = 0; i + 5 <= got; ++i) {
362 if (std::memcmp(chunk.data() + i, eof, 5) == 0) {
363 last_eof_end = total + i + 5;
366 carry_len = std::min<size_t>(4, got);
367 std::memcpy(carry, chunk.data() + got - carry_len, carry_len);
372 if (last_eof_end > 0) {
375 r.size = last_eof_end;
377 unsigned char tail[2];
378 if (peek_more(file_disk_off + last_eof_end, tail, 2) > 0) {
380 if (tail[0] ==
'\r' || tail[0] ==
'\n') ++extra;
381 if (extra == 1 && (tail[1] ==
'\r' || tail[1] ==
'\n')) ++extra;
384 if (r.size > max_file_size) { r.size = max_file_size; r.size_is_capped =
true; }
398 uint64_t file_disk_off,
399 uint64_t max_file_size,
402 if (window_len < 30)
return r;
407 const uint16_t method =
le16(window + 8);
408 if (method > 99)
return r;
411 constexpr unsigned char eocd[4] = {0x50, 0x4B, 0x05, 0x06};
412 constexpr size_t SCAN_CHUNK = 1024 * 1024;
413 std::vector<unsigned char> chunk(SCAN_CHUNK);
415 uint64_t last_eocd_off = 0;
418 for (
size_t i = 0; i + 4 <= window_len; ++i) {
419 if (std::memcmp(window + i, eocd, 4) == 0) {
424 uint64_t total = window_len;
425 uint64_t cursor = file_disk_off + window_len;
426 unsigned char carry[3] = {0, 0, 0};
427 size_t carry_len = std::min<size_t>(3, window_len);
428 if (window_len > 0) {
429 std::memcpy(carry, window + window_len - carry_len, carry_len);
431 while (total < max_file_size) {
432 size_t got = peek_more(cursor, chunk.data(), SCAN_CHUNK);
434 std::vector<unsigned char> bnd(carry_len + std::min<size_t>(got, 3));
435 std::memcpy(bnd.data(), carry, carry_len);
436 std::memcpy(bnd.data() + carry_len, chunk.data(),
437 std::min<size_t>(got, 3));
438 for (
size_t i = 0; i + 4 <= bnd.size(); ++i) {
439 if (std::memcmp(bnd.data() + i, eocd, 4) == 0) {
440 last_eocd_off = total - carry_len + i;
444 for (
size_t i = 0; i + 4 <= got; ++i) {
445 if (std::memcmp(chunk.data() + i, eocd, 4) == 0) {
446 last_eocd_off = total + i;
450 carry_len = std::min<size_t>(3, got);
451 std::memcpy(carry, chunk.data() + got - carry_len, carry_len);
456 if (!found)
return r;
469 unsigned char eocd_hdr[22];
470 if (peek_more(file_disk_off + last_eocd_off, eocd_hdr, 22) != 22)
return r;
471 const uint16_t comment_len =
le16(eocd_hdr + 20);
472 const uint64_t total_size = last_eocd_off + 22 + comment_len;
473 if (total_size > max_file_size) {
475 r.size = max_file_size;
476 r.size_is_capped =
true;
491 uint64_t max_file_size,
494 if (window_len < 14)
return r;
495 const uint32_t fsz =
le32(window + 2);
498 if (window_len < 18)
return r;
499 const uint32_t dib_size =
le32(window + 14);
500 static const uint32_t valid_dib[] = {12, 40, 52, 56, 64, 108, 124};
502 for (uint32_t v : valid_dib)
if (dib_size == v) { dib_ok =
true;
break; }
503 if (!dib_ok)
return r;
504 if (fsz < 26 || fsz > max_file_size) {
505 if (fsz > max_file_size) {
507 r.size = max_file_size;
508 r.size_is_capped =
true;
527 uint64_t file_disk_off,
528 uint64_t max_file_size,
531 if (window_len < 16)
return r;
533 const uint32_t atom1_size =
be32(window);
534 if (atom1_size < 8 || atom1_size > 1024)
return r;
535 if (std::memcmp(window + 4,
"ftyp", 4) != 0)
return r;
540 bool brand_ok =
true;
541 for (
int i = 0; i < 4; ++i) {
542 const unsigned char c = window[8 + i];
543 if (!(c ==
' ' || (c >=
'0' && c <=
'9') ||
544 (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z'))) {
549 if (!brand_ok)
return r;
552 constexpr int MAX_ATOMS = 10000;
554 for (
int n = 0; n < MAX_ATOMS; ++n) {
555 if (pos + 8 > max_file_size) {
557 r.size = max_file_size;
558 r.size_is_capped =
true;
561 unsigned char hdr[16];
564 if (pos + 8 <= window_len) {
565 std::memcpy(hdr, window + pos, 8);
568 got = peek_more(file_disk_off + pos, hdr, 16);
570 if (got < 8)
return r;
571 uint64_t atom_size =
be32(hdr);
572 if (atom_size == 1) {
575 got += peek_more(file_disk_off + pos + 8, hdr + 8, 8);
577 if (got < 16)
return r;
578 atom_size =
be64(hdr + 8);
579 }
else if (atom_size == 0) {
582 r.size = std::min<uint64_t>(max_file_size, pos + 8);
585 if (atom_size < 8 || atom_size > max_file_size)
return r;
587 if (pos > max_file_size) {
589 r.size = max_file_size;
590 r.size_is_capped =
true;
607 uint64_t max_file_size,
610 if (window_len < 10)
return r;
616 if (window[3] == 0xFF || window[4] == 0xFF)
return r;
618 const uint32_t s0 = window[6] & 0x7F;
619 const uint32_t s1 = window[7] & 0x7F;
620 const uint32_t s2 = window[8] & 0x7F;
621 const uint32_t s3 = window[9] & 0x7F;
622 const uint32_t tag_size = (s0 << 21) | (s1 << 14) | (s2 << 7) | s3;
626 const uint64_t prefix = 10 + tag_size;
628 constexpr uint64_t MP3_HARD_CAP = 30ull * 1024 * 1024;
629 const uint64_t cap = std::min<uint64_t>(MP3_HARD_CAP, max_file_size);
630 if (prefix > cap)
return r;
633 r.size_is_capped =
true;
639 uint64_t max_file_size,
642 if (window_len < 4)
return r;
646 const uint8_t b1 = window[1];
647 const uint8_t b2 = window[2];
648 if ((b1 & 0xE0) != 0xE0)
return r;
649 const uint8_t version = (b1 >> 3) & 0x03;
650 const uint8_t layer = (b1 >> 1) & 0x03;
651 if (version == 0x01)
return r;
652 if (layer == 0x00)
return r;
653 const uint8_t bitrate_idx = (b2 >> 4) & 0x0F;
654 const uint8_t sample_idx = (b2 >> 2) & 0x03;
655 if (bitrate_idx == 0x0F || sample_idx == 0x03)
return r;
657 constexpr uint64_t MP3_HARD_CAP = 30ull * 1024 * 1024;
659 r.size = std::min<uint64_t>(MP3_HARD_CAP, max_file_size);
660 r.size_is_capped =
true;
672 uint64_t file_disk_off,
673 uint64_t max_file_size,
676 if (window_len < 27)
return r;
678 if (window[4] != 0x00)
return r;
680 auto read_at = [&](uint64_t off,
unsigned char* dst,
size_t want) ->
size_t {
681 if (off >= file_disk_off &&
682 off + want <= file_disk_off + window_len) {
683 std::memcpy(dst, window + (off - file_disk_off), want);
686 return peek_more(off, dst, want);
690 constexpr int MAX_PAGES = 100000;
691 for (
int n = 0; n < MAX_PAGES; ++n) {
692 if (pos + 27 > max_file_size) {
694 r.size = max_file_size;
695 r.size_is_capped =
true;
698 unsigned char hdr[27];
699 if (read_at(file_disk_off + pos, hdr, 27) != 27) {
708 if (std::memcmp(hdr,
"OggS", 4) != 0) {
717 const uint8_t header_type = hdr[5];
718 const uint8_t segment_count = hdr[26];
720 std::vector<unsigned char> seg_table(segment_count);
721 if (segment_count > 0 &&
722 read_at(file_disk_off + pos + 27, seg_table.data(),
723 segment_count) != segment_count)
return r;
724 uint32_t body_size = 0;
725 for (uint8_t i = 0; i < segment_count; ++i) body_size += seg_table[i];
726 const uint64_t page_size = 27 + segment_count + body_size;
729 if (header_type & 0x04) {
747 uint64_t max_file_size,
750 if (window_len < 8)
return r;
752 const bool little_endian = (window[0] ==
'I');
753 const uint32_t ifd_off = little_endian
756 if (ifd_off < 8 || ifd_off > 100ull * 1024 * 1024)
return r;
757 constexpr uint64_t TIFF_HARD_CAP = 50ull * 1024 * 1024;
759 r.size = std::min<uint64_t>(TIFF_HARD_CAP, max_file_size);
760 r.size_is_capped =
true;
774 uint64_t max_file_size,
777 if (window_len < 76)
return r;
780 const uint16_t sec_shift =
le16(window + 30);
781 if (sec_shift != 9 && sec_shift != 12)
return r;
784 const uint32_t num_dir_sectors =
le32(window + 40);
785 if (num_dir_sectors > 100000)
return r;
787 constexpr uint64_t OLE_HARD_CAP = 100ull * 1024 * 1024;
789 r.size = std::min<uint64_t>(OLE_HARD_CAP, max_file_size);
790 r.size_is_capped =
true;
801 uint64_t max_file_size,
804 if (window_len < 12)
return r;
806 const bool is_wav = std::memcmp(window + 8,
"WAVE", 4) == 0;
807 const bool is_avi = std::memcmp(window + 8,
"AVI ", 4) == 0;
808 const bool is_webp = std::memcmp(window + 8,
"WEBP", 4) == 0;
809 if (!is_wav && !is_avi && !is_webp)
return r;
810 const uint32_t riff_size =
le32(window + 4);
811 if (riff_size < 4)
return r;
812 const uint64_t total =
static_cast<uint64_t
>(riff_size) + 8;
813 if (total > max_file_size) {
815 r.size = max_file_size;
816 r.size_is_capped =
true;
837 uint64_t max_file_size,
840 if (window_len < 16)
return r;
845 if (window[4] == 0x00)
return r;
846 constexpr uint64_t MKV_HARD_CAP = 4ull * 1024 * 1024 * 1024;
848 r.size = std::min<uint64_t>(MKV_HARD_CAP, max_file_size);
849 r.size_is_capped =
true;
861 uint64_t max_file_size,
864 if (window_len < 100)
return r;
867 const uint16_t ps_field = (
static_cast<uint16_t
>(window[16]) << 8) | window[17];
868 uint32_t page_size = 0;
872 page_size = ps_field;
873 if (page_size < 512 || page_size > 32768)
return r;
874 if ((page_size & (page_size - 1)) != 0)
return r;
877 const uint32_t page_count =
878 (
static_cast<uint32_t
>(window[28]) << 24) |
879 (
static_cast<uint32_t
>(window[29]) << 16) |
880 (
static_cast<uint32_t
>(window[30]) << 8) |
881 static_cast<uint32_t
>(window[31]);
882 if (page_count == 0)
return r;
883 const uint64_t total =
static_cast<uint64_t
>(page_size) * page_count;
884 if (total > max_file_size) {
886 r.size = max_file_size;
887 r.size_is_capped =
true;
900 std::vector<CarverFormat> v;
901 v.push_back({
"jpeg",
"jpg",
903 v.push_back({
"png",
"png",
904 {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}, 0,
906 v.push_back({
"gif",
"gif",
908 v.push_back({
"gif87",
"gif",
910 v.push_back({
"pdf",
"pdf",
912 v.push_back({
"zip",
"zip",
914 v.push_back({
"bmp",
"bmp",
919 v.push_back({
"riff",
"riff",
921 v.push_back({
"mp4",
"mp4",
924 v.push_back({
"mp3-id3",
"mp3",
929 v.push_back({
"mp3-frame",
"mp3",
931 v.push_back({
"mp3-frame-mpeg2",
"mp3",
933 v.push_back({
"ogg",
"ogg",
935 v.push_back({
"tiff-le",
"tif",
937 v.push_back({
"tiff-be",
"tif",
940 v.push_back({
"ole-cf",
"ole",
941 {0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1}, 0,
944 v.push_back({
"mkv",
"mkv",
946 v.push_back({
"sqlite",
"sqlite",
947 {
'S',
'Q',
'L',
'i',
't',
'e',
' ',
'f',
'o',
'r',
'm',
'a',
't',
955 const std::string& output_dir,
957 std::vector<RecoveredFileRecord>& recovered,
958 std::vector<std::string>& logs,
959 std::string& error) {
960 const uint64_t disk_size = reader.
size();
961 if (disk_size == 0) {
962 error =
"Carving: disk size is zero";
967 : std::min<uint64_t>(disk_size,
970 fs::path out_root = fs::path(output_dir) /
"carved";
973 fs::create_directories(out_root, ec);
976 auto formats = build_formats();
978 size_t longest_magic = 0;
979 for (
const auto& f : formats) {
980 const size_t needed = f.magic.size() + f.magic_offset_in_file;
981 if (needed > longest_magic) longest_magic = needed;
984 constexpr size_t MAIN_WINDOW = 16 * 1024 * 1024;
985 const size_t overlap = longest_magic;
986 std::vector<unsigned char> window(MAIN_WINDOW + overlap);
988 size_t carved_count = 0;
990 int ident_counter = 0;
992 auto peek_more = [&](uint64_t abs_off,
unsigned char* dst,
993 size_t want) ->
size_t {
994 if (abs_off >= disk_size)
return 0;
995 const size_t can =
static_cast<size_t>(
996 std::min<uint64_t>(want, disk_size - abs_off));
997 return reader.
read_at(abs_off, dst, can) ? can : 0;
1000 logs.push_back(
trs(
"Carving: starting scan up to ") +
1001 std::to_string(scan_limit / (1024 * 1024)) +
" MiB");
1003 while (pos < scan_limit) {
1004 const size_t want =
static_cast<size_t>(
1005 std::min<uint64_t>(window.size(), scan_limit - pos));
1006 if (!reader.
read_at(pos, window.data(), want)) {
1007 logs.push_back(
trs(
"Carving: read failure at offset ") +
1008 std::to_string(pos) +
trs(
", skipping ahead"));
1014 const size_t scan_end = (want > overlap) ? (want - overlap) : want;
1016 const bool last = (pos + want >= scan_limit);
1017 const size_t actual_end = last ? want : scan_end;
1019 for (
size_t i = 0; i < actual_end; ++i) {
1020 for (
const auto& f : formats) {
1021 const size_t mlen = f.magic.size();
1022 if (i + mlen > want)
continue;
1023 if (std::memcmp(window.data() + i, f.magic.data(), mlen) != 0)
1026 if (i < f.magic_offset_in_file)
continue;
1027 const size_t file_local_start = i - f.magic_offset_in_file;
1028 const uint64_t file_disk_off = pos + file_local_start;
1031 const size_t window_remaining = want - file_local_start;
1033 DetectResult dr = f.detect(
1034 window.data() + file_local_start,
1035 window_remaining, file_disk_off,
1037 const_cast<PeekMore&
>(
static_cast<const PeekMore&
>(peek_more))
1040 if (!dr.ok)
continue;
1041 if (dr.size == 0 || dr.size > opts.
max_file_size + 1)
continue;
1044 fs::path out_dir = out_root / f.name;
1047 fs::create_directories(out_dir, ec);
1049 std::ostringstream nm;
1050 nm << std::hex << file_disk_off <<
"_" << ident_counter
1051 <<
"." << f.extension;
1053 fs::path out_path = out_dir / nm.str();
1055 std::ofstream out(out_path, std::ios::binary | std::ios::trunc);
1058 constexpr size_t WBUF = 1024 * 1024;
1059 std::vector<unsigned char> wbuf(WBUF);
1060 uint64_t written = 0;
1061 while (written < dr.size) {
1062 const size_t step =
static_cast<size_t>(
1063 std::min<uint64_t>(WBUF, dr.size - written));
1064 if (!reader.
read_at(file_disk_off + written,
1065 wbuf.data(), step))
break;
1066 out.write(
reinterpret_cast<const char*
>(wbuf.data()),
1067 static_cast<std::streamsize
>(step));
1073 std::string note =
"carved-";
1075 if (dr.size_is_capped) note +=
"-capped";
1076 recovered.push_back({
1077 out_path.string(),
"carving",
1078 (
"carved/" + std::string(f.name) +
"/" + nm.str()),
1080 dr.size_is_capped ?
"partial" :
"full",
1088 const uint64_t skip_until = file_disk_off + dr.size;
1089 if (skip_until > pos + i) {
1090 const uint64_t skip = skip_until - (pos + i);
1091 if (skip > 0 && skip < want - i) {
1092 i +=
static_cast<size_t>(skip - 1);
1102 std::ostringstream m;
1103 m <<
trs(
"Carving: completed. Files recovered: ") << carved_count;
1104 logs.push_back(m.str());
1106 return carved_count > 0;
bool read_at(uint64_t offset, void *buffer, size_t len)
std::string trs(const char *msgid)
DetectResult detect_riff(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
DetectResult detect_gif(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
size_t find_pattern(const unsigned char *buf, size_t buf_len, const unsigned char *pat, size_t pat_len, size_t start=0)
DetectResult detect_jpeg(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
DetectResult detect_mkv(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
DetectResult detect_pdf(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
DetectResult detect_ogg(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
DetectResult detect_tiff(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
uint64_t be64(const unsigned char *p)
DetectResult detect_ole(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
DetectResult detect_zip(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
std::function< size_t(uint64_t abs_off, unsigned char *dst, size_t want)> PeekMore
uint16_t le16(const unsigned char *p)
uint32_t be32(const unsigned char *p)
DetectResult detect_bmp(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
DetectResult detect_mp3_frame(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
DetectResult detect_mp4(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
std::vector< CarverFormat > build_formats()
uint32_t le32(const unsigned char *p)
DetectResult detect_mp3_id3(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
DetectResult detect_png(const unsigned char *window, size_t window_len, uint64_t file_disk_off, uint64_t max_file_size, PeekMore &peek_more)
DetectResult detect_sqlite(const unsigned char *window, size_t window_len, uint64_t, uint64_t max_file_size, PeekMore &)
bool run_carving(DiskReader &reader, const std::string &output_dir, const CarvingOptions &opts, std::vector< RecoveredFileRecord > &recovered, std::vector< std::string > &logs, std::string &error)
uint64_t max_bytes_to_scan