basefilereader.js

import { parseURL, text2buffer } from './util';

/**
 * Abstract class that should be extended
 */
class BaseFileReader {
  /**
   * Constructs a file reader for specific file types
   *
   * @param {BlueFileHeader|MatFileHeader} header_class
   * @param {object} options
   * @returns {BaseFileReader}
   */
  constructor(header_class, options) {
    this.header_class = header_class;
    this.options = options;
  }

  /**
   * Internal method that will read a file or stop at the header
   *
   * @private
   * @memberof BaseFileReader
   * @param {File} theFile - a File object for the Bluefile or Matfile
   * @param {function} onload - callback when the header has been read
   * @param {boolean} justHeader - Whether or not to only read the header
   */
  _read(theFile, onload, justHeader) {
    const that = this;
    const reader = new FileReader();

    // Note: webkitSlice is Chrome specific and deprecated now.
    // For some backwards-compatibility, we'll continue to support it.
    // In a future version, this will just use `File.slice`.
    const sliceMethod =
      theFile.webkitSlice === undefined ? 'slice' : 'webkitSlice';
    const blob = justHeader ? theFile[sliceMethod](0, 512) : theFile;

    // Closure to capture the file information.
    reader.onloadend = ((theFile) => {
      return function (e) {
        if (e.target.error) {
          onload(null);
          return;
        }
        const raw = reader.result;
        const hdr = new that.header_class(raw, that.options);
        hdr.file = theFile;
        hdr.file_name = theFile.name;
        onload(hdr);
      };
    })(theFile);
    reader.readAsArrayBuffer(blob);
  }

  /**
   * Read only the header from a local {Blue,Mat}file.
   *
   * @memberof BaseFileReader
   * @param {File} theFile - a File object for the Bluefile or Matfile
   * @param {function} onload - callback when the header has been read
   */
  readheader(theFile, onload) {
    this._read(theFile, onload, true);
  }

  /**
   * Read a local Bluefile or Matfile on disk.
   *
   * @memberof BaseFileReader
   * @param {File} theFile - a File object for the Bluefile or Matfile
   * @param {function} onload - callback when the file has been read
   */
  read(theFile, onload) {
    this._read(theFile, onload, false);
  }

  /**
   * Read a Bluefile or Matfile from a URL
   *
   * @memberof BaseFileReader
   * @param {string} href - the URL for the Bluefile or Matfile
   * @param {function} onload - callback when the header has been read
   */
  read_http(href, onload) {
    const that = this;
    const oReq = new XMLHttpRequest();
    oReq.open('GET', href, true);
    oReq.responseType = 'arraybuffer';
    oReq.overrideMimeType('text/plain; charset=x-user-defined');
    oReq.onload = function (_oEvent) {
      if (oReq.readyState === 4) {
        if (oReq.status === 200 || oReq.status === 0) {
          // status = 0 is necessary for file URL
          let arrayBuffer = null; // Note: not oReq.responseText
          if (oReq.response) {
            arrayBuffer = oReq.response;
            const hdr = new that.header_class(arrayBuffer, that.options);
            const fileUrl = parseURL(href);
            hdr.file_name = fileUrl.file;
            onload(hdr);
          } else if (oReq.responseText) {
            text2buffer(oReq.responseText, function (arrayBuffer) {
              const hdr = new that.header_class(arrayBuffer, that.options);
              const fileUrl = parseURL(href);
              hdr.file_name = fileUrl.file;
              onload(hdr);
            });
          }
          return;
        }
      }
      onload(null);
    };
    oReq.onerror = function (_oEvent) {
      onload(null);
    };
    oReq.send(null);
    return oReq;
  }
}

export { BaseFileReader };