| 101 | } |
| 102 | |
| 103 | FramePtr FileSystem::loadJpeg(const char *path, const JpegConfig &config, |
| 104 | fl::string *error_message) { |
| 105 | fl::ifstream file = openRead(path); |
| 106 | if (!file.is_open()) { |
| 107 | if (error_message) { *error_message = "Failed to open file: "; error_message->append(path); } |
| 108 | FL_WARN("Failed to open JPEG file: " << path); return FramePtr(); |
| 109 | } |
| 110 | fl::size fileSize = file.size(); |
| 111 | if (fileSize == 0) { |
| 112 | if (error_message) { *error_message = "File is empty: "; error_message->append(path); } |
| 113 | file.close(); return FramePtr(); |
| 114 | } |
| 115 | fl::vector<u8> buffer; |
| 116 | buffer.reserve(fileSize); buffer.resize(fileSize); |
| 117 | fl::size bytesRead = 0; |
| 118 | while (bytesRead < fileSize && file.available()) { |
| 119 | fl::size chunkSize = min<fl::size>(4096, fileSize - bytesRead); |
| 120 | fl::size n = file.read(buffer.data() + bytesRead, chunkSize); |
| 121 | if (n == 0) break; |
| 122 | bytesRead += n; |
| 123 | } |
| 124 | file.close(); |
| 125 | if (bytesRead != fileSize) { |
| 126 | if (error_message) { |
| 127 | *error_message = "Failed to read complete file. Expected "; |
| 128 | error_message->append(static_cast<u32>(fileSize)); |
| 129 | error_message->append(" bytes, got "); |
| 130 | error_message->append(static_cast<u32>(bytesRead)); |
| 131 | } |
| 132 | FL_WARN("Failed to read complete JPEG file: " << path); return FramePtr(); |
| 133 | } |
| 134 | fl::span<const u8> jpegData(buffer.data(), buffer.size()); |
| 135 | FramePtr frame = Jpeg::decode(config, jpegData, error_message); |
| 136 | if (!frame && error_message && error_message->empty()) { |
| 137 | *error_message = "Failed to decode JPEG from file: "; error_message->append(path); |
| 138 | } |
| 139 | return frame; |
| 140 | } |
| 141 | |
| 142 | fl::Mp3DecoderPtr FileSystem::openMp3(const char *path, fl::string *error_message) { |
| 143 | fl::ifstream file = openRead(path); |