1 // Copyright 2019 The PDFium Authors
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 <algorithm>
10 #include <limits>
11 #include <type_traits>
12
13 #include "core/fxcrt/compiler_specific.h"
14 #include "core/fxcrt/fx_memcpy_wrappers.h"
15 #include "core/fxcrt/numerics/safe_conversions.h"
16
17 namespace fxcodec {
18
DecodeData(pdfium::span<const uint8_t> data)19 DecodeData::DecodeData(pdfium::span<const uint8_t> data)
20 : src_data(data.data()),
21 src_size(pdfium::checked_cast<OPJ_SIZE_T>(data.size())) {}
22
opj_read_from_memory(void * p_buffer,OPJ_SIZE_T nb_bytes,void * p_user_data)23 OPJ_SIZE_T opj_read_from_memory(void* p_buffer,
24 OPJ_SIZE_T nb_bytes,
25 void* p_user_data) {
26 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
27 if (!srcData || !srcData->src_data || srcData->src_size == 0)
28 return static_cast<OPJ_SIZE_T>(-1);
29
30 // Reads at EOF return an error code.
31 if (srcData->offset >= srcData->src_size)
32 return static_cast<OPJ_SIZE_T>(-1);
33
34 UNSAFE_TODO({
35 OPJ_SIZE_T bufferLength = srcData->src_size - srcData->offset;
36 OPJ_SIZE_T readlength = nb_bytes < bufferLength ? nb_bytes : bufferLength;
37 FXSYS_memcpy(p_buffer, &srcData->src_data[srcData->offset], readlength);
38 srcData->offset += readlength;
39 return readlength;
40 })
41 }
42
opj_skip_from_memory(OPJ_OFF_T nb_bytes,void * p_user_data)43 OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) {
44 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
45 if (!srcData || !srcData->src_data || srcData->src_size == 0)
46 return static_cast<OPJ_OFF_T>(-1);
47
48 // Offsets are signed and may indicate a negative skip. Do not support this
49 // because of the strange return convention where either bytes skipped or
50 // -1 is returned. Following that convention, a successful relative seek of
51 // -1 bytes would be required to to give the same result as the error case.
52 if (nb_bytes < 0)
53 return static_cast<OPJ_OFF_T>(-1);
54
55 auto unsigned_nb_bytes =
56 static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes);
57 // Additionally, the offset may take us beyond the range of a size_t (e.g.
58 // 32-bit platforms). If so, just clamp at EOF.
59 if (unsigned_nb_bytes >
60 std::numeric_limits<OPJ_SIZE_T>::max() - srcData->offset) {
61 srcData->offset = srcData->src_size;
62 } else {
63 OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(unsigned_nb_bytes);
64 // Otherwise, mimic fseek() semantics to always succeed, even past EOF,
65 // clamping at EOF. We can get away with this since we don't actually
66 // provide negative relative skips from beyond EOF back to inside the
67 // data, which would be the only reason to need to know exactly how far
68 // beyond EOF we are.
69 srcData->offset =
70 std::min(srcData->offset + checked_nb_bytes, srcData->src_size);
71 }
72 return nb_bytes;
73 }
74
opj_seek_from_memory(OPJ_OFF_T nb_bytes,void * p_user_data)75 OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) {
76 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
77 if (!srcData || !srcData->src_data || srcData->src_size == 0)
78 return OPJ_FALSE;
79
80 // Offsets are signed and may indicate a negative position, which would
81 // be before the start of the file. Do not support this.
82 if (nb_bytes < 0)
83 return OPJ_FALSE;
84
85 auto unsigned_nb_bytes =
86 static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes);
87 // Additionally, the offset may take us beyond the range of a size_t (e.g.
88 // 32-bit platforms). If so, just clamp at EOF.
89 if (unsigned_nb_bytes > std::numeric_limits<OPJ_SIZE_T>::max()) {
90 srcData->offset = srcData->src_size;
91 } else {
92 OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(nb_bytes);
93 // Otherwise, mimic fseek() semantics to always succeed, even past EOF,
94 // again clamping at EOF.
95 srcData->offset = std::min(checked_nb_bytes, srcData->src_size);
96 }
97 return OPJ_TRUE;
98 }
99
100 } // namespace fxcodec
101