decode() function implementation
| 267 | |
| 268 | // decode() function implementation |
| 269 | JSString* gjs_decode_from_uint8array(JSContext* cx, JS::HandleObject byte_array, |
| 270 | const char* encoding, |
| 271 | GjsStringTermination string_termination, |
| 272 | bool fatal) { |
| 273 | g_assert(encoding && "encoding must be non-null"); |
| 274 | |
| 275 | if (!JS_IsUint8Array(byte_array)) { |
| 276 | gjs_throw(cx, "Argument to decode() must be a Uint8Array"); |
| 277 | return nullptr; |
| 278 | } |
| 279 | |
| 280 | uint8_t* data; |
| 281 | size_t len; |
| 282 | bool is_shared_memory; |
| 283 | js::GetUint8ArrayLengthAndData(byte_array, &len, &is_shared_memory, &data); |
| 284 | |
| 285 | // If the desired behavior is zero-terminated, calculate the |
| 286 | // zero-terminated length of the given data. |
| 287 | if (len && string_termination == GjsStringTermination::ZERO_TERMINATED) |
| 288 | len = zero_terminated_length(data, len); |
| 289 | |
| 290 | // If the calculated length is 0 we can just return an empty string. |
| 291 | if (len == 0) |
| 292 | return JS_GetEmptyString(cx); |
| 293 | |
| 294 | // Optimization, only use glib's iconv-based converters if we're dealing |
| 295 | // with a non-UTF8 encoding. SpiderMonkey has highly optimized UTF-8 decoder |
| 296 | // and encoders. |
| 297 | bool encoding_is_utf8 = is_utf8_label(encoding); |
| 298 | if (!encoding_is_utf8) |
| 299 | return gjs_decode_from_uint8array_slow(cx, data, len, encoding, fatal); |
| 300 | |
| 301 | JS::RootedString decoded(cx); |
| 302 | if (!fatal) { |
| 303 | decoded.set(gjs_lossy_string_from_utf8_n( |
| 304 | cx, reinterpret_cast<char*>(data), len)); |
| 305 | } else { |
| 306 | JS::UTF8Chars chars(reinterpret_cast<char*>(data), len); |
| 307 | JS::RootedString str(cx, JS_NewStringCopyUTF8N(cx, chars)); |
| 308 | |
| 309 | // If an exception occurred, we need to check if the |
| 310 | // exception was an InternalError. Unfortunately, |
| 311 | // SpiderMonkey's decoder can throw InternalError for some |
| 312 | // invalid UTF-8 sources, we have to convert this into a |
| 313 | // TypeError to match the Encoding specification. |
| 314 | if (str) { |
| 315 | decoded.set(str); |
| 316 | } else { |
| 317 | JS::RootedValue exc(cx); |
| 318 | if (!JS_GetPendingException(cx, &exc) || !exc.isObject()) |
| 319 | return nullptr; |
| 320 | |
| 321 | JS::RootedObject exc_obj(cx, &exc.toObject()); |
| 322 | const JSClass* internal_error = |
| 323 | js::ProtoKeyToClass(JSProto_InternalError); |
| 324 | if (JS_InstanceOf(cx, exc_obj, internal_error, nullptr)) { |
| 325 | // Clear the existing exception. |
| 326 | JS_ClearPendingException(cx); |
no test coverage detected