| 36 | } |
| 37 | |
| 38 | static bool has_valid_png_structure(const uint8_t* data, size_t size) { |
| 39 | if (!data || size < 8) { |
| 40 | return false; |
| 41 | } |
| 42 | |
| 43 | static const uint8_t kPngSig[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; |
| 44 | if (std::memcmp(data, kPngSig, sizeof(kPngSig)) != 0) { |
| 45 | return false; |
| 46 | } |
| 47 | |
| 48 | size_t offset = 8; |
| 49 | bool saw_ihdr = false; |
| 50 | bool saw_iend = false; |
| 51 | |
| 52 | while (offset + 12 <= size) { |
| 53 | const uint32_t chunk_len = read_be32(data + offset); |
| 54 | const uint8_t* chunk_type = data + offset + 4; |
| 55 | const size_t full_chunk = static_cast<size_t>(chunk_len) + 12; |
| 56 | |
| 57 | if (offset + full_chunk > size) { |
| 58 | return false; |
| 59 | } |
| 60 | |
| 61 | const bool is_ihdr = chunk_type[0] == 'I' && chunk_type[1] == 'H' && chunk_type[2] == 'D' && chunk_type[3] == 'R'; |
| 62 | const bool is_iend = chunk_type[0] == 'I' && chunk_type[1] == 'E' && chunk_type[2] == 'N' && chunk_type[3] == 'D'; |
| 63 | |
| 64 | if (!saw_ihdr) { |
| 65 | if (!is_ihdr || chunk_len != 13) { |
| 66 | return false; |
| 67 | } |
| 68 | saw_ihdr = true; |
| 69 | } |
| 70 | |
| 71 | if (is_iend) { |
| 72 | if (chunk_len != 0) { |
| 73 | return false; |
| 74 | } |
| 75 | saw_iend = true; |
| 76 | return offset + full_chunk == size; |
| 77 | } |
| 78 | |
| 79 | offset += full_chunk; |
| 80 | } |
| 81 | |
| 82 | return false; |
| 83 | } |
| 84 | |
| 85 | static bool has_valid_jpeg_structure(const uint8_t* data, size_t size) { |
| 86 | if (!data || size < 4) { |
no test coverage detected