• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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