%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/lib/internal/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/lib/internal/blob.js

'use strict';

const {
  ArrayFrom,
  MathMax,
  MathMin,
  ObjectDefineProperties,
  ObjectDefineProperty,
  ObjectSetPrototypeOf,
  PromiseReject,
  RegExpPrototypeExec,
  RegExpPrototypeSymbolReplace,
  StringPrototypeToLowerCase,
  StringPrototypeSplit,
  Symbol,
  SymbolIterator,
  SymbolToStringTag,
  Uint8Array,
} = primordials;

const {
  createBlob: _createBlob,
  createBlobFromFilePath: _createBlobFromFilePath,
  concat,
  getDataObject,
} = internalBinding('blob');
const {
  kMaxLength,
} = internalBinding('buffer');

const {
  TextDecoder,
  TextEncoder,
} = require('internal/encoding');
const { URL } = require('internal/url');

const {
  markTransferMode,
  kClone,
  kDeserialize,
} = require('internal/worker/js_transferable');

const {
  isAnyArrayBuffer,
  isArrayBufferView,
} = require('internal/util/types');

const {
  createDeferredPromise,
  customInspectSymbol: kInspect,
  kEmptyObject,
  kEnumerableProperty,
  lazyDOMException,
} = require('internal/util');
const { inspect } = require('internal/util/inspect');

const {
  codes: {
    ERR_INVALID_ARG_TYPE,
    ERR_INVALID_ARG_VALUE,
    ERR_INVALID_THIS,
    ERR_INVALID_STATE,
    ERR_BUFFER_TOO_LARGE,
  },
} = require('internal/errors');

const {
  validateDictionary,
} = require('internal/validators');

const {
  CountQueuingStrategy,
} = require('internal/webstreams/queuingstrategies');

const { queueMicrotask } = require('internal/process/task_queues');

const kHandle = Symbol('kHandle');
const kType = Symbol('kType');
const kLength = Symbol('kLength');
const kNotCloneable = Symbol('kNotCloneable');

const disallowedTypeCharacters = /[^\u{0020}-\u{007E}]/u;

let ReadableStream;

const enc = new TextEncoder();
let dec;

// Yes, lazy loading is annoying but because of circular
// references between the url, internal/blob, and buffer
// modules, lazy loading here makes sure that things work.

function lazyReadableStream(options) {
  // eslint-disable-next-line no-global-assign
  ReadableStream ??=
    require('internal/webstreams/readablestream').ReadableStream;
  return new ReadableStream(options);
}

const { EOL } = require('internal/constants');

function isBlob(object) {
  return object?.[kHandle] !== undefined;
}

function getSource(source, endings) {
  if (isBlob(source))
    return [source.size, source[kHandle]];

  if (isAnyArrayBuffer(source)) {
    source = new Uint8Array(source);
  } else if (!isArrayBufferView(source)) {
    source = `${source}`;
    if (endings === 'native')
      source = RegExpPrototypeSymbolReplace(/\n|\r\n/g, source, EOL);
    source = enc.encode(source);
  }

  // We copy into a new Uint8Array because the underlying
  // BackingStores are going to be detached and owned by
  // the Blob.
  const { buffer, byteOffset, byteLength } = source;
  const slice = buffer.slice(byteOffset, byteOffset + byteLength);
  return [byteLength, new Uint8Array(slice)];
}

class Blob {
  /**
   * @typedef {string|ArrayBuffer|ArrayBufferView|Blob} SourcePart
   */

  /**
   * @param {SourcePart[]} [sources]
   * @param {{
   *   endings? : string,
   *   type? : string,
   * }} [options]
   * @constructs {Blob}
   */
  constructor(sources = [], options) {
    markTransferMode(this, true, false);

    if (sources === null ||
        typeof sources[SymbolIterator] !== 'function' ||
        typeof sources === 'string') {
      throw new ERR_INVALID_ARG_TYPE('sources', 'a sequence', sources);
    }
    validateDictionary(options, 'options');
    let {
      type = '',
      endings = 'transparent',
    } = options ?? kEmptyObject;

    endings = `${endings}`;
    if (endings !== 'transparent' && endings !== 'native')
      throw new ERR_INVALID_ARG_VALUE('options.endings', endings);

    let length = 0;
    const sources_ = ArrayFrom(sources, (source) => {
      const { 0: len, 1: src } = getSource(source, endings);
      length += len;
      return src;
    });

    if (length > kMaxLength)
      throw new ERR_BUFFER_TOO_LARGE(kMaxLength);

    this[kHandle] = _createBlob(sources_, length);
    this[kLength] = length;

    type = `${type}`;
    this[kType] = RegExpPrototypeExec(disallowedTypeCharacters, type) !== null ?
      '' : StringPrototypeToLowerCase(type);
  }

  [kInspect](depth, options) {
    if (depth < 0)
      return this;

    const opts = {
      ...options,
      depth: options.depth == null ? null : options.depth - 1,
    };

    return `Blob ${inspect({
      size: this.size,
      type: this.type,
    }, opts)}`;
  }

  [kClone]() {
    if (this[kNotCloneable]) {
      // We do not currently allow file-backed Blobs to be cloned or passed across
      // worker threads.
      throw new ERR_INVALID_STATE.TypeError('File-backed Blobs are not cloneable');
    }
    const handle = this[kHandle];
    const type = this[kType];
    const length = this[kLength];
    return {
      data: { handle, type, length },
      deserializeInfo: 'internal/blob:Blob',
    };
  }

  [kDeserialize]({ handle, type, length }) {
    this[kHandle] = handle;
    this[kType] = type;
    this[kLength] = length;
  }

  /**
   * @readonly
   * @type {string}
   */
  get type() {
    if (!isBlob(this))
      throw new ERR_INVALID_THIS('Blob');
    return this[kType];
  }

  /**
   * @readonly
   * @type {number}
   */
  get size() {
    if (!isBlob(this))
      throw new ERR_INVALID_THIS('Blob');
    return this[kLength];
  }

  /**
   * @param {number} [start]
   * @param {number} [end]
   * @param {string} [contentType]
   * @returns {Blob}
   */
  slice(start = 0, end = this[kLength], contentType = '') {
    if (!isBlob(this))
      throw new ERR_INVALID_THIS('Blob');
    if (start < 0) {
      start = MathMax(this[kLength] + start, 0);
    } else {
      start = MathMin(start, this[kLength]);
    }
    start |= 0;

    if (end < 0) {
      end = MathMax(this[kLength] + end, 0);
    } else {
      end = MathMin(end, this[kLength]);
    }
    end |= 0;

    contentType = `${contentType}`;
    if (RegExpPrototypeExec(disallowedTypeCharacters, contentType) !== null) {
      contentType = '';
    } else {
      contentType = StringPrototypeToLowerCase(contentType);
    }

    const span = MathMax(end - start, 0);

    return createBlob(
      this[kHandle].slice(start, start + span),
      span,
      contentType);
  }

  /**
   * @returns {Promise<ArrayBuffer>}
   */
  arrayBuffer() {
    if (!isBlob(this))
      return PromiseReject(new ERR_INVALID_THIS('Blob'));

    const { promise, resolve, reject } = createDeferredPromise();
    const reader = this[kHandle].getReader();
    const buffers = [];
    const readNext = () => {
      reader.pull((status, buffer) => {
        if (status === 0) {
          // EOS, concat & resolve
          // buffer should be undefined here
          resolve(concat(buffers));
          return;
        } else if (status < 0) {
          // The read could fail for many different reasons when reading
          // from a non-memory resident blob part (e.g. file-backed blob).
          // The error details the system error code.
          const error = lazyDOMException('The blob could not be read', 'NotReadableError');
          reject(error);
          return;
        }
        if (buffer !== undefined)
          buffers.push(buffer);
        queueMicrotask(() => readNext());
      });
    };
    readNext();
    return promise;
  }

  /**
   * @returns {Promise<string>}
   */
  async text() {
    if (!isBlob(this))
      throw new ERR_INVALID_THIS('Blob');

    dec ??= new TextDecoder();

    return dec.decode(await this.arrayBuffer());
  }

  /**
   * @returns {ReadableStream}
   */
  stream() {
    if (!isBlob(this))
      throw new ERR_INVALID_THIS('Blob');

    const reader = this[kHandle].getReader();
    return new lazyReadableStream({
      type: 'bytes',
      start(c) {
        // There really should only be one read at a time so using an
        // array here is purely defensive.
        this.pendingPulls = [];
      },
      pull(c) {
        const { promise, resolve, reject } = createDeferredPromise();
        this.pendingPulls.push({ resolve, reject });
        const readNext = () => {
          reader.pull((status, buffer) => {
            // If pendingPulls is empty here, the stream had to have
            // been canceled, and we don't really care about the result.
            // We can simply exit.
            if (this.pendingPulls.length === 0) {
              return;
            }
            if (status === 0) {
              // EOS
              c.close();
              // This is to signal the end for byob readers
              // see https://streams.spec.whatwg.org/#example-rbs-pull
              c.byobRequest?.respond(0);
              const pending = this.pendingPulls.shift();
              pending.resolve();
              return;
            } else if (status < 0) {
              // The read could fail for many different reasons when reading
              // from a non-memory resident blob part (e.g. file-backed blob).
              // The error details the system error code.
              const error = lazyDOMException('The blob could not be read', 'NotReadableError');
              const pending = this.pendingPulls.shift();
              c.error(error);
              pending.reject(error);
              return;
            }
            // ReadableByteStreamController.enqueue errors if we submit a 0-length
            // buffer. We need to check for that here.
            if (buffer !== undefined && buffer.byteLength !== 0) {
              c.enqueue(new Uint8Array(buffer));
            }
            // We keep reading until we either reach EOS, some error, or we
            // hit the flow rate of the stream (c.desiredSize).
            queueMicrotask(() => {
              if (c.desiredSize < 0) {
                // A manual backpressure check.
                if (this.pendingPulls.length !== 0) {
                  // A case of waiting pull finished (= not yet canceled)
                  const pending = this.pendingPulls.shift();
                  pending.resolve();
                }
                return;
              }
              readNext();
            });
          });
        };
        readNext();
        return promise;
      },
      cancel(reason) {
        // Reject any currently pending pulls here.
        for (const pending of this.pendingPulls) {
          pending.reject(reason);
        }
        this.pendingPulls = [];
      },
    // We set the highWaterMark to 0 because we do not want the stream to
    // start reading immediately on creation. We want it to wait until read
    // is called.
    }, new CountQueuingStrategy({ highWaterMark: 0 }));
  }
}

function TransferableBlob(handle, length, type = '') {
  markTransferMode(this, true, false);
  this[kHandle] = handle;
  this[kType] = type;
  this[kLength] = length;
}

ObjectSetPrototypeOf(TransferableBlob.prototype, Blob.prototype);
ObjectSetPrototypeOf(TransferableBlob, Blob);

function createBlob(handle, length, type = '') {
  const transferredBlob = new TransferableBlob(handle, length, type);

  // Fix issues like: https://github.com/nodejs/node/pull/49730#discussion_r1331720053
  transferredBlob.constructor = Blob;

  return transferredBlob;
}

ObjectDefineProperty(Blob.prototype, SymbolToStringTag, {
  __proto__: null,
  configurable: true,
  value: 'Blob',
});

ObjectDefineProperties(Blob.prototype, {
  size: kEnumerableProperty,
  type: kEnumerableProperty,
  slice: kEnumerableProperty,
  stream: kEnumerableProperty,
  text: kEnumerableProperty,
  arrayBuffer: kEnumerableProperty,
});

function resolveObjectURL(url) {
  url = `${url}`;
  try {
    const parsed = new URL(url);

    const split = StringPrototypeSplit(parsed.pathname, ':');

    if (split.length !== 2)
      return;

    const {
      0: base,
      1: id,
    } = split;

    if (base !== 'nodedata')
      return;

    const ret = getDataObject(id);

    if (ret === undefined)
      return;

    const {
      0: handle,
      1: length,
      2: type,
    } = ret;

    if (handle !== undefined)
      return createBlob(handle, length, type);
  } catch {
    // If there's an error, it's ignored and nothing is returned
  }
}

// TODO(@jasnell): Now that the File class exists, we might consider having
// this return a `File` instead of a `Blob`.
function createBlobFromFilePath(path, options) {
  const maybeBlob = _createBlobFromFilePath(path);
  if (maybeBlob === undefined) {
    return lazyDOMException('The blob could not be read', 'NotReadableError');
  }
  const { 0: blob, 1: length } = maybeBlob;
  const res = createBlob(blob, length, options?.type);
  res[kNotCloneable] = true;
  return res;
}

module.exports = {
  Blob,
  createBlob,
  createBlobFromFilePath,
  isBlob,
  kHandle,
  resolveObjectURL,
};

Zerion Mini Shell 1.0