JSFiddle - React, Tailwind, and code Playground

by philfreo

HTML

<script src="http://underscorejs.org/underscore-min.js"></script>
<input type="file" id="myfile" />

JavaScript

var fileInput = document.getElementById('myfile');

fileInput.addEventListener('change', function(e) {
    var file = e.currentTarget.files[0];
    FileDetector.verifyFileType(file, ['mp3', 'wav'], function(isType) {
        alert(!!isType);
    });
});

var FileDetector = (function() {

	// https://en.wikipedia.org/wiki/List_of_file_signatures
  var fileSignatures = {
    'mp3': [
      // MPEG-1 Layer 3 file without an ID3 tag or with an ID3v1 tag (which's appended at the end of the file)
      Uint8Array.from([0xFF, 0xFB]),
      // MP3 file with an ID3v2 container
      Uint8Array.from([0x49, 0x44, 0x33])
   ]
   'wav': [
      // Waveform Audio File Format
      // Empty slots can be any byte. Can't look at only first 4 or else .avi files match
   		Uint8Array.from([0x52, 0x49, 0x46, 0x46, , , , , 0x57, 0x41, 0x56, 0x45])
   ]
  };
  
  /**
   * Compare two Uint8Arrays. This function could be replaced by _.isEqual except
   * for the fact that the signatures (e.g. wav files) can have wildcard slots.
   * value, meaning that we should ignore those bytes.
   * @param {Uint8Array} sig - pattern from fileSignatures
   * @param {Uint8Array} actual - bytes from file (already sliced to match length of sig)
   * @returns {boolean}
   */
  var compareSignature = function(sig, actual) {
    if (sig.length !== actual.length) return false;
    for (var i = 0, l = sig.length, i < l; i++) {
      if (sig[i] !== actual[i] && typeof sig[i] !== 'undefined') return false;
    }
    return true;
  };
   
  /**
   * @param {Uint8Array} uint8
   * @param {string} type
   * @returns {boolean}
   */
  var matchesFileType = function(uint8, type) {
    return _.find(fileSignatures[type], function(sig) {
      return compareSignature(sig, uint8.slice(0, sig.length));
    });
  };

  return {
    /**
     * Detect, through file signature / mime sniffing detection, if a given File 
     * matches an expected type or types. The types supported are the keys in
     * fileSignatures...