Skip to content

Instantly share code, notes, and snippets.

@feilongfl
Last active October 10, 2018 23:20
Show Gist options
  • Save feilongfl/13e9b5b44eadc4b1917b596de5934bbe to your computer and use it in GitHub Desktop.
Save feilongfl/13e9b5b44eadc4b1917b596de5934bbe to your computer and use it in GitHub Desktop.
ebb-json-decoder
#/usr/bin/env python
# written by https://github.com/v-python
def decompress(compressed):
if (compressed is None) or (compressed == ''):
return ''
dictionary = {}
enlargeIn = 4
dictSize = 4
numBits = 3
(entry, result, w, c) = ('', '', '', '')
(i, nnext, bits, resb, maxpower, power) = (0, 0, 0, 0, 0, 0)
data_string = compressed
data_val = ord(compressed[0])
data_position = 32768
data_index = 1
for i in range(3):
# dictionary[i] = i
dictionary[i] = ''
bits = 0
maxpower = pow(2, 2)
power = 1
while power != maxpower:
resb = data_val & data_position
data_position >>= 1
if data_position == 0:
data_position = 32768
data_val = ord(data_string[data_index])
data_index += 1
bits |= (1 if resb > 0 else 0) * power
power <<= 1
nnext = bits
if nnext == 0:
bits = 0
maxpower = pow(2, 8)
power = 1
while power != maxpower:
resb = data_val & data_position
data_position >>= 1
if data_position == 0:
data_position = 32768
data_val = ord(data_string[data_index])
data_index += 1
bits |= (1 if resb > 0 else 0) * power
power <<= 1
c = chr(bits)
elif nnext == 1:
bits = 0
maxpower = pow(2, 16)
power = 1
while power != maxpower:
resb = data_val & data_position
data_position >>= 1
if data_position == 0:
data_position = 32768
data_val = ord(data_string[data_index])
data_index += 1
bits |= (1 if resb > 0 else 0) * power
power <<= 1
c = chr(bits)
elif nnext == 2:
return ''
dictionary[3] = c
result = c
w = result
while True:
if data_index > len(data_string):
return ''
bits = 0
maxpower = pow(2, numBits)
power = 1
while power != maxpower:
resb = data_val & data_position
data_position >>= 1
if data_position == 0:
data_position = 32768
data_val = ord(data_string[data_index])
data_index += 1
bits |= (1 if resb > 0 else 0) * power
power <<= 1
c = bits
if c == 0:
bits = 0
maxpower = pow(2, 8)
power = 1
while power != maxpower:
resb = data_val & data_position
data_position >>= 1
if data_position == 0:
data_position = 32768
data_val = ord(data_string[data_index])
data_index += 1
bits |= (1 if resb > 0 else 0) * power
power <<= 1
dictionary[dictSize] = chr(bits)
dictSize += 1
c = dictSize - 1
enlargeIn -= 1
elif c == 1:
bits = 0
maxpower = pow(2, 16)
power = 1
while power != maxpower:
resb = data_val & data_position
data_position >>= 1
if data_position == 0:
data_position = 32768
data_val = ord(data_string[data_index])
data_index += 1
bits |= (1 if resb > 0 else 0) * power
power <<= 1
dictionary[dictSize] = chr(bits)
dictSize += 1
c = dictSize - 1
enlargeIn -= 1
elif c == 2:
return result
if enlargeIn == 0:
enlargeIn = pow(2, numBits)
numBits += 1
if c in dictionary:
entry = dictionary[c]
else:
if c == dictSize:
entry = w + w[0]
else:
return None
result += entry
dictionary[dictSize] = w + entry[0]
dictSize += 1
enlargeIn -= 1
w = entry
if enlargeIn == 0:
enlargeIn = pow(2, numBits)
numBits += 1
def decompressFromUTF16(string):
if not string:
return ""
output = ""
status = 0
for i, k in enumerate(string):
c = ord(k) - 32
if status == 0:
status = 1
current = c << 1
elif status == 1:
status = 2
output += chr(current + (c >> 14))
current = (c & 16383) << 2
elif status == 2:
status = 3
output += chr(current + (c >> 13))
current = (c & 8191) << 3
elif status == 3:
status = 4
output += chr(current + (c >> 12))
current = (c & 4095) << 4
elif status == 4:
status = 5
output += chr(current + (c >> 11))
current = (c & 2047) << 5
elif status == 5:
status = 6
output += chr(current + (c >> 10))
current = (c & 1023) << 6
elif status == 6:
status = 7
output += chr(current + (c >> 9))
current = (c & 511) << 7
elif status == 7:
status = 8
output += chr(current + (c >> 8))
current = (c & 255) << 8
elif status == 8:
status = 9
output += chr(current + (c >> 7))
current = (c & 127) << 9
elif status == 9:
status = 10
output += chr(current + (c >> 6))
current = (c & 63) << 10
elif status == 10:
status = 11
output += chr(current + (c >> 5))
current = (c & 31) << 11
elif status == 11:
status = 12
output += chr(current + (c >> 4))
current = (c & 15) << 12
elif status == 12:
status = 13
output += chr(current + (c >> 3))
current = (c & 7) << 13
elif status == 13:
status = 14
output += chr(current + (c >> 2))
current = (c & 3) << 14
elif status == 14:
status = 15
output += chr(current + (c >> 1))
current = (c & 1) << 15
elif status == 15:
status = 0
output += chr(current + c)
current = (c & 1) << 15
return decompress(output)
# test
f = open('anime_list', 'r')
r = decompressFromUTF16(f.read())
print(r)
#!/usr/bin/env node
var f = String.fromCharCode;
decompressFromUTF16 = function(compressed) {
if (compressed == null) return "";
if (compressed == "") return null;
return _decompress(compressed.length, 16384, function(index) {
return compressed.charCodeAt(index) - 32;
});
}
_decompress = function(length, resetValue, getNextValue) {
var dictionary = [],
next,
enlargeIn = 4,
dictSize = 4,
numBits = 3,
entry = "",
result = [],
i,
w,
bits, resb, maxpower, power,
c,
data = {
val: getNextValue(0),
position: resetValue,
index: 1
};
for (i = 0; i < 3; i += 1) {
dictionary[i] = i;
}
bits = 0;
maxpower = Math.pow(2, 2);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
switch (next = bits) {
case 0:
bits = 0;
maxpower = Math.pow(2, 8);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
c = f(bits);
break;
case 1:
bits = 0;
maxpower = Math.pow(2, 16);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
c = f(bits);
break;
case 2:
return "";
}
dictionary[3] = c;
w = c;
result.push(c);
while (true) {
if (data.index > length) {
return "";
}
bits = 0;
maxpower = Math.pow(2, numBits);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
switch (c = bits) {
case 0:
bits = 0;
maxpower = Math.pow(2, 8);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
dictionary[dictSize++] = f(bits);
c = dictSize - 1;
enlargeIn--;
break;
case 1:
bits = 0;
maxpower = Math.pow(2, 16);
power = 1;
while (power != maxpower) {
resb = data.val & data.position;
data.position >>= 1;
if (data.position == 0) {
data.position = resetValue;
data.val = getNextValue(data.index++);
}
bits |= (resb > 0 ? 1 : 0) * power;
power <<= 1;
}
dictionary[dictSize++] = f(bits);
c = dictSize - 1;
enlargeIn--;
break;
case 2:
return result.join('');
}
if (enlargeIn == 0) {
enlargeIn = Math.pow(2, numBits);
numBits++;
}
if (dictionary[c]) {
entry = dictionary[c];
} else {
if (c === dictSize) {
entry = w + w.charAt(0);
} else {
return null;
}
}
result.push(entry);
// Add w+entry[0] to the dictionary.
dictionary[dictSize++] = w + entry.charAt(0);
enlargeIn--;
w = entry;
if (enlargeIn == 0) {
enlargeIn = Math.pow(2, numBits);
numBits++;
}
}
}
function decode(code) {
return JSON.parse(decompressFromUTF16(code))
}
var rf = require("fs");
var data = rf.readFileSync("anime_list", "utf-8");
// console.log(data);
console.log(JSON.stringify(decode(data)));
@feilongfl
Copy link
Author

example:

JSON.stringify(decode("ᯡࡓ䅼ಅՓᡠᜠ⸢㡶ð䀻Ō惌吡ء渐஋ұ砢㙠ଠภ汛䵆䄚⠠⸓Ⴄɻ䘥௦˥ᐠठ穣DŽ犠㮆ၼ㶂砢堠㮱ࢸ಄吭碅䰫ႆ⧪℥`㶺࣠牭ₐ盀㣬〴੅␣㱈㔘婱硖嵄ࡀᑴ栭ழĩ䴡䧉䁺ᒀ୛⠥梔àᤠ咺䁿ᯀಌ栫�ʑ猠⺚䀸䀀෵改䰥戊ǁ檠୥㖀Х⠠杴Ϋ唡æ䀸忀఑⠧纔˯ᔡ楦䁹岀ᰨ፴ᰠㄺũ姥䀪㫘瀤ᜂ䰧楺�⦠྇຀ࣽᠫቶᘠąÐᕡ儀ᄧ⠬瓴ͩ೺⤲䤼怷ᣰ൷డ䀥㮫�礱怩嫰̢劮ᔠ❈懢灹ຠዚ〪ࣔŞ庠ආ㔈⨡廪䀵盩ᇈᚠெ倡歬 ಾ਴䀣䴰␠්ɑ䠠প䵰桂Ӱׂ㪘倻ᜧエ倠ᆠނ爠暆Р̙〴匩ࠄ,㪍ਰ屹㙧ᨵ䅨⠯ỉ૥稤囥䨹⧂廯奢ٛ%㆒哈Ѱ̈瀠㗌$砡準̤䤢㲤⼶݃㰲哔⼢喀つ佄痨⬫䶀Ⲵἲ䩡墼⢔䜯䣜⁥ס敀…丏娡䛺佉ྣↀॵᕋ䛙ᦘʠ䀸₨䀦⠠⨠⪠ɀɨĒ椯〥ࢮY➷ì僜Ы₂䡈ᖄ⇍挠ⵝ㧚䩛⥵ᒧᰗ⩾‣八枠୧欢硢̻愨ᯐᚰ䇓㲱磄❖夜秏᝕┮ը社➱瞞⿫墜⾢玜柚㱐஠䐡ʠ偍ءဠཀྵ䈠᮶䀠ṇ嘠f扈䅎簪¾噪䊁〳ޞ忿稡瘸ڡ灒ځ⨢䐀,漠傊ᘠ烍⨚䉦ᕈ禆޲塰ឰ祣櫡▖ш瀼枸䑺悥ჰ䊥催ᶥ烢ብ䢢⠱⢺ᝤᢿ楇⓹ၰᓊⓄ哎Ꮷ磂ф䔁⮋㴁ⱉ  "))

resault:

"{"success":true,"list":{"anime":{"id":486,"name_chi":"軒轅劍 蒼之曜","name_jpn":"軒轅剣・蒼き曜","author":"大宇資訊","description":"故事時間設定為「太白曆」99年,當時太白帝國全國各地均持續出現反抗軍與帝國軍戰鬥,在帝國軍的「機關獸」面前,一名反抗軍少女手持「軒轅劍」挺身而出,但與此同時,該名少女的一名青梅竹馬少年卻淪為帝國的奴隸。","tags":[{"id":22,"name":"戰爭","color":"c17134"},{"id":30,"name":"少女","color":"eac7c7"},{"id":48,"name":"戰鬥","color":"d6512c"}],"keywords":"","is_ended":0},"seasons":[{"id":818,"anime_id":486,"season_title":"第一季","aired":201810,"studio":"STUDIO DEEN","last_updated":"2018-10-10T02:52:29.000Z","is_hidden":0,"episodes":[{"id":"583595086277902336","title":"02","sl":"https://vpx.ebbstatic.com/s/583595086277902336/manifest.csv"},{"id":"583074987997528064","title":"01","sl":"https://vpx.ebbstatic.com/s/583074987997528064/manifest.csv"}]}]}}"

@feilongfl
Copy link
Author

原来是lz-string压缩,学习了

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