| // Copyright 2019 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fxcodec/jpx/jpx_decode_utils.h" |
| |
| #include <stddef.h> |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <limits> |
| #include <type_traits> |
| |
| namespace fxcodec { |
| |
| OPJ_SIZE_T opj_read_from_memory(void* p_buffer, |
| OPJ_SIZE_T nb_bytes, |
| void* p_user_data) { |
| DecodeData* srcData = static_cast<DecodeData*>(p_user_data); |
| if (!srcData || !srcData->src_data || srcData->src_size == 0) |
| return static_cast<OPJ_SIZE_T>(-1); |
| |
| // Reads at EOF return an error code. |
| if (srcData->offset >= srcData->src_size) |
| return static_cast<OPJ_SIZE_T>(-1); |
| |
| OPJ_SIZE_T bufferLength = srcData->src_size - srcData->offset; |
| OPJ_SIZE_T readlength = nb_bytes < bufferLength ? nb_bytes : bufferLength; |
| memcpy(p_buffer, &srcData->src_data[srcData->offset], readlength); |
| srcData->offset += readlength; |
| return readlength; |
| } |
| |
| OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { |
| DecodeData* srcData = static_cast<DecodeData*>(p_user_data); |
| if (!srcData || !srcData->src_data || srcData->src_size == 0) |
| return static_cast<OPJ_OFF_T>(-1); |
| |
| // Offsets are signed and may indicate a negative skip. Do not support this |
| // because of the strange return convention where either bytes skipped or |
| // -1 is returned. Following that convention, a successful relative seek of |
| // -1 bytes would be required to to give the same result as the error case. |
| if (nb_bytes < 0) |
| return static_cast<OPJ_OFF_T>(-1); |
| |
| auto unsigned_nb_bytes = |
| static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes); |
| // Additionally, the offset may take us beyond the range of a size_t (e.g. |
| // 32-bit platforms). If so, just clamp at EOF. |
| if (unsigned_nb_bytes > |
| std::numeric_limits<OPJ_SIZE_T>::max() - srcData->offset) { |
| srcData->offset = srcData->src_size; |
| } else { |
| OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(unsigned_nb_bytes); |
| // Otherwise, mimic fseek() semantics to always succeed, even past EOF, |
| // clamping at EOF. We can get away with this since we don't actually |
| // provide negative relative skips from beyond EOF back to inside the |
| // data, which would be the only reason to need to know exactly how far |
| // beyond EOF we are. |
| srcData->offset = |
| std::min(srcData->offset + checked_nb_bytes, srcData->src_size); |
| } |
| return nb_bytes; |
| } |
| |
| OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { |
| DecodeData* srcData = static_cast<DecodeData*>(p_user_data); |
| if (!srcData || !srcData->src_data || srcData->src_size == 0) |
| return OPJ_FALSE; |
| |
| // Offsets are signed and may indicate a negative position, which would |
| // be before the start of the file. Do not support this. |
| if (nb_bytes < 0) |
| return OPJ_FALSE; |
| |
| auto unsigned_nb_bytes = |
| static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes); |
| // Additionally, the offset may take us beyond the range of a size_t (e.g. |
| // 32-bit platforms). If so, just clamp at EOF. |
| if (unsigned_nb_bytes > std::numeric_limits<OPJ_SIZE_T>::max()) { |
| srcData->offset = srcData->src_size; |
| } else { |
| OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(nb_bytes); |
| // Otherwise, mimic fseek() semantics to always succeed, even past EOF, |
| // again clamping at EOF. |
| srcData->offset = std::min(checked_nb_bytes, srcData->src_size); |
| } |
| return OPJ_TRUE; |
| } |
| |
| } // namespace fxcodec |