| 26 | } |
| 27 | |
| 28 | GifInfo Gif::parseGifInfo(fl::span<const fl::u8> data, fl::string* error_message) { |
| 29 | GifInfo info; |
| 30 | |
| 31 | // Validate input data |
| 32 | if (data.empty()) { |
| 33 | if (error_message) { |
| 34 | *error_message = "Empty GIF data"; |
| 35 | } |
| 36 | return info; // returns invalid info |
| 37 | } |
| 38 | |
| 39 | // Minimum size check - GIF must have at least the header (6 bytes) + some content |
| 40 | if (data.size() < 13) { // GIF header (6) + screen descriptor (7) |
| 41 | if (error_message) { |
| 42 | *error_message = "GIF data too small"; |
| 43 | } |
| 44 | return info; |
| 45 | } |
| 46 | |
| 47 | // Check GIF signature |
| 48 | if (data[0] != 'G' || data[1] != 'I' || data[2] != 'F') { |
| 49 | if (error_message) { |
| 50 | *error_message = "Invalid GIF signature"; |
| 51 | } |
| 52 | return info; |
| 53 | } |
| 54 | |
| 55 | // Check version (87a or 89a) |
| 56 | if (!((data[3] == '8' && data[4] == '7' && data[5] == 'a') || |
| 57 | (data[3] == '8' && data[4] == '9' && data[5] == 'a'))) { |
| 58 | if (error_message) { |
| 59 | *error_message = "Unsupported GIF version"; |
| 60 | } |
| 61 | return info; |
| 62 | } |
| 63 | |
| 64 | // Parse logical screen descriptor (starts at byte 6) |
| 65 | // Width (2 bytes, little endian) at offset 6-7 |
| 66 | // Height (2 bytes, little endian) at offset 8-9 |
| 67 | fl::u16 width = data[6] | (data[7] << 8); |
| 68 | fl::u16 height = data[8] | (data[9] << 8); |
| 69 | |
| 70 | if (width == 0 || height == 0) { |
| 71 | if (error_message) { |
| 72 | *error_message = "Invalid GIF dimensions"; |
| 73 | } |
| 74 | return info; |
| 75 | } |
| 76 | |
| 77 | // For a more complete parsing, we would need to create a temporary decoder |
| 78 | // and let libnsgif parse the structure. Let's use the existing decoder briefly. |
| 79 | auto decoder = fl::make_shared<fl::third_party::SoftwareGifDecoder>(PixelFormat::RGB888); |
| 80 | auto stream = fl::make_shared<fl::memorybuf>(data.size()); |
| 81 | stream->write(data); |
| 82 | |
| 83 | if (decoder->begin(stream)) { |
| 84 | // Now we can extract more detailed info using the decoder's methods |
| 85 | info.width = decoder->getWidth(); |