| 108 | } |
| 109 | |
| 110 | GJS_JSAPI_RETURN_CONVENTION |
| 111 | static bool from_gbytes_func(JSContext* cx, unsigned argc, JS::Value* vp) { |
| 112 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
| 113 | JS::RootedObject bytes_obj{cx}; |
| 114 | |
| 115 | if (!gjs_parse_call_args(cx, "fromGBytes", args, "o", "bytes", &bytes_obj)) |
| 116 | return false; |
| 117 | |
| 118 | if (!StructBase::typecheck(cx, bytes_obj, G_TYPE_BYTES)) |
| 119 | return false; |
| 120 | |
| 121 | GBytes* gbytes = StructBase::to_c_ptr<GBytes>(cx, bytes_obj); |
| 122 | if (!gbytes) |
| 123 | return false; |
| 124 | |
| 125 | size_t len; |
| 126 | const void* data = g_bytes_get_data(gbytes, &len); |
| 127 | if (len == 0) { |
| 128 | JS::RootedObject empty_array{cx, JS_NewUint8Array(cx, 0)}; |
| 129 | if (!empty_array || !define_legacy_tostring(cx, empty_array)) |
| 130 | return false; |
| 131 | |
| 132 | args.rval().setObject(*empty_array); |
| 133 | return true; |
| 134 | } |
| 135 | |
| 136 | JS::RootedObject array_buffer{cx, JS::NewArrayBuffer(cx, len)}; |
| 137 | if (!array_buffer) |
| 138 | return false; |
| 139 | |
| 140 | // Copy the data into the ArrayBuffer so that the copy is aligned, and |
| 141 | // because the GBytes data pointer may point into immutable memory. |
| 142 | { |
| 143 | JS::AutoCheckCannotGC nogc; |
| 144 | bool unused; |
| 145 | uint8_t* storage = JS::GetArrayBufferData(array_buffer, &unused, nogc); |
| 146 | std::copy_n(static_cast<const uint8_t*>(data), len, storage); |
| 147 | } |
| 148 | |
| 149 | JS::RootedObject obj{cx, |
| 150 | JS_NewUint8ArrayWithBuffer(cx, array_buffer, 0, -1)}; |
| 151 | if (!obj || !define_legacy_tostring(cx, obj)) |
| 152 | return false; |
| 153 | |
| 154 | args.rval().setObject(*obj); |
| 155 | return true; |
| 156 | } |
| 157 | |
| 158 | JSObject* gjs_byte_array_from_data_copy(JSContext* cx, size_t nbytes, |
| 159 | void* data) { |
nothing calls this directly
no test coverage detected