| 10499 | } |
| 10500 | |
| 10501 | int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, |
| 10502 | const EXRHeader **exr_headers, |
| 10503 | unsigned int num_parts, |
| 10504 | const unsigned char *memory, |
| 10505 | const size_t size, const char **err) { |
| 10506 | if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || |
| 10507 | memory == NULL || (size <= tinyexr::kEXRVersionSize)) { |
| 10508 | tinyexr::SetErrorMessage( |
| 10509 | "Invalid argument for LoadEXRMultipartImageFromMemory()", err); |
| 10510 | return TINYEXR_ERROR_INVALID_ARGUMENT; |
| 10511 | } |
| 10512 | |
| 10513 | // compute total header size. |
| 10514 | size_t total_header_size = 0; |
| 10515 | for (unsigned int i = 0; i < num_parts; i++) { |
| 10516 | if (exr_headers[i]->header_len == 0) { |
| 10517 | tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); |
| 10518 | return TINYEXR_ERROR_INVALID_ARGUMENT; |
| 10519 | } |
| 10520 | |
| 10521 | total_header_size += exr_headers[i]->header_len; |
| 10522 | } |
| 10523 | |
| 10524 | const char *marker = reinterpret_cast<const char *>( |
| 10525 | memory + total_header_size + 4 + |
| 10526 | 4); // +8 for magic number and version header. |
| 10527 | |
| 10528 | marker += 1; // Skip empty header. |
| 10529 | |
| 10530 | // NOTE 1: |
| 10531 | // In multipart image, There is 'part number' before chunk data. |
| 10532 | // 4 byte : part number |
| 10533 | // 4+ : chunk |
| 10534 | // |
| 10535 | // NOTE 2: |
| 10536 | // EXR spec says 'part number' is 'unsigned long' but actually this is |
| 10537 | // 'unsigned int(4 bytes)' in OpenEXR implementation... |
| 10538 | // http://www.openexr.com/openexrfilelayout.pdf |
| 10539 | |
| 10540 | // Load chunk offset table. |
| 10541 | std::vector<tinyexr::OffsetData> chunk_offset_table_list; |
| 10542 | chunk_offset_table_list.reserve(num_parts); |
| 10543 | for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) { |
| 10544 | chunk_offset_table_list.resize(chunk_offset_table_list.size() + 1); |
| 10545 | tinyexr::OffsetData& offset_data = chunk_offset_table_list.back(); |
| 10546 | if (!exr_headers[i]->tiled || exr_headers[i]->tile_level_mode == TINYEXR_TILE_ONE_LEVEL) { |
| 10547 | tinyexr::InitSingleResolutionOffsets(offset_data, size_t(exr_headers[i]->chunk_count)); |
| 10548 | std::vector<tinyexr::tinyexr_uint64>& offset_table = offset_data.offsets[0][0]; |
| 10549 | |
| 10550 | for (size_t c = 0; c < offset_table.size(); c++) { |
| 10551 | tinyexr::tinyexr_uint64 offset; |
| 10552 | memcpy(&offset, marker, 8); |
| 10553 | tinyexr::swap8(&offset); |
| 10554 | |
| 10555 | if (offset >= size) { |
| 10556 | tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", |
| 10557 | err); |
| 10558 | return TINYEXR_ERROR_INVALID_DATA; |
no test coverage detected