1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
#define PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
#include <stddef.h>
#include <string>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_math.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace chrome_pdf {
namespace internal {
// Helper to deal with the fact that many PDFium APIs write the null-terminator
// into string buffers that are passed to them, but the PDF code likes to use
// std::strings / std::u16strings, where one should not count on the internal
// string buffers to be null-terminated.
template <class StringType>
class PDFiumAPIStringBufferAdapter {
public:
// `str` is the string to write into.
// `expected_size` is the number of characters the PDFium API will write,
// including the null-terminator. It should be at least 1.
// `check_expected_size` whether to check the actual number of characters
// written into `str` against `expected_size` when calling Close().
PDFiumAPIStringBufferAdapter(StringType* str,
size_t expected_size,
bool check_expected_size);
PDFiumAPIStringBufferAdapter(const PDFiumAPIStringBufferAdapter&) = delete;
PDFiumAPIStringBufferAdapter& operator=(const PDFiumAPIStringBufferAdapter&) =
delete;
~PDFiumAPIStringBufferAdapter();
// Returns a pointer to `str_`'s buffer. The buffer's size is large enough to
// hold `expected_size_` + 1 characters, so the PDFium API that uses the
// pointer has space to write a null-terminator.
void* GetData();
// Resizes `str_` to `actual_size` - 1 characters, thereby removing the extra
// null-terminator. This must be called prior to the adapter's destruction.
// The pointer returned by GetData() should be considered invalid.
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_;
};
// Helper to deal with the fact that many PDFium APIs write the null-terminator
// into string buffers that are passed to them, but the PDF code likes to use
// std::strings / std::u16strings, where one should not count on the internal
// string buffers to be null-terminated. This version is suitable for APIs that
// work in terms of number of bytes instead of the number of characters. Though
// for std::strings, PDFiumAPIStringBufferAdapter is equivalent.
class PDFiumAPIStringBufferSizeInBytesAdapter {
public:
// `str` is the string to write into.
// `expected_size` is the number of bytes the PDFium API will write,
// including the null-terminator. It should be at least the size of a
// character in bytes.
// `check_expected_size` whether to check the actual number of bytes
// written into `str` against `expected_size` when calling Close().
PDFiumAPIStringBufferSizeInBytesAdapter(std::u16string* str,
size_t expected_size,
bool check_expected_size);
~PDFiumAPIStringBufferSizeInBytesAdapter();
// Returns a pointer to `str_`'s buffer. The buffer's size is large enough to
// hold `expected_size_` + sizeof(char16_t) bytes, so the PDFium API that
// uses the pointer has space to write a null-terminator.
void* GetData();
// Resizes `str_` to `actual_size` - sizeof(char16_t) bytes, thereby
// removing the extra null-terminator. This must be called prior to the
// adapter's destruction. The pointer returned by GetData() should be
// considered invalid.
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>
absl::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 absl::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>
StringType CallPDFiumStringBufferApi(
base::RepeatingCallback<ReturnType(BufferType*, ReturnType)> api,
bool check_expected_size) {
absl::optional<StringType> result =
CallPDFiumStringBufferApiAndReturnOptional<AdapterType, StringType>(
api, check_expected_size);
return result.value_or(StringType());
}
} // namespace internal
// Helper function to call PDFium APIs where the output buffer is expected to
// hold UTF-16 data, and the buffer length is specified in bytes.
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);
}
// Variant of CallPDFiumWideStringBufferApi() that distinguishes between API
// call failures and empty string return values.
template <typename BufferType>
absl::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);
}
// Helper function to call PDFium APIs where the output buffer is expected to
// hold ASCII or UTF-8 data, and the buffer length is specified in bytes.
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);
}
// Expose internal::PDFiumAPIStringBufferAdapter for special cases that cannot
// use the CallPDFiumStringBuffer* functions above.
template <class StringType>
using PDFiumAPIStringBufferAdapter =
internal::PDFiumAPIStringBufferAdapter<StringType>;
} // namespace chrome_pdf
#endif // PDF_PDFIUM_PDFIUM_API_STRING_BUFFER_ADAPTER_H_
|