| 8941 | } |
| 8942 | |
| 8943 | int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, |
| 8944 | const EXRHeader **exr_headers, |
| 8945 | unsigned int num_parts, |
| 8946 | const unsigned char *memory, |
| 8947 | const size_t size, const char **err) { |
| 8948 | if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || |
| 8949 | memory == NULL || (size <= tinyexr::kEXRVersionSize)) { |
| 8950 | tinyexr::SetErrorMessage( |
| 8951 | "Invalid argument for LoadEXRMultipartImageFromMemory()", err); |
| 8952 | return TINYEXR_ERROR_INVALID_ARGUMENT; |
| 8953 | } |
| 8954 | |
| 8955 | // compute total header size. |
| 8956 | size_t total_header_size = 0; |
| 8957 | for (unsigned int i = 0; i < num_parts; i++) { |
| 8958 | if (exr_headers[i]->header_len == 0) { |
| 8959 | tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); |
| 8960 | return TINYEXR_ERROR_INVALID_ARGUMENT; |
| 8961 | } |
| 8962 | |
| 8963 | total_header_size += exr_headers[i]->header_len; |
| 8964 | } |
| 8965 | |
| 8966 | const char *marker = reinterpret_cast<const char *>( |
| 8967 | memory + total_header_size + 4 + |
| 8968 | 4); // +8 for magic number and version header. |
| 8969 | |
| 8970 | marker += 1; // Skip empty header. |
| 8971 | |
| 8972 | // NOTE 1: |
| 8973 | // In multipart image, There is 'part number' before chunk data. |
| 8974 | // 4 byte : part number |
| 8975 | // 4+ : chunk |
| 8976 | // |
| 8977 | // NOTE 2: |
| 8978 | // EXR spec says 'part number' is 'unsigned long' but actually this is |
| 8979 | // 'unsigned int(4 bytes)' in OpenEXR implementation... |
| 8980 | // http://www.openexr.com/openexrfilelayout.pdf |
| 8981 | |
| 8982 | // Load chunk offset table. |
| 8983 | std::vector<tinyexr::OffsetData> chunk_offset_table_list; |
| 8984 | chunk_offset_table_list.reserve(num_parts); |
| 8985 | for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) { |
| 8986 | chunk_offset_table_list.resize(chunk_offset_table_list.size() + 1); |
| 8987 | tinyexr::OffsetData& offset_data = chunk_offset_table_list.back(); |
| 8988 | if (!exr_headers[i]->tiled || exr_headers[i]->tile_level_mode == TINYEXR_TILE_ONE_LEVEL) { |
| 8989 | tinyexr::InitSingleResolutionOffsets(offset_data, size_t(exr_headers[i]->chunk_count)); |
| 8990 | std::vector<tinyexr::tinyexr_uint64>& offset_table = offset_data.offsets[0][0]; |
| 8991 | |
| 8992 | for (size_t c = 0; c < offset_table.size(); c++) { |
| 8993 | tinyexr::tinyexr_uint64 offset; |
| 8994 | memcpy(&offset, marker, 8); |
| 8995 | tinyexr::swap8(&offset); |
| 8996 | |
| 8997 | if (offset >= size) { |
| 8998 | tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", |
| 8999 | err); |
| 9000 | return TINYEXR_ERROR_INVALID_DATA; |
no test coverage detected