DataViewConstructor.cs 3.7 KB

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