[gjs] GVariant: add JS wrappers for packing and unpacking



commit 522b15e116e93a997d6b2188e21836f192c39b9f
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Tue Apr 5 18:37:23 2011 +0200

    GVariant: add JS wrappers for packing and unpacking
    
    Using JS overrides, adds glue code that packs and unpacks GVariants
    into JS objects (hash maps, arrays and primitive types)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=622344

 Makefile-modules.am       |    1 +
 modules/overrides/GLib.js |  261 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+), 0 deletions(-)
---
diff --git a/Makefile-modules.am b/Makefile-modules.am
index fb1864d..45c7d9d 100644
--- a/Makefile-modules.am
+++ b/Makefile-modules.am
@@ -4,6 +4,7 @@ dist_gjstweener_DATA =			\
 	modules/tweener/tweenList.js
 
 dist_gjsoverride_DATA = 		\
+	modules/overrides/GLib.js	\
 	modules/overrides/Gio.js
 
 dist_gjsjs_DATA +=		\
diff --git a/modules/overrides/GLib.js b/modules/overrides/GLib.js
new file mode 100644
index 0000000..41d2b60
--- /dev/null
+++ b/modules/overrides/GLib.js
@@ -0,0 +1,261 @@
+// application/javascript;version=1.8
+// Copyright 2011 Giovanni Campagna
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+let GLib;
+let originalVariantClass;
+
+const SIMPLE_TYPES = ['b', 'y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd', 's', 'o', 'g'];
+
+function _read_single_type(signature, forceSimple) {
+    let char = signature.shift();
+    let isSimple = false;
+
+    if (SIMPLE_TYPES.indexOf(char) == -1) {
+	if (forceSimple)
+	    throw new TypeError('Invalid GVariant signature (a simple type was expected)');
+    } else
+	isSimple = true;
+
+    if (char == 'm' || char == 'a')
+	return [char].concat(_read_single_type(signature, false));
+    if (char == '{') {
+	let key = _read_single_type(signature, true);
+	let val = _read_single_type(signature, false);
+	let close = signature.shift();
+	if (close != '}')
+	    throw new TypeError('Invalid GVariant signature for type DICT_ENTRY (expected "}"');
+	return [char].concat(key, val, close);
+    }
+    if (char == '(') {
+	let res = [char];
+	while (true) {
+	    if (signature.length == 0)
+		throw new TypeError('Invalid GVariant signature for type TUPLE (expected ")")');
+	    let next = signature[0];
+	    if (next == ')') {
+		signature.shift();
+		return res.concat(next);
+	    }
+	    let el = _read_single_type(signature);
+	    res = res.concat(el);
+	}
+    }
+
+    // Valid types are simple types, arrays, maybes, tuples, dictionary entries and variants
+    if (!isSimple && char != 'v')
+	throw new TypeError('Invalid GVariant signature (' + char + ' is not a valid type)');
+
+    return [char];
+}
+
+
+function _pack_variant(signature, value) {
+    if (signature.length == 0)
+	    throw new TypeError('GVariant signature cannot be empty');
+
+    let char = signature.shift();
+    switch (char) {
+    case 'b':
+	return GLib.Variant.new_boolean(value);
+    case 'y':
+	return GLib.Variant.new_byte(value);
+    case 'n':
+	return GLib.Variant.new_int16(value);
+    case 'q':
+	return GLib.Variant.new_uint16(value);
+    case 'i':
+	return GLib.Variant.new_int32(value);
+    case 'u':
+	return GLib.Variant.new_uint32(value);
+    case 'x':
+	return GLib.Variant.new_int64(value);
+    case 't':
+	return GLib.Variant.new_uint64(value);
+    case 'h':
+	return GLib.Variant.new_handle(value);
+    case 'd':
+	return GLib.Variant.new_double(value);
+    case 's':
+	return GLib.Variant.new_string(value);
+    case 'o':
+	return GLib.Variant.new_object_path(value);
+    case 'g':
+	return GLib.Variant.new_signature(value);
+    case 'v':
+	return GLib.Variant.new_variant(value);
+    case 'm':
+	if (value != null)
+	    return GLib.Variant.new_maybe(null, _pack_variant(signature, value))
+	else
+	    return GLib.Variant.new_maybe(GLib.VariantType.new(_read_single_type(signature, false).join('')), null);
+    case 'a':
+	let arrayType = _read_single_type(signature, false);
+	if (arrayType[0] == 's') {
+	    // special case for array of strings
+	    return GLib.Variant.new_strv(value, value.length);
+	}
+	if (arrayType[0] == 'y') {
+	    // special case for array of bytes
+	    return GLib.Variant.new_bytestring(value);
+	}
+	if (arrayType[0] == 'a' && arrayType[1] == 'y') {
+	    // special case for array of array of bytes
+	    return GLib.Variant.new_bytestring_array(value, value.length);
+	}
+
+	let arrayValue = [];
+	if (arrayType[0] == '{') {
+	    // special case for dictionaries
+	    for (let key in value) {
+		let copy = [].concat(arrayType);
+		let child = _pack_variant(copy, [key, value[key]]);
+		arrayValue.push(child);
+	    }
+	} else {
+	    for (let i = 0; i < value.length; i++) {
+		let copy = [].concat(arrayType);
+		let child = _pack_variant(copy, value[i]);
+		arrayValue.push(child);
+	    }
+	}
+	return GLib.Variant.new_array(GLib.VariantType.new(arrayType.join('')), arrayValue, arrayValue.length);
+    case '(':
+	let children = [ ];
+	for (let i = 0; i < value.length; i++) {
+	    let next = signature[0];
+	    if (next == ')')
+		break;
+	    children.push(_pack_variant(signature, value[i]));
+	}
+
+	if (signature[0] != ')')
+	    throw new TypeError('Invalid GVariant signature for type TUPLE (expected ")")');
+	signature.shift();
+	return GLib.Variant.new_tuple(children, children.length);
+    case '{':
+	let key = _pack_variant(signature, value[0]);
+	let child = _pack_variant(signature, value[1]);
+
+	if (signature[0] != '}')
+	    throw new TypeError('Invalid GVariant signature for type DICT_ENTRY (expected "}")');
+	signature.shift();
+
+	return GLib.Variant.new_dict_entry(key, child);
+    default:
+	throw new TypeError('Invalid GVariant signature (unexpected character ' + char + ')');
+    }
+}
+
+function _unpack_variant(variant, deep) {
+    switch (String.fromCharCode(variant.classify())) {
+    case 'b':
+	return variant.get_boolean();
+    case 'y':
+	return variant.get_byte();
+    case 'n':
+	return variant.get_int16();
+    case 'q':
+	return variant.get_uint16();
+    case 'i':
+	return variant.get_int32();
+    case 'u':
+	return variant.get_uint32();
+    case 'x':
+	return variant.get_int64();
+    case 't':
+	return variant.get_uint64();
+    case 'h':
+	return variant.get_handle();
+    case 'd':
+	return variant.get_double();
+    case 'o':
+    case 'g':
+    case 's':
+	// g_variant_get_string has length as out argument
+	return variant.get_string()[0];
+    case 'v':
+	return variant.get_variant();
+    case 'm':
+	let val = variant.get_maybe();
+	if (deep)
+	    return _unpack_variant(val, deep);
+	else
+	    return val;
+    case 'a':
+	if (variant.is_of_type(GLib.VariantType.new('a{?*}'))) {
+	    // special case containers
+	    let ret = { };
+	    let nElements = variant.n_children();
+	    for (let i = 0; i < nElements; i++) {
+		// always unpack the dictionary entry, and always unpack
+		// the key (or it cannot be added as a key)
+		let val = _unpack_variant(variant.get_child_value(i), deep);
+		let key
+		if (!deep)
+		    key = _unpack_variant(val[0], true);
+		else
+		    key = val[0];
+		ret[key] = val[1];
+	    }
+	    return ret;
+	}
+	// fall through
+    case '(':
+    case '{':
+	let ret = [ ];
+	let nElements = variant.n_children();
+	for (let i = 0; i < nElements; i++) {
+	    let val = variant.get_child_value(i);
+	    if (deep)
+		ret.push(_unpack_variant(val, deep));
+	    else
+		ret.push(val);
+	}
+	return ret;
+    }
+
+    throw new Error('Assertion failure: this code should not be reached');
+}
+
+function _init() {
+    // this is imports.gi.GLib
+
+    GLib = this;
+
+    this.Variant.new = function (sig, value) {
+	let signature = Array.prototype.slice.call(sig);
+
+	let variant = _pack_variant(signature, value);
+	if (signature.length != 0)
+	    throw new TypeError('Invalid GVariant signature (more than one single complete type)');
+
+	return variant;
+    }
+    this.Variant.prototype.unpack = function() {
+	return _unpack_variant(this, false);
+    }
+    this.Variant.prototype.deep_unpack = function() {
+	return _unpack_variant(this, true);
+    }
+    this.Variant.prototype.toString = function() {
+	return '[object variant of type "' + this.get_type_string() + '"]';
+    }
+}
\ No newline at end of file



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