DataViewConstructor.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using Jint.Native.Function;
  2. using Jint.Native.Object;
  3. using Jint.Runtime;
  4. using Jint.Runtime.Descriptors;
  5. namespace Jint.Native.DataView;
  6. /// <summary>
  7. /// https://tc39.es/ecma262/#sec-dataview-constructor
  8. /// </summary>
  9. internal sealed class DataViewConstructor : Constructor
  10. {
  11. private static readonly JsString _functionName = new("DataView");
  12. internal DataViewConstructor(
  13. Engine engine,
  14. Realm realm,
  15. FunctionPrototype functionPrototype,
  16. ObjectPrototype objectPrototype)
  17. : base(engine, realm, _functionName)
  18. {
  19. _prototype = functionPrototype;
  20. PrototypeObject = new DataViewPrototype(engine, this, objectPrototype);
  21. _length = new PropertyDescriptor(1, PropertyFlag.Configurable);
  22. _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
  23. }
  24. private DataViewPrototype PrototypeObject { get; }
  25. public override ObjectInstance Construct(JsCallArguments arguments, JsValue newTarget)
  26. {
  27. if (newTarget.IsUndefined())
  28. {
  29. Throw.TypeError(_realm);
  30. }
  31. var buffer = arguments.At(0) as JsArrayBuffer;
  32. var byteOffset = arguments.At(1);
  33. var byteLength = arguments.At(2);
  34. if (buffer is null)
  35. {
  36. Throw.TypeError(_realm, "First argument to DataView constructor must be an ArrayBuffer");
  37. }
  38. var offset = TypeConverter.ToIndex(_realm, byteOffset);
  39. if (buffer.IsDetachedBuffer)
  40. {
  41. Throw.TypeError(_realm);
  42. }
  43. var bufferByteLength = (uint) buffer.ArrayBufferByteLength;
  44. if (offset > bufferByteLength)
  45. {
  46. Throw.RangeError(_realm, "Start offset " + offset + " is outside the bounds of the buffer");
  47. }
  48. var bufferIsFixedLength = buffer.IsFixedLengthArrayBuffer;
  49. uint viewByteLength;
  50. if (byteLength.IsUndefined())
  51. {
  52. if (bufferIsFixedLength)
  53. {
  54. viewByteLength = bufferByteLength - offset;
  55. }
  56. else
  57. {
  58. viewByteLength = JsTypedArray.LengthAuto;
  59. }
  60. }
  61. else
  62. {
  63. viewByteLength = TypeConverter.ToIndex(_realm, byteLength);
  64. if (offset + viewByteLength > bufferByteLength)
  65. {
  66. Throw.RangeError(_realm, "Invalid DataView length");
  67. }
  68. }
  69. var o = OrdinaryCreateFromConstructor(
  70. newTarget,
  71. static intrinsics => intrinsics.DataView.PrototypeObject,
  72. static (Engine engine, Realm _, object? _) => new JsDataView(engine));
  73. if (buffer.IsDetachedBuffer)
  74. {
  75. Throw.TypeError(_realm);
  76. }
  77. bufferByteLength = (uint) buffer.ArrayBufferByteLength;
  78. if (offset > bufferByteLength)
  79. {
  80. Throw.RangeError(_realm, "Invalid DataView offset");
  81. }
  82. if (!byteLength.IsUndefined())
  83. {
  84. if (offset + viewByteLength > bufferByteLength)
  85. {
  86. Throw.RangeError(_realm, "Invalid DataView length");
  87. }
  88. }
  89. o._viewedArrayBuffer = buffer;
  90. o._byteLength = viewByteLength;
  91. o._byteOffset = offset;
  92. return o;
  93. }
  94. }