Skip to content

Instantly share code, notes, and snippets.

@Gamer92000
Last active December 22, 2023 16:19
Show Gist options
  • Save Gamer92000/c39de1a608b7997aab94a4084f92eeae to your computer and use it in GitHub Desktop.
Save Gamer92000/c39de1a608b7997aab94a4084f92eeae to your computer and use it in GitHub Desktop.
// --==-- FFE Test Case Generator --==--
// This script will use all images on the page and assemble them into a test
// case. All images will be downloaded 300 times and then zipped up. The
// TeamSpeak client imposes several restrictions that complicate this. By
// default, it is not possible to load scripts from external sources. This
// means that the JSZip library has to be pasted into the console. The
// TeamSpeak client also does not allow to download files from the JavaScript
// context. This means that the zip file has to be converted to a base64
// string and then printed to the console. This string can then be copied
// into a new file and decoded with a base64 decoder. The resulting file
// will be a zip file containing all images. However, as the TeamSpeak client
// shadows the `console.log` and `console.warn` functions, the output will
// be printed to the console using `console.error`.
// -=- Libraries -=-
// JSZip: https://stuk.github.io/jszip/ -> https://raw.githubusercontent.com/Stuk/jszip/master/dist/jszip.min.js
// using more tries would give potentially more diverse results, but crashes due to memory usage
let tries = 300;
// find all image sources on the page
let images = [].slice.call(document.getElementsByTagName("IMG")).map((image) => image.src);
// exclude duplicates and non-relevant images
images = new Set(images.filter((image) => image.endsWith("ts-frame=1") && image.startsWith("tsic://")));
(async () => {
for (image of images) {
console.error(image);
let zip = new JSZip();
for (let i = 0; i < tries; i++) {
await fetch(image, {
cache: "no-store",
mode: "no-cors"
}).then((r) => r.arrayBuffer()).then((j) => {
zip.file(`${String(i).padStart(2, '0')}.png`, j);
});
}
zip.generateAsync({ type: "blob" })
.then((blob) => blob.arrayBuffer())
.then((buffer) => {
// convert buffer to base64 string
// this can't be done through the spread operator
// as the recursion will be too deep and fail
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
let base64Image = window.btoa(binary);
console.error(base64Image);
});
}
})();
from pathlib import Path
def compare_file_content(files: list[Path]):
with open(files[0], "rb") as f:
data = f.read()
for f in files[1:]:
with open(f, "rb") as f2:
data2 = f2.read()
if data != data2:
return False
return True
def check_break_point(files: list[Path], max_size: int):
# it's enough to check the first file
with open(files[0], "rb") as f:
data = f.read()
if len(data) % 2**16 != 0:
return False
if len(data) >= max_size:
return False
return True
for i, image in enumerate(sorted([*Path("./results").iterdir()], key=lambda x: x.name)):
print(f"πŸ” Analyzing subject: {i+1}")
# for each image there are 300 files
# some files are broken, most are not
# we can distinguish them by their size
# so find the most common size
sizes = {}
for f in image.iterdir():
size = f.stat().st_size
if size not in sizes:
sizes[size] = 0
sizes[size] += 1
most_common_size = max(sizes, key=lambda x: sizes[x])
# now we can find the broken files
broken_files = []
for f in image.iterdir():
if f.stat().st_size != most_common_size:
broken_files.append(f)
print(f" πŸ“ Expected size: {most_common_size} bytes")
if len(broken_files) == 0:
print(" βœ… No broken files")
continue
print(f" ⚠️ Found {len(broken_files) / 300:.2%} broken files ({len(broken_files)}/300)")
# group the broken files by their size
broken_files_by_size = {}
for f in broken_files:
size = f.stat().st_size
if size not in broken_files_by_size:
broken_files_by_size[size] = []
broken_files_by_size[size].append(f)
# run checks for each group
for size in broken_files_by_size:
files = broken_files_by_size[size]
print(f" πŸ“ Checking {len(files)} broken files ({len(files)/300:.2%}) of size {size}")
# check if the files are the same
if compare_file_content(files):
print(f" βœ… All files are the same")
else:
print(f" ❌ The Files differ in their content")
# check if the files are broken at an expected point
if check_break_point(files, most_common_size):
print(f" βœ… The files are truncated at a multiple of 2^16")
continue
else:
print(f" ❌ The files exhibit an unexpected size")
expected_file = None
# find a file with the expected size
for f in image.iterdir():
if f.stat().st_size == most_common_size:
with open(f, "rb") as f2:
expected_file = f2.read()
break
# if the file is larger than the expected size,
# compare the expected bytes with the actual bytes
# if size > most_common_size:
# find the offset up to which the bytes are the same
offset = 0
with open(files[0], "rb") as f:
data = f.read()
while expected_file[offset] == data[offset]:
offset += 1
print(f" πŸ“ The files differ in content at offset {offset} from the expectation")
# assume the file ends correctly
# find the offset from the end up to which the bytes are the same
offset_end = 0
with open(files[0], "rb") as f:
data = f.read()
while expected_file[-offset_end] == data[-offset_end]:
offset_end += 1
# calculate offset from the beginning
print(f" 🟰 The unexpected content matches the expectation between offset {len(data) - offset_end} and the end")
# if the file is smaller than the expected size,
# find the missing bytes
if size < most_common_size:
print(f" πŸŸ₯ The files are missing {most_common_size - offset - offset_end + 1} bytes in the middle")
# if the file is larger than the expected size,
# find the extra bytes
if size > most_common_size:
if data[offset:-offset_end] == expected_file[offset-2^16:-offset_end-2^16]:
print(f" πŸŸ₯ The files have {size - most_common_size} duplicate bytes in the middle")
else:
print(f" πŸŸ₯ The files have {size - most_common_size} extra bytes in the middle")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment