Repository: qpdf/qpdf
Pull request #628 (2022-02-04 17:20:07)

C-API add two binary UTF8 funtions
add qpdf_oh_new_binary_unicode_string and qpdf_oh_get_binary_utf8_value


Patch:
diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h
index b62f2e09..bd2fb0d5 100644
--- a/include/qpdf/qpdf-c.h
+++ b/include/qpdf/qpdf-c.h
@@ -742,6 +742,9 @@ extern "C" {
     QPDF_DLL
     char const* qpdf_oh_get_binary_string_value(
         qpdf_data qpdf, qpdf_oh oh, size_t* length);
+    QPDF_DLL
+    char const* qpdf_oh_get_binary_utf8_value(
+        qpdf_data qpdf, qpdf_oh oh, size_t* length);
 
     QPDF_DLL
     int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh);
@@ -800,6 +803,9 @@ extern "C" {
     QPDF_DLL
     qpdf_oh qpdf_oh_new_binary_string(
         qpdf_data qpdf, char const* str, size_t length);
+     QPDF_DLL
+    qpdf_oh qpdf_oh_new_binary_unicode_string(
+        qpdf_data qpdf, char const* str, size_t length);
     QPDF_DLL
     qpdf_oh qpdf_oh_new_array(qpdf_data qpdf);
     QPDF_DLL
diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc
index c7300cae..596ce4f7 100644
--- a/libqpdf/qpdf-c.cc
+++ b/libqpdf/qpdf-c.cc
@@ -1327,6 +1327,20 @@ char const* qpdf_oh_get_binary_string_value(
         });
 }
 
+char const* qpdf_oh_get_binary_utf8_value(
+    qpdf_data qpdf, qpdf_oh oh, size_t* length)
+{
+    return do_with_oh<char const*>(
+        qpdf, oh,
+        return_T<char const*>(""),
+        [qpdf, length](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_binary_utf8_value");
+            qpdf->tmp_string = o.getUTF8Value();
+            *length = qpdf->tmp_string.length();
+            return qpdf->tmp_string.c_str();
+        });
+}
+
 int qpdf_oh_get_array_n_items(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<int>(
@@ -1468,6 +1482,14 @@ qpdf_oh qpdf_oh_new_binary_string(
         qpdf, QPDFObjectHandle::newString(std::string(str, length)));
 }
 
+qpdf_oh qpdf_oh_new_binary_unicode_string(
+    qpdf_data qpdf, char const* utf8_str, size_t length)
+{
+    QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_binary_unicode_string");
+    return new_object(
+        qpdf, QPDFObjectHandle::newUnicodeString(std::string(utf8_str, length)));
+}
+
 qpdf_oh qpdf_oh_new_array(qpdf_data qpdf)
 {
     QTC::TC("qpdf", "qpdf-c called qpdf_oh_new_array");


Test patch:
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c
index e9a7f1a8..414c0eaa 100644
--- a/qpdf/qpdf-ctest.c
+++ b/qpdf/qpdf-ctest.c
@@ -740,10 +740,13 @@ static void test25(char const* infile,
     qpdf_oh_append_item(
         qpdf, new_array,
         qpdf_oh_new_unicode_string(qpdf, "qww\xc3\xb7\xcf\x80"));
+    qpdf_oh_append_item(
+        qpdf, new_array,
+        qpdf_oh_new_binary_unicode_string(qpdf, "qw\x00w\xc3\xb7\xcf\x80", 8));
     qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 2 */
     qpdf_oh_append_item(qpdf, new_array, qpdf_oh_new_null(qpdf)); /* 3 */
     qpdf_oh_set_array_item(
-        qpdf, new_array, 2,
+        qpdf, new_array, 3,
         qpdf_oh_new_name(qpdf, "/Quack"));
     qpdf_oh_append_item(
         qpdf, new_array,
@@ -803,6 +806,24 @@ static void test27(char const* infile,
                   "potato\000salad", 13) == 0);
     assert(qpdf_get_last_string_length(qpdf) == 12);
     assert(length == 12);
+    /* repeat for UTF8 string */
+    qpdf_oh p_utf8_string_with_null = qpdf_oh_parse(qpdf, 
+                                          "<feff007100770000007700f703c0>");
+    assert(qpdf_oh_is_string(qpdf, p_utf8_string_with_null));
+    assert(strcmp(qpdf_oh_get_utf8_value(qpdf, p_utf8_string_with_null),
+                  "qw\x00w\xc3\xb7\xcf\x80") == 0);
+    assert(qpdf_get_last_string_length(qpdf) == 8);
+    /* memcmp adds a character to verify the trailing null */
+    assert(memcmp(qpdf_oh_get_utf8_value(qpdf, p_utf8_string_with_null),
+                  "qw\x00w\xc3\xb7\xcf\x80", 8) == 0);
+    p_utf8_string_with_null = qpdf_oh_new_binary_unicode_string(
+                                  qpdf, "qw\x00w\xc3\xb7\xcf\x80", 8);
+    /* memcmp adds a character to verify the trailing null */
+    assert(memcmp(qpdf_oh_get_binary_utf8_value(
+                      qpdf, p_utf8_string_with_null, &length),
+                  "qw\x00w\xc3\xb7\xcf\x80", 9) == 0);
+    assert(qpdf_get_last_string_length(qpdf) == 8);
+    assert(length == 8);
 }
 
 static void test28(char const* infile,
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index 28af71cb..1e0f336e 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -620,7 +620,9 @@ qpdf-c called qpdf_oh_get_page_content_data 0
 qpdf-c called qpdf_oh_replace_stream_data 0
 qpdf-c silence oh errors 0
 qpdf-c called qpdf_oh_get_binary_string_value 0
+qpdf-c called qpdf_oh_get_binary_utf8_value 0
 qpdf-c called qpdf_oh_new_binary_string 0
+qpdf-c called qpdf_oh_new_binary_unicode_string 0
 QPDFJob duplicated pages password 0
 QPDFJob misplaced pages password 0
 QPDFJob check encrypted encrypted 0
diff --git a/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf b/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf
index 729feb0d..a3ec67b8 100644
--- a/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf
+++ b/qpdf/qtest/qpdf/c-object-handle-creation-out.pdf
@@ -9,6 +9,7 @@
     /B [
       (potato)
       <feff00710077007700f703c0>
+      <feff007100770000007700f703c0>
       /Quack
       null
       4.12
@@ -95,17 +96,17 @@ xref
 0 8
 0000000000 65535 f 
 0000000025 00000 n 
-0000000277 00000 n 
-0000000359 00000 n 
-0000000574 00000 n 
-0000000673 00000 n 
-0000000692 00000 n 
-0000000810 00000 n 
+0000000314 00000 n 
+0000000396 00000 n 
+0000000611 00000 n 
+0000000710 00000 n 
+0000000729 00000 n 
+0000000847 00000 n 
 trailer <<
   /Root 1 0 R
   /Size 8
   /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
 >>
 startxref
-845
+882
 %%EOF