blob: 54d65cfdea5cd778bfddcae41ffb411432d426f4 [file] [log] [blame]
// Copyright 2019 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fxcodec/jpx/jpx_decode_utils.h"
#include <algorithm>
#include <limits>
#include <type_traits>
#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/fx_memcpy_wrappers.h"
namespace fxcodec {
OPJ_SIZE_T opj_read_from_memory(void* p_buffer,
OPJ_SIZE_T nb_bytes,
void* p_user_data) {
DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
if (!srcData || !srcData->src_data || srcData->src_size == 0)
return static_cast<OPJ_SIZE_T>(-1);
// Reads at EOF return an error code.
if (srcData->offset >= srcData->src_size)
return static_cast<OPJ_SIZE_T>(-1);
UNSAFE_TODO({
OPJ_SIZE_T bufferLength = srcData->src_size - srcData->offset;
OPJ_SIZE_T readlength = nb_bytes < bufferLength ? nb_bytes : bufferLength;
FXSYS_memcpy(p_buffer, &srcData->src_data[srcData->offset], readlength);
srcData->offset += readlength;
return readlength;
})
}
OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) {
DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
if (!srcData || !srcData->src_data || srcData->src_size == 0)
return static_cast<OPJ_OFF_T>(-1);
// Offsets are signed and may indicate a negative skip. Do not support this
// because of the strange return convention where either bytes skipped or
// -1 is returned. Following that convention, a successful relative seek of
// -1 bytes would be required to to give the same result as the error case.
if (nb_bytes < 0)
return static_cast<OPJ_OFF_T>(-1);
auto unsigned_nb_bytes =
static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes);
// Additionally, the offset may take us beyond the range of a size_t (e.g.
// 32-bit platforms). If so, just clamp at EOF.
if (unsigned_nb_bytes >
std::numeric_limits<OPJ_SIZE_T>::max() - srcData->offset) {
srcData->offset = srcData->src_size;
} else {
OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(unsigned_nb_bytes);
// Otherwise, mimic fseek() semantics to always succeed, even past EOF,
// clamping at EOF. We can get away with this since we don't actually
// provide negative relative skips from beyond EOF back to inside the
// data, which would be the only reason to need to know exactly how far
// beyond EOF we are.
srcData->offset =
std::min(srcData->offset + checked_nb_bytes, srcData->src_size);
}
return nb_bytes;
}
OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data) {
DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
if (!srcData || !srcData->src_data || srcData->src_size == 0)
return OPJ_FALSE;
// Offsets are signed and may indicate a negative position, which would
// be before the start of the file. Do not support this.
if (nb_bytes < 0)
return OPJ_FALSE;
auto unsigned_nb_bytes =
static_cast<std::make_unsigned<OPJ_OFF_T>::type>(nb_bytes);
// Additionally, the offset may take us beyond the range of a size_t (e.g.
// 32-bit platforms). If so, just clamp at EOF.
if (unsigned_nb_bytes > std::numeric_limits<OPJ_SIZE_T>::max()) {
srcData->offset = srcData->src_size;
} else {
OPJ_SIZE_T checked_nb_bytes = static_cast<OPJ_SIZE_T>(nb_bytes);
// Otherwise, mimic fseek() semantics to always succeed, even past EOF,
// again clamping at EOF.
srcData->offset = std::min(checked_nb_bytes, srcData->src_size);
}
return OPJ_TRUE;
}
} // namespace fxcodec