/*
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