[gjs] Allow passing a JS string as a C array of int8/uint8/int16/uint16.



commit c01ad5f14e878179592712fb2f0b5360bff63790
Author: C. Scott Ananian <cscott litl com>
Date:   Tue Apr 28 17:07:34 2009 -0400

    Allow passing a JS string as a C array of int8/uint8/int16/uint16.
    
    We can now pass values into C functions which take arrays of small integers
    using the standard "one value per character" encoding of buffers as JavaScript
    strings.  This is primarily useful for methods which take binary buffers
    as gint8* or uint8* (instead of char *).
    
    Test cases against the 'Everything' module show how this works.
---
 gi/arg.c                       |   53 ++++++++++++++++++++++++++++++++++++++++
 gjs/jsapi-util-string.c        |   34 +++++++++++++++++++++++++
 gjs/jsapi-util.h               |    4 +++
 test/js/testEverythingBasic.js |    5 ++++
 4 files changed, 96 insertions(+), 0 deletions(-)

diff --git a/gi/arg.c b/gi/arg.c
index 2d492f7..74a98eb 100644
--- a/gi/arg.c
+++ b/gi/arg.c
@@ -240,6 +240,43 @@ gjs_array_to_strv(JSContext   *context,
 }
 
 static JSBool
+gjs_string_to_intarray(JSContext   *context,
+                       jsval        string_val,
+                       GITypeInfo  *param_info,
+                       void       **arr_p)
+{
+    GITypeTag element_type;
+    char *result;
+    guint16 *result16;
+    gsize length;
+
+    element_type = g_type_info_get_tag(param_info);
+    element_type = normalize_int_types(element_type);
+
+    switch (element_type) {
+    case GI_TYPE_TAG_INT8:
+    case GI_TYPE_TAG_UINT8:
+        if (!gjs_string_get_binary_data(context, string_val,
+                                        &result, &length))
+            return JS_FALSE;
+        *arr_p = result;
+        return JS_TRUE;
+
+    case GI_TYPE_TAG_INT16:
+    case GI_TYPE_TAG_UINT16:
+        if (!gjs_string_get_uint16_data(context, string_val,
+                                        &result16, &length))
+            return JS_FALSE;
+        *arr_p = result16;
+        return JS_TRUE;
+
+    default:
+        // can't convert a string to this type.
+        return JS_FALSE;
+    }
+}
+
+static JSBool
 gjs_array_to_intarray(JSContext   *context,
                       jsval        array_value,
                       unsigned int length,
@@ -738,6 +775,22 @@ gjs_value_to_g_argument(JSContext      *context,
     case GI_TYPE_TAG_ARRAY:
         if (JSVAL_IS_NULL(value)) {
             arg->v_pointer = NULL;
+            if (!may_be_null) {
+                wrong = TRUE;
+                report_type_mismatch = TRUE;
+            }
+        } else if (JSVAL_IS_STRING(value)) {
+            /* Allow strings as int8/uint8/int16/uint16 arrays */
+            GITypeInfo *param_info;
+
+            param_info = g_type_info_get_param_type(type_info, 0);
+            g_assert(param_info != NULL);
+
+            if (!gjs_string_to_intarray(context, value, param_info,
+                                        &arg->v_pointer))
+                wrong = TRUE;
+
+            g_base_info_unref((GIBaseInfo*) param_info);
         } else if (!JSVAL_IS_OBJECT(value)) {
             wrong = TRUE;
             report_type_mismatch = TRUE;
diff --git a/gjs/jsapi-util-string.c b/gjs/jsapi-util-string.c
index bad5f32..f12b587 100644
--- a/gjs/jsapi-util-string.c
+++ b/gjs/jsapi-util-string.c
@@ -329,6 +329,40 @@ gjs_string_from_binary_data(JSContext       *context,
 }
 
 /**
+ * gjs_string_get_uint16_data:
+ * @context: js context
+ * @value: a jsval
+ * @data_p: address to return allocated data buffer
+ * @len_p: address to return length of data (number of 16-bit integers)
+ *
+ * Get the binary data (as a sequence of 16-bit integers) in the JSString
+ * contained in @value.
+ * Throws a JS exception if value is not a string.
+ *
+ * Returns: JS_FALSE if exception thrown
+ **/
+JSBool
+gjs_string_get_uint16_data(JSContext       *context,
+                           jsval            value,
+                           guint16        **data_p,
+                           gsize           *len_p)
+{
+    jschar *js_data;
+
+    if (!JSVAL_IS_STRING(value)) {
+        gjs_throw(context,
+                  "Value is not a string, can't return binary data from it");
+        return JS_FALSE;
+    }
+
+    js_data = JS_GetStringChars(JSVAL_TO_STRING(value));
+    *len_p = JS_GetStringLength(JSVAL_TO_STRING(value));
+    *data_p = g_memdup(js_data, sizeof(*js_data)*(*len_p));
+
+    return JS_TRUE;
+}
+
+/**
  * gjs_get_string_id:
  * @id_val: a jsval that is an object hash key (could be an int or string)
  * @name_p place to store ASCII string version of key
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 2f12a75..27f09ba 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -221,6 +221,10 @@ JSBool      gjs_string_from_binary_data      (JSContext       *context,
                                               const char      *data,
                                               gsize            len,
                                               jsval           *value_p);
+JSBool      gjs_string_get_uint16_data       (JSContext       *context,
+                                              jsval            value,
+                                              guint16        **data_p,
+                                              gsize           *len_p);
 JSBool      gjs_get_string_id                (jsval            id_val,
                                               const char     **name_p);
 const char* gjs_get_type_name                (jsval            value);
diff --git a/test/js/testEverythingBasic.js b/test/js/testEverythingBasic.js
index e994fe6..5f69b2f 100644
--- a/test/js/testEverythingBasic.js
+++ b/test/js/testEverythingBasic.js
@@ -216,6 +216,11 @@ function testArrayIn() {
     assertEquals(10, Everything.test_array_gint32_in(4, [1,2,3,4]));
     // FIXME: arrays of int64 are unimplemented
     //assertEquals(10, Everything.test_array_gint64_in(4, [1,2,3,4]));
+
+    // implicit conversions from strings to int arrays
+    assertEquals(10, Everything.test_array_gint8_in(4, "\x01\x02\x03\x04"));
+    assertEquals(10, Everything.test_array_gint16_in(4, "\x01\x02\x03\x04"));
+    assertEquals(2560, Everything.test_array_gint16_in(4, "\u0100\u0200\u0300\u0400"));
 }
 
 function testArrayOut() {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]