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 
opj_read_from_memory(void * p_buffer,OPJ_SIZE_T nb_bytes,void * p_user_data)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 
opj_skip_from_memory(OPJ_OFF_T nb_bytes,void * p_user_data)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 
opj_seek_from_memory(OPJ_OFF_T nb_bytes,void * p_user_data)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
92