Haibo Huang | 49cc930 | 2020-04-27 16:14:24 -0700 | [diff] [blame^] | 1 | // Copyright 2019 PDFium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | |
| 7 | #include "core/fxcodec/jpx/jpx_decode_utils.h" |
| 8 | |
| 9 | #include <string.h> |
| 10 | |
| 11 | #include <algorithm> |
| 12 | #include <limits> |
| 13 | |
| 14 | namespace fxcodec { |
| 15 | |
| 16 | OPJ_SIZE_T opj_read_from_memory(void* p_buffer, |
| 17 | OPJ_SIZE_T nb_bytes, |
| 18 | void* p_user_data) { |
| 19 | DecodeData* srcData = static_cast<DecodeData*>(p_user_data); |
| 20 | if (!srcData || !srcData->src_data || srcData->src_size == 0) |
| 21 | return static_cast<OPJ_SIZE_T>(-1); |
| 22 | |
| 23 | // Reads at EOF return an error code. |
| 24 | if (srcData->offset >= srcData->src_size) |
| 25 | return static_cast<OPJ_SIZE_T>(-1); |
| 26 | |
| 27 | OPJ_SIZE_T bufferLength = srcData->src_size - srcData->offset; |
| 28 | OPJ_SIZE_T readlength = nb_bytes < bufferLength ? nb_bytes : bufferLength; |
| 29 | memcpy(p_buffer, &srcData->src_data[srcData->offset], readlength); |
| 30 | srcData->offset += readlength; |
| 31 | return readlength; |
| 32 | } |
| 33 | |
| 34 | OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { |
| 35 | DecodeData* srcData = static_cast<DecodeData*>(p_user_data); |
| 36 | if (!srcData || !srcData->src_data || srcData->src_size == 0) |
| 37 | return static_cast<OPJ_OFF_T>(-1); |
| 38 | |
| 39 | // Offsets are signed and may indicate a negative skip. Do not support this |
| 40 | // because of the strange return convention where either bytes skipped or |
| 41 | // -1 is returned. Following that convention, a successful relative seek of |
| 42 | // -1 bytes would be required to to give the same result as the error case. |
| 43 | if (nb_bytes < 0) |
| 44 | return static_cast<OPJ_OFF_T>(-1); |
| 45 | |
| 46 | auto unsigned_nb_bytes = |
| 47 | static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes); |
| 48 | // Additionally, the offset may take us beyond the range of a size_t (e.g. |
| 49 | // 32-bit platforms). If so, just clamp at EOF. |
| 50 | if (unsigned_nb_bytes > |
| 51 | std::numeric_limits<OPJ_SIZE_T>::max() - srcData->offset) { |
| 52 | srcData->offset = srcData->src_size; |
| 53 | } else { |
| 54 | OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(unsigned_nb_bytes); |
| 55 | // Otherwise, mimic fseek() semantics to always succeed, even past EOF, |
| 56 | // clamping at EOF. We can get away with this since we don't actually |
| 57 | // provide negative relative skips from beyond EOF back to inside the |
| 58 | // data, which would be the only reason to need to know exactly how far |
| 59 | // beyond EOF we are. |
| 60 | srcData->offset = |
| 61 | std::min(srcData->offset + checked_nb_bytes, srcData->src_size); |
| 62 | } |
| 63 | return nb_bytes; |
| 64 | } |
| 65 | |
| 66 | OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) { |
| 67 | DecodeData* srcData = static_cast<DecodeData*>(p_user_data); |
| 68 | if (!srcData || !srcData->src_data || srcData->src_size == 0) |
| 69 | return OPJ_FALSE; |
| 70 | |
| 71 | // Offsets are signed and may indicate a negative position, which would |
| 72 | // be before the start of the file. Do not support this. |
| 73 | if (nb_bytes < 0) |
| 74 | return OPJ_FALSE; |
| 75 | |
| 76 | auto unsigned_nb_bytes = |
| 77 | static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes); |
| 78 | // Additionally, the offset may take us beyond the range of a size_t (e.g. |
| 79 | // 32-bit platforms). If so, just clamp at EOF. |
| 80 | if (unsigned_nb_bytes > std::numeric_limits<OPJ_SIZE_T>::max()) { |
| 81 | srcData->offset = srcData->src_size; |
| 82 | } else { |
| 83 | OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(nb_bytes); |
| 84 | // Otherwise, mimic fseek() semantics to always succeed, even past EOF, |
| 85 | // again clamping at EOF. |
| 86 | srcData->offset = std::min(checked_nb_bytes, srcData->src_size); |
| 87 | } |
| 88 | return OPJ_TRUE; |
| 89 | } |
| 90 | |
| 91 | } // namespace fxcodec |