Skip to content

Instantly share code, notes, and snippets.

@loilo
Last active November 4, 2024 20:42
Show Gist options
  • Save loilo/92220c23567d6ed085a28f2c3e84e311 to your computer and use it in GitHub Desktop.
Save loilo/92220c23567d6ed085a28f2c3e84e311 to your computer and use it in GitHub Desktop.
URL-Safe LZMA Compression

URL-Safe LZMA Compression

This Gist provides JavaScript functions to compress a string for usage in URLs using a very space-efficient but comparatively slow algorithm. It's great for sharing larger amounts of data as part of a URL.

The raw algorithm is forked from lzma-js, converted to an ES module and with some features stripped off (e.g. async mode, worker support), the URL-safe functionality was added by me.

If you need to compress data very frequently (e.g. on each keystroke of a user), you probably should look out for a faster alternative (e.g. lz-string).

Usage

Note: The JavaScript files of this Gist are using some ES2015 features in general and ES modules in particular. You can safely use them in modern browsers, however using them in Node.js or legacy browsers would need an additional transpile and/or bundling step.

Compress

Let's compress this example JSON data set (you can see the code in action on CodeSandbox):

import { compressUrlSafe } from './lzma-url.js'

const data = {
  id: '0001',
  type: 'donut',
  name: 'Cake',
  ppu: 0.55,
  batters: {
    batter: [
      { id: '1001', type: 'Regular' },
      { id: '1002', type: 'Chocolate' },
      { id: '1003', type: 'Blueberry' },
      { id: '1004', type: "Devil's Food" }
    ]
  },
  topping: [
    { id: '5001', type: 'None' },
    { id: '5002', type: 'Glazed' },
    { id: '5005', type: 'Sugar' },
    { id: '5007', type: 'Powdered Sugar' },
    { id: '5006', type: 'Chocolate with Sprinkles' },
    { id: '5003', type: 'Chocolate' },
    { id: '5004', type: 'Maple' }
  ]
}

const serializedData = JSON.stringify(data)
const compressedSerializedData = compressUrlSafe(serializedData)

console.log(`${serializedData.length} -> ${compressedSerializedData.length} bytes`)

This outputs 456 -> 294 bytes and generates the following compressed string:

  XQAAgADIAQAAAAAAAAA9iIkmgZNThWHvkoxYOhkMap8xuPc5WJAnOm0EWWnOco5kpp0Q6jEiL_ERvnqVST8OmSqcdDKPT_LOC3CazYNsg7FftTjd4Zel5ueEC81Jpd5wHZQR2Or1OaZBQ3T3cv4zYtBAgADqtQSoIb_JFbnNtPzJZzYWb3R6wEDt_nh-9LPC-aOKFlNdD2fxD3YrgY_VF8FHT_gZfYm3QyLnmLTiLMkEzDyXZfIlts_0cuEGCwzFxXr3RqKT4Sn_h8BYuRXcvvLu4BHB_-aH5pg%3D

This example shows a reduction of just ≈35%, however especially when encoding JSON structures (where usually there is a lot of duplicate content), space-efficiency increases greatly for larger data sets (my test dataset of 30 KB went down to just 4.9 KB).

Decompress

Inversely, we can take our generated string from above and convert it back to plain text:

import { decompressUrlSafe } from './lzma-url.js'

const compressedSerializedData = `XQAAgADIAQAAAAAAAAA9iIkmgZNThWHvkoxYOhkMap8xuPc5WJAnOm0EWWnOco5kpp0Q6jEiL_ERvnqVST8OmSqcdDKPT_LOC3CazYNsg7FftTjd4Zel5ueEC81Jpd5wHZQR2Or1OaZBQ3T3cv4zYtBAgADqtQSoIb_JFbnNtPzJZzYWb3R6wEDt_nh-9LPC-aOKFlNdD2fxD3YrgY_VF8FHT_gZfYm3QyLnmLTiLMkEzDyXZfIlts_0cuEGCwzFxXr3RqKT4Sn_h8BYuRXcvvLu4BHB_-aH5pg%3D`

const serializedData = decompressUrlSafe(compressedSerializedData)

The serializedData variable now contains the serialized JSON data:

{"id":"0001","type":"donut","name":"Cake","ppu":0.55,"batters":{"batter":[{"id":"1001","type":"Regular"},{"id":"1002","type":"Chocolate"},{"id":"1003","type":"Blueberry"},{"id":"1004","type":"Devil's Food"}]},"topping":[{"id":"5001","type":"None"},{"id":"5002","type":"Glazed"},{"id":"5005","type":"Sugar"},{"id":"5007","type":"Powdered Sugar"},{"id":"5006","type":"Chocolate with Sprinkles"},{"id":"5003","type":"Chocolate"},{"id":"5004","type":"Maple"}]}

To get back our original data, we'd just have to pass that through JSON.parse().

/**
* Convert between Uint8Array and Base64 strings
* Allows for any encoded JS string to be converted (as opposed to atob()/btoa() which only supports latin1)
*
* Original implementation by madmurphy on MDN
* @see https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Solution_1_–_JavaScript%27s_UTF-16_%3E_base64
*/
function b64ToUint6(nChr) {
return nChr > 64 && nChr < 91
? nChr - 65
: nChr > 96 && nChr < 123
? nChr - 71
: nChr > 47 && nChr < 58
? nChr + 4
: nChr === 43
? 62
: nChr === 47
? 63
: 0
}
export function decodeToArray(base64string, blockSize) {
var sB64Enc = base64string.replace(/[^A-Za-z0-9\+\/]/g, ''),
nInLen = sB64Enc.length,
nOutLen = blockSize
? Math.ceil(((nInLen * 3 + 1) >>> 2) / blockSize) * blockSize
: (nInLen * 3 + 1) >>> 2,
aBytes = new Uint8Array(nOutLen)
for (
var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0;
nInIdx < nInLen;
nInIdx++
) {
nMod4 = nInIdx & 3
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (18 - 6 * nMod4)
if (nMod4 === 3 || nInLen - nInIdx === 1) {
for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) {
aBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255
}
nUint24 = 0
}
}
return aBytes
}
function uint6ToB64(nUint6) {
return nUint6 < 26
? nUint6 + 65
: nUint6 < 52
? nUint6 + 71
: nUint6 < 62
? nUint6 - 4
: nUint6 === 62
? 43
: nUint6 === 63
? 47
: 65
}
export function encodeFromArray(bytes) {
var eqLen = (3 - (bytes.length % 3)) % 3,
sB64Enc = ''
for (
var nMod3, nLen = bytes.length, nUint24 = 0, nIdx = 0;
nIdx < nLen;
nIdx++
) {
nMod3 = nIdx % 3
/* Uncomment the following line in order to split the output in lines 76-character long: */
/*
if (nIdx > 0 && (nIdx * 4 / 3) % 76 === 0) { sB64Enc += "\r\n"; }
*/
nUint24 |= bytes[nIdx] << ((16 >>> nMod3) & 24)
if (nMod3 === 2 || bytes.length - nIdx === 1) {
sB64Enc += String.fromCharCode(
uint6ToB64((nUint24 >>> 18) & 63),
uint6ToB64((nUint24 >>> 12) & 63),
uint6ToB64((nUint24 >>> 6) & 63),
uint6ToB64(nUint24 & 63)
)
nUint24 = 0
}
}
return eqLen === 0
? sB64Enc
: sB64Enc.substring(0, sB64Enc.length - eqLen) + (eqLen === 1 ? '=' : '==')
}
/**
* URL-safe variants of Base64 conversion functions (aka base64url)
* @see https://tools.ietf.org/html/rfc4648#section-5
*/
export function encodeFromArrayUrlSafe(bytes) {
return encodeURIComponent(
encodeFromArray(bytes)
.replace(/\+/g, '-')
.replace(/\//g, '_')
)
}
export function decodeToArrayUrlSafe(base64string) {
return decodeToArray(
decodeURIComponent(base64string)
.replace(/-/g, '+')
.replace(/_/g, '/')
)
}
/*
The LZMA impementation is forked from https://npm.is/lzma-js, converted to an ES module and with some features stripped off (e.g. async mode, worker support)
Here's the according MIT license:
© 2016 Nathan Rugg <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import * as base64 from './base64.js'
const __4294967296 = 4294967296,
N1_longLit = [4294967295, -__4294967296],
MIN_VALUE = [0, -9223372036854775808],
P0_longLit = [0, 0],
P1_longLit = [1, 0]
function add(a, b) {
return create(a[0] + b[0], a[1] + b[1])
}
function initDim(len) {
// NOTE: This is MUCH faster than "initDim(len)" in newer versions of v8 (starting with Node.js 0.11.15, which uses v8 3.28.73).
var a = []
a[len - 1] = undefined
return a
}
function and(a, b) {
return makeFromBits(
~~Math.max(Math.min(a[1] / __4294967296, 2147483647), -2147483648) &
~~Math.max(Math.min(b[1] / __4294967296, 2147483647), -2147483648),
lowBits_0(a) & lowBits_0(b)
)
}
function compare(a, b) {
var nega, negb
if (a[0] == b[0] && a[1] == b[1]) {
return 0
}
nega = a[1] < 0
negb = b[1] < 0
if (nega && !negb) {
return -1
}
if (!nega && negb) {
return 1
}
if (sub(a, b)[1] < 0) {
return -1
}
return 1
}
function create(valueLow, valueHigh) {
var diffHigh, diffLow
valueHigh %= 1.8446744073709552e19
valueLow %= 1.8446744073709552e19
diffHigh = valueHigh % __4294967296
diffLow = Math.floor(valueLow / __4294967296) * __4294967296
valueHigh = valueHigh - diffHigh + diffLow
valueLow = valueLow - diffLow + diffHigh
while (valueLow < 0) {
valueLow += __4294967296
valueHigh -= __4294967296
}
while (valueLow > 4294967295) {
valueLow -= __4294967296
valueHigh += __4294967296
}
valueHigh = valueHigh % 1.8446744073709552e19
while (valueHigh > 9223372032559808512) {
valueHigh -= 1.8446744073709552e19
}
while (valueHigh < -9223372036854775808) {
valueHigh += 1.8446744073709552e19
}
return [valueLow, valueHigh]
}
function eq(a, b) {
return a[0] == b[0] && a[1] == b[1]
}
function fromInt(value) {
if (value >= 0) {
return [value, 0]
} else {
return [value + __4294967296, -__4294967296]
}
}
function lowBits_0(a) {
if (a[0] >= 2147483648) {
return ~~Math.max(Math.min(a[0] - __4294967296, 2147483647), -2147483648)
} else {
return ~~Math.max(Math.min(a[0], 2147483647), -2147483648)
}
}
function makeFromBits(highBits, lowBits) {
var high, low
high = highBits * __4294967296
low = lowBits
if (lowBits < 0) {
low += __4294967296
}
return [low, high]
}
function pwrAsDouble(n) {
if (n <= 30) {
return 1 << n
} else {
return pwrAsDouble(30) * pwrAsDouble(n - 30)
}
}
function shl(a, n) {
var diff, newHigh, newLow, twoToN
n &= 63
if (eq(a, MIN_VALUE)) {
if (!n) {
return a
}
return P0_longLit
}
if (a[1] < 0) {
throw new Error('Neg')
}
twoToN = pwrAsDouble(n)
newHigh = (a[1] * twoToN) % 1.8446744073709552e19
newLow = a[0] * twoToN
diff = newLow - (newLow % __4294967296)
newHigh += diff
newLow -= diff
if (newHigh >= 9223372036854775807) {
newHigh -= 1.8446744073709552e19
}
return [newLow, newHigh]
}
function shr(a, n) {
var shiftFact
n &= 63
shiftFact = pwrAsDouble(n)
return create(Math.floor(a[0] / shiftFact), a[1] / shiftFact)
}
function shru(a, n) {
var sr
n &= 63
sr = shr(a, n)
if (a[1] < 0) {
sr = add(sr, shl([2, 0], 63 - n))
}
return sr
}
function sub(a, b) {
return create(a[0] - b[0], a[1] - b[1])
}
function $ByteArrayInputStream(this$static, buf) {
this$static.buf = buf
this$static.pos = 0
this$static.count = buf.length
return this$static
}
function $read(this$static) {
if (this$static.pos >= this$static.count) return -1
return this$static.buf[this$static.pos++] & 255
}
function $read_0(this$static, buf, off, len) {
if (this$static.pos >= this$static.count) return -1
len = Math.min(len, this$static.count - this$static.pos)
arraycopy(this$static.buf, this$static.pos, buf, off, len)
this$static.pos += len
return len
}
function $ByteArrayOutputStream(this$static) {
this$static.buf = initDim(32)
this$static.count = 0
return this$static
}
function $toByteArray(this$static) {
var data = this$static.buf
data.length = this$static.count
return data
}
function $write(this$static, b) {
this$static.buf[this$static.count++] = (b << 24) >> 24
}
function $write_0(this$static, buf, off, len) {
arraycopy(buf, off, this$static.buf, this$static.count, len)
this$static.count += len
}
function $getChars(this$static, srcBegin, srcEnd, dst, dstBegin) {
var srcIdx
for (srcIdx = srcBegin; srcIdx < srcEnd; ++srcIdx) {
dst[dstBegin++] = this$static.charCodeAt(srcIdx)
}
}
function arraycopy(src, srcOfs, dest, destOfs, len) {
for (var i = 0; i < len; ++i) {
dest[destOfs + i] = src[srcOfs + i]
}
}
function $configure(this$static, encoder) {
$SetDictionarySize_0(encoder, 1 << this$static.s)
encoder._numFastBytes = this$static.f
$SetMatchFinder(encoder, this$static.m)
// lc is always 3
// lp is always 0
// pb is always 2
encoder._numLiteralPosStateBits = 0
encoder._numLiteralContextBits = 3
encoder._posStateBits = 2
encoder._posStateMask = 3
}
function $init(this$static, input, output, length_0, mode, enableEndMark) {
var encoder, i
if (compare(length_0, N1_longLit) < 0)
throw new Error('invalid length ' + length_0)
this$static.length_0 = length_0
encoder = $Encoder({})
$configure(mode, encoder)
encoder._writeEndMark = enableEndMark
$WriteCoderProperties(encoder, output)
for (i = 0; i < 64; i += 8) $write(output, lowBits_0(shr(length_0, i)) & 255)
this$static.chunker =
((encoder._needReleaseMFStream = 0),
((encoder._inStream = input),
(encoder._finished = 0),
$Create_2(encoder),
(encoder._rangeEncoder.Stream = output),
$Init_4(encoder),
$FillDistancesPrices(encoder),
$FillAlignPrices(encoder),
(encoder._lenEncoder._tableSize = encoder._numFastBytes + 1 - 2),
$UpdateTables(encoder._lenEncoder, 1 << encoder._posStateBits),
(encoder._repMatchLenEncoder._tableSize = encoder._numFastBytes + 1 - 2),
$UpdateTables(encoder._repMatchLenEncoder, 1 << encoder._posStateBits),
(encoder.nowPos64 = P0_longLit),
undefined),
$Chunker_0({}, encoder))
}
function $LZMAByteArrayCompressor(this$static, data, mode, enableEndMark) {
this$static.output = $ByteArrayOutputStream({})
$init(
this$static,
$ByteArrayInputStream({}, data),
this$static.output,
fromInt(data.length),
mode,
enableEndMark
)
return this$static
}
function $init_0(this$static, input, output) {
var decoder,
hex_length = '',
i,
properties = [],
r,
tmp_length
for (i = 0; i < 5; ++i) {
r = $read(input)
if (r == -1) throw new Error('truncated input')
properties[i] = (r << 24) >> 24
}
decoder = $Decoder({})
if (!$SetDecoderProperties(decoder, properties)) {
throw new Error('corrupted input')
}
for (i = 0; i < 64; i += 8) {
r = $read(input)
if (r == -1) throw new Error('truncated input')
r = r.toString(16)
if (r.length == 1) r = '0' + r
hex_length = r + '' + hex_length
}
// Was the length set in the header (if it was compressed from a stream, the length is all f"s).
if (/^0+$|^f+$/i.test(hex_length)) {
// The length is unknown, so set to -1.
this$static.length_0 = N1_longLit
} else {
// NOTE: If there is a problem with the decoder because of the length, you can always set the length to -1 (N1_longLit) which means unknown.
tmp_length = parseInt(hex_length, 16)
// If the length is too long to handle, just set it to unknown.
if (tmp_length > 4294967295) {
this$static.length_0 = N1_longLit
} else {
this$static.length_0 = fromInt(tmp_length)
}
}
this$static.chunker = $CodeInChunks(
decoder,
input,
output,
this$static.length_0
)
}
function $LZMAByteArrayDecompressor(this$static, data) {
this$static.output = $ByteArrayOutputStream({})
$init_0(this$static, $ByteArrayInputStream({}, data), this$static.output)
return this$static
}
function $Create_4(this$static, keepSizeBefore, keepSizeAfter, keepSizeReserv) {
var blockSize
this$static._keepSizeBefore = keepSizeBefore
this$static._keepSizeAfter = keepSizeAfter
blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv
if (this$static._bufferBase == null || this$static._blockSize != blockSize) {
this$static._bufferBase = null
this$static._blockSize = blockSize
this$static._bufferBase = initDim(this$static._blockSize)
}
this$static._pointerToLastSafePosition =
this$static._blockSize - keepSizeAfter
}
function $GetIndexByte(this$static, index) {
return this$static._bufferBase[
this$static._bufferOffset + this$static._pos + index
]
}
function $GetMatchLen(this$static, index, distance, limit) {
var i, pby
if (this$static._streamEndWasReached) {
if (this$static._pos + index + limit > this$static._streamPos) {
limit = this$static._streamPos - (this$static._pos + index)
}
}
++distance
pby = this$static._bufferOffset + this$static._pos + index
for (
i = 0;
i < limit &&
this$static._bufferBase[pby + i] ==
this$static._bufferBase[pby + i - distance];
++i
) {}
return i
}
function $GetNumAvailableBytes(this$static) {
return this$static._streamPos - this$static._pos
}
function $MoveBlock(this$static) {
var i, numBytes, offset
offset =
this$static._bufferOffset + this$static._pos - this$static._keepSizeBefore
if (offset > 0) {
--offset
}
numBytes = this$static._bufferOffset + this$static._streamPos - offset
for (i = 0; i < numBytes; ++i) {
this$static._bufferBase[i] = this$static._bufferBase[offset + i]
}
this$static._bufferOffset -= offset
}
function $MovePos_1(this$static) {
var pointerToPostion
++this$static._pos
if (this$static._pos > this$static._posLimit) {
pointerToPostion = this$static._bufferOffset + this$static._pos
if (pointerToPostion > this$static._pointerToLastSafePosition) {
$MoveBlock(this$static)
}
$ReadBlock(this$static)
}
}
function $ReadBlock(this$static) {
var numReadBytes, pointerToPostion, size
if (this$static._streamEndWasReached) return
while (1) {
size =
-this$static._bufferOffset +
this$static._blockSize -
this$static._streamPos
if (!size) return
numReadBytes = $read_0(
this$static._stream,
this$static._bufferBase,
this$static._bufferOffset + this$static._streamPos,
size
)
if (numReadBytes == -1) {
this$static._posLimit = this$static._streamPos
pointerToPostion = this$static._bufferOffset + this$static._posLimit
if (pointerToPostion > this$static._pointerToLastSafePosition) {
this$static._posLimit =
this$static._pointerToLastSafePosition - this$static._bufferOffset
}
this$static._streamEndWasReached = 1
return
}
this$static._streamPos += numReadBytes
if (
this$static._streamPos >=
this$static._pos + this$static._keepSizeAfter
) {
this$static._posLimit =
this$static._streamPos - this$static._keepSizeAfter
}
}
}
function $ReduceOffsets(this$static, subValue) {
this$static._bufferOffset += subValue
this$static._posLimit -= subValue
this$static._pos -= subValue
this$static._streamPos -= subValue
}
var CrcTable = (function() {
var i,
j,
r,
CrcTable = []
for (i = 0; i < 256; ++i) {
r = i
for (j = 0; j < 8; ++j)
if ((r & 1) != 0) {
r = (r >>> 1) ^ -306674912
} else {
r >>>= 1
}
CrcTable[i] = r
}
return CrcTable
})()
function $Create_3(
this$static,
historySize,
keepAddBufferBefore,
matchMaxLen,
keepAddBufferAfter
) {
var cyclicBufferSize, hs, windowReservSize
if (historySize < 1073741567) {
this$static._cutValue = 16 + (matchMaxLen >> 1)
windowReservSize =
~~(
(historySize + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) /
2
) + 256
$Create_4(
this$static,
historySize + keepAddBufferBefore,
matchMaxLen + keepAddBufferAfter,
windowReservSize
)
this$static._matchMaxLen = matchMaxLen
cyclicBufferSize = historySize + 1
if (this$static._cyclicBufferSize != cyclicBufferSize) {
this$static._son = initDim(
(this$static._cyclicBufferSize = cyclicBufferSize) * 2
)
}
hs = 65536
if (this$static.HASH_ARRAY) {
hs = historySize - 1
hs |= hs >> 1
hs |= hs >> 2
hs |= hs >> 4
hs |= hs >> 8
hs >>= 1
hs |= 65535
if (hs > 16777216) hs >>= 1
this$static._hashMask = hs
++hs
hs += this$static.kFixHashSize
}
if (hs != this$static._hashSizeSum) {
this$static._hash = initDim((this$static._hashSizeSum = hs))
}
}
}
function $GetMatches(this$static, distances) {
var count,
cur,
curMatch,
curMatch2,
curMatch3,
cyclicPos,
delta,
hash2Value,
hash3Value,
hashValue,
len,
len0,
len1,
lenLimit,
matchMinPos,
maxLen,
offset,
pby1,
ptr0,
ptr1,
temp
if (this$static._pos + this$static._matchMaxLen <= this$static._streamPos) {
lenLimit = this$static._matchMaxLen
} else {
lenLimit = this$static._streamPos - this$static._pos
if (lenLimit < this$static.kMinMatchCheck) {
$MovePos_0(this$static)
return 0
}
}
offset = 0
matchMinPos =
this$static._pos > this$static._cyclicBufferSize
? this$static._pos - this$static._cyclicBufferSize
: 0
cur = this$static._bufferOffset + this$static._pos
maxLen = 1
hash2Value = 0
hash3Value = 0
if (this$static.HASH_ARRAY) {
temp =
CrcTable[this$static._bufferBase[cur] & 255] ^
(this$static._bufferBase[cur + 1] & 255)
hash2Value = temp & 1023
temp ^= (this$static._bufferBase[cur + 2] & 255) << 8
hash3Value = temp & 65535
hashValue =
(temp ^ (CrcTable[this$static._bufferBase[cur + 3] & 255] << 5)) &
this$static._hashMask
} else {
hashValue =
(this$static._bufferBase[cur] & 255) ^
((this$static._bufferBase[cur + 1] & 255) << 8)
}
curMatch = this$static._hash[this$static.kFixHashSize + hashValue] || 0
if (this$static.HASH_ARRAY) {
curMatch2 = this$static._hash[hash2Value] || 0
curMatch3 = this$static._hash[1024 + hash3Value] || 0
this$static._hash[hash2Value] = this$static._pos
this$static._hash[1024 + hash3Value] = this$static._pos
if (curMatch2 > matchMinPos) {
if (
this$static._bufferBase[this$static._bufferOffset + curMatch2] ==
this$static._bufferBase[cur]
) {
distances[offset++] = maxLen = 2
distances[offset++] = this$static._pos - curMatch2 - 1
}
}
if (curMatch3 > matchMinPos) {
if (
this$static._bufferBase[this$static._bufferOffset + curMatch3] ==
this$static._bufferBase[cur]
) {
if (curMatch3 == curMatch2) {
offset -= 2
}
distances[offset++] = maxLen = 3
distances[offset++] = this$static._pos - curMatch3 - 1
curMatch2 = curMatch3
}
}
if (offset != 0 && curMatch2 == curMatch) {
offset -= 2
maxLen = 1
}
}
this$static._hash[this$static.kFixHashSize + hashValue] = this$static._pos
ptr0 = (this$static._cyclicBufferPos << 1) + 1
ptr1 = this$static._cyclicBufferPos << 1
len0 = len1 = this$static.kNumHashDirectBytes
if (this$static.kNumHashDirectBytes != 0) {
if (curMatch > matchMinPos) {
if (
this$static._bufferBase[
this$static._bufferOffset + curMatch + this$static.kNumHashDirectBytes
] != this$static._bufferBase[cur + this$static.kNumHashDirectBytes]
) {
distances[offset++] = maxLen = this$static.kNumHashDirectBytes
distances[offset++] = this$static._pos - curMatch - 1
}
}
}
count = this$static._cutValue
while (1) {
if (curMatch <= matchMinPos || count-- == 0) {
this$static._son[ptr0] = this$static._son[ptr1] = 0
break
}
delta = this$static._pos - curMatch
cyclicPos =
(delta <= this$static._cyclicBufferPos
? this$static._cyclicBufferPos - delta
: this$static._cyclicBufferPos -
delta +
this$static._cyclicBufferSize) << 1
pby1 = this$static._bufferOffset + curMatch
len = len0 < len1 ? len0 : len1
if (
this$static._bufferBase[pby1 + len] == this$static._bufferBase[cur + len]
) {
while (++len != lenLimit) {
if (
this$static._bufferBase[pby1 + len] !=
this$static._bufferBase[cur + len]
) {
break
}
}
if (maxLen < len) {
distances[offset++] = maxLen = len
distances[offset++] = delta - 1
if (len == lenLimit) {
this$static._son[ptr1] = this$static._son[cyclicPos]
this$static._son[ptr0] = this$static._son[cyclicPos + 1]
break
}
}
}
if (
(this$static._bufferBase[pby1 + len] & 255) <
(this$static._bufferBase[cur + len] & 255)
) {
this$static._son[ptr1] = curMatch
ptr1 = cyclicPos + 1
curMatch = this$static._son[ptr1]
len1 = len
} else {
this$static._son[ptr0] = curMatch
ptr0 = cyclicPos
curMatch = this$static._son[ptr0]
len0 = len
}
}
$MovePos_0(this$static)
return offset
}
function $Init_5(this$static) {
this$static._bufferOffset = 0
this$static._pos = 0
this$static._streamPos = 0
this$static._streamEndWasReached = 0
$ReadBlock(this$static)
this$static._cyclicBufferPos = 0
$ReduceOffsets(this$static, -1)
}
function $MovePos_0(this$static) {
var subValue
if (++this$static._cyclicBufferPos >= this$static._cyclicBufferSize) {
this$static._cyclicBufferPos = 0
}
$MovePos_1(this$static)
if (this$static._pos == 1073741823) {
subValue = this$static._pos - this$static._cyclicBufferSize
$NormalizeLinks(
this$static._son,
this$static._cyclicBufferSize * 2,
subValue
)
$NormalizeLinks(this$static._hash, this$static._hashSizeSum, subValue)
$ReduceOffsets(this$static, subValue)
}
}
// NOTE: This is only called after reading one whole gigabyte.
function $NormalizeLinks(items, numItems, subValue) {
var i, value
for (i = 0; i < numItems; ++i) {
value = items[i] || 0
if (value <= subValue) {
value = 0
} else {
value -= subValue
}
items[i] = value
}
}
function $SetType(this$static, numHashBytes) {
this$static.HASH_ARRAY = numHashBytes > 2
if (this$static.HASH_ARRAY) {
this$static.kNumHashDirectBytes = 0
this$static.kMinMatchCheck = 4
this$static.kFixHashSize = 66560
} else {
this$static.kNumHashDirectBytes = 2
this$static.kMinMatchCheck = 3
this$static.kFixHashSize = 0
}
}
function $Skip(this$static, num) {
var count,
cur,
curMatch,
cyclicPos,
delta,
hash2Value,
hash3Value,
hashValue,
len,
len0,
len1,
lenLimit,
matchMinPos,
pby1,
ptr0,
ptr1,
temp
do {
if (this$static._pos + this$static._matchMaxLen <= this$static._streamPos) {
lenLimit = this$static._matchMaxLen
} else {
lenLimit = this$static._streamPos - this$static._pos
if (lenLimit < this$static.kMinMatchCheck) {
$MovePos_0(this$static)
continue
}
}
matchMinPos =
this$static._pos > this$static._cyclicBufferSize
? this$static._pos - this$static._cyclicBufferSize
: 0
cur = this$static._bufferOffset + this$static._pos
if (this$static.HASH_ARRAY) {
temp =
CrcTable[this$static._bufferBase[cur] & 255] ^
(this$static._bufferBase[cur + 1] & 255)
hash2Value = temp & 1023
this$static._hash[hash2Value] = this$static._pos
temp ^= (this$static._bufferBase[cur + 2] & 255) << 8
hash3Value = temp & 65535
this$static._hash[1024 + hash3Value] = this$static._pos
hashValue =
(temp ^ (CrcTable[this$static._bufferBase[cur + 3] & 255] << 5)) &
this$static._hashMask
} else {
hashValue =
(this$static._bufferBase[cur] & 255) ^
((this$static._bufferBase[cur + 1] & 255) << 8)
}
curMatch = this$static._hash[this$static.kFixHashSize + hashValue]
this$static._hash[this$static.kFixHashSize + hashValue] = this$static._pos
ptr0 = (this$static._cyclicBufferPos << 1) + 1
ptr1 = this$static._cyclicBufferPos << 1
len0 = len1 = this$static.kNumHashDirectBytes
count = this$static._cutValue
while (1) {
if (curMatch <= matchMinPos || count-- == 0) {
this$static._son[ptr0] = this$static._son[ptr1] = 0
break
}
delta = this$static._pos - curMatch
cyclicPos =
(delta <= this$static._cyclicBufferPos
? this$static._cyclicBufferPos - delta
: this$static._cyclicBufferPos -
delta +
this$static._cyclicBufferSize) << 1
pby1 = this$static._bufferOffset + curMatch
len = len0 < len1 ? len0 : len1
if (
this$static._bufferBase[pby1 + len] ==
this$static._bufferBase[cur + len]
) {
while (++len != lenLimit) {
if (
this$static._bufferBase[pby1 + len] !=
this$static._bufferBase[cur + len]
) {
break
}
}
if (len == lenLimit) {
this$static._son[ptr1] = this$static._son[cyclicPos]
this$static._son[ptr0] = this$static._son[cyclicPos + 1]
break
}
}
if (
(this$static._bufferBase[pby1 + len] & 255) <
(this$static._bufferBase[cur + len] & 255)
) {
this$static._son[ptr1] = curMatch
ptr1 = cyclicPos + 1
curMatch = this$static._son[ptr1]
len1 = len
} else {
this$static._son[ptr0] = curMatch
ptr0 = cyclicPos
curMatch = this$static._son[ptr0]
len0 = len
}
}
$MovePos_0(this$static)
} while (--num != 0)
}
function $CopyBlock(this$static, distance, len) {
var pos = this$static._pos - distance - 1
if (pos < 0) {
pos += this$static._windowSize
}
for (; len != 0; --len) {
if (pos >= this$static._windowSize) {
pos = 0
}
this$static._buffer[this$static._pos++] = this$static._buffer[pos++]
if (this$static._pos >= this$static._windowSize) {
$Flush_0(this$static)
}
}
}
function $Create_5(this$static, windowSize) {
if (this$static._buffer == null || this$static._windowSize != windowSize) {
this$static._buffer = initDim(windowSize)
}
this$static._windowSize = windowSize
this$static._pos = 0
this$static._streamPos = 0
}
function $Flush_0(this$static) {
var size = this$static._pos - this$static._streamPos
if (!size) {
return
}
$write_0(
this$static._stream,
this$static._buffer,
this$static._streamPos,
size
)
if (this$static._pos >= this$static._windowSize) {
this$static._pos = 0
}
this$static._streamPos = this$static._pos
}
function $GetByte(this$static, distance) {
var pos = this$static._pos - distance - 1
if (pos < 0) {
pos += this$static._windowSize
}
return this$static._buffer[pos]
}
function $PutByte(this$static, b) {
this$static._buffer[this$static._pos++] = b
if (this$static._pos >= this$static._windowSize) {
$Flush_0(this$static)
}
}
function $ReleaseStream(this$static) {
$Flush_0(this$static)
this$static._stream = null
}
function GetLenToPosState(len) {
len -= 2
if (len < 4) {
return len
}
return 3
}
function StateUpdateChar(index) {
if (index < 4) {
return 0
}
if (index < 10) {
return index - 3
}
return index - 6
}
function $Chunker_0(this$static, encoder) {
this$static.encoder = encoder
this$static.decoder = null
this$static.alive = 1
return this$static
}
function $Chunker(this$static, decoder) {
this$static.decoder = decoder
this$static.encoder = null
this$static.alive = 1
return this$static
}
function $processChunk(this$static) {
if (!this$static.alive) {
throw new Error('bad state')
}
if (this$static.encoder) {
$processEncoderChunk(this$static)
} else {
$processDecoderChunk(this$static)
}
return this$static.alive
}
function $processDecoderChunk(this$static) {
var result = $CodeOneChunk(this$static.decoder)
if (result == -1) {
throw new Error('corrupted input')
}
this$static.inBytesProcessed = N1_longLit
this$static.outBytesProcessed = this$static.decoder.nowPos64
if (
result ||
(compare(this$static.decoder.outSize, P0_longLit) >= 0 &&
compare(this$static.decoder.nowPos64, this$static.decoder.outSize) >= 0)
) {
$Flush_0(this$static.decoder.m_OutWindow)
$ReleaseStream(this$static.decoder.m_OutWindow)
this$static.decoder.m_RangeDecoder.Stream = null
this$static.alive = 0
}
}
function $processEncoderChunk(this$static) {
$CodeOneBlock(
this$static.encoder,
this$static.encoder.processedInSize,
this$static.encoder.processedOutSize,
this$static.encoder.finished
)
this$static.inBytesProcessed = this$static.encoder.processedInSize[0]
if (this$static.encoder.finished[0]) {
$ReleaseStreams(this$static.encoder)
this$static.alive = 0
}
}
function $CodeInChunks(this$static, inStream, outStream, outSize) {
this$static.m_RangeDecoder.Stream = inStream
$ReleaseStream(this$static.m_OutWindow)
this$static.m_OutWindow._stream = outStream
$Init_1(this$static)
this$static.state = 0
this$static.rep0 = 0
this$static.rep1 = 0
this$static.rep2 = 0
this$static.rep3 = 0
this$static.outSize = outSize
this$static.nowPos64 = P0_longLit
this$static.prevByte = 0
return $Chunker({}, this$static)
}
function $CodeOneChunk(this$static) {
var decoder2, distance, len, numDirectBits, posSlot, posState
posState = lowBits_0(this$static.nowPos64) & this$static.m_PosStateMask
if (
!$DecodeBit(
this$static.m_RangeDecoder,
this$static.m_IsMatchDecoders,
(this$static.state << 4) + posState
)
) {
decoder2 = $GetDecoder(
this$static.m_LiteralDecoder,
lowBits_0(this$static.nowPos64),
this$static.prevByte
)
if (this$static.state < 7) {
this$static.prevByte = $DecodeNormal(decoder2, this$static.m_RangeDecoder)
} else {
this$static.prevByte = $DecodeWithMatchByte(
decoder2,
this$static.m_RangeDecoder,
$GetByte(this$static.m_OutWindow, this$static.rep0)
)
}
$PutByte(this$static.m_OutWindow, this$static.prevByte)
this$static.state = StateUpdateChar(this$static.state)
this$static.nowPos64 = add(this$static.nowPos64, P1_longLit)
} else {
if (
$DecodeBit(
this$static.m_RangeDecoder,
this$static.m_IsRepDecoders,
this$static.state
)
) {
len = 0
if (
!$DecodeBit(
this$static.m_RangeDecoder,
this$static.m_IsRepG0Decoders,
this$static.state
)
) {
if (
!$DecodeBit(
this$static.m_RangeDecoder,
this$static.m_IsRep0LongDecoders,
(this$static.state << 4) + posState
)
) {
this$static.state = this$static.state < 7 ? 9 : 11
len = 1
}
} else {
if (
!$DecodeBit(
this$static.m_RangeDecoder,
this$static.m_IsRepG1Decoders,
this$static.state
)
) {
distance = this$static.rep1
} else {
if (
!$DecodeBit(
this$static.m_RangeDecoder,
this$static.m_IsRepG2Decoders,
this$static.state
)
) {
distance = this$static.rep2
} else {
distance = this$static.rep3
this$static.rep3 = this$static.rep2
}
this$static.rep2 = this$static.rep1
}
this$static.rep1 = this$static.rep0
this$static.rep0 = distance
}
if (!len) {
len =
$Decode(
this$static.m_RepLenDecoder,
this$static.m_RangeDecoder,
posState
) + 2
this$static.state = this$static.state < 7 ? 8 : 11
}
} else {
this$static.rep3 = this$static.rep2
this$static.rep2 = this$static.rep1
this$static.rep1 = this$static.rep0
len =
2 +
$Decode(this$static.m_LenDecoder, this$static.m_RangeDecoder, posState)
this$static.state = this$static.state < 7 ? 7 : 10
posSlot = $Decode_0(
this$static.m_PosSlotDecoder[GetLenToPosState(len)],
this$static.m_RangeDecoder
)
if (posSlot >= 4) {
numDirectBits = (posSlot >> 1) - 1
this$static.rep0 = (2 | (posSlot & 1)) << numDirectBits
if (posSlot < 14) {
this$static.rep0 += ReverseDecode(
this$static.m_PosDecoders,
this$static.rep0 - posSlot - 1,
this$static.m_RangeDecoder,
numDirectBits
)
} else {
this$static.rep0 +=
$DecodeDirectBits(this$static.m_RangeDecoder, numDirectBits - 4) <<
4
this$static.rep0 += $ReverseDecode(
this$static.m_PosAlignDecoder,
this$static.m_RangeDecoder
)
if (this$static.rep0 < 0) {
if (this$static.rep0 == -1) {
return 1
}
return -1
}
}
} else this$static.rep0 = posSlot
}
if (
compare(fromInt(this$static.rep0), this$static.nowPos64) >= 0 ||
this$static.rep0 >= this$static.m_DictionarySizeCheck
) {
return -1
}
$CopyBlock(this$static.m_OutWindow, this$static.rep0, len)
this$static.nowPos64 = add(this$static.nowPos64, fromInt(len))
this$static.prevByte = $GetByte(this$static.m_OutWindow, 0)
}
return 0
}
function $Decoder(this$static) {
this$static.m_OutWindow = {}
this$static.m_RangeDecoder = {}
this$static.m_IsMatchDecoders = initDim(192)
this$static.m_IsRepDecoders = initDim(12)
this$static.m_IsRepG0Decoders = initDim(12)
this$static.m_IsRepG1Decoders = initDim(12)
this$static.m_IsRepG2Decoders = initDim(12)
this$static.m_IsRep0LongDecoders = initDim(192)
this$static.m_PosSlotDecoder = initDim(4)
this$static.m_PosDecoders = initDim(114)
this$static.m_PosAlignDecoder = $BitTreeDecoder({}, 4)
this$static.m_LenDecoder = $Decoder$LenDecoder({})
this$static.m_RepLenDecoder = $Decoder$LenDecoder({})
this$static.m_LiteralDecoder = {}
for (var i = 0; i < 4; ++i) {
this$static.m_PosSlotDecoder[i] = $BitTreeDecoder({}, 6)
}
return this$static
}
function $Init_1(this$static) {
this$static.m_OutWindow._streamPos = 0
this$static.m_OutWindow._pos = 0
InitBitModels(this$static.m_IsMatchDecoders)
InitBitModels(this$static.m_IsRep0LongDecoders)
InitBitModels(this$static.m_IsRepDecoders)
InitBitModels(this$static.m_IsRepG0Decoders)
InitBitModels(this$static.m_IsRepG1Decoders)
InitBitModels(this$static.m_IsRepG2Decoders)
InitBitModels(this$static.m_PosDecoders)
$Init_0(this$static.m_LiteralDecoder)
for (var i = 0; i < 4; ++i) {
InitBitModels(this$static.m_PosSlotDecoder[i].Models)
}
$Init(this$static.m_LenDecoder)
$Init(this$static.m_RepLenDecoder)
InitBitModels(this$static.m_PosAlignDecoder.Models)
$Init_8(this$static.m_RangeDecoder)
}
function $SetDecoderProperties(this$static, properties) {
var dictionarySize, i, lc, lp, pb, remainder, val
if (properties.length < 5) return 0
val = properties[0] & 255
lc = val % 9
remainder = ~~(val / 9)
lp = remainder % 5
pb = ~~(remainder / 5)
dictionarySize = 0
for (i = 0; i < 4; ++i) {
dictionarySize += (properties[1 + i] & 255) << (i * 8)
}
// NOTE: If the input is bad, it might call for an insanely large dictionary size, which would crash the script.
if (dictionarySize > 99999999 || !$SetLcLpPb(this$static, lc, lp, pb)) {
return 0
}
return $SetDictionarySize(this$static, dictionarySize)
}
function $SetDictionarySize(this$static, dictionarySize) {
if (dictionarySize < 0) {
return 0
}
if (this$static.m_DictionarySize != dictionarySize) {
this$static.m_DictionarySize = dictionarySize
this$static.m_DictionarySizeCheck = Math.max(
this$static.m_DictionarySize,
1
)
$Create_5(
this$static.m_OutWindow,
Math.max(this$static.m_DictionarySizeCheck, 4096)
)
}
return 1
}
function $SetLcLpPb(this$static, lc, lp, pb) {
if (lc > 8 || lp > 4 || pb > 4) {
return 0
}
$Create_0(this$static.m_LiteralDecoder, lp, lc)
var numPosStates = 1 << pb
$Create(this$static.m_LenDecoder, numPosStates)
$Create(this$static.m_RepLenDecoder, numPosStates)
this$static.m_PosStateMask = numPosStates - 1
return 1
}
function $Create(this$static, numPosStates) {
for (
;
this$static.m_NumPosStates < numPosStates;
++this$static.m_NumPosStates
) {
this$static.m_LowCoder[this$static.m_NumPosStates] = $BitTreeDecoder({}, 3)
this$static.m_MidCoder[this$static.m_NumPosStates] = $BitTreeDecoder({}, 3)
}
}
function $Decode(this$static, rangeDecoder, posState) {
if (!$DecodeBit(rangeDecoder, this$static.m_Choice, 0)) {
return $Decode_0(this$static.m_LowCoder[posState], rangeDecoder)
}
var symbol = 8
if (!$DecodeBit(rangeDecoder, this$static.m_Choice, 1)) {
symbol += $Decode_0(this$static.m_MidCoder[posState], rangeDecoder)
} else {
symbol += 8 + $Decode_0(this$static.m_HighCoder, rangeDecoder)
}
return symbol
}
function $Decoder$LenDecoder(this$static) {
this$static.m_Choice = initDim(2)
this$static.m_LowCoder = initDim(16)
this$static.m_MidCoder = initDim(16)
this$static.m_HighCoder = $BitTreeDecoder({}, 8)
this$static.m_NumPosStates = 0
return this$static
}
function $Init(this$static) {
InitBitModels(this$static.m_Choice)
for (var posState = 0; posState < this$static.m_NumPosStates; ++posState) {
InitBitModels(this$static.m_LowCoder[posState].Models)
InitBitModels(this$static.m_MidCoder[posState].Models)
}
InitBitModels(this$static.m_HighCoder.Models)
}
function $Create_0(this$static, numPosBits, numPrevBits) {
var i, numStates
if (
this$static.m_Coders != null &&
this$static.m_NumPrevBits == numPrevBits &&
this$static.m_NumPosBits == numPosBits
)
return
this$static.m_NumPosBits = numPosBits
this$static.m_PosMask = (1 << numPosBits) - 1
this$static.m_NumPrevBits = numPrevBits
numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits)
this$static.m_Coders = initDim(numStates)
for (i = 0; i < numStates; ++i)
this$static.m_Coders[i] = $Decoder$LiteralDecoder$Decoder2({})
}
function $GetDecoder(this$static, pos, prevByte) {
return this$static.m_Coders[
((pos & this$static.m_PosMask) << this$static.m_NumPrevBits) +
((prevByte & 255) >>> (8 - this$static.m_NumPrevBits))
]
}
function $Init_0(this$static) {
var i, numStates
numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits)
for (i = 0; i < numStates; ++i) {
InitBitModels(this$static.m_Coders[i].m_Decoders)
}
}
function $DecodeNormal(this$static, rangeDecoder) {
var symbol = 1
do {
symbol =
(symbol << 1) | $DecodeBit(rangeDecoder, this$static.m_Decoders, symbol)
} while (symbol < 256)
return (symbol << 24) >> 24
}
function $DecodeWithMatchByte(this$static, rangeDecoder, matchByte) {
var bit,
matchBit,
symbol = 1
do {
matchBit = (matchByte >> 7) & 1
matchByte <<= 1
bit = $DecodeBit(
rangeDecoder,
this$static.m_Decoders,
((1 + matchBit) << 8) + symbol
)
symbol = (symbol << 1) | bit
if (matchBit != bit) {
while (symbol < 256) {
symbol =
(symbol << 1) |
$DecodeBit(rangeDecoder, this$static.m_Decoders, symbol)
}
break
}
} while (symbol < 256)
return (symbol << 24) >> 24
}
function $Decoder$LiteralDecoder$Decoder2(this$static) {
this$static.m_Decoders = initDim(768)
return this$static
}
var g_FastPos = (function() {
var j,
k,
slotFast,
c = 2,
g_FastPos = [0, 1]
for (slotFast = 2; slotFast < 22; ++slotFast) {
k = 1 << ((slotFast >> 1) - 1)
for (j = 0; j < k; ++j, ++c) g_FastPos[c] = (slotFast << 24) >> 24
}
return g_FastPos
})()
function $Backward(this$static, cur) {
var backCur, backMem, posMem, posPrev
this$static._optimumEndIndex = cur
posMem = this$static._optimum[cur].PosPrev
backMem = this$static._optimum[cur].BackPrev
do {
if (this$static._optimum[cur].Prev1IsChar) {
$MakeAsChar(this$static._optimum[posMem])
this$static._optimum[posMem].PosPrev = posMem - 1
if (this$static._optimum[cur].Prev2) {
this$static._optimum[posMem - 1].Prev1IsChar = 0
this$static._optimum[posMem - 1].PosPrev =
this$static._optimum[cur].PosPrev2
this$static._optimum[posMem - 1].BackPrev =
this$static._optimum[cur].BackPrev2
}
}
posPrev = posMem
backCur = backMem
backMem = this$static._optimum[posPrev].BackPrev
posMem = this$static._optimum[posPrev].PosPrev
this$static._optimum[posPrev].BackPrev = backCur
this$static._optimum[posPrev].PosPrev = cur
cur = posPrev
} while (cur > 0)
this$static.backRes = this$static._optimum[0].BackPrev
this$static._optimumCurrentIndex = this$static._optimum[0].PosPrev
return this$static._optimumCurrentIndex
}
function $BaseInit(this$static) {
this$static._state = 0
this$static._previousByte = 0
for (var i = 0; i < 4; ++i) {
this$static._repDistances[i] = 0
}
}
function $CodeOneBlock(this$static, inSize, outSize, finished) {
var baseVal,
complexState,
curByte,
distance,
footerBits,
i,
len,
lenToPosState,
matchByte,
pos,
posReduced,
posSlot,
posState,
progressPosValuePrev,
subCoder
inSize[0] = P0_longLit
outSize[0] = P0_longLit
finished[0] = 1
if (this$static._inStream) {
this$static._matchFinder._stream = this$static._inStream
$Init_5(this$static._matchFinder)
this$static._needReleaseMFStream = 1
this$static._inStream = null
}
if (this$static._finished) {
return
}
this$static._finished = 1
progressPosValuePrev = this$static.nowPos64
if (eq(this$static.nowPos64, P0_longLit)) {
if (!$GetNumAvailableBytes(this$static._matchFinder)) {
$Flush(this$static, lowBits_0(this$static.nowPos64))
return
}
$ReadMatchDistances(this$static)
posState = lowBits_0(this$static.nowPos64) & this$static._posStateMask
$Encode_3(
this$static._rangeEncoder,
this$static._isMatch,
(this$static._state << 4) + posState,
0
)
this$static._state = StateUpdateChar(this$static._state)
curByte = $GetIndexByte(
this$static._matchFinder,
-this$static._additionalOffset
)
$Encode_1(
$GetSubCoder(
this$static._literalEncoder,
lowBits_0(this$static.nowPos64),
this$static._previousByte
),
this$static._rangeEncoder,
curByte
)
this$static._previousByte = curByte
--this$static._additionalOffset
this$static.nowPos64 = add(this$static.nowPos64, P1_longLit)
}
if (!$GetNumAvailableBytes(this$static._matchFinder)) {
$Flush(this$static, lowBits_0(this$static.nowPos64))
return
}
while (1) {
len = $GetOptimum(this$static, lowBits_0(this$static.nowPos64))
pos = this$static.backRes
posState = lowBits_0(this$static.nowPos64) & this$static._posStateMask
complexState = (this$static._state << 4) + posState
if (len == 1 && pos == -1) {
$Encode_3(
this$static._rangeEncoder,
this$static._isMatch,
complexState,
0
)
curByte = $GetIndexByte(
this$static._matchFinder,
-this$static._additionalOffset
)
subCoder = $GetSubCoder(
this$static._literalEncoder,
lowBits_0(this$static.nowPos64),
this$static._previousByte
)
if (this$static._state < 7) {
$Encode_1(subCoder, this$static._rangeEncoder, curByte)
} else {
matchByte = $GetIndexByte(
this$static._matchFinder,
-this$static._repDistances[0] - 1 - this$static._additionalOffset
)
$EncodeMatched(subCoder, this$static._rangeEncoder, matchByte, curByte)
}
this$static._previousByte = curByte
this$static._state = StateUpdateChar(this$static._state)
} else {
$Encode_3(
this$static._rangeEncoder,
this$static._isMatch,
complexState,
1
)
if (pos < 4) {
$Encode_3(
this$static._rangeEncoder,
this$static._isRep,
this$static._state,
1
)
if (!pos) {
$Encode_3(
this$static._rangeEncoder,
this$static._isRepG0,
this$static._state,
0
)
if (len == 1) {
$Encode_3(
this$static._rangeEncoder,
this$static._isRep0Long,
complexState,
0
)
} else {
$Encode_3(
this$static._rangeEncoder,
this$static._isRep0Long,
complexState,
1
)
}
} else {
$Encode_3(
this$static._rangeEncoder,
this$static._isRepG0,
this$static._state,
1
)
if (pos == 1) {
$Encode_3(
this$static._rangeEncoder,
this$static._isRepG1,
this$static._state,
0
)
} else {
$Encode_3(
this$static._rangeEncoder,
this$static._isRepG1,
this$static._state,
1
)
$Encode_3(
this$static._rangeEncoder,
this$static._isRepG2,
this$static._state,
pos - 2
)
}
}
if (len == 1) {
this$static._state = this$static._state < 7 ? 9 : 11
} else {
$Encode_0(
this$static._repMatchLenEncoder,
this$static._rangeEncoder,
len - 2,
posState
)
this$static._state = this$static._state < 7 ? 8 : 11
}
distance = this$static._repDistances[pos]
if (pos != 0) {
for (i = pos; i >= 1; --i) {
this$static._repDistances[i] = this$static._repDistances[i - 1]
}
this$static._repDistances[0] = distance
}
} else {
$Encode_3(
this$static._rangeEncoder,
this$static._isRep,
this$static._state,
0
)
this$static._state = this$static._state < 7 ? 7 : 10
$Encode_0(
this$static._lenEncoder,
this$static._rangeEncoder,
len - 2,
posState
)
pos -= 4
posSlot = GetPosSlot(pos)
lenToPosState = GetLenToPosState(len)
$Encode_2(
this$static._posSlotEncoder[lenToPosState],
this$static._rangeEncoder,
posSlot
)
if (posSlot >= 4) {
footerBits = (posSlot >> 1) - 1
baseVal = (2 | (posSlot & 1)) << footerBits
posReduced = pos - baseVal
if (posSlot < 14) {
ReverseEncode(
this$static._posEncoders,
baseVal - posSlot - 1,
this$static._rangeEncoder,
footerBits,
posReduced
)
} else {
$EncodeDirectBits(
this$static._rangeEncoder,
posReduced >> 4,
footerBits - 4
)
$ReverseEncode(
this$static._posAlignEncoder,
this$static._rangeEncoder,
posReduced & 15
)
++this$static._alignPriceCount
}
}
distance = pos
for (i = 3; i >= 1; --i) {
this$static._repDistances[i] = this$static._repDistances[i - 1]
}
this$static._repDistances[0] = distance
++this$static._matchPriceCount
}
this$static._previousByte = $GetIndexByte(
this$static._matchFinder,
len - 1 - this$static._additionalOffset
)
}
this$static._additionalOffset -= len
this$static.nowPos64 = add(this$static.nowPos64, fromInt(len))
if (!this$static._additionalOffset) {
if (this$static._matchPriceCount >= 128) {
$FillDistancesPrices(this$static)
}
if (this$static._alignPriceCount >= 16) {
$FillAlignPrices(this$static)
}
inSize[0] = this$static.nowPos64
outSize[0] = $GetProcessedSizeAdd(this$static._rangeEncoder)
if (!$GetNumAvailableBytes(this$static._matchFinder)) {
$Flush(this$static, lowBits_0(this$static.nowPos64))
return
}
if (
compare(sub(this$static.nowPos64, progressPosValuePrev), [4096, 0]) >= 0
) {
this$static._finished = 0
finished[0] = 0
return
}
}
}
}
function $Create_2(this$static) {
var bt, numHashBytes
if (!this$static._matchFinder) {
bt = {}
numHashBytes = 4
if (!this$static._matchFinderType) {
numHashBytes = 2
}
$SetType(bt, numHashBytes)
this$static._matchFinder = bt
}
$Create_1(
this$static._literalEncoder,
this$static._numLiteralPosStateBits,
this$static._numLiteralContextBits
)
if (
this$static._dictionarySize == this$static._dictionarySizePrev &&
this$static._numFastBytesPrev == this$static._numFastBytes
) {
return
}
$Create_3(
this$static._matchFinder,
this$static._dictionarySize,
4096,
this$static._numFastBytes,
274
)
this$static._dictionarySizePrev = this$static._dictionarySize
this$static._numFastBytesPrev = this$static._numFastBytes
}
function $Encoder(this$static) {
var i
this$static._repDistances = initDim(4)
this$static._optimum = []
this$static._rangeEncoder = {}
this$static._isMatch = initDim(192)
this$static._isRep = initDim(12)
this$static._isRepG0 = initDim(12)
this$static._isRepG1 = initDim(12)
this$static._isRepG2 = initDim(12)
this$static._isRep0Long = initDim(192)
this$static._posSlotEncoder = []
this$static._posEncoders = initDim(114)
this$static._posAlignEncoder = $BitTreeEncoder({}, 4)
this$static._lenEncoder = $Encoder$LenPriceTableEncoder({})
this$static._repMatchLenEncoder = $Encoder$LenPriceTableEncoder({})
this$static._literalEncoder = {}
this$static._matchDistances = []
this$static._posSlotPrices = []
this$static._distancesPrices = []
this$static._alignPrices = initDim(16)
this$static.reps = initDim(4)
this$static.repLens = initDim(4)
this$static.processedInSize = [P0_longLit]
this$static.processedOutSize = [P0_longLit]
this$static.finished = [0]
this$static.properties = initDim(5)
this$static.tempPrices = initDim(128)
this$static._longestMatchLength = 0
this$static._matchFinderType = 1
this$static._numDistancePairs = 0
this$static._numFastBytesPrev = -1
this$static.backRes = 0
for (i = 0; i < 4096; ++i) {
this$static._optimum[i] = {}
}
for (i = 0; i < 4; ++i) {
this$static._posSlotEncoder[i] = $BitTreeEncoder({}, 6)
}
return this$static
}
function $FillAlignPrices(this$static) {
for (var i = 0; i < 16; ++i) {
this$static._alignPrices[i] = $ReverseGetPrice(
this$static._posAlignEncoder,
i
)
}
this$static._alignPriceCount = 0
}
function $FillDistancesPrices(this$static) {
var baseVal, encoder, footerBits, i, lenToPosState, posSlot, st, st2
for (i = 4; i < 128; ++i) {
posSlot = GetPosSlot(i)
footerBits = (posSlot >> 1) - 1
baseVal = (2 | (posSlot & 1)) << footerBits
this$static.tempPrices[i] = ReverseGetPrice(
this$static._posEncoders,
baseVal - posSlot - 1,
footerBits,
i - baseVal
)
}
for (lenToPosState = 0; lenToPosState < 4; ++lenToPosState) {
encoder = this$static._posSlotEncoder[lenToPosState]
st = lenToPosState << 6
for (posSlot = 0; posSlot < this$static._distTableSize; ++posSlot) {
this$static._posSlotPrices[st + posSlot] = $GetPrice_1(encoder, posSlot)
}
for (posSlot = 14; posSlot < this$static._distTableSize; ++posSlot) {
this$static._posSlotPrices[st + posSlot] += ((posSlot >> 1) - 1 - 4) << 6
}
st2 = lenToPosState * 128
for (i = 0; i < 4; ++i) {
this$static._distancesPrices[st2 + i] = this$static._posSlotPrices[st + i]
}
for (; i < 128; ++i) {
this$static._distancesPrices[st2 + i] =
this$static._posSlotPrices[st + GetPosSlot(i)] +
this$static.tempPrices[i]
}
}
this$static._matchPriceCount = 0
}
function $Flush(this$static, nowPos) {
$ReleaseMFStream(this$static)
$WriteEndMarker(this$static, nowPos & this$static._posStateMask)
for (var i = 0; i < 5; ++i) {
$ShiftLow(this$static._rangeEncoder)
}
}
function $GetOptimum(this$static, position) {
var cur,
curAnd1Price,
curAndLenCharPrice,
curAndLenPrice,
curBack,
curPrice,
currentByte,
distance,
i,
len,
lenEnd,
lenMain,
lenRes,
lenTest,
lenTest2,
lenTestTemp,
matchByte,
matchPrice,
newLen,
nextIsChar,
nextMatchPrice,
nextOptimum,
nextRepMatchPrice,
normalMatchPrice,
numAvailableBytes,
numAvailableBytesFull,
numDistancePairs,
offs,
offset,
opt,
optimum,
pos,
posPrev,
posState,
posStateNext,
price_4,
repIndex,
repLen,
repMatchPrice,
repMaxIndex,
shortRepPrice,
startLen,
state,
state2,
t,
price,
price_0,
price_1,
price_2,
price_3
if (this$static._optimumEndIndex != this$static._optimumCurrentIndex) {
lenRes =
this$static._optimum[this$static._optimumCurrentIndex].PosPrev -
this$static._optimumCurrentIndex
this$static.backRes =
this$static._optimum[this$static._optimumCurrentIndex].BackPrev
this$static._optimumCurrentIndex =
this$static._optimum[this$static._optimumCurrentIndex].PosPrev
return lenRes
}
this$static._optimumCurrentIndex = this$static._optimumEndIndex = 0
if (this$static._longestMatchWasFound) {
lenMain = this$static._longestMatchLength
this$static._longestMatchWasFound = 0
} else {
lenMain = $ReadMatchDistances(this$static)
}
numDistancePairs = this$static._numDistancePairs
numAvailableBytes = $GetNumAvailableBytes(this$static._matchFinder) + 1
if (numAvailableBytes < 2) {
this$static.backRes = -1
return 1
}
if (numAvailableBytes > 273) {
numAvailableBytes = 273
}
repMaxIndex = 0
for (i = 0; i < 4; ++i) {
this$static.reps[i] = this$static._repDistances[i]
this$static.repLens[i] = $GetMatchLen(
this$static._matchFinder,
-1,
this$static.reps[i],
273
)
if (this$static.repLens[i] > this$static.repLens[repMaxIndex]) {
repMaxIndex = i
}
}
if (this$static.repLens[repMaxIndex] >= this$static._numFastBytes) {
this$static.backRes = repMaxIndex
lenRes = this$static.repLens[repMaxIndex]
$MovePos(this$static, lenRes - 1)
return lenRes
}
if (lenMain >= this$static._numFastBytes) {
this$static.backRes = this$static._matchDistances[numDistancePairs - 1] + 4
$MovePos(this$static, lenMain - 1)
return lenMain
}
currentByte = $GetIndexByte(this$static._matchFinder, -1)
matchByte = $GetIndexByte(
this$static._matchFinder,
-this$static._repDistances[0] - 1 - 1
)
if (
lenMain < 2 &&
currentByte != matchByte &&
this$static.repLens[repMaxIndex] < 2
) {
this$static.backRes = -1
return 1
}
this$static._optimum[0].State = this$static._state
posState = position & this$static._posStateMask
this$static._optimum[1].Price =
ProbPrices[
this$static._isMatch[(this$static._state << 4) + posState] >>> 2
] +
$GetPrice_0(
$GetSubCoder(
this$static._literalEncoder,
position,
this$static._previousByte
),
this$static._state >= 7,
matchByte,
currentByte
)
$MakeAsChar(this$static._optimum[1])
matchPrice =
ProbPrices[
(2048 - this$static._isMatch[(this$static._state << 4) + posState]) >>> 2
]
repMatchPrice =
matchPrice +
ProbPrices[(2048 - this$static._isRep[this$static._state]) >>> 2]
if (matchByte == currentByte) {
shortRepPrice =
repMatchPrice +
$GetRepLen1Price(this$static, this$static._state, posState)
if (shortRepPrice < this$static._optimum[1].Price) {
this$static._optimum[1].Price = shortRepPrice
$MakeAsShortRep(this$static._optimum[1])
}
}
lenEnd =
lenMain >= this$static.repLens[repMaxIndex]
? lenMain
: this$static.repLens[repMaxIndex]
if (lenEnd < 2) {
this$static.backRes = this$static._optimum[1].BackPrev
return 1
}
this$static._optimum[1].PosPrev = 0
this$static._optimum[0].Backs0 = this$static.reps[0]
this$static._optimum[0].Backs1 = this$static.reps[1]
this$static._optimum[0].Backs2 = this$static.reps[2]
this$static._optimum[0].Backs3 = this$static.reps[3]
len = lenEnd
do {
this$static._optimum[len--].Price = 268435455
} while (len >= 2)
for (i = 0; i < 4; ++i) {
repLen = this$static.repLens[i]
if (repLen < 2) {
continue
}
price_4 =
repMatchPrice +
$GetPureRepPrice(this$static, i, this$static._state, posState)
do {
curAndLenPrice =
price_4 +
$GetPrice(this$static._repMatchLenEncoder, repLen - 2, posState)
optimum = this$static._optimum[repLen]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = 0
optimum.BackPrev = i
optimum.Prev1IsChar = 0
}
} while (--repLen >= 2)
}
normalMatchPrice =
matchPrice + ProbPrices[this$static._isRep[this$static._state] >>> 2]
len = this$static.repLens[0] >= 2 ? this$static.repLens[0] + 1 : 2
if (len <= lenMain) {
offs = 0
while (len > this$static._matchDistances[offs]) {
offs += 2
}
for (; ; ++len) {
distance = this$static._matchDistances[offs + 1]
curAndLenPrice =
normalMatchPrice + $GetPosLenPrice(this$static, distance, len, posState)
optimum = this$static._optimum[len]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = 0
optimum.BackPrev = distance + 4
optimum.Prev1IsChar = 0
}
if (len == this$static._matchDistances[offs]) {
offs += 2
if (offs == numDistancePairs) {
break
}
}
}
}
cur = 0
while (1) {
++cur
if (cur == lenEnd) {
return $Backward(this$static, cur)
}
newLen = $ReadMatchDistances(this$static)
numDistancePairs = this$static._numDistancePairs
if (newLen >= this$static._numFastBytes) {
this$static._longestMatchLength = newLen
this$static._longestMatchWasFound = 1
return $Backward(this$static, cur)
}
++position
posPrev = this$static._optimum[cur].PosPrev
if (this$static._optimum[cur].Prev1IsChar) {
--posPrev
if (this$static._optimum[cur].Prev2) {
state = this$static._optimum[this$static._optimum[cur].PosPrev2].State
if (this$static._optimum[cur].BackPrev2 < 4) {
state = state < 7 ? 8 : 11
} else {
state = state < 7 ? 7 : 10
}
} else {
state = this$static._optimum[posPrev].State
}
state = StateUpdateChar(state)
} else {
state = this$static._optimum[posPrev].State
}
if (posPrev == cur - 1) {
if (!this$static._optimum[cur].BackPrev) {
state = state < 7 ? 9 : 11
} else {
state = StateUpdateChar(state)
}
} else {
if (
this$static._optimum[cur].Prev1IsChar &&
this$static._optimum[cur].Prev2
) {
posPrev = this$static._optimum[cur].PosPrev2
pos = this$static._optimum[cur].BackPrev2
state = state < 7 ? 8 : 11
} else {
pos = this$static._optimum[cur].BackPrev
if (pos < 4) {
state = state < 7 ? 8 : 11
} else {
state = state < 7 ? 7 : 10
}
}
opt = this$static._optimum[posPrev]
if (pos < 4) {
if (!pos) {
this$static.reps[0] = opt.Backs0
this$static.reps[1] = opt.Backs1
this$static.reps[2] = opt.Backs2
this$static.reps[3] = opt.Backs3
} else if (pos == 1) {
this$static.reps[0] = opt.Backs1
this$static.reps[1] = opt.Backs0
this$static.reps[2] = opt.Backs2
this$static.reps[3] = opt.Backs3
} else if (pos == 2) {
this$static.reps[0] = opt.Backs2
this$static.reps[1] = opt.Backs0
this$static.reps[2] = opt.Backs1
this$static.reps[3] = opt.Backs3
} else {
this$static.reps[0] = opt.Backs3
this$static.reps[1] = opt.Backs0
this$static.reps[2] = opt.Backs1
this$static.reps[3] = opt.Backs2
}
} else {
this$static.reps[0] = pos - 4
this$static.reps[1] = opt.Backs0
this$static.reps[2] = opt.Backs1
this$static.reps[3] = opt.Backs2
}
}
this$static._optimum[cur].State = state
this$static._optimum[cur].Backs0 = this$static.reps[0]
this$static._optimum[cur].Backs1 = this$static.reps[1]
this$static._optimum[cur].Backs2 = this$static.reps[2]
this$static._optimum[cur].Backs3 = this$static.reps[3]
curPrice = this$static._optimum[cur].Price
currentByte = $GetIndexByte(this$static._matchFinder, -1)
matchByte = $GetIndexByte(
this$static._matchFinder,
-this$static.reps[0] - 1 - 1
)
posState = position & this$static._posStateMask
curAnd1Price =
curPrice +
ProbPrices[this$static._isMatch[(state << 4) + posState] >>> 2] +
$GetPrice_0(
$GetSubCoder(
this$static._literalEncoder,
position,
$GetIndexByte(this$static._matchFinder, -2)
),
state >= 7,
matchByte,
currentByte
)
nextOptimum = this$static._optimum[cur + 1]
nextIsChar = 0
if (curAnd1Price < nextOptimum.Price) {
nextOptimum.Price = curAnd1Price
nextOptimum.PosPrev = cur
nextOptimum.BackPrev = -1
nextOptimum.Prev1IsChar = 0
nextIsChar = 1
}
matchPrice =
curPrice +
ProbPrices[(2048 - this$static._isMatch[(state << 4) + posState]) >>> 2]
repMatchPrice =
matchPrice + ProbPrices[(2048 - this$static._isRep[state]) >>> 2]
if (
matchByte == currentByte &&
!(nextOptimum.PosPrev < cur && !nextOptimum.BackPrev)
) {
shortRepPrice =
repMatchPrice +
(ProbPrices[this$static._isRepG0[state] >>> 2] +
ProbPrices[this$static._isRep0Long[(state << 4) + posState] >>> 2])
if (shortRepPrice <= nextOptimum.Price) {
nextOptimum.Price = shortRepPrice
nextOptimum.PosPrev = cur
nextOptimum.BackPrev = 0
nextOptimum.Prev1IsChar = 0
nextIsChar = 1
}
}
numAvailableBytesFull = $GetNumAvailableBytes(this$static._matchFinder) + 1
numAvailableBytesFull =
4095 - cur < numAvailableBytesFull ? 4095 - cur : numAvailableBytesFull
numAvailableBytes = numAvailableBytesFull
if (numAvailableBytes < 2) {
continue
}
if (numAvailableBytes > this$static._numFastBytes) {
numAvailableBytes = this$static._numFastBytes
}
if (!nextIsChar && matchByte != currentByte) {
t = Math.min(numAvailableBytesFull - 1, this$static._numFastBytes)
lenTest2 = $GetMatchLen(
this$static._matchFinder,
0,
this$static.reps[0],
t
)
if (lenTest2 >= 2) {
state2 = StateUpdateChar(state)
posStateNext = (position + 1) & this$static._posStateMask
nextRepMatchPrice =
curAnd1Price +
ProbPrices[
(2048 - this$static._isMatch[(state2 << 4) + posStateNext]) >>> 2
] +
ProbPrices[(2048 - this$static._isRep[state2]) >>> 2]
offset = cur + 1 + lenTest2
while (lenEnd < offset) {
this$static._optimum[++lenEnd].Price = 268435455
}
curAndLenPrice =
nextRepMatchPrice +
((price = $GetPrice(
this$static._repMatchLenEncoder,
lenTest2 - 2,
posStateNext
)),
price + $GetPureRepPrice(this$static, 0, state2, posStateNext))
optimum = this$static._optimum[offset]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = cur + 1
optimum.BackPrev = 0
optimum.Prev1IsChar = 1
optimum.Prev2 = 0
}
}
}
startLen = 2
for (repIndex = 0; repIndex < 4; ++repIndex) {
lenTest = $GetMatchLen(
this$static._matchFinder,
-1,
this$static.reps[repIndex],
numAvailableBytes
)
if (lenTest < 2) {
continue
}
lenTestTemp = lenTest
do {
while (lenEnd < cur + lenTest) {
this$static._optimum[++lenEnd].Price = 268435455
}
curAndLenPrice =
repMatchPrice +
((price_0 = $GetPrice(
this$static._repMatchLenEncoder,
lenTest - 2,
posState
)),
price_0 + $GetPureRepPrice(this$static, repIndex, state, posState))
optimum = this$static._optimum[cur + lenTest]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = cur
optimum.BackPrev = repIndex
optimum.Prev1IsChar = 0
}
} while (--lenTest >= 2)
lenTest = lenTestTemp
if (!repIndex) {
startLen = lenTest + 1
}
if (lenTest < numAvailableBytesFull) {
t = Math.min(
numAvailableBytesFull - 1 - lenTest,
this$static._numFastBytes
)
lenTest2 = $GetMatchLen(
this$static._matchFinder,
lenTest,
this$static.reps[repIndex],
t
)
if (lenTest2 >= 2) {
state2 = state < 7 ? 8 : 11
posStateNext = (position + lenTest) & this$static._posStateMask
curAndLenCharPrice =
repMatchPrice +
((price_1 = $GetPrice(
this$static._repMatchLenEncoder,
lenTest - 2,
posState
)),
price_1 +
$GetPureRepPrice(this$static, repIndex, state, posState)) +
ProbPrices[
this$static._isMatch[(state2 << 4) + posStateNext] >>> 2
] +
$GetPrice_0(
$GetSubCoder(
this$static._literalEncoder,
position + lenTest,
$GetIndexByte(this$static._matchFinder, lenTest - 1 - 1)
),
1,
$GetIndexByte(
this$static._matchFinder,
lenTest - 1 - (this$static.reps[repIndex] + 1)
),
$GetIndexByte(this$static._matchFinder, lenTest - 1)
)
state2 = StateUpdateChar(state2)
posStateNext = (position + lenTest + 1) & this$static._posStateMask
nextMatchPrice =
curAndLenCharPrice +
ProbPrices[
(2048 - this$static._isMatch[(state2 << 4) + posStateNext]) >>> 2
]
nextRepMatchPrice =
nextMatchPrice +
ProbPrices[(2048 - this$static._isRep[state2]) >>> 2]
offset = lenTest + 1 + lenTest2
while (lenEnd < cur + offset) {
this$static._optimum[++lenEnd].Price = 268435455
}
curAndLenPrice =
nextRepMatchPrice +
((price_2 = $GetPrice(
this$static._repMatchLenEncoder,
lenTest2 - 2,
posStateNext
)),
price_2 + $GetPureRepPrice(this$static, 0, state2, posStateNext))
optimum = this$static._optimum[cur + offset]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = cur + lenTest + 1
optimum.BackPrev = 0
optimum.Prev1IsChar = 1
optimum.Prev2 = 1
optimum.PosPrev2 = cur
optimum.BackPrev2 = repIndex
}
}
}
}
if (newLen > numAvailableBytes) {
newLen = numAvailableBytes
for (
numDistancePairs = 0;
newLen > this$static._matchDistances[numDistancePairs];
numDistancePairs += 2
) {}
this$static._matchDistances[numDistancePairs] = newLen
numDistancePairs += 2
}
if (newLen >= startLen) {
normalMatchPrice =
matchPrice + ProbPrices[this$static._isRep[state] >>> 2]
while (lenEnd < cur + newLen) {
this$static._optimum[++lenEnd].Price = 268435455
}
offs = 0
while (startLen > this$static._matchDistances[offs]) {
offs += 2
}
for (lenTest = startLen; ; ++lenTest) {
curBack = this$static._matchDistances[offs + 1]
curAndLenPrice =
normalMatchPrice +
$GetPosLenPrice(this$static, curBack, lenTest, posState)
optimum = this$static._optimum[cur + lenTest]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = cur
optimum.BackPrev = curBack + 4
optimum.Prev1IsChar = 0
}
if (lenTest == this$static._matchDistances[offs]) {
if (lenTest < numAvailableBytesFull) {
t = Math.min(
numAvailableBytesFull - 1 - lenTest,
this$static._numFastBytes
)
lenTest2 = $GetMatchLen(
this$static._matchFinder,
lenTest,
curBack,
t
)
if (lenTest2 >= 2) {
state2 = state < 7 ? 7 : 10
posStateNext = (position + lenTest) & this$static._posStateMask
curAndLenCharPrice =
curAndLenPrice +
ProbPrices[
this$static._isMatch[(state2 << 4) + posStateNext] >>> 2
] +
$GetPrice_0(
$GetSubCoder(
this$static._literalEncoder,
position + lenTest,
$GetIndexByte(this$static._matchFinder, lenTest - 1 - 1)
),
1,
$GetIndexByte(
this$static._matchFinder,
lenTest - (curBack + 1) - 1
),
$GetIndexByte(this$static._matchFinder, lenTest - 1)
)
state2 = StateUpdateChar(state2)
posStateNext =
(position + lenTest + 1) & this$static._posStateMask
nextMatchPrice =
curAndLenCharPrice +
ProbPrices[
(2048 -
this$static._isMatch[(state2 << 4) + posStateNext]) >>>
2
]
nextRepMatchPrice =
nextMatchPrice +
ProbPrices[(2048 - this$static._isRep[state2]) >>> 2]
offset = lenTest + 1 + lenTest2
while (lenEnd < cur + offset) {
this$static._optimum[++lenEnd].Price = 268435455
}
curAndLenPrice =
nextRepMatchPrice +
((price_3 = $GetPrice(
this$static._repMatchLenEncoder,
lenTest2 - 2,
posStateNext
)),
price_3 +
$GetPureRepPrice(this$static, 0, state2, posStateNext))
optimum = this$static._optimum[cur + offset]
if (curAndLenPrice < optimum.Price) {
optimum.Price = curAndLenPrice
optimum.PosPrev = cur + lenTest + 1
optimum.BackPrev = 0
optimum.Prev1IsChar = 1
optimum.Prev2 = 1
optimum.PosPrev2 = cur
optimum.BackPrev2 = curBack + 4
}
}
}
offs += 2
if (offs == numDistancePairs) break
}
}
}
}
}
function $GetPosLenPrice(this$static, pos, len, posState) {
var price,
lenToPosState = GetLenToPosState(len)
if (pos < 128) {
price = this$static._distancesPrices[lenToPosState * 128 + pos]
} else {
price =
this$static._posSlotPrices[(lenToPosState << 6) + GetPosSlot2(pos)] +
this$static._alignPrices[pos & 15]
}
return price + $GetPrice(this$static._lenEncoder, len - 2, posState)
}
function $GetPureRepPrice(this$static, repIndex, state, posState) {
var price
if (!repIndex) {
price = ProbPrices[this$static._isRepG0[state] >>> 2]
price +=
ProbPrices[
(2048 - this$static._isRep0Long[(state << 4) + posState]) >>> 2
]
} else {
price = ProbPrices[(2048 - this$static._isRepG0[state]) >>> 2]
if (repIndex == 1) {
price += ProbPrices[this$static._isRepG1[state] >>> 2]
} else {
price += ProbPrices[(2048 - this$static._isRepG1[state]) >>> 2]
price += GetPrice(this$static._isRepG2[state], repIndex - 2)
}
}
return price
}
function $GetRepLen1Price(this$static, state, posState) {
return (
ProbPrices[this$static._isRepG0[state] >>> 2] +
ProbPrices[this$static._isRep0Long[(state << 4) + posState] >>> 2]
)
}
function $Init_4(this$static) {
$BaseInit(this$static)
$Init_9(this$static._rangeEncoder)
InitBitModels(this$static._isMatch)
InitBitModels(this$static._isRep0Long)
InitBitModels(this$static._isRep)
InitBitModels(this$static._isRepG0)
InitBitModels(this$static._isRepG1)
InitBitModels(this$static._isRepG2)
InitBitModels(this$static._posEncoders)
$Init_3(this$static._literalEncoder)
for (var i = 0; i < 4; ++i) {
InitBitModels(this$static._posSlotEncoder[i].Models)
}
$Init_2(this$static._lenEncoder, 1 << this$static._posStateBits)
$Init_2(this$static._repMatchLenEncoder, 1 << this$static._posStateBits)
InitBitModels(this$static._posAlignEncoder.Models)
this$static._longestMatchWasFound = 0
this$static._optimumEndIndex = 0
this$static._optimumCurrentIndex = 0
this$static._additionalOffset = 0
}
function $MovePos(this$static, num) {
if (num > 0) {
$Skip(this$static._matchFinder, num)
this$static._additionalOffset += num
}
}
function $ReadMatchDistances(this$static) {
var lenRes = 0
this$static._numDistancePairs = $GetMatches(
this$static._matchFinder,
this$static._matchDistances
)
if (this$static._numDistancePairs > 0) {
lenRes = this$static._matchDistances[this$static._numDistancePairs - 2]
if (lenRes == this$static._numFastBytes)
lenRes += $GetMatchLen(
this$static._matchFinder,
lenRes - 1,
this$static._matchDistances[this$static._numDistancePairs - 1],
273 - lenRes
)
}
++this$static._additionalOffset
return lenRes
}
function $ReleaseMFStream(this$static) {
if (this$static._matchFinder && this$static._needReleaseMFStream) {
this$static._matchFinder._stream = null
this$static._needReleaseMFStream = 0
}
}
function $ReleaseStreams(this$static) {
$ReleaseMFStream(this$static)
this$static._rangeEncoder.Stream = null
}
function $SetDictionarySize_0(this$static, dictionarySize) {
this$static._dictionarySize = dictionarySize
for (var dicLogSize = 0; dictionarySize > 1 << dicLogSize; ++dicLogSize) {}
this$static._distTableSize = dicLogSize * 2
}
function $SetMatchFinder(this$static, matchFinderIndex) {
var matchFinderIndexPrev = this$static._matchFinderType
this$static._matchFinderType = matchFinderIndex
if (
this$static._matchFinder &&
matchFinderIndexPrev != this$static._matchFinderType
) {
this$static._dictionarySizePrev = -1
this$static._matchFinder = null
}
}
function $WriteCoderProperties(this$static, outStream) {
this$static.properties[0] =
(((this$static._posStateBits * 5 + this$static._numLiteralPosStateBits) *
9 +
this$static._numLiteralContextBits) <<
24) >>
24
for (var i = 0; i < 4; ++i) {
this$static.properties[1 + i] =
((this$static._dictionarySize >> (8 * i)) << 24) >> 24
}
$write_0(outStream, this$static.properties, 0, 5)
}
function $WriteEndMarker(this$static, posState) {
if (!this$static._writeEndMark) {
return
}
$Encode_3(
this$static._rangeEncoder,
this$static._isMatch,
(this$static._state << 4) + posState,
1
)
$Encode_3(
this$static._rangeEncoder,
this$static._isRep,
this$static._state,
0
)
this$static._state = this$static._state < 7 ? 7 : 10
$Encode_0(this$static._lenEncoder, this$static._rangeEncoder, 0, posState)
var lenToPosState = GetLenToPosState(2)
$Encode_2(
this$static._posSlotEncoder[lenToPosState],
this$static._rangeEncoder,
63
)
$EncodeDirectBits(this$static._rangeEncoder, 67108863, 26)
$ReverseEncode(this$static._posAlignEncoder, this$static._rangeEncoder, 15)
}
function GetPosSlot(pos) {
if (pos < 2048) {
return g_FastPos[pos]
}
if (pos < 2097152) {
return g_FastPos[pos >> 10] + 20
}
return g_FastPos[pos >> 20] + 40
}
function GetPosSlot2(pos) {
if (pos < 131072) {
return g_FastPos[pos >> 6] + 12
}
if (pos < 134217728) {
return g_FastPos[pos >> 16] + 32
}
return g_FastPos[pos >> 26] + 52
}
function $Encode(this$static, rangeEncoder, symbol, posState) {
if (symbol < 8) {
$Encode_3(rangeEncoder, this$static._choice, 0, 0)
$Encode_2(this$static._lowCoder[posState], rangeEncoder, symbol)
} else {
symbol -= 8
$Encode_3(rangeEncoder, this$static._choice, 0, 1)
if (symbol < 8) {
$Encode_3(rangeEncoder, this$static._choice, 1, 0)
$Encode_2(this$static._midCoder[posState], rangeEncoder, symbol)
} else {
$Encode_3(rangeEncoder, this$static._choice, 1, 1)
$Encode_2(this$static._highCoder, rangeEncoder, symbol - 8)
}
}
}
function $Encoder$LenEncoder(this$static) {
this$static._choice = initDim(2)
this$static._lowCoder = initDim(16)
this$static._midCoder = initDim(16)
this$static._highCoder = $BitTreeEncoder({}, 8)
for (var posState = 0; posState < 16; ++posState) {
this$static._lowCoder[posState] = $BitTreeEncoder({}, 3)
this$static._midCoder[posState] = $BitTreeEncoder({}, 3)
}
return this$static
}
function $Init_2(this$static, numPosStates) {
InitBitModels(this$static._choice)
for (var posState = 0; posState < numPosStates; ++posState) {
InitBitModels(this$static._lowCoder[posState].Models)
InitBitModels(this$static._midCoder[posState].Models)
}
InitBitModels(this$static._highCoder.Models)
}
function $SetPrices(this$static, posState, numSymbols, prices, st) {
var a0, a1, b0, b1, i
a0 = ProbPrices[this$static._choice[0] >>> 2]
a1 = ProbPrices[(2048 - this$static._choice[0]) >>> 2]
b0 = a1 + ProbPrices[this$static._choice[1] >>> 2]
b1 = a1 + ProbPrices[(2048 - this$static._choice[1]) >>> 2]
i = 0
for (i = 0; i < 8; ++i) {
if (i >= numSymbols) return
prices[st + i] = a0 + $GetPrice_1(this$static._lowCoder[posState], i)
}
for (; i < 16; ++i) {
if (i >= numSymbols) return
prices[st + i] = b0 + $GetPrice_1(this$static._midCoder[posState], i - 8)
}
for (; i < numSymbols; ++i) {
prices[st + i] = b1 + $GetPrice_1(this$static._highCoder, i - 8 - 8)
}
}
function $Encode_0(this$static, rangeEncoder, symbol, posState) {
$Encode(this$static, rangeEncoder, symbol, posState)
if (--this$static._counters[posState] == 0) {
$SetPrices(
this$static,
posState,
this$static._tableSize,
this$static._prices,
posState * 272
)
this$static._counters[posState] = this$static._tableSize
}
}
function $Encoder$LenPriceTableEncoder(this$static) {
$Encoder$LenEncoder(this$static)
this$static._prices = []
this$static._counters = []
return this$static
}
function $GetPrice(this$static, symbol, posState) {
return this$static._prices[posState * 272 + symbol]
}
function $UpdateTables(this$static, numPosStates) {
for (var posState = 0; posState < numPosStates; ++posState) {
$SetPrices(
this$static,
posState,
this$static._tableSize,
this$static._prices,
posState * 272
)
this$static._counters[posState] = this$static._tableSize
}
}
function $Create_1(this$static, numPosBits, numPrevBits) {
var i, numStates
if (
this$static.m_Coders != null &&
this$static.m_NumPrevBits == numPrevBits &&
this$static.m_NumPosBits == numPosBits
) {
return
}
this$static.m_NumPosBits = numPosBits
this$static.m_PosMask = (1 << numPosBits) - 1
this$static.m_NumPrevBits = numPrevBits
numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits)
this$static.m_Coders = initDim(numStates)
for (i = 0; i < numStates; ++i) {
this$static.m_Coders[i] = $Encoder$LiteralEncoder$Encoder2({})
}
}
function $GetSubCoder(this$static, pos, prevByte) {
return this$static.m_Coders[
((pos & this$static.m_PosMask) << this$static.m_NumPrevBits) +
((prevByte & 255) >>> (8 - this$static.m_NumPrevBits))
]
}
function $Init_3(this$static) {
var i,
numStates = 1 << (this$static.m_NumPrevBits + this$static.m_NumPosBits)
for (i = 0; i < numStates; ++i) {
InitBitModels(this$static.m_Coders[i].m_Encoders)
}
}
function $Encode_1(this$static, rangeEncoder, symbol) {
var bit,
i,
context = 1
for (i = 7; i >= 0; --i) {
bit = (symbol >> i) & 1
$Encode_3(rangeEncoder, this$static.m_Encoders, context, bit)
context = (context << 1) | bit
}
}
function $EncodeMatched(this$static, rangeEncoder, matchByte, symbol) {
var bit,
i,
matchBit,
state,
same = 1,
context = 1
for (i = 7; i >= 0; --i) {
bit = (symbol >> i) & 1
state = context
if (same) {
matchBit = (matchByte >> i) & 1
state += (1 + matchBit) << 8
same = matchBit == bit
}
$Encode_3(rangeEncoder, this$static.m_Encoders, state, bit)
context = (context << 1) | bit
}
}
function $Encoder$LiteralEncoder$Encoder2(this$static) {
this$static.m_Encoders = initDim(768)
return this$static
}
function $GetPrice_0(this$static, matchMode, matchByte, symbol) {
var bit,
context = 1,
i = 7,
matchBit,
price = 0
if (matchMode) {
for (; i >= 0; --i) {
matchBit = (matchByte >> i) & 1
bit = (symbol >> i) & 1
price += GetPrice(
this$static.m_Encoders[((1 + matchBit) << 8) + context],
bit
)
context = (context << 1) | bit
if (matchBit != bit) {
--i
break
}
}
}
for (; i >= 0; --i) {
bit = (symbol >> i) & 1
price += GetPrice(this$static.m_Encoders[context], bit)
context = (context << 1) | bit
}
return price
}
function $MakeAsChar(this$static) {
this$static.BackPrev = -1
this$static.Prev1IsChar = 0
}
function $MakeAsShortRep(this$static) {
this$static.BackPrev = 0
this$static.Prev1IsChar = 0
}
function $BitTreeDecoder(this$static, numBitLevels) {
this$static.NumBitLevels = numBitLevels
this$static.Models = initDim(1 << numBitLevels)
return this$static
}
function $Decode_0(this$static, rangeDecoder) {
var bitIndex,
m = 1
for (bitIndex = this$static.NumBitLevels; bitIndex != 0; --bitIndex) {
m = (m << 1) + $DecodeBit(rangeDecoder, this$static.Models, m)
}
return m - (1 << this$static.NumBitLevels)
}
function $ReverseDecode(this$static, rangeDecoder) {
var bit,
bitIndex,
m = 1,
symbol = 0
for (bitIndex = 0; bitIndex < this$static.NumBitLevels; ++bitIndex) {
bit = $DecodeBit(rangeDecoder, this$static.Models, m)
m <<= 1
m += bit
symbol |= bit << bitIndex
}
return symbol
}
function ReverseDecode(Models, startIndex, rangeDecoder, NumBitLevels) {
var bit,
bitIndex,
m = 1,
symbol = 0
for (bitIndex = 0; bitIndex < NumBitLevels; ++bitIndex) {
bit = $DecodeBit(rangeDecoder, Models, startIndex + m)
m <<= 1
m += bit
symbol |= bit << bitIndex
}
return symbol
}
function $BitTreeEncoder(this$static, numBitLevels) {
this$static.NumBitLevels = numBitLevels
this$static.Models = initDim(1 << numBitLevels)
return this$static
}
function $Encode_2(this$static, rangeEncoder, symbol) {
var bit,
bitIndex,
m = 1
for (bitIndex = this$static.NumBitLevels; bitIndex != 0; ) {
--bitIndex
bit = (symbol >>> bitIndex) & 1
$Encode_3(rangeEncoder, this$static.Models, m, bit)
m = (m << 1) | bit
}
}
function $GetPrice_1(this$static, symbol) {
var bit,
bitIndex,
m = 1,
price = 0
for (bitIndex = this$static.NumBitLevels; bitIndex != 0; ) {
--bitIndex
bit = (symbol >>> bitIndex) & 1
price += GetPrice(this$static.Models[m], bit)
m = (m << 1) + bit
}
return price
}
function $ReverseEncode(this$static, rangeEncoder, symbol) {
var bit,
i,
m = 1
for (i = 0; i < this$static.NumBitLevels; ++i) {
bit = symbol & 1
$Encode_3(rangeEncoder, this$static.Models, m, bit)
m = (m << 1) | bit
symbol >>= 1
}
}
function $ReverseGetPrice(this$static, symbol) {
var bit,
i,
m = 1,
price = 0
for (i = this$static.NumBitLevels; i != 0; --i) {
bit = symbol & 1
symbol >>>= 1
price += GetPrice(this$static.Models[m], bit)
m = (m << 1) | bit
}
return price
}
function ReverseEncode(Models, startIndex, rangeEncoder, NumBitLevels, symbol) {
var bit,
i,
m = 1
for (i = 0; i < NumBitLevels; ++i) {
bit = symbol & 1
$Encode_3(rangeEncoder, Models, startIndex + m, bit)
m = (m << 1) | bit
symbol >>= 1
}
}
function ReverseGetPrice(Models, startIndex, NumBitLevels, symbol) {
var bit,
i,
m = 1,
price = 0
for (i = NumBitLevels; i != 0; --i) {
bit = symbol & 1
symbol >>>= 1
price += ProbPrices[(((Models[startIndex + m] - bit) ^ -bit) & 2047) >>> 2]
m = (m << 1) | bit
}
return price
}
function $DecodeBit(this$static, probs, index) {
var newBound,
prob = probs[index]
newBound = (this$static.Range >>> 11) * prob
if ((this$static.Code ^ -2147483648) < (newBound ^ -2147483648)) {
this$static.Range = newBound
probs[index] = ((prob + ((2048 - prob) >>> 5)) << 16) >> 16
if (!(this$static.Range & -16777216)) {
this$static.Code = (this$static.Code << 8) | $read(this$static.Stream)
this$static.Range <<= 8
}
return 0
} else {
this$static.Range -= newBound
this$static.Code -= newBound
probs[index] = ((prob - (prob >>> 5)) << 16) >> 16
if (!(this$static.Range & -16777216)) {
this$static.Code = (this$static.Code << 8) | $read(this$static.Stream)
this$static.Range <<= 8
}
return 1
}
}
function $DecodeDirectBits(this$static, numTotalBits) {
var i,
t,
result = 0
for (i = numTotalBits; i != 0; --i) {
this$static.Range >>>= 1
t = (this$static.Code - this$static.Range) >>> 31
this$static.Code -= this$static.Range & (t - 1)
result = (result << 1) | (1 - t)
if (!(this$static.Range & -16777216)) {
this$static.Code = (this$static.Code << 8) | $read(this$static.Stream)
this$static.Range <<= 8
}
}
return result
}
function $Init_8(this$static) {
this$static.Code = 0
this$static.Range = -1
for (var i = 0; i < 5; ++i) {
this$static.Code = (this$static.Code << 8) | $read(this$static.Stream)
}
}
function InitBitModels(probs) {
for (var i = probs.length - 1; i >= 0; --i) {
probs[i] = 1024
}
}
var ProbPrices = (function() {
var end,
i,
j,
start,
ProbPrices = []
for (i = 8; i >= 0; --i) {
start = 1 << (9 - i - 1)
end = 1 << (9 - i)
for (j = start; j < end; ++j) {
ProbPrices[j] = (i << 6) + (((end - j) << 6) >>> (9 - i - 1))
}
}
return ProbPrices
})()
function $Encode_3(this$static, probs, index, symbol) {
var newBound,
prob = probs[index]
newBound = (this$static.Range >>> 11) * prob
if (!symbol) {
this$static.Range = newBound
probs[index] = ((prob + ((2048 - prob) >>> 5)) << 16) >> 16
} else {
this$static.Low = add(
this$static.Low,
and(fromInt(newBound), [4294967295, 0])
)
this$static.Range -= newBound
probs[index] = ((prob - (prob >>> 5)) << 16) >> 16
}
if (!(this$static.Range & -16777216)) {
this$static.Range <<= 8
$ShiftLow(this$static)
}
}
function $EncodeDirectBits(this$static, v, numTotalBits) {
for (var i = numTotalBits - 1; i >= 0; --i) {
this$static.Range >>>= 1
if (((v >>> i) & 1) == 1) {
this$static.Low = add(this$static.Low, fromInt(this$static.Range))
}
if (!(this$static.Range & -16777216)) {
this$static.Range <<= 8
$ShiftLow(this$static)
}
}
}
function $GetProcessedSizeAdd(this$static) {
return add(add(fromInt(this$static._cacheSize), this$static._position), [
4,
0
])
}
function $Init_9(this$static) {
this$static._position = P0_longLit
this$static.Low = P0_longLit
this$static.Range = -1
this$static._cacheSize = 1
this$static._cache = 0
}
function $ShiftLow(this$static) {
var temp,
LowHi = lowBits_0(shru(this$static.Low, 32))
if (LowHi != 0 || compare(this$static.Low, [4278190080, 0]) < 0) {
this$static._position = add(
this$static._position,
fromInt(this$static._cacheSize)
)
temp = this$static._cache
do {
$write(this$static.Stream, temp + LowHi)
temp = 255
} while (--this$static._cacheSize != 0)
this$static._cache = lowBits_0(this$static.Low) >>> 24
}
++this$static._cacheSize
this$static.Low = shl(and(this$static.Low, [16777215, 0]), 8)
}
function GetPrice(Prob, symbol) {
return ProbPrices[(((Prob - symbol) ^ -symbol) & 2047) >>> 2]
}
function decode(utf) {
var i = 0,
j = 0,
x,
y,
z,
l = utf.length,
buf = [],
charCodes = []
for (; i < l; ++i, ++j) {
x = utf[i] & 255
if (!(x & 128)) {
if (!x) {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
charCodes[j] = x
} else if ((x & 224) == 192) {
if (i + 1 >= l) {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
y = utf[++i] & 255
if ((y & 192) != 128) {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
charCodes[j] = ((x & 31) << 6) | (y & 63)
} else if ((x & 240) == 224) {
if (i + 2 >= l) {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
y = utf[++i] & 255
if ((y & 192) != 128) {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
z = utf[++i] & 255
if ((z & 192) != 128) {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
charCodes[j] = ((x & 15) << 12) | ((y & 63) << 6) | (z & 63)
} else {
// It appears that this is binary data, so it cannot be converted to a string, so just send it back.
return utf
}
if (j == 16383) {
buf.push(String.fromCharCode.apply(String, charCodes))
j = -1
}
}
if (j > 0) {
charCodes.length = j
buf.push(String.fromCharCode.apply(String, charCodes))
}
return buf.join('')
}
function encode(s) {
var ch,
chars = [],
data,
elen = 0,
i,
l = s.length
// Be able to handle binary arrays and buffers.
if (typeof s == 'object') {
return s
} else {
$getChars(s, 0, l, chars, 0)
}
// Add extra spaces in the array to break up the unicode symbols.
for (i = 0; i < l; ++i) {
ch = chars[i]
if (ch >= 1 && ch <= 127) {
++elen
} else if (!ch || (ch >= 128 && ch <= 2047)) {
elen += 2
} else {
elen += 3
}
}
data = []
elen = 0
for (i = 0; i < l; ++i) {
ch = chars[i]
if (ch >= 1 && ch <= 127) {
data[elen++] = (ch << 24) >> 24
} else if (!ch || (ch >= 128 && ch <= 2047)) {
data[elen++] = ((192 | ((ch >> 6) & 31)) << 24) >> 24
data[elen++] = ((128 | (ch & 63)) << 24) >> 24
} else {
data[elen++] = ((224 | ((ch >> 12) & 15)) << 24) >> 24
data[elen++] = ((128 | ((ch >> 6) & 63)) << 24) >> 24
data[elen++] = ((128 | (ch & 63)) << 24) >> 24
}
}
return data
}
// s is dictionarySize
// f is fb
// m is matchFinder
// NOTE: Because some values are always the same, they have been removed.
// lc is always 3
// lp is always 0
// pb is always 2
const modes = [
{ s: 16, f: 64, m: 0 },
{ s: 20, f: 64, m: 0 },
{ s: 19, f: 64, m: 1 },
{ s: 20, f: 64, m: 1 },
{ s: 21, f: 128, m: 1 },
{ s: 22, f: 128, m: 1 },
{ s: 23, f: 128, m: 1 },
{ s: 24, f: 255, m: 1 },
{ s: 25, f: 255, m: 1 }
]
function get_mode_obj(mode) {
return modes[mode - 1] || modes[6]
}
/**
* Compress a string with the LZMA algorithm
*
* @param {string} value The string to be compressed
* @param {object} options
* @param {1|2|3|4|5|6|7|8|9} options.mode Which mode to use (1 through 9, defaults to 7)
* @param {boolean} options.enableEndMark Whether to write an end mark
* @returns {string}
*/
export function compress(value, { mode = 7, enableEndMark = true } = {}) {
var this$static = {}
this$static.c = $LZMAByteArrayCompressor(
{},
encode(value),
get_mode_obj(mode),
enableEndMark
)
while ($processChunk(this$static.c.chunker));
return $toByteArray(this$static.c.output)
}
/**
* Compress a string with the LZMA algorithm to URL-safe characters
*
* @param {string} value The string to be compressed
* @param {object} options
* @param {1|2|3|4|5|6|7|8|9} options.mode Which mode to use (1 through 9, defaults to 7)
* @param {boolean} options.enableEndMark Whether to write an end mark
* @returns {string}
*/
export function compressUrlSafe(
string,
{ mode = 7, enableEndMark = true } = {}
) {
const compressedString = compress(string, { mode, enableEndMark })
const compressedBytes = new Uint8Array(compressedString)
return base64.encodeFromArrayUrlSafe(compressedBytes)
}
/**
* Decompress a string compressed with the LZMA algorithm
*
* @param {number[]|Int8Array} bytes The int8 array created by the compress() function
* @returns {string}
*/
export function decompress(bytes) {
var this$static = {}
this$static.d = $LZMAByteArrayDecompressor({}, bytes)
while ($processChunk(this$static.d.chunker));
return decode($toByteArray(this$static.d.output))
}
/**
* Decompress a string compressed with the URL-safe compress function
*
* @param {string} string The URL-safe string generated by the compressUrlSafe() function
* @returns {string}
*/
export function decompressUrlSafe(string) {
return decompress(new Int8Array(base64.decodeToArrayUrlSafe(string)))
}
@flou-ainan
Copy link

Hey dude, I've came to same results using other method. Just for sharing, soon it will be avaliable on github.

I though that no one had this idea before so started doing it myself.
All base conversions were implemented by myself based on a mongodb shortID code that I've came across in the past and forked to fit my needs.
Intead of using LZMA I've searched for a JavaScript Gzip implementation, and after most of the hard job were already done I've searched for compressing data into URLs and found your gist.
This project is a part of this one
Then when I finished my code, I tested your data for benchmarking and curiously they reached the same result with your data

My testing results:

-----
Test Data:     |      length: 456 
{"id":"0001","type":"donut","name":"Cake","ppu":0.55,"batters":{"batter":[{"id":"1001","type":"Regular"},{"id":"1002","type":"Chocolate"},{"id":"1003","type":"Blueberry"},{"id":"1004","type":"Devil's Food"}]},"topping":[{"id":"5001","type":"None"},{"id":"5002","type":"Glazed"},{"id":"5005","type":"Sugar"},{"id":"5007","type":"Powdered Sugar"},{"id":"5006","type":"Chocolate with Sprinkles"},{"id":"5003","type":"Chocolate"},{"id":"5004","type":"Maple"}]}
-----
-----
Ziped Bytes Array:     |      length: 220 
31,139,8,0,150,29,44,102,0,3,125,144,203,10,194,48,16,69,127,165,204,198,77,145,250,136,66,151,42,186,82,196,46,197,69,52,67,27,140,73,72,19,165,150,254,187,17,133,24,20,119,185,156,195,100,238,180,192,25,228,144,101,217,0,82,176,141,70,159,152,146,206,250,40,233,229,25,231,244,140,62,105,237,32,207,250,132,164,112,164,214,162,169,33,111,223,79,200,247,237,107,210,32,154,180,195,210,9,106,160,75,3,30,6,60,175,212,73,9,106,49,18,70,65,152,9,135,71,52,166,137,132,113,16,22,120,229,162,87,39,75,165,24,116,135,206,3,165,53,151,101,216,136,68,27,109,148,252,248,141,68,235,172,4,189,35,139,40,9,180,112,229,103,19,15,167,1,110,213,141,161,65,150,124,91,147,31,125,147,27,183,85,82,104,195,229,89,96,29,249,163,191,247,33,81,253,53,213,2,159,189,31,235,221,89,114,200,1,0,0
-----
-----
Hexadecimal String:     |      length: 440 
1f8b0800961d2c6600037d90cb0ac23010457fa5ccc64d91fa8842972aba52c42ec54534431b8c494813a596febb1185181477b99cc364eeb4c019e49065d90052b08d469f9892cefa28e9e519e7f48c3e69ed20cffa84a470a4d6a2a9216fdf4fc8f7ed6bd2209ab4c3d2096aa04b031e063cafd449096a311246419809874734a6898471101678e5a257274ba5187487ce03a5359765d888441b6d94fcf88d44ebac04bd238b2809b470e567130fa7016ed58da141967c5b931f7d931bb7555268c3e559601df9a3bff72151fd35d5029fbd1febdd5972c8010000
-----
-----
Base 64 string:     |      length: 294 
7UI809otb6o00TSgOMH2c115vWncNASh!Ex2BOGWkIgKNkkQgNKcikwjFpr!KN6561hTKpP3peWQM1DAA6np05aMzkqvC9be!yzFVhDDZ8M!quQwP$G4F72ARGaF8m$vjYzTXmLi89GQMZ89qG1b0NU6fa$kigBGch96gpw9xQsQFEC4sh0muemylOtbFhxQxYU3Fjmnpty8h1JJBfPUzkjHH0iZ8UIE2rhMVmsj3Ws1rJmdEk6mv5Kj7TSj6XtlkCz3VlBw7vCzL$sxkvQRRgavLh$HTlBOO04000
-----
-----
Hex String from Base 64:     |      length: 441 
1f8b0800961d2c6600037d90cb0ac23010457fa5ccc64d91fa8842972aba52c42ec54534431b8c494813a596febb1185181477b99cc364eeb4c019e49065d90052b08d469f9892cefa28e9e519e7f48c3e69ed20cffa84a470a4d6a2a9216fdf4fc8f7ed6bd2209ab4c3d2096aa04b031e063cafd449096a311246419809874734a6898471101678e5a257274ba5187487ce03a5359765d888441b6d94fcf88d44ebac04bd238b2809b470e567130fa7016ed58da141967c5b931f7d931bb7555268c3e559601df9a3bff72151fd35d5029fbd1febdd5972c80100000
-----
-----
Ziped Bytes Array from hex string:     |      length: 220 
31,139,8,0,150,29,44,102,0,3,125,144,203,10,194,48,16,69,127,165,204,198,77,145,250,136,66,151,42,186,82,196,46,197,69,52,67,27,140,73,72,19,165,150,254,187,17,133,24,20,119,185,156,195,100,238,180,192,25,228,144,101,217,0,82,176,141,70,159,152,146,206,250,40,233,229,25,231,244,140,62,105,237,32,207,250,132,164,112,164,214,162,169,33,111,223,79,200,247,237,107,210,32,154,180,195,210,9,106,160,75,3,30,6,60,175,212,73,9,106,49,18,70,65,152,9,135,71,52,166,137,132,113,16,22,120,229,162,87,39,75,165,24,116,135,206,3,165,53,151,101,216,136,68,27,109,148,252,248,141,68,235,172,4,189,35,139,40,9,180,112,229,103,19,15,167,1,110,213,141,161,65,150,124,91,147,31,125,147,27,183,85,82,104,195,229,89,96,29,249,163,191,247,33,81,253,53,213,2,159,189,31,235,221,89,114,200,1,0,0
-----
-----
Original Data:     |      length: 456 
{"id":"0001","type":"donut","name":"Cake","ppu":0.55,"batters":{"batter":[{"id":"1001","type":"Regular"},{"id":"1002","type":"Chocolate"},{"id":"1003","type":"Blueberry"},{"id":"1004","type":"Devil's Food"}]},"topping":[{"id":"5001","type":"None"},{"id":"5002","type":"Glazed"},{"id":"5005","type":"Sugar"},{"id":"5007","type":"Powdered Sugar"},{"id":"5006","type":"Chocolate with Sprinkles"},{"id":"5003","type":"Chocolate"},{"id":"5004","type":"Maple"}]}
-----
{
  id: '0001',
  type: 'donut',
  name: 'Cake',
  ppu: 0.55,
  batters: { batter: [ [Object], [Object], [Object], [Object] ] },
  topping: [
    { id: '5001', type: 'None' },
    { id: '5002', type: 'Glazed' },
    { id: '5005', type: 'Sugar' },
    { id: '5007', type: 'Powdered Sugar' },
    { id: '5006', type: 'Chocolate with Sprinkles' },
    { id: '5003', type: 'Chocolate' },
    { id: '5004', type: 'Maple' }
  ]
}

This test can be acessed here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment