aaaaaa123456789 icon

JS ResizableMemoryBlock

aaaaaa123456789 | PRO | 12/02/16 08:47:10 AM UTC | 0 ⭐ | 418 👁️ | Never ⏰ | []
JavaScript |

6.87 KB

|

None

|

0 👍

/

0 👎

/*
   This code is hereby released to the public domain.
   ~aaaaaa123456789, 2016-12-02, updated 2016-12-05
*/
 
function ResizableMemoryBlock (initial_size = 0) {
  var self = this;
 
  var current_size;
  var parts = [];
 
  for (current_size = 0; current_size < initial_size; current_size += 8192) parts[current_size >>> 13] = new DataView(new ArrayBuffer(8192));
  current_size = initial_size;
 
  self.size = function () {
    return current_size;
  };
 
  function shrink (size) {
    var new_parts = (size + 8191) >>> 13;
    var old_offset = current_size & 8191, new_offset = size & 8191;
    if (old_offset === 0) old_offset = 8192;
    if (new_offset === 0) new_offset = 8192;
    if (new_parts != parts.length) {
      while (parts.length > new_parts) parts.pop();
      old_offset = 8192;
    }
    var offset, part = parts.length - 1;
    for (offset = new_offset; offset < old_offset; offset ++) parts[part].setUint8(offset, 0);
    current_size = size;
  }
 
  function expand (size) {
    var new_parts = (size + 8191) >>> 13;
    while (parts.length < new_parts) parts.push(new DataView(new ArrayBuffer(8192)));
    current_size = size;
  }
 
  self.resize = function (size) {
    if (size == current_size) return;
    if (size > current_size) return expand(size);
    return shrink(size);
  };
 
  function break_into_bytes (value, size) {
    var bytes = [];
    while (bytes.length < size) {
      bytes.push(value & 0xff);
      value >>>= 8;
    }
    return bytes;
  }
 
  self.set_byte = function (position, value) {
    if (position >= current_size) expand(position + 1);
    parts[position >>> 13].setUint8(position & 8191, value & 0xff);
  };
 
  self.set_halfword = function (position, value) {
    if (position > (current_size - 2)) expand(position + 2);
    var offset = position & 8191, part = position >>> 13;
    value &= 0xffff;
    if (offset <= 8190) return parts[part].setUint16(offset, value, true);
    var bytes = break_into_bytes(value, 2);
    while (bytes.length > 0) {
      parts[part].setUint8(offset ++, bytes.shift());
      if (offset == 8192) {
        part ++;
        offset = 0;
      }
    }
  };
 
  self.set_word = function (position, value) {
    if (position > (current_size - 4)) expand(position + 4);
    var offset = position & 8191, part = position >>> 13;
    value >>>= 0;
    if (offset <= 8188) return parts[part].setUint32(offset, value, true);
    var bytes = break_into_bytes(value, 4);
    while (bytes.length > 0) {
      parts[part].setUint8(offset ++, bytes.shift());
      if (offset == 8192) {
        part ++;
        offset = 0;
      }
    }
  };
 
  function gather_bytes (bytes) {
    var result = 0;
    while (bytes.length) result = ((result << 8) >>> 0) + bytes.pop();
    return result;
  }
 
  self.get_byte = function (position) {
    if (position >= current_size) throw "attempted to read past the end of the buffer";
    return parts[position >>> 13].getUint8(position & 8191);
  };
 
  self.get_halfword = function (position) {
    if (position > (current_size - 2)) throw "attempted to read past the end of the buffer";
    var offset = position & 8191, part = position >>> 13;
    if (offset <= 8190) return parts[part].getUint16(offset, true);
    var bytes = [];
    var count;
    for (count = 0; count < 2; count ++) {
      bytes.push(parts[part].getUint8(offset ++));
      if (offset == 8192) {
        offset = 0;
        part ++;
      }
    }
    return gather_bytes(bytes);
  };
 
  self.get_word = function (position) {
    if (position > (current_size - 4)) throw "attempted to read past the end of the buffer";
    var offset = position & 8191, part = position >>> 13;
    if (offset <= 8188) return parts[part].getUint32(offset, true);
    var bytes = [];
    var count;
    for (count = 0; count < 4; count ++) {
      bytes.push(parts[part].getUint8(offset ++));
      if (offset == 8192) {
        offset = 0;
        part ++;
      }
    }
    return gather_bytes(bytes);
  };
 
  self.generate_array_buffer = function () {
    var result = new ArrayBuffer(current_size);
    var view = new Uint8Array(result);
    var part_count = current_size >>> 13, extra_offset = current_size & 8191;
    var pos;
    for (pos = 0; pos < part_count; pos ++) view.set(new Uint8Array(parts[pos].buffer), (pos << 13) >>> 0);
    for (pos = 0; pos < extra_offset; pos ++) view[pos + ((part_count << 13) >>> 0)] = parts[part_count].getUint8(pos);
    return result;
  };
 
  self.calculate_sha1 = function () {
    function rotate (value, count) {
      return ((value << count) | (value >>> (32 - count))) >>> 0;
    }
 
    function mixing_function (counter, first, second, third) {
      if (counter < 20)
        return ((first & second) | (~first & third)) >>> 0;
      else if ((counter >= 40) && (counter < 60))
        return ((first & second) | (first & third) | (second & third)) >>> 0;
      else
        return (first ^ second ^ third) >>> 0;
    }
 
    function hash_constant (counter) {
      // constants used by SHA-1; they are actually simply the square roots of 2, 3, 5 and 10 as a fixed-point number (2.30 format)
      return ([0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6])[(counter / 20) >>> 0];
    }
 
    function process_block (state, block) {
      var words = new Uint32Array(80);
      var pos;
      for (pos = 0; pos < 16; pos ++) words[pos] = block.getUint32(pos << 2);
      for (; pos < 80; pos ++) words[pos] = rotate((words[pos - 3] ^ words[pos - 8] ^ words[pos - 14] ^ words[pos - 16]) >>> 0, 1);
      var temp, a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
      for (pos = 0; pos < 80; pos ++) {
        temp = (rotate(a, 5) + mixing_function(pos, b, c, d) + e + words[pos] + hash_constant(pos)) >>> 0;
        e = d;
        d = c;
        c = rotate(b, 30);
        b = a;
        a = temp;
      }
      return [(state[0] + a) >>> 0, (state[1] + b) >>> 0, (state[2] + c) >>> 0, (state[3] + d) >>> 0, (state[4] + e) >>> 0];
    }
 
    var state = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
    var pos, buf;
    for (pos = 0; pos < ((current_size & 0xffffffc0) >>> 0); pos += 64)
      state = process_block(state, new DataView(parts[pos >>> 13].buffer.slice(pos & 8191, (pos & 8191) + 64)));
    buf = new DataView(new ArrayBuffer(64));
    for (; pos < current_size; pos ++) buf.setUint8(pos & 63, parts[pos >>> 13].getUint8(pos & 8191));
    buf.setUint8(pos & 63, 0x80);
    if ((pos & 63) >= 56) {
      state = process_block(state, buf);
      buf = new DataView(new ArrayBuffer(64));
    }
    buf.setUint8(59, current_size >>> 29);
    buf.setUint32(60, (current_size << 3) >>> 0);
    state = process_block(state, buf);
    buf = new Uint8Array(20);
    for (pos = 0; pos < 20; pos ++) buf[pos] = (state[pos >> 2] >>> ((3 - (pos & 3)) << 3)) & 0xff;
    return buf;
  };
}

Comments