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