Give buffers in experimental fpdf_annot.h APIs clearer types.

Change some buffer parameters' types from void* to FPDF_WCHAR*. Then:

- Clarify in the documentation that the buffer length is in bytes.
- Change callers to use containers of FPDF_WCHAR instead of char.
- Change callers to avoid casting and converting FPDF_WCHAR to char.
- Add GetFPDFWideStringBuffer() to help create std::vector<FPDF_WCHAR>
  without having to byte length to FPDF_WCHAR count conversions.
- Remove BufferToWString() and BufferToString() helpers.
- Check the md5sum of a large buffer, instead of just the two ends.

The affected APIs are:

- FPDFAnnot_GetStringValue()
- FPDFAnnot_GetAP()
- FPDFAnnot_GetOptionLabel()

Change-Id: Ie4fd1831af97221ea74d4353be2456758d6a945e
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/52872
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index 1d11cec..c6214dc 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -719,7 +719,7 @@
 FPDF_EXPORT unsigned long FPDF_CALLCONV
 FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
                          FPDF_BYTESTRING key,
-                         void* buffer,
+                         FPDF_WCHAR* buffer,
                          unsigned long buflen) {
   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
   if (!pAnnotDict)
@@ -792,7 +792,7 @@
 FPDF_EXPORT unsigned long FPDF_CALLCONV
 FPDFAnnot_GetAP(FPDF_ANNOTATION annot,
                 FPDF_ANNOT_APPEARANCEMODE appearanceMode,
-                void* buffer,
+                FPDF_WCHAR* buffer,
                 unsigned long buflen) {
   CPDF_Dictionary* pAnnotDict = GetAnnotDictFromFPDFAnnotation(annot);
   if (!pAnnotDict)
@@ -905,7 +905,7 @@
 FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,
                          FPDF_ANNOTATION annot,
                          int index,
-                         void* buffer,
+                         FPDF_WCHAR* buffer,
                          unsigned long buflen) {
   CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle);
   if (!pForm)
diff --git a/fpdfsdk/fpdf_annot_embeddertest.cpp b/fpdfsdk/fpdf_annot_embeddertest.cpp
index 19b22f5..281eaa0 100644
--- a/fpdfsdk/fpdf_annot_embeddertest.cpp
+++ b/fpdfsdk/fpdf_annot_embeddertest.cpp
@@ -18,17 +18,10 @@
 #include "testing/fx_string_testhelpers.h"
 #include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/utils/hash.h"
 
 class FPDFAnnotEmbedderTest : public EmbedderTest {};
 
-std::wstring BufferToWString(const std::vector<char>& buf) {
-  return GetPlatformWString(reinterpret_cast<FPDF_WIDESTRING>(buf.data()));
-}
-
-std::string BufferToString(const std::vector<char>& buf) {
-  return GetPlatformString(reinterpret_cast<FPDF_WIDESTRING>(buf.data()));
-}
-
 TEST_F(FPDFAnnotEmbedderTest, BadParams) {
   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
   FPDF_PAGE page = LoadPage(0);
@@ -56,7 +49,7 @@
   ScopedFPDFWideString text = GetFPDFWideString(kContents);
   EXPECT_FALSE(FPDFAnnot_SetStringValue(nullptr, "foo", text.get()));
 
-  char buffer[128];
+  FPDF_WCHAR buffer[64];
   EXPECT_EQ(0u, FPDFAnnot_GetStringValue(nullptr, "foo", nullptr, 0));
   EXPECT_EQ(0u, FPDFAnnot_GetStringValue(nullptr, "foo", buffer, 0));
   EXPECT_EQ(0u,
@@ -136,24 +129,25 @@
     static const char kAuthorKey[] = "T";
     EXPECT_EQ(FPDF_OBJECT_STRING,
               FPDFAnnot_GetValueType(annot.get(), kAuthorKey));
-    unsigned long len =
+    unsigned long length_bytes =
         FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, nullptr, 0);
-    std::vector<char> buf(len);
+    ASSERT_EQ(28u, length_bytes);
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(28u, FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, buf.data(),
-                                            len));
-    EXPECT_STREQ(L"Jae Hyun Park", BufferToWString(buf).c_str());
+                                            length_bytes));
+    EXPECT_EQ(L"Jae Hyun Park", GetPlatformWString(buf.data()));
 
     // Check that the content is correct.
     EXPECT_EQ(
         FPDF_OBJECT_STRING,
         FPDFAnnot_GetValueType(annot.get(), pdfium::annotation::kContents));
-    len = FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kContents,
-                                   nullptr, 0);
-    buf.clear();
-    buf.resize(len);
-    EXPECT_EQ(2690u,
-              FPDFAnnot_GetStringValue(
-                  annot.get(), pdfium::annotation::kContents, buf.data(), len));
+    length_bytes = FPDFAnnot_GetStringValue(
+        annot.get(), pdfium::annotation::kContents, nullptr, 0);
+    ASSERT_EQ(2690u, length_bytes);
+    buf = GetFPDFWideStringBuffer(length_bytes);
+    EXPECT_EQ(2690u, FPDFAnnot_GetStringValue(annot.get(),
+                                              pdfium::annotation::kContents,
+                                              buf.data(), length_bytes));
     static const wchar_t kContents[] =
         L"This is a note for that highlight annotation. Very long highlight "
         "annotation. Long long long Long long longLong long longLong long "
@@ -175,7 +169,7 @@
         "longLong long longLong long longLong long longLong long longLong long "
         "longLong long longLong long longLong long longLong long longLong long "
         "longLong long long. END";
-    EXPECT_STREQ(kContents, BufferToWString(buf).c_str());
+    EXPECT_EQ(kContents, GetPlatformWString(buf.data()));
 
     // Check that the quadpoints are correct.
     FS_QUADPOINTSF quadpoints;
@@ -320,13 +314,14 @@
     ASSERT_TRUE(FPDFAnnot_SetStringValue(
         annot.get(), pdfium::annotation::kContents, text.get()));
     // Check that the content has been set correctly.
-    unsigned long len = FPDFAnnot_GetStringValue(
+    unsigned long length_bytes = FPDFAnnot_GetStringValue(
         annot.get(), pdfium::annotation::kContents, nullptr, 0);
-    std::vector<char> buf(len);
-    EXPECT_EQ(74u,
-              FPDFAnnot_GetStringValue(
-                  annot.get(), pdfium::annotation::kContents, buf.data(), len));
-    EXPECT_STREQ(kContents, BufferToWString(buf).c_str());
+    ASSERT_EQ(74u, length_bytes);
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
+    EXPECT_EQ(74u, FPDFAnnot_GetStringValue(annot.get(),
+                                            pdfium::annotation::kContents,
+                                            buf.data(), length_bytes));
+    EXPECT_EQ(kContents, GetPlatformWString(buf.data()));
   }
   UnloadPage(page);
 }
@@ -1085,23 +1080,24 @@
     // Check that the string value of the hash is correct.
     static const char kHashKey[] = "AAPL:Hash";
     EXPECT_EQ(FPDF_OBJECT_NAME, FPDFAnnot_GetValueType(annot.get(), kHashKey));
-    unsigned long len =
+    unsigned long length_bytes =
         FPDFAnnot_GetStringValue(annot.get(), kHashKey, nullptr, 0);
-    std::vector<char> buf(len);
-    EXPECT_EQ(66u,
-              FPDFAnnot_GetStringValue(annot.get(), kHashKey, buf.data(), len));
-    EXPECT_STREQ(L"395fbcb98d558681742f30683a62a2ad",
-                 BufferToWString(buf).c_str());
+    ASSERT_EQ(66u, length_bytes);
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
+    EXPECT_EQ(66u, FPDFAnnot_GetStringValue(annot.get(), kHashKey, buf.data(),
+                                            length_bytes));
+    EXPECT_EQ(L"395fbcb98d558681742f30683a62a2ad",
+              GetPlatformWString(buf.data()));
 
     // Check that the string value of the modified date is correct.
     EXPECT_EQ(FPDF_OBJECT_NAME, FPDFAnnot_GetValueType(annot.get(), kHashKey));
-    len = FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kM, nullptr,
-                                   0);
-    buf.clear();
-    buf.resize(len);
+    length_bytes = FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kM,
+                                            nullptr, 0);
+    ASSERT_EQ(44u, length_bytes);
+    buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(44u, FPDFAnnot_GetStringValue(annot.get(), pdfium::annotation::kM,
-                                            buf.data(), len));
-    EXPECT_STREQ(L"D:201706071721Z00'00'", BufferToWString(buf).c_str());
+                                            buf.data(), length_bytes));
+    EXPECT_EQ(L"D:201706071721Z00'00'", GetPlatformWString(buf.data()));
 
     // Update the date entry for the annotation.
     ScopedFPDFWideString text = GetFPDFWideString(kNewDate);
@@ -1131,13 +1127,14 @@
     // Check that the string value of the modified date is the newly-set value.
     EXPECT_EQ(FPDF_OBJECT_STRING,
               FPDFAnnot_GetValueType(new_annot.get(), pdfium::annotation::kM));
-    unsigned long len = FPDFAnnot_GetStringValue(
+    unsigned long length_bytes = FPDFAnnot_GetStringValue(
         new_annot.get(), pdfium::annotation::kM, nullptr, 0);
-    std::vector<char> buf(len);
+    ASSERT_EQ(44u, length_bytes);
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(44u,
               FPDFAnnot_GetStringValue(new_annot.get(), pdfium::annotation::kM,
-                                       buf.data(), len));
-    EXPECT_STREQ(kNewDate, BufferToWString(buf).c_str());
+                                       buf.data(), length_bytes));
+    EXPECT_EQ(kNewDate, GetPlatformWString(buf.data()));
   }
 
   CloseSavedPage(page);
@@ -1191,60 +1188,58 @@
   ASSERT_TRUE(page);
 
   {
+    static const char kMd5NormalAP[] = "be903df0343fd774fadab9c8900cdf4a";
+    static constexpr size_t kExpectNormalAPLength = 73970;
+
     // Retrieve the first annotation.
     ScopedFPDFAnnotation annot(FPDFPage_GetAnnot(page, 0));
     ASSERT_TRUE(annot);
 
     // Check that the string value of an AP returns the expected length.
-    unsigned long normal_len = FPDFAnnot_GetAP(
+    unsigned long normal_length_bytes = FPDFAnnot_GetAP(
         annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL, nullptr, 0);
-    EXPECT_EQ(73970u, normal_len);
+    ASSERT_EQ(kExpectNormalAPLength, normal_length_bytes);
 
     // Check that the string value of an AP is not returned if the buffer is too
     // small. The result buffer should be overwritten with an empty string.
-    std::vector<char> buf(normal_len - 1);
-    // Write L"z" in the buffer to verify it's not overwritten.
-    wcscpy(reinterpret_cast<wchar_t*>(buf.data()), L"z");
-    EXPECT_EQ(73970u,
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(normal_length_bytes);
+    // Write in the buffer to verify it's not overwritten.
+    memcpy(buf.data(), "abcdefgh", 8);
+    EXPECT_EQ(kExpectNormalAPLength,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
-                              buf.data(), buf.size()));
-    std::string ap = BufferToString(buf);
-    EXPECT_STREQ("z", ap.c_str());
+                              buf.data(), normal_length_bytes - 1));
+    EXPECT_EQ(0, memcmp(buf.data(), "abcdefgh", 8));
 
     // Check that the string value of an AP is returned through a buffer that is
     // the right size.
-    buf.clear();
-    buf.resize(normal_len);
-    EXPECT_EQ(73970u,
+    EXPECT_EQ(kExpectNormalAPLength,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
-                              buf.data(), buf.size()));
-    ap = BufferToString(buf);
-    EXPECT_THAT(ap, testing::StartsWith("q Q q 7.442786 w 2 J"));
-    EXPECT_THAT(ap, testing::EndsWith("c 716.5381 327.7156 l S Q Q"));
+                              buf.data(), normal_length_bytes));
+    EXPECT_EQ(kMd5NormalAP,
+              GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()),
+                                normal_length_bytes));
 
     // Check that the string value of an AP is returned through a buffer that is
     // larger than necessary.
-    buf.clear();
-    buf.resize(normal_len + 1);
-    EXPECT_EQ(73970u,
+    buf = GetFPDFWideStringBuffer(normal_length_bytes + 2);
+    EXPECT_EQ(kExpectNormalAPLength,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
-                              buf.data(), buf.size()));
-    ap = BufferToString(buf);
-    EXPECT_THAT(ap, testing::StartsWith("q Q q 7.442786 w 2 J"));
-    EXPECT_THAT(ap, testing::EndsWith("c 716.5381 327.7156 l S Q Q"));
+                              buf.data(), normal_length_bytes + 2));
+    EXPECT_EQ(kMd5NormalAP,
+              GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()),
+                                normal_length_bytes));
 
     // Check that getting an AP for a mode that does not have an AP returns an
     // empty string.
-    unsigned long rollover_len = FPDFAnnot_GetAP(
+    unsigned long rollover_length_bytes = FPDFAnnot_GetAP(
         annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
-    EXPECT_EQ(2u, rollover_len);
+    ASSERT_EQ(2u, rollover_length_bytes);
 
-    buf.clear();
-    buf.resize(1000);
+    buf = GetFPDFWideStringBuffer(1000);
     EXPECT_EQ(2u,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
-                              buf.data(), buf.size()));
-    EXPECT_STREQ("", BufferToString(buf).c_str());
+                              buf.data(), 1000));
+    EXPECT_EQ(L"", GetPlatformWString(buf.data()));
 
     // Check that setting the AP for an invalid appearance mode fails.
     ScopedFPDFWideString ap_text = GetFPDFWideString(L"new test ap");
@@ -1259,25 +1254,23 @@
                                 ap_text.get()));
 
     // Check that the new annotation value is equal to the value we just set.
-    rollover_len = FPDFAnnot_GetAP(
+    rollover_length_bytes = FPDFAnnot_GetAP(
         annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
-    EXPECT_EQ(24u, rollover_len);
-    buf.clear();
-    buf.resize(rollover_len);
+    ASSERT_EQ(24u, rollover_length_bytes);
+    buf = GetFPDFWideStringBuffer(rollover_length_bytes);
     EXPECT_EQ(24u,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
-                              buf.data(), buf.size()));
-    EXPECT_STREQ(L"new test ap", BufferToWString(buf).c_str());
+                              buf.data(), rollover_length_bytes));
+    EXPECT_EQ(L"new test ap", GetPlatformWString(buf.data()));
 
     // Check that the Normal AP was not touched when the Rollover AP was set.
-    buf.clear();
-    buf.resize(normal_len);
-    EXPECT_EQ(73970u,
+    buf = GetFPDFWideStringBuffer(normal_length_bytes);
+    EXPECT_EQ(kExpectNormalAPLength,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_NORMAL,
-                              buf.data(), buf.size()));
-    ap = BufferToString(buf);
-    EXPECT_THAT(ap, testing::StartsWith("q Q q 7.442786 w 2 J"));
-    EXPECT_THAT(ap, testing::EndsWith("c 716.5381 327.7156 l S Q Q"));
+                              buf.data(), normal_length_bytes));
+    EXPECT_EQ(kMd5NormalAP,
+              GenerateMD5Base16(reinterpret_cast<uint8_t*>(buf.data()),
+                                normal_length_bytes));
   }
 
   // Save the modified document, then reopen it.
@@ -1291,14 +1284,15 @@
 
     // Check that the new annotation value is equal to the value we set before
     // saving.
-    unsigned long rollover_len = FPDFAnnot_GetAP(
+    unsigned long rollover_length_bytes = FPDFAnnot_GetAP(
         new_annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER, nullptr, 0);
-    EXPECT_EQ(24u, rollover_len);
-    std::vector<char> buf(rollover_len);
+    ASSERT_EQ(24u, rollover_length_bytes);
+    std::vector<FPDF_WCHAR> buf =
+        GetFPDFWideStringBuffer(rollover_length_bytes);
     EXPECT_EQ(24u, FPDFAnnot_GetAP(new_annot.get(),
                                    FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
-                                   buf.data(), buf.size()));
-    EXPECT_STREQ(L"new test ap", BufferToWString(buf).c_str());
+                                   buf.data(), rollover_length_bytes));
+    EXPECT_EQ(L"new test ap", GetPlatformWString(buf.data()));
   }
 
   // Close saved document.
@@ -1632,7 +1626,8 @@
 
   static const char kTestKey[] = "test";
   static const wchar_t kData[] = L"\xf6\xe4";
-  std::vector<char> buf(12);
+  static const size_t kBufSize = 12;
+  std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(kBufSize);
 
   {
     // Add a text annotation to the page.
@@ -1644,16 +1639,16 @@
     // Make sure there is no test key, add set a value there, and read it back.
     std::fill(buf.begin(), buf.end(), 'x');
     ASSERT_EQ(2u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
-                                           buf.size()));
-    EXPECT_STREQ(L"", BufferToWString(buf).c_str());
+                                           kBufSize));
+    EXPECT_EQ(L"", GetPlatformWString(buf.data()));
 
     ScopedFPDFWideString text = GetFPDFWideString(kData);
     EXPECT_TRUE(FPDFAnnot_SetStringValue(annot.get(), kTestKey, text.get()));
 
     std::fill(buf.begin(), buf.end(), 'x');
     ASSERT_EQ(6u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
-                                           buf.size()));
-    EXPECT_STREQ(kData, BufferToWString(buf).c_str());
+                                           kBufSize));
+    EXPECT_EQ(kData, GetPlatformWString(buf.data()));
   }
 
   {
@@ -1665,8 +1660,8 @@
     std::fill(buf.begin(), buf.end(), 'x');
     ASSERT_EQ(2u,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
-                              buf.data(), buf.size()));
-    EXPECT_STREQ(L"", BufferToWString(buf).c_str());
+                              buf.data(), kBufSize));
+    EXPECT_EQ(L"", GetPlatformWString(buf.data()));
 
     ScopedFPDFWideString text = GetFPDFWideString(kData);
     EXPECT_TRUE(FPDFAnnot_SetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
@@ -1675,8 +1670,8 @@
     std::fill(buf.begin(), buf.end(), 'x');
     ASSERT_EQ(6u,
               FPDFAnnot_GetAP(annot.get(), FPDF_ANNOT_APPEARANCEMODE_ROLLOVER,
-                              buf.data(), buf.size()));
-    EXPECT_STREQ(kData, BufferToWString(buf).c_str());
+                              buf.data(), kBufSize));
+    EXPECT_EQ(kData, GetPlatformWString(buf.data()));
   }
 
   UnloadPage(page);
@@ -1697,8 +1692,8 @@
 
       std::fill(buf.begin(), buf.end(), 'x');
       ASSERT_EQ(6u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
-                                             buf.size()));
-      EXPECT_STREQ(kData, BufferToWString(buf).c_str());
+                                             kBufSize));
+      EXPECT_EQ(kData, GetPlatformWString(buf.data()));
     }
 
     {
@@ -1709,8 +1704,8 @@
 
       std::fill(buf.begin(), buf.end(), 'x');
       ASSERT_EQ(6u, FPDFAnnot_GetStringValue(annot.get(), kTestKey, buf.data(),
-                                             buf.size()));
-      EXPECT_STREQ(kData, BufferToWString(buf).c_str());
+                                             kBufSize));
+      EXPECT_EQ(kData, GetPlatformWString(buf.data()));
     }
 
     CloseSavedPage(saved_page);
@@ -1798,33 +1793,33 @@
     ASSERT_TRUE(annot);
 
     int index = 0;
-    unsigned long len =
+    unsigned long length_bytes =
         FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
-    std::vector<char> buf(len);
+    ASSERT_EQ(8u, length_bytes);
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(8u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
-                                           buf.data(), len));
-    EXPECT_STREQ(L"Foo", BufferToWString(buf).c_str());
+                                           buf.data(), length_bytes));
+    EXPECT_EQ(L"Foo", GetPlatformWString(buf.data()));
 
     annot.reset(FPDFPage_GetAnnot(page, 1));
     ASSERT_TRUE(annot);
 
     index = 0;
-    len =
+    length_bytes =
         FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
-    buf.clear();
-    buf.resize(len);
+    ASSERT_EQ(12u, length_bytes);
+    buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(12u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
-                                            buf.data(), len));
-    EXPECT_STREQ(L"Apple", BufferToWString(buf).c_str());
+                                            buf.data(), length_bytes));
+    EXPECT_EQ(L"Apple", GetPlatformWString(buf.data()));
 
     index = 25;
-    len =
+    length_bytes =
         FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
-    buf.clear();
-    buf.resize(len);
+    buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(18u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
-                                            buf.data(), len));
-    EXPECT_STREQ(L"Zucchini", BufferToWString(buf).c_str());
+                                            buf.data(), length_bytes));
+    EXPECT_EQ(L"Zucchini", GetPlatformWString(buf.data()));
 
     // Indices out of range
     EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), -1,
@@ -1854,33 +1849,34 @@
     ASSERT_TRUE(annot);
 
     int index = 0;
-    unsigned long len =
+    unsigned long length_bytes =
         FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
-    std::vector<char> buf(len);
+    ASSERT_EQ(8u, length_bytes);
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(8u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
-                                           buf.data(), len));
-    EXPECT_STREQ(L"Foo", BufferToWString(buf).c_str());
+                                           buf.data(), length_bytes));
+    EXPECT_EQ(L"Foo", GetPlatformWString(buf.data()));
 
     annot.reset(FPDFPage_GetAnnot(page, 1));
     ASSERT_TRUE(annot);
 
     index = 0;
-    len =
+    length_bytes =
         FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
-    buf.clear();
-    buf.resize(len);
+    ASSERT_EQ(12u, length_bytes);
+    buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(12u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
-                                            buf.data(), len));
-    EXPECT_STREQ(L"Apple", BufferToWString(buf).c_str());
+                                            buf.data(), length_bytes));
+    EXPECT_EQ(L"Apple", GetPlatformWString(buf.data()));
 
     index = 25;
-    len =
+    length_bytes =
         FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index, nullptr, 0);
-    buf.clear();
-    buf.resize(len);
+    ASSERT_EQ(18u, length_bytes);
+    buf = GetFPDFWideStringBuffer(length_bytes);
     EXPECT_EQ(18u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), index,
-                                            buf.data(), len));
-    EXPECT_STREQ(L"Zucchini", BufferToWString(buf).c_str());
+                                            buf.data(), length_bytes));
+    EXPECT_EQ(L"Zucchini", GetPlatformWString(buf.data()));
 
     // indices out of range
     EXPECT_EQ(0u, FPDFAnnot_GetOptionLabel(form_handle(), annot.get(), -1,
diff --git a/public/fpdf_annot.h b/public/fpdf_annot.h
index 4313aae..f2622e6 100644
--- a/public/fpdf_annot.h
+++ b/public/fpdf_annot.h
@@ -422,13 +422,13 @@
 //   annot  - handle to an annotation.
 //   key    - the key to the requested dictionary entry, encoded in UTF-8.
 //   buffer - buffer for holding the value string, encoded in UTF16-LE.
-//   buflen - length of the buffer.
+//   buflen - length of the buffer in bytes.
 //
-// Returns the length of the string value.
+// Returns the length of the string value in bytes.
 FPDF_EXPORT unsigned long FPDF_CALLCONV
 FPDFAnnot_GetStringValue(FPDF_ANNOTATION annot,
                          FPDF_BYTESTRING key,
-                         void* buffer,
+                         FPDF_WCHAR* buffer,
                          unsigned long buflen);
 
 // Experimental API.
@@ -478,13 +478,13 @@
 //   appearanceMode - the appearance mode (normal, rollover or down) for which
 //                    to get the AP.
 //   buffer         - buffer for holding the value string, encoded in UTF16-LE.
-//   buflen         - length of the buffer.
+//   buflen         - length of the buffer in bytes.
 //
-// Returns the length of the string value.
+// Returns the length of the string value in bytes.
 FPDF_EXPORT unsigned long FPDF_CALLCONV
 FPDFAnnot_GetAP(FPDF_ANNOTATION annot,
                 FPDF_ANNOT_APPEARANCEMODE appearanceMode,
-                void* buffer,
+                FPDF_WCHAR* buffer,
                 unsigned long buflen);
 
 // Experimental API.
@@ -579,15 +579,16 @@
 //   annot   - handle to an annotation.
 //   index   - numeric index of the option in the "Opt" array
 //   buffer  - buffer for holding the value string, encoded in UTF16-LE.
-//   buflen  - length of the buffer.
+//   buflen  - length of the buffer in bytes.
 //
-// Returns the length of the string value or 0 if annot does not have "Opt"
-// array, index is out of range or other error.
+// Returns the length of the string value in bytes.
+// If |annot| does not have an "Opt" array, |index| is out of range or if any
+// other error occurs, returns 0.
 FPDF_EXPORT unsigned long FPDF_CALLCONV
 FPDFAnnot_GetOptionLabel(FPDF_FORMHANDLE hHandle,
                          FPDF_ANNOTATION annot,
                          int index,
-                         void* buffer,
+                         FPDF_WCHAR* buffer,
                          unsigned long buflen);
 
 #ifdef __cplusplus
diff --git a/samples/pdfium_test_write_helper.cc b/samples/pdfium_test_write_helper.cc
index fb783b9..5b3fe2d 100644
--- a/samples/pdfium_test_write_helper.cc
+++ b/samples/pdfium_test_write_helper.cc
@@ -297,20 +297,17 @@
     // Retrieve the annotation's contents and author.
     static constexpr char kContentsKey[] = "Contents";
     static constexpr char kAuthorKey[] = "T";
-    unsigned long len =
+    unsigned long length_bytes =
         FPDFAnnot_GetStringValue(annot.get(), kContentsKey, nullptr, 0);
-    std::vector<char> buf(len);
-    FPDFAnnot_GetStringValue(annot.get(), kContentsKey, buf.data(), len);
-    fprintf(fp, "Content: %ls\n",
-            GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
-                .c_str());
-    len = FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, nullptr, 0);
-    buf.clear();
-    buf.resize(len);
-    FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, buf.data(), len);
-    fprintf(fp, "Author: %ls\n",
-            GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
-                .c_str());
+    std::vector<FPDF_WCHAR> buf = GetFPDFWideStringBuffer(length_bytes);
+    FPDFAnnot_GetStringValue(annot.get(), kContentsKey, buf.data(),
+                             length_bytes);
+    fprintf(fp, "Content: %ls\n", GetPlatformWString(buf.data()).c_str());
+    length_bytes =
+        FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, nullptr, 0);
+    buf = GetFPDFWideStringBuffer(length_bytes);
+    FPDFAnnot_GetStringValue(annot.get(), kAuthorKey, buf.data(), length_bytes);
+    fprintf(fp, "Author: %ls\n", GetPlatformWString(buf.data()).c_str());
 
     // Retrieve the annotation's quadpoints if it is a markup annotation.
     if (FPDFAnnot_HasAttachmentPoints(annot.get())) {
diff --git a/testing/fx_string_testhelpers.cpp b/testing/fx_string_testhelpers.cpp
index 8087e12..17d90cc 100644
--- a/testing/fx_string_testhelpers.cpp
+++ b/testing/fx_string_testhelpers.cpp
@@ -70,3 +70,8 @@
   result_span[i] = 0;
   return result;
 }
+
+std::vector<FPDF_WCHAR> GetFPDFWideStringBuffer(size_t length_bytes) {
+  ASSERT(length_bytes % sizeof(FPDF_WCHAR) == 0);
+  return std::vector<FPDF_WCHAR>(length_bytes / sizeof(FPDF_WCHAR));
+}
diff --git a/testing/fx_string_testhelpers.h b/testing/fx_string_testhelpers.h
index 67ba836..b90838a 100644
--- a/testing/fx_string_testhelpers.h
+++ b/testing/fx_string_testhelpers.h
@@ -33,4 +33,8 @@
 // Deals with differences between UTF16LE and wchar_t.
 ScopedFPDFWideString GetFPDFWideString(const std::wstring& wstr);
 
+// Returns a FPDF_WCHAR vector of |length_bytes| bytes. |length_bytes| must be a
+// multiple of sizeof(FPDF_WCHAR).
+std::vector<FPDF_WCHAR> GetFPDFWideStringBuffer(size_t length_bytes);
+
 #endif  // TESTING_FX_STRING_TESTHELPERS_H_