Repository: qpdf/qpdf
Pull request #630 (2022-02-05 20:28:28)

C-API expose QPDFObjectHandle::getValueAs... accessors

m-holger: Sorry for the first attempt.
jberkenbilt: > Sorry for the first attempt.

No problem. You've certainly seen enough of my slips. :-)

Patch:
diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h
index 982f0c90..c4e88de8 100644
--- a/include/qpdf/qpdf-c.h
+++ b/include/qpdf/qpdf-c.h
@@ -707,26 +707,50 @@ extern "C" {
 
     QPDF_DLL
     QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh);
+    QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_bool(
+        qpdf_data qpdf, qpdf_oh oh, QPDF_BOOL* value);
 
     QPDF_DLL
     long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh);
     QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_longlong(
+        qpdf_data qpdf, qpdf_oh oh, long long* value);
+    QPDF_DLL
     int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh);
     QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_int(
+        qpdf_data qpdf, qpdf_oh oh, int* value);
+    QPDF_DLL
     unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh);
     QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_ulonglong(
+        qpdf_data qpdf, qpdf_oh oh, unsigned long long* value);
+    QPDF_DLL
     unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh);
+    QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_uint(
+        qpdf_data qpdf, qpdf_oh oh, unsigned int* value);
 
     QPDF_DLL
     char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh);
+    QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_real(
+        qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
 
     QPDF_DLL
     QPDF_BOOL qpdf_oh_is_number(qpdf_data qpdf, qpdf_oh oh);
     QPDF_DLL
     double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh);
+    QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_number(
+        qpdf_data qpdf, qpdf_oh oh, double* value);
 
     QPDF_DLL
     char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh);
+    QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_name(
+        qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
 
     /* Return the length of the last string returned. This enables you
      * to retrieve the entire string for cases in which a char*
@@ -747,8 +771,14 @@ extern "C" {
     QPDF_DLL
     char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh);
     QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_string(
+        qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
+    QPDF_DLL
     char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh);
     QPDF_DLL
+    QPDF_BOOL qpdf_oh_get_value_as_utf8(
+        qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length);
+    QPDF_DLL
     char const* qpdf_oh_get_binary_string_value(
         qpdf_data qpdf, qpdf_oh oh, size_t* length);
     QPDF_DLL
diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc
index 8ca8fb42..ac728e8b 100644
--- a/libqpdf/qpdf-c.cc
+++ b/libqpdf/qpdf-c.cc
@@ -1238,6 +1238,22 @@ QPDF_BOOL qpdf_oh_get_bool_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_bool(
+    qpdf_data qpdf, qpdf_oh oh, QPDF_BOOL* value)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [value](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_bool");
+            bool v = *value;
+            QPDF_BOOL result = o.getValueAsBool(v);
+            if (result)
+            {
+                *value = v;
+            }
+            return result;
+        });
+}
+
 long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<long long>(
@@ -1247,6 +1263,16 @@ long long qpdf_oh_get_int_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_longlong(
+    qpdf_data qpdf, qpdf_oh oh, long long* value)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [value](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_longlong");
+            return o.getValueAsInt(*value);
+        });
+}
+
 int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<int>(
@@ -1256,6 +1282,16 @@ int qpdf_oh_get_int_value_as_int(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_int(
+    qpdf_data qpdf, qpdf_oh oh, int* value)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [value](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_int");
+            return o.getValueAsInt(*value);
+        });
+}
+
 unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<unsigned long long>(
@@ -1265,6 +1301,16 @@ unsigned long long qpdf_oh_get_uint_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_ulonglong(
+    qpdf_data qpdf, qpdf_oh oh, unsigned long long* value)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [value](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_ulonglong");
+            return o.getValueAsUInt(*value);
+        });
+}
+
 unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<unsigned int>(
@@ -1274,6 +1320,16 @@ unsigned int qpdf_oh_get_uint_value_as_uint(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_uint(
+    qpdf_data qpdf, qpdf_oh oh, unsigned int* value)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [value](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_uint");
+            return o.getValueAsUInt(*value);
+        });
+}
+
 char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<char const*>(
@@ -1284,6 +1340,22 @@ char const* qpdf_oh_get_real_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_real(
+    qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [qpdf, value, length](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_real");
+            auto result = o.getValueAsReal(qpdf->tmp_string);
+            if (result)
+            {
+                *value = qpdf->tmp_string.c_str();
+                *length = qpdf->tmp_string.length();
+            }
+            return result;
+        });
+}
+
 double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<double>(
@@ -1293,6 +1365,16 @@ double qpdf_oh_get_numeric_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_number(
+    qpdf_data qpdf, qpdf_oh oh, double* value)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [value](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_number");
+            return o.getValueAsNumber(*value);
+        });
+}
+
 char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<char const*>(
@@ -1303,6 +1385,22 @@ char const* qpdf_oh_get_name(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_name(
+    qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [qpdf, value, length](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_name");
+            auto result = o.getValueAsName(qpdf->tmp_string);
+            if (result)
+            {
+                *value = qpdf->tmp_string.c_str();
+                *length = qpdf->tmp_string.length();
+            }
+            return result;
+        });
+}
+
 char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<char const*>(
@@ -1313,6 +1411,22 @@ char const* qpdf_oh_get_string_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_string(
+    qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [qpdf, value, length](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_string");
+            auto result = o.getValueAsString(qpdf->tmp_string);
+            if (result)
+            {
+                *value = qpdf->tmp_string.c_str();
+                *length = qpdf->tmp_string.length();
+            }
+            return result;
+        });
+}
+
 char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh)
 {
     return do_with_oh<char const*>(
@@ -1323,6 +1437,22 @@ char const* qpdf_oh_get_utf8_value(qpdf_data qpdf, qpdf_oh oh)
         });
 }
 
+QPDF_BOOL qpdf_oh_get_value_as_utf8(
+    qpdf_data qpdf, qpdf_oh oh, char const** value, size_t* length)
+{
+    return do_with_oh<QPDF_BOOL>(
+        qpdf, oh, return_false, [qpdf, value, length](QPDFObjectHandle& o) {
+            QTC::TC("qpdf", "qpdf-c called qpdf_oh_get_value_as_utf8");
+            auto result = o.getValueAsUTF8(qpdf->tmp_string);
+            if (result)
+            {
+                *value = qpdf->tmp_string.c_str();
+                *length = qpdf->tmp_string.length();
+            }
+            return result;
+        });
+}
+
 char const* qpdf_oh_get_binary_string_value(
     qpdf_data qpdf, qpdf_oh oh, size_t* length)
 {


Test patch:
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c
index 502cede9..7738bdf6 100644
--- a/qpdf/qpdf-ctest.c
+++ b/qpdf/qpdf-ctest.c
@@ -673,26 +673,78 @@ static void test25(char const* infile,
 
     /* Parse objects from a string */
     qpdf_oh parsed = qpdf_oh_parse(
-        qpdf, "[ 1 2.0 (3\xf7) << /Four [/Five] >> null true ]");
+        qpdf, "[ 1 2.0 (3\xf7) << /Four [/Five] >> null true false /Six]");
     qpdf_oh p_int = qpdf_oh_get_array_item(qpdf, parsed, 0);
     qpdf_oh p_real = qpdf_oh_get_array_item(qpdf, parsed, 1);
     qpdf_oh p_string = qpdf_oh_get_array_item(qpdf, parsed, 2);
     qpdf_oh p_dict = qpdf_oh_get_array_item(qpdf, parsed, 3);
     qpdf_oh p_null = qpdf_oh_get_array_item(qpdf, parsed, 4);
     qpdf_oh p_bool = qpdf_oh_get_array_item(qpdf, parsed, 5);
+    qpdf_oh p_bool_f = qpdf_oh_get_array_item(qpdf, parsed, 6);
+    qpdf_oh p_name = qpdf_oh_get_array_item(qpdf, parsed, 7);
     assert(qpdf_oh_is_integer(qpdf, p_int) &&
            qpdf_oh_get_int_value_as_int(qpdf, p_int) == 1);
+    long long l = 0;
+    assert(qpdf_oh_get_value_as_longlong(qpdf, p_bool, &l) == QPDF_FALSE);
+    assert((qpdf_oh_get_value_as_longlong(qpdf, p_int, &l) == QPDF_TRUE) &&
+            (l == 1));
+    int i = 0;
+    assert(qpdf_oh_get_value_as_int(qpdf, p_bool, &i) == QPDF_FALSE);
+    assert((qpdf_oh_get_value_as_int(qpdf, p_int, &i) == QPDF_TRUE) &&
+            (i == 1));
+    unsigned long long ul = 0u;
+    assert(qpdf_oh_get_value_as_ulonglong(qpdf, p_bool, &ul) == QPDF_FALSE);
+    assert((qpdf_oh_get_value_as_ulonglong(qpdf, p_int, &ul) == QPDF_TRUE) &&
+            (ul == 1u));
+    unsigned int u = 0u;
+    assert(qpdf_oh_get_value_as_uint(qpdf, p_bool, &u) == QPDF_FALSE);
+    assert((qpdf_oh_get_value_as_uint(qpdf, p_int, &u) == QPDF_TRUE) &&
+            (u == 1u));
+    double d = 0.0;
+    assert(qpdf_oh_get_value_as_number(qpdf, p_bool, &d) == QPDF_FALSE);
+    assert((qpdf_oh_get_value_as_number(qpdf, p_int, &d) == QPDF_TRUE) &&
+            (((d - 1.0) * (d - 1.0)) < 1e-100));
     assert(qpdf_oh_get_type_code(qpdf, p_int) == ot_integer);
     assert(strcmp(qpdf_oh_get_type_name(qpdf, p_int), "integer") == 0);
     assert(qpdf_oh_is_real(qpdf, p_real) &&
            (strcmp(qpdf_oh_get_real_value(qpdf, p_real), "2.0") == 0) &&
            qpdf_oh_get_numeric_value(qpdf, p_real) == 2.0);
+    const char* r = "";
+    size_t length = 0;
+    assert((qpdf_oh_get_value_as_real(qpdf, p_name, &r, &length) ==
+                                      QPDF_FALSE) &&
+            (strcmp(r, "") == 0) &&
+            (length == 0));
+    assert((qpdf_oh_get_value_as_real(qpdf, p_real, &r, &length) ==
+                                      QPDF_TRUE) &&
+            (strcmp(r, "2.0") == 0) &&
+            (length == 3));
     assert(qpdf_oh_get_type_code(qpdf, p_real) == ot_real);
     assert(strcmp(qpdf_oh_get_type_name(qpdf, p_real), "real") == 0);
     assert(qpdf_oh_is_string(qpdf, p_string) &&
            (strcmp(qpdf_oh_get_string_value(qpdf, p_string), "3\xf7") == 0) &&
            (strcmp(qpdf_oh_get_utf8_value(qpdf, p_string), "3\xc3\xb7") == 0) &&
            (strcmp(qpdf_oh_unparse_binary(qpdf, p_string), "<33f7>") == 0));
+    const char* str = "";
+    length = 0;
+    assert((qpdf_oh_get_value_as_string(qpdf, p_name, &str, &length) ==
+                                        QPDF_FALSE) &&
+            (strcmp(str, "") == 0) &&
+            (length == 0));
+    assert((qpdf_oh_get_value_as_string(qpdf, p_string, &str, &length) ==
+                                        QPDF_TRUE) &&
+            (strcmp(str, "3\xf7") == 0) &&
+            (length == 2));
+    const char* utf8 = "";
+    length = 0;
+    assert((qpdf_oh_get_value_as_utf8(qpdf, p_name, &utf8, &length) ==
+                                      QPDF_FALSE) &&
+            (strcmp(utf8, "") == 0) &&
+            (length == 0));
+    assert((qpdf_oh_get_value_as_utf8(qpdf, p_string, &utf8, &length) ==
+                                      QPDF_TRUE) &&
+            (strcmp(utf8, "3\xc3\xb7") == 0) &&
+            (length == 3));
     assert(qpdf_oh_get_type_code(qpdf, p_string) == ot_string);
     assert(! qpdf_oh_is_name_and_equals(qpdf, p_string, "3\xf7"));
     assert(strcmp(qpdf_oh_get_type_name(qpdf, p_string), "string") == 0);
@@ -709,8 +761,25 @@ static void test25(char const* infile,
     assert(strcmp(qpdf_oh_get_type_name(qpdf, p_null), "null") == 0);
     assert(qpdf_oh_is_bool(qpdf, p_bool) &&
            (qpdf_oh_get_bool_value(qpdf, p_bool) == QPDF_TRUE));
+    QPDF_BOOL b = QPDF_FALSE;
+    assert((qpdf_oh_get_value_as_bool(qpdf, p_int, &b) == QPDF_FALSE) &&
+            b == QPDF_FALSE);
+    assert((qpdf_oh_get_value_as_bool(qpdf, p_bool, &b) == QPDF_TRUE) &&
+            b == QPDF_TRUE);
+    assert((qpdf_oh_get_value_as_bool(qpdf, p_bool_f, &b) == QPDF_TRUE) &&
+            b == QPDF_FALSE);
     assert(qpdf_oh_get_type_code(qpdf, p_bool) == ot_boolean);
     assert(strcmp(qpdf_oh_get_type_name(qpdf, p_bool), "boolean") == 0);
+    const char* n = "";
+    length = 0;
+    assert((qpdf_oh_get_value_as_name(qpdf, p_string, &n, &length) ==
+                                      QPDF_FALSE) &&
+            (strcmp(n, "") == 0) &&
+            (length == 0));
+    assert((qpdf_oh_get_value_as_name(qpdf, p_name, &n, &length) ==
+                                      QPDF_TRUE) &&
+            (strcmp(n, "/Six") == 0) &&
+            (length == 4));
     qpdf_oh_erase_item(qpdf, parsed, 4);
     qpdf_oh_insert_item(
         qpdf, parsed, 2,
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index 77ef2fc9..5e87b831 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -477,16 +477,26 @@ qpdf-c array to wrap_in_array 0
 qpdf-c non-array to wrap_in_array 0
 qpdf-c called qpdf_oh_parse 0
 qpdf-c called qpdf_oh_get_bool_value 0
+qpdf-c called qpdf_oh_get_value_as_bool 0
 qpdf-c called qpdf_oh_get_int_value 0
+qpdf-c called qpdf_oh_get_value_as_longlong 0
 qpdf-c called qpdf_oh_get_int_value_as_int 0
+qpdf-c called qpdf_oh_get_value_as_int 0
 qpdf-c called qpdf_oh_get_uint_value 0
+qpdf-c called qpdf_oh_get_value_as_ulonglong 0
 qpdf-c called qpdf_oh_get_uint_value_as_uint 0
+qpdf-c called qpdf_oh_get_value_as_uint 0
 qpdf-c called qpdf_oh_get_real_value 0
+qpdf-c called qpdf_oh_get_value_as_real 0
 qpdf-c called qpdf_oh_is_number 0
+qpdf-c called qpdf_oh_get_value_as_number 0
 qpdf-c called qpdf_oh_get_numeric_value 0
 qpdf-c called qpdf_oh_get_name 0
+qpdf-c called qpdf_oh_get_value_as_name 0
 qpdf-c called qpdf_oh_get_string_value 0
+qpdf-c called qpdf_oh_get_value_as_string 0
 qpdf-c called qpdf_oh_get_utf8_value 0
+qpdf-c called qpdf_oh_get_value_as_utf8 0
 qpdf-c called qpdf_oh_get_array_n_items 0
 qpdf-c called qpdf_oh_get_array_item 0
 qpdf-c called qpdf_oh_begin_dict_key_iter 0