blob: d3842d706263a3581a3addd4b829cd8c866fb159 [file] [log] [blame]
Haibo Huang49cc9302020-04-27 16:14:24 -07001// 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
14namespace fxcodec {
15
16OPJ_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
34OPJ_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
66OPJ_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