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