zlib doesn't have a file extension unlike gzip or bzip, so you won't need to change the filename.
First let's try checking what's inside the file.
Here's the first 30 bytes of package.pack.
import zlib
with open("package.pack", "rb") as f:
content = f.read()
print(content[:30])
print()
# b'x\x9c\x00\n@\xf5\xbfx\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c'It gave me a whole bunch of byte strings so I checked the first 30 bytes to see if there if I could recognize a file header.
Nothing really special. After searching online for a bit, zlib's default compressions file headers are 0x78, 0x9c. I can't find the 0x78 but we can spot the \x9c in package.pack.
Let's try checking the 2 starting bytes of the byte-string.
When indexing byte-strings, Python will return the integer value of that specific byte.
start=b'x\x9c'
hex(start[0]) # 0x78
hex(start[1]) # 0x9c You still might have a confusion on how b'x\x9c' returns 0x78 and 0x9c when using hex.
b'x\x9c' is made up of two bytes. b'x' and b'\x9c'.
b'x'.hex() # 0x78
b'\x9c'.hex() # 0x9c The '\x' used in the byte-string are used for representing hexadecimal characters. Python uses '\x' to enable escape sequences.
It looks like it matches the zlib file header explained here.
Now we can finally ascertain that package.pack is a default compressed zlib file.
Then I tried decompressing package.pack which also gave me binary data that started with b\x\x9c. Python has a built-in zilb module. For decompressing zlib files I used zlib.decompress.
output = zlib.decompress(content)
print(output[:30])
# b'x\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c'I'm not even sure that we're dealing with proper zlib files but maybe I should decompress until the byte-string doesn't start with b'x\x9c'.
Here's the following code.
import zlib
import bz2
with open("package.pack", "rb") as f:
content = f.read()
while True:
try:
data = zlib.decompress(content)
content = data
print(data[:30])
except zlib.error:
break
# b'x\x9c\x00\x07@\xf8\xbfx\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c'
# b'x\x9c\x00\x06@\xf9\xbfx\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c\x84vuT\x14N\xd4'
# b'x\x9c\x00\xff?\x00\xc0x\x9c\x00\xff?\x00\xc0x\x9c\x84vuT\x14N\xd46\xddH#\xad\x80\x84'
# b'x\x9c\x00\xff?\x00\xc0x\x9c\x84vuT\x14N\xd46\xddH#\xad\x80\x84tH\x97\x80\x94\x80 '
# b'x\x9c\x84vuT\x14N\xd46\xddH#\xad\x80\x84tH\x97\x80\x94\x80 -)\xd2\xdd \xb1H'
# b'BZh91AY&SY\x91\xe8/+\x00v\xa9\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'Decompressing until it's not a zlib file will give you a bzip file. You can tell that it's a zlib file with the file header BZh91AY as we've experienced before back in level8.
import zlib
import bz2
with open("package.pack", "rb") as f:
content = f.read()
while True:
try:
data = zlib.decompress(content)
content = data
print(data[:30])
except zlib.error:
try:
data=bz2.decompress(content)
content=data
except OSError:
breakI used OSError because when bz2 can't decompress a bzip file using bz2.decompress it returns an OSError like below OSError: Invalid data stream During handling of the above exception, another exception occurred:
Now let's check which kind of file package.pack is after decompressing it zlib and bzip.
I checked the first 30 bytes of what was leftover after zlip decompressing and bzip decompressing.
data[:30]
b'\x80\x8d\x96\xcb\xb5r\xa7\x00\x06Xz\xdafO\x19\xee\x84k\xa4dAB\xe1\x14\xc9]\xfc\xffT!'Now I'm stuck again. what should I do lol...
Then I remembered that the readme.txt file said this When I had no idea what to do, I looked backwards.
Let's try inspecting the bytes backwards.
I reversed the string and selected the first 30 bytes. Here's what we get.
print(data[::-1][:30]) # b'x\x9c\x00\x0c@\xf3\xbfx\x9c\x00\x05@\xfa\xbfx\x9c\x00\x05@\xfa\xbfx\x9c\x84\xb7UT\x1c\xbe\x17'Hey it looks like a zlib file again!. The zlib file header we saw before b'x\x9c is at the start of the reversed byte-string.
So we can probably deflate it if it's a zlib file or a bzip file or reverse the bytes if it's neither of them.
Here's the code that I wrote.
import zlib
import bz2
with open("package.pack", "rb") as f:
content = f.read()
while True:
try:
data = zlib.decompress(content)
content = data
except zlib.error:
try:
data = bz2.decompress(content)
content = data
except OSError:
try:
data = zlib.decompress(content[::-1])
content = data
except zlib.error:
try:
data = bz2.decompress(content[::-1])
content = data
except OSError:
break
print(data) # b'sgol ruoy ta kool'b'sgol ruoy ta kool' is the result. I can't read it lol, we should probably reverse it as well.
b'sgol ruoy ta kool'[::-1]
# b'look at your logs'When reversing the string it says to look at my logs. What am I supposed to do now.
Let's try printing characters when package.pack is a zlib file, a bzip file or neither(reversed).
import zlib
import bz2
with open("package.pack", "rb") as f:
content = f.read()
while True:
try:
data = zlib.decompress(content)
content = data
print("z",end=" ")
except zlib.error:
try:
data = bz2.decompress(content)
content = data
print("b",end=" ")
except OSError:
try:
data = zlib.decompress(content[::-1])
content = data
print("r")
except zlib.error:
try:
data = bz2.decompress(content[::-1])
content = data
except OSError:
breakHere's the output.
z z z z z z b b b z z z z z z z z z z b b b z z z z z z b b b b b b b b z z z z b b b b b b b b z z z z b b b b b b b b b b z z b b b b b b b b r
z z z b b b b b b b z z z z z z b b b b b b b z z z z b b b b b b b b b z z z b b b b b b b b b z z z b b b b b b b b b z z z b b b b b b b b b r
z z b b z z z z z b b z z z z b b z z z z z b b z z z b b z z z z z z b b z z b b z z z z z z b b z z b b z z z z z z z z z z b b z z z z z z b b r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b z z z z z z b b z z b b z z z z z z b b z z b b z z z z z z z z z z b b z z z z z z b b r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b b b b b b b b z z z b b b b b b b b b z z z b b b b b b b b z z z z b b b b b b b b b r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b b b b b b b z z z z b b b b b b b b z z z z b b b b b b b b z z z z b b b b b b b b z r
z b b z z z z z z z z z z z b b z z z z z z z b b z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z b b z r
z z b b z z z z z b b z z z z b b z z z z z b b z z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b z z z z b b z r
z z z b b b b b b b z z z z z z b b b b b b b z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b b b b b b b b z z z b b z z z z z b b z r
z z z z z b b b z z z z z z z z z z b b b z z z z z z b b z z z z z z z z z z b b z z z z z z z z z z b b b b b b b b b b z z b b z z z z z z b b
It looks like crap, but if you zoom out on the output the result looks like the word copper.
Now that we know the result is copper.
Let's try cleaning the code so it only prints the word copper.
I modified the code so we don't have to zoom out to see the word copper.
Here's the final code.
import zlib
import bz2
with open("package.pack", "rb") as f:
content = f.read()
copper=""
while True:
try:
data = zlib.decompress(content)
content = data
copper+=" "
except zlib.error:
try:
data = bz2.decompress(content)
content = data
copper+="#"
except OSError:
try:
data = zlib.decompress(content[::-1])
content = data
copper+="\n"
except zlib.error:
try:
data = bz2.decompress(content[::-1])
content = data
except OSError:
break
print(copper)The cleaned up copper looks like this. BTW concatenating strings in Python isn't a good practice I used it because that was the only way I could print copper neatly, if anyone has a better method please tell me.
####### ####### ######### ######### ######### #########
## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ##
## ## ## ######### ######### ######## #########
## ## ## ######## ######## ######## ########
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ##
####### ####### ## ## ######### ## ##
### ### ## ## ########## ## ##
Now that we've taken care of everything let's change the url to http://www.butter:fly@pythonchallenge.com/pc/hex/copper.html.
We're on level22. Man that was a lot ...