#ifndef PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
#define PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
#include <stddef.h>
#include <optional>
#include <string>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_math.h"
namespace chrome_pdf {
namespace internal {
template <class StringType>
class PDFiumAPIStringBufferAdapter {
public:
PDFiumAPIStringBufferAdapter(StringType* str,
size_t expected_size,
bool check_expected_size);
PDFiumAPIStringBufferAdapter(const PDFiumAPIStringBufferAdapter&) = delete;
PDFiumAPIStringBufferAdapter& operator=(const PDFiumAPIStringBufferAdapter&) =
delete;
~PDFiumAPIStringBufferAdapter();
void* GetData();
void Close(size_t actual_size);
template <typename IntType>
void Close(IntType actual_size) {
Close(base::checked_cast<size_t>(actual_size));
}
private:
const raw_ptr<StringType> str_;
const raw_ptr<void> data_;
const size_t expected_size_;
const bool check_expected_size_;
bool is_closed_;
};
class PDFiumAPIStringBufferSizeInBytesAdapter {
public:
PDFiumAPIStringBufferSizeInBytesAdapter(std::u16string* str,
size_t expected_size,
bool check_expected_size);
~PDFiumAPIStringBufferSizeInBytesAdapter();
void* GetData();
void Close(size_t actual_size);
template <typename IntType>
void Close(IntType actual_size) {
Close(base::checked_cast<size_t>(actual_size));
}
private:
PDFiumAPIStringBufferAdapter<std::u16string> adapter_;
};
template <class AdapterType,
class StringType,
typename BufferType,
typename ReturnType>
std::optional<StringType> CallPDFiumStringBufferApiAndReturnOptional(
base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
bool check_expected_size) {
ReturnType expected_size = api.Run(nullptr, 0);
if (expected_size == 0)
return std::nullopt;
StringType str;
AdapterType api_string_adapter(&str, expected_size, check_expected_size);
auto* data = reinterpret_cast<BufferType*>(api_string_adapter.GetData());
api_string_adapter.Close(api.Run(data, expected_size));
return str;
}
template <class AdapterType,
class StringType,
typename BufferType,
typename ReturnType>
std::optional<StringType> CallPDFiumStringBufferApiAndReturnOptional(
base::RepeatingCallback<
ReturnType(BufferType*, unsigned long, unsigned long*)> api,
bool check_expected_size) {
unsigned long expected_size;
ReturnType success = api.Run(nullptr, 0, &expected_size);
if (!success || expected_size == 0) {
return std::nullopt;
}
StringType str;
AdapterType api_string_adapter(&str, expected_size, check_expected_size);
auto* data = reinterpret_cast<BufferType*>(api_string_adapter.GetData());
unsigned long actual_size = 0;
success = api.Run(data, expected_size, &actual_size);
if (!success) {
return std::nullopt;
}
api_string_adapter.Close(actual_size);
return str;
}
template <class AdapterType,
class StringType,
typename BufferType,
typename ReturnType>
StringType CallPDFiumStringBufferApi(
base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
bool check_expected_size) {
std::optional<StringType> result =
CallPDFiumStringBufferApiAndReturnOptional<AdapterType, StringType>(
api, check_expected_size);
return result.value_or(StringType());
}
}
template <typename BufferType>
std::u16string CallPDFiumWideStringBufferApi(
base::RepeatingCallback<unsigned long(BufferType*, unsigned long)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter;
return internal::CallPDFiumStringBufferApi<adapter_type, std::u16string>(
api, check_expected_size);
}
template <typename BufferType>
std::optional<std::u16string> CallPDFiumWideStringBufferApiAndReturnOptional(
base::RepeatingCallback<unsigned long(BufferType*, unsigned long)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter;
return internal::CallPDFiumStringBufferApiAndReturnOptional<adapter_type,
std::u16string>(
api, check_expected_size);
}
template <typename BufferType, typename ReturnType>
std::string CallPDFiumStringBufferApi(
base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferAdapter<std::string>;
return internal::CallPDFiumStringBufferApi<adapter_type, std::string>(
api, check_expected_size);
}
template <typename BufferType, typename ReturnType>
std::optional<std::u16string> CallPDFiumWideStringBufferApiAndReturnOptional(
base::RepeatingCallback<
ReturnType(BufferType*, unsigned long, unsigned long*)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferSizeInBytesAdapter;
return internal::CallPDFiumStringBufferApiAndReturnOptional<
adapter_type, std::u16string, BufferType, ReturnType>(
api, check_expected_size);
}
template <typename BufferType, typename ReturnType>
std::optional<std::string> CallPDFiumStringBufferApiAndReturnOptional(
base::RepeatingCallback<
ReturnType(BufferType*, unsigned long, unsigned long*)> api,
bool check_expected_size) {
using adapter_type = internal::PDFiumAPIStringBufferAdapter<std::string>;
return internal::CallPDFiumStringBufferApiAndReturnOptional<
adapter_type, std::string, BufferType, ReturnType>(api,
check_expected_size);
}
template <class StringType>
using PDFiumAPIStringBufferAdapter =
internal::PDFiumAPIStringBufferAdapter<StringType>;
}
#endif