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