| 483 | } |
| 484 | |
| 485 | bool JPEGFileLoader(RGBA8Image* image, const char* filename, std::FILE* fp) |
| 486 | { |
| 487 | static constexpr u32 BUFFER_SIZE = 16384; |
| 488 | |
| 489 | struct FileCallback |
| 490 | { |
| 491 | // Must be the first member (&this == &mgr) |
| 492 | // We pass a pointer of mgr to libjpeg, and we need to be able to cast it back to FileCallback. |
| 493 | jpeg_source_mgr mgr; |
| 494 | |
| 495 | std::FILE* fp; |
| 496 | std::unique_ptr<u8[]> buffer; |
| 497 | bool end_of_file; |
| 498 | }; |
| 499 | |
| 500 | FileCallback cb = { |
| 501 | .mgr = { |
| 502 | .init_source = [](j_decompress_ptr cinfo) {}, |
| 503 | .fill_input_buffer = [](j_decompress_ptr cinfo) -> boolean { |
| 504 | FileCallback* cb = reinterpret_cast<FileCallback*>(cinfo->src); |
| 505 | cb->mgr.next_input_byte = cb->buffer.get(); |
| 506 | if (cb->end_of_file) |
| 507 | { |
| 508 | cb->buffer[0] = 0xFF; |
| 509 | cb->buffer[1] = JPEG_EOI; |
| 510 | cb->mgr.bytes_in_buffer = 2; |
| 511 | return TRUE; |
| 512 | } |
| 513 | |
| 514 | const size_t r = std::fread(cb->buffer.get(), 1, BUFFER_SIZE, cb->fp); |
| 515 | cb->end_of_file |= (std::feof(cb->fp) != 0); |
| 516 | cb->mgr.bytes_in_buffer = r; |
| 517 | return TRUE; |
| 518 | }, |
| 519 | .skip_input_data = |
| 520 | [](j_decompress_ptr cinfo, long num_bytes) { |
| 521 | FileCallback* cb = reinterpret_cast<FileCallback*>(cinfo->src); |
| 522 | const size_t skip_in_buffer = std::min<size_t>(cb->mgr.bytes_in_buffer, static_cast<size_t>(num_bytes)); |
| 523 | cb->mgr.next_input_byte += skip_in_buffer; |
| 524 | cb->mgr.bytes_in_buffer -= skip_in_buffer; |
| 525 | |
| 526 | const size_t seek_cur = static_cast<size_t>(num_bytes) - skip_in_buffer; |
| 527 | if (seek_cur > 0) |
| 528 | { |
| 529 | if (FileSystem::FSeek64(cb->fp, static_cast<size_t>(seek_cur), SEEK_CUR) != 0) |
| 530 | { |
| 531 | cb->end_of_file = true; |
| 532 | return; |
| 533 | } |
| 534 | } |
| 535 | }, |
| 536 | .resync_to_restart = jpeg_resync_to_restart, |
| 537 | .term_source = [](j_decompress_ptr cinfo) {}, |
| 538 | }, |
| 539 | .fp = fp, |
| 540 | .buffer = std::make_unique<u8[]>(BUFFER_SIZE), |
| 541 | .end_of_file = false, |
| 542 | }; |
nothing calls this directly
no test coverage detected