|
22 | 22 |
|
23 | 23 | #include "APICast.h" |
24 | 24 | #include "APIUtils.h" |
| 25 | +#include "JSArrayBuffer.h" |
25 | 26 | #include "JSCCallbackFunction.h" |
26 | 27 | #include "JSCClassPrivate.h" |
27 | 28 | #include "JSCContextPrivate.h" |
28 | 29 | #include "JSCInlines.h" |
29 | 30 | #include "JSCValuePrivate.h" |
30 | 31 | #include "JSRetainPtr.h" |
| 32 | +#include "JSTypedArray.h" |
31 | 33 | #include "LiteralParser.h" |
32 | 34 | #include "OpaqueJSString.h" |
33 | 35 | #include <gobject/gvaluecollector.h> |
@@ -1461,6 +1463,183 @@ JSCValue* jsc_value_constructor_callv(JSCValue* value, unsigned parametersCount, |
1461 | 1463 | return jscContextGetOrCreateValue(priv->context.get(), result).leakRef(); |
1462 | 1464 | } |
1463 | 1465 |
|
| 1466 | +struct ArrayBufferDeallocatorContext { |
| 1467 | + gpointer userData; |
| 1468 | + GDestroyNotify destroyNotify; |
| 1469 | +}; |
| 1470 | +WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ArrayBufferDeallocatorContext) |
| 1471 | + |
| 1472 | +/** |
| 1473 | + * jsc_value_new_array_buffer: |
| 1474 | + * @context: A #JSCContext |
| 1475 | + * @data: Pointer to a region of memory. |
| 1476 | + * @size: Size in bytes of the memory region. |
| 1477 | + * @destroy_notify: (nullable): destroy notifier for @user_data. |
| 1478 | + * @user_data: (closure): user data. |
| 1479 | + * |
| 1480 | + * Creates a new %ArrayBuffer from existing @data in memory. |
| 1481 | + * |
| 1482 | + * The @data is not copied: while this allows sharing data with JavaScript |
| 1483 | + * efficiently, the caller must ensure that the memory region remains valid |
| 1484 | + * until the newly created object is released by JSC. |
| 1485 | + * |
| 1486 | + * Optionally, a @destroy_notify callback can be provided, which will be |
| 1487 | + * invoked with @user_data as parameter when the %ArrayBuffer object is |
| 1488 | + * released. This is intended to be used for freeing resources related to |
| 1489 | + * the memory region which contains the data: |
| 1490 | + * |
| 1491 | + * |[!<-- language="C" --> |
| 1492 | + * GMappedFile *f = g_mapped_file_new (file_path, TRUE, NULL); |
| 1493 | + * JSCValue *value = jsc_value_new_array_buffer (context, |
| 1494 | + * g_mapped_file_get_contents (f), g_mapped_file_get_length (f), |
| 1495 | + * (GDestroyNotify) g_mapped_file_unref, f); |
| 1496 | + * ]| |
| 1497 | + * |
| 1498 | + * Note that the @user_data can be the same value as @data: |
| 1499 | + * |
| 1500 | + * |[!<-- language="C" --> |
| 1501 | + * void *bytes = g_malloc0 (100); |
| 1502 | + * JSCValue *value = jsc_value_new_array_buffer (context, bytes, 100, g_free, bytes); |
| 1503 | + * ]| |
| 1504 | + * |
| 1505 | + * Returns: (transfer full) (nullable): A #JSCValue, or %NULL in case of exception. |
| 1506 | + * |
| 1507 | + * Since: 2.38 |
| 1508 | + */ |
| 1509 | +JSCValue* jsc_value_new_array_buffer(JSCContext* context, void* data, size_t length, GDestroyNotify destroyNotify, gpointer userData) |
| 1510 | +{ |
| 1511 | + g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr); |
| 1512 | + |
| 1513 | + ArrayBufferDeallocatorContext* deallocatorContext = nullptr; |
| 1514 | + if (destroyNotify) { |
| 1515 | + deallocatorContext = createArrayBufferDeallocatorContext(); |
| 1516 | + deallocatorContext->destroyNotify = destroyNotify; |
| 1517 | + deallocatorContext->userData = userData; |
| 1518 | + } |
| 1519 | + |
| 1520 | + JSValueRef exception = nullptr; |
| 1521 | + auto* jsContext = jscContextGetJSContext(context); |
| 1522 | + auto* jsArrayBuffer = JSObjectMakeArrayBufferWithBytesNoCopy(jsContext, data, length, [](void*, void* deallocatorContext) { |
| 1523 | + if (deallocatorContext) { |
| 1524 | + auto* context = static_cast<ArrayBufferDeallocatorContext*>(deallocatorContext); |
| 1525 | + context->destroyNotify(context->userData); |
| 1526 | + destroyArrayBufferDeallocatorContext(context); |
| 1527 | + } |
| 1528 | + }, deallocatorContext, &exception); |
| 1529 | + |
| 1530 | + if (jscContextHandleExceptionIfNeeded(context, exception)) |
| 1531 | + return nullptr; |
| 1532 | + |
| 1533 | + return jscContextGetOrCreateValue(context, jsArrayBuffer).leakRef(); |
| 1534 | +} |
| 1535 | + |
| 1536 | +/** |
| 1537 | + * jsc_value_is_array_buffer: |
| 1538 | + * @value: A #JSCValue. |
| 1539 | + * |
| 1540 | + * Check whether the @value is an %ArrayBuffer. |
| 1541 | + * |
| 1542 | + * Returns: whether the value is an %ArrayBuffer |
| 1543 | + * |
| 1544 | + * Since: 2.38 |
| 1545 | + */ |
| 1546 | +gboolean jsc_value_is_array_buffer(JSCValue* value) |
| 1547 | +{ |
| 1548 | + g_return_val_if_fail(JSC_IS_VALUE(value), FALSE); |
| 1549 | + |
| 1550 | + using namespace JSC; |
| 1551 | + |
| 1552 | + JSGlobalObject* globalObject = toJS(jscContextGetJSContext(value->priv->context.get())); |
| 1553 | + VM& vm = globalObject->vm(); |
| 1554 | + JSLockHolder locker(vm); |
| 1555 | + |
| 1556 | + JSValue jsValue = toJS(globalObject, value->priv->jsValue); |
| 1557 | + if (!jsValue.isObject()) |
| 1558 | + return FALSE; |
| 1559 | + |
| 1560 | + return !!jsDynamicCast<JSArrayBuffer*>(vm, jsValue.getObject()); |
| 1561 | +} |
| 1562 | + |
| 1563 | +/** |
| 1564 | + * jsc_value_array_buffer_get_data: |
| 1565 | + * @value: A #JSCValue |
| 1566 | + * @size: (nullable): location where to store the size of the memory region. |
| 1567 | + * |
| 1568 | + * Gets a pointer to memory that contains the array buffer data. |
| 1569 | + * |
| 1570 | + * Obtains a pointer to the memory region that holds the contents of the |
| 1571 | + * %ArrayBuffer; modifications done to the data will be visible to JavaScript |
| 1572 | + * code. If @size is not %NULL, the size in bytes of the memory region |
| 1573 | + * will also be stored in the pointed location. |
| 1574 | + * |
| 1575 | + * Note that the pointer returned by this function is not guaranteed to remain |
| 1576 | + * the same after calls to other JSC API functions. If you plan to access the |
| 1577 | + * data of the %ArrayBuffer later, you can keep a reference to the @value and |
| 1578 | + * obtain the data pointer at a later point. Keep in mind that if JavaScript |
| 1579 | + * code has a chance to run, for example due to main loop events that result |
| 1580 | + * in JSC being called, the contents of the memory region might be modified in |
| 1581 | + * the meantime. Consider taking a copy of the data and using the copy instead |
| 1582 | + * in asynchronous code. |
| 1583 | + * |
| 1584 | + * Returns: (transfer none): pointer to memory. |
| 1585 | + * |
| 1586 | + * Since: 2.38 |
| 1587 | + */ |
| 1588 | +gpointer jsc_value_array_buffer_get_data(JSCValue* value, gsize* size) |
| 1589 | +{ |
| 1590 | + g_return_val_if_fail(JSC_IS_VALUE(value), nullptr); |
| 1591 | + |
| 1592 | + auto* jsContext = jscContextGetJSContext(value->priv->context.get()); |
| 1593 | + |
| 1594 | + JSValueRef exception = nullptr; |
| 1595 | + auto* jsObject = JSValueToObject(jsContext, value->priv->jsValue, &exception); |
| 1596 | + if (jscContextHandleExceptionIfNeeded(value->priv->context.get(), exception)) |
| 1597 | + return nullptr; |
| 1598 | + |
| 1599 | + void* data = JSObjectGetArrayBufferBytesPtr(jsContext, jsObject, &exception); |
| 1600 | + if (jscContextHandleExceptionIfNeeded(value->priv->context.get(), exception)) |
| 1601 | + return nullptr; |
| 1602 | + |
| 1603 | + if (size) { |
| 1604 | + *size = JSObjectGetArrayBufferByteLength(jsContext, jsObject, &exception); |
| 1605 | + if (jscContextHandleExceptionIfNeeded(value->priv->context.get(), exception)) |
| 1606 | + return nullptr; |
| 1607 | + } |
| 1608 | + |
| 1609 | + return data; |
| 1610 | +} |
| 1611 | + |
| 1612 | +/** |
| 1613 | + * jsc_value_array_buffer_get_size: |
| 1614 | + * @value: A #JSCValue |
| 1615 | + * |
| 1616 | + * Gets the size of the array buffer. |
| 1617 | + * |
| 1618 | + * Obtains the size in bytes of the memory region that holds the contents of |
| 1619 | + * an %ArrayBuffer. |
| 1620 | + * |
| 1621 | + * Returns: size, in bytes. |
| 1622 | + * |
| 1623 | + * Since: 2.38 |
| 1624 | + */ |
| 1625 | +gsize jsc_value_array_buffer_get_size(JSCValue* value) |
| 1626 | +{ |
| 1627 | + g_return_val_if_fail(JSC_IS_VALUE(value), 0); |
| 1628 | + |
| 1629 | + auto* jsContext = jscContextGetJSContext(value->priv->context.get()); |
| 1630 | + |
| 1631 | + JSValueRef exception = nullptr; |
| 1632 | + auto* jsObject = JSValueToObject(jsContext, value->priv->jsValue, &exception); |
| 1633 | + if (jscContextHandleExceptionIfNeeded(value->priv->context.get(), exception)) |
| 1634 | + return 0; |
| 1635 | + |
| 1636 | + size_t size = JSObjectGetArrayBufferByteLength(jsContext, jsObject, &exception); |
| 1637 | + if (jscContextHandleExceptionIfNeeded(value->priv->context.get(), exception)) |
| 1638 | + return 0; |
| 1639 | + |
| 1640 | + return size; |
| 1641 | +} |
| 1642 | + |
1464 | 1643 | /** |
1465 | 1644 | * jsc_value_new_from_json: |
1466 | 1645 | * @context: a #JSCContext |
|
0 commit comments