DataViewConstructor.cs 3.7 KB

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