unpak.js
Version:
Modern TypeScript library for reading Unreal Engine pak files and assets, inspired by CUE4Parse
252 lines • 10.4 kB
JavaScript
"use strict";
/*
* Copyright (C) 2012 tamtam180
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CityHash = void 0;
const long_1 = __importDefault(require("long"));
/**
* @author tamtam180 - kirscheless at gmail.com
* @author modified by amrsatrio
* @author ported by Sprayxe
* @see <a href="https://opensource.googleblog.com/2011/04/introducing-cityhash.html">https://opensource.googleblog.com/2011/04/introducing-cityhash.html</a>
* @see <a href="https://github.com/google/cityhash">https://github.com/google/cityhash</a>
*/
class CityHash {
// Some primes between 2^63 and 2^64 for various uses.
static k0 = long_1.default.fromString('14097894508562428199', true);
static k1 = long_1.default.fromString('13011662864482103923', true);
static k2 = long_1.default.fromString('11160318154034397263', true);
static toLongLE(b, i) {
return long_1.default.fromNumber(b[i + 7], true)
.shl(56)
.add(long_1.default.fromNumber(b[i + 6] & 255, true).shl(48))
.add(long_1.default.fromNumber(b[i + 5] & 255, true).shl(40))
.add(long_1.default.fromNumber(b[i + 4] & 255, true).shl(32))
.add(long_1.default.fromNumber(b[i + 3] & 255, true).shl(24))
.add(long_1.default.fromNumber(b[i + 2] & 255, true).shl(16))
.add(long_1.default.fromNumber(b[i + 1] & 255, true).shl(8))
.add(b[i] & 255);
}
static toIntLE(b, i) {
return (((b[i + 3] & 255) << 24) + ((b[i + 2] & 255) << 16) + ((b[i + 1] & 255) << 8) + (b[i] & 255));
}
static bswap64(value) {
const b1 = value.and(0xff);
const b2 = value.shr(8).and(0xff);
const b3 = value.shr(16).and(0xff);
const b4 = value.shr(24).and(0xff);
const b5 = value.shr(32).and(0xff);
const b6 = value.shr(40).and(0xff);
const b7 = value.shr(48).and(0xff);
const b8 = value.shr(56).and(0xff);
return b1
.shl(56)
.or(b2.shl(48))
.or(b3.shl(40))
.or(b4.shl(32))
.or(b5.shl(24))
.or(b6.shl(16))
.or(b7.shl(8))
.or(b8);
}
static fetch64(s, pos) {
return this.toLongLE(s, pos);
}
static fetch32(s, pos) {
return this.toIntLE(s, pos);
}
/**
* Bitwise right rotate. Normally this will compile to a single
* instruction, especially if the shift is a manifest constant.
*/
static rotate(val, shift) {
// Avoid shifting by 64: doing so yields an undefined result.
return shift === 0 ? val : val.shru(shift).or(val.shl(64 - shift));
}
static shiftMix(val) {
return val.xor(val.shru(47));
}
static hashLen16(u, v) {
return this.cityHash128to64(u, v);
}
static hashLen16Mul(u, v, mul) {
// Murmur-inspired hashing.
let a = u.xor(v).multiply(mul);
a = a.xor(a.shru(47));
let b = v.xor(a).multiply(mul);
b = b.xor(b.shru(47));
b = b.multiply(mul);
return b;
}
static hashLen0to16(s, pos, len) {
if (len > 8) {
const mul = this.k2.add(len * 2);
const a = this.fetch64(s, pos).add(this.k2);
const b = this.fetch64(s, pos + len - 8);
const c = this.rotate(b, 37).multiply(mul).add(a);
const d = this.rotate(a, 25).add(b).multiply(mul);
return this.hashLen16Mul(c, d, mul);
}
if (len >= 4) {
const mul = this.k2.add(len * 2);
const a = this.fetch32(s, pos);
return this.hashLen16Mul(long_1.default.fromNumber(len + (a << 3), true), long_1.default.fromNumber(this.fetch32(s, pos + len - 4), true), mul);
}
if (len > 0) {
const a = s[pos] & 0xff;
const b = s[pos + (len >>> 1)] & 0xff;
const c = s[pos + len - 1] & 0xff;
const y = a + (b << 8);
const z = len + (c << 2);
return this.shiftMix(this.k2.multiply(y).xor(this.k0.multiply(z))).multiply(this.k2);
}
return this.k2;
}
/**
* This probably works well for 16-byte strings as well, but it may be overkill
* in that case.
*/
static hashLen17to32(s, pos, len) {
const mul = this.k2.add(len * 2);
const a = this.fetch64(s, pos).multiply(this.k1);
const b = this.fetch64(s, pos + 8);
const c = this.fetch64(s, pos + len - 8).multiply(mul);
const d = this.fetch64(s, pos + len - 16).multiply(this.k2);
return this.hashLen16Mul(this.rotate(a.add(b), 43).add(this.rotate(c, 30).add(d)), a.add(this.rotate(b.add(this.k2), 18)).add(c), mul);
}
/**
* Return a 16-byte hash for 48 bytes. Quick and dirty.
* Callers do best to use "random-looking" values for a and b.
*/
static weakHashLen32WithSeeds0(w, x, y, z, a, b) {
a = a.add(w);
b = this.rotate(b.add(a).add(z), 21);
const c = a;
a = a.add(x);
a = a.add(y);
b = b.add(this.rotate(a, 44));
return [a.add(z), b.add(c)];
}
/**
* Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
*/
static weakHashLen32WithSeeds1(s, pos, a, b) {
return this.weakHashLen32WithSeeds0(this.fetch64(s, pos), this.fetch64(s, pos + 8), this.fetch64(s, pos + 16), this.fetch64(s, pos + 24), a, b);
}
/**
* Return an 8-byte hash for 33 to 64 bytes.
*/
static hashLen33to64(s, pos, len) {
const mul = this.k2.add(len * 2);
let a = this.fetch64(s, pos).multiply(this.k2);
let b = this.fetch64(s, pos + 8);
const c = this.fetch64(s, pos + len - 24);
const d = this.fetch64(s, pos + len - 32);
const e = this.fetch64(s, pos + 16).multiply(this.k2);
const f = this.fetch64(s, pos + 24).multiply(9);
const g = this.fetch64(s, pos + len - 8);
const h = this.fetch64(s, pos + len - 16).multiply(mul);
const u = this.rotate(a.add(g), 43).add(this.rotate(b, 30).add(c).multiply(9));
const v = a.add(g).xor(d).add(f).add(1);
const w = this.bswap64(u.add(v).multiply(mul)).add(h);
const x = this.rotate(e.add(f), 42).add(c);
const y = this.bswap64(v.add(w).multiply(mul)).add(g).multiply(mul);
const z = e.add(f).add(c);
a = this.bswap64(x.add(z).multiply(mul).add(y)).add(b);
b = this.shiftMix(z.add(a).multiply(mul).add(d).add(h)).multiply(mul);
return b.add(x);
}
/**
* Hash function for a byte array.
*/
static cityHash64(s, pos, len) {
if (len <= 32) {
if (len <= 16) {
return this.hashLen0to16(s, pos, len);
}
else {
return this.hashLen17to32(s, pos, len);
}
}
else if (len <= 64) {
return this.hashLen33to64(s, pos, len);
}
// For strings over 64 bytes we hash the end first, and then as we
// loop we keep 56 bytes of state: v, w, x, y, and z.
let x = this.fetch64(s, pos + len - 40);
let y = this.fetch64(s, pos + len - 16).add(this.fetch64(s, pos + len - 56));
let z = this.hashLen16(this.fetch64(s, pos + len - 48).add(len), this.fetch64(s, pos + len - 24));
let v = this.weakHashLen32WithSeeds1(s, pos + len - 64, long_1.default.fromNumber(len, true), z);
let w = this.weakHashLen32WithSeeds1(s, pos + len - 32, y.add(this.k1), x);
x = x.multiply(this.k1).add(this.fetch64(s, pos));
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
len = (len - 1) & ~63;
do {
x = this.rotate(x
.add(y)
.add(v[0])
.add(this.fetch64(s, pos + 8)), 37).multiply(this.k1);
y = this.rotate(y.add(v[1]).add(this.fetch64(s, pos + 48)), 42).multiply(this.k1);
x = x.xor(w[1]);
y = y.add(v[0].add(this.fetch64(s, pos + 40)));
z = this.rotate(z.add(w[0]), 33).multiply(this.k1);
v = this.weakHashLen32WithSeeds1(s, pos, v[1].multiply(this.k1), x.add(w[0]));
w = this.weakHashLen32WithSeeds1(s, pos + 32, z.add(w[1]), y.add(this.fetch64(s, pos + 16)));
{
const swap = z;
z = x;
x = swap;
}
pos += 64;
len -= 64;
} while (len !== 0);
return this.hashLen16(this.hashLen16(v[0], w[0]).add(this.shiftMix(y).multiply(this.k1)).add(z), this.hashLen16(v[1], w[1]).add(x));
}
/**
* Hash function for a byte array. For convenience, a 64-bit seed is also
* hashed into the result.
*/
static cityHash64WithSeed(s, pos, len, seed) {
return this.cityHash64WithSeeds(s, pos, len, this.k2, seed);
}
static cityHash64WithSeeds(s, pos, len, seed0, seed1) {
return this.hashLen16(this.cityHash64(s, pos, len).subtract(seed0), seed1);
}
/**
* Hash function for a byte array. Most useful in 32-bit binaries.
*/
static cityHash32(_s, _pos, _len) {
return long_1.default.fromNumber(-1);
}
/**
* Hash 128 input bits down to 64 bits of output.
* This is intended to be a reasonably good hash function.
*/
static cityHash128to64(u, v) {
const kMul = long_1.default.fromString('11376068507788127593', true);
let a = u.xor(v).multiply(kMul);
a = a.xor(a.shru(47));
let b = v.xor(a).multiply(kMul);
b = b.xor(b.shru(47));
b = b.multiply(kMul);
return b;
}
}
exports.CityHash = CityHash;
//# sourceMappingURL=CityHash.js.map