diff --git a/TODO.norg b/TODO.norg
index 411a4c1..33a119c 100644
--- a/TODO.norg
+++ b/TODO.norg
@@ -3,7 +3,12 @@ This is a list of tasks that would be cool to add.
* Tasks
** Basic
*** Files
- - ( ) Hex dumper
+ - (-) Hex dumper
+ - (x) Dump basic files with format
+ - (x) Dump basic files with chars
+ - (x) Be able to dump larger files or put out an error
+ - ( ) Stop reading when read gets blocked /somehow/
+ - ( ) Install script to system
*** Networking
- ( ) Mini curl
*** Packaging
diff --git a/Tasks.md b/Tasks.md
index d56e6cc..1f12dbd 100644
--- a/Tasks.md
+++ b/Tasks.md
@@ -406,37 +406,84 @@ don't like windows either, so no support for installing stuff on windows.
### A. Hexdumper
Difficulty: 3/5
-
1. Dump the data of [data/metasyntactic.md](./data/metasyntactic.md) -- In
Hexadecimal.
2. Make the dumped Bytes look pretty, something like the example below:
+3. Make use of command line arguments to add a help option (triggered with `-h` or
+ `--help`) and a `-C` or `--chars` option that adds another section that
+ prints the bytes interpreted as text. Those bytes that have no text
+ representation should be displayed as `.`. You may use the `argparse` library
+ to work with the arguments.
Hexdump Example Display
-`data/metasyntactic.md` looks like this when hexdumped:
+`data/metasyntactic.md` should look like this when hexdumped:
```text
Line Data
=================================================
-0000000 ┃ 6f4e 6574 203a 6854 7369 6920 2073 6874
-0000010 ┃ 2065 6957 696b 6570 6964 2061 6170 6567
-0000020 ┃ 6620 726f 6d20 7465 7361 6e79 6174 7463
-0000030 ┃ 6369 7620 7261 6169 6c62 7365 6920 206e
-0000040 ┃ 6e45 6c67 7369 2c68 3220 3230 2d33 3930
-0000050 ┃ 302d 2e35 4620 6e69 2064 6874 0a65 7075
-0000060 ┃ 7420 206f 6164 6574 6f20 6972 6967 616e
-0000070 ┃ 206c 685b 7265 5d65 6828 7474 7370 2f3a
-0000080 ┃ 652f 2e6e 6977 696b 6570 6964 2e61 726f
-0000090 ┃ 2f67 6977 696b 4d2f 7465 7361 6e79 6174
-00000a0 ┃ 7463 6369 765f 7261 6169 6c62 2965 0a2e
-00000b0 ┃ 230a 4d20 7465 7361 6e79 6174 7463 6369
-00000c0 ┃ 7620 7261 6169 6c62 0a65 230a 2023 6f54
-00000d0 ┃ 6c6f 0a73 460a 6f72 206d 6957 696b 6570
-00000e0 ┃ 6964 2c61 7420 6568 6620 6572 2065 6e65
-00000f0 ┃ 7963 6c63 706f 6465 6169 540a 6968 2073
-0000100 ┃ 7261 6974 6c63 2065 7369 6120 6f62 7475
-0000110 ┃ 6d20 7465 7361 6e79 6174 7463 6369 7620
+0000000 | 6f4e 6574 203a 6854 7369 6920 2073 6874
+0000010 | 2065 6957 696b 6570 6964 2061 6170 6567
+0000020 | 6620 726f 6d20 7465 7361 6e79 6174 7463
+0000030 | 6369 7620 7261 6169 6c62 7365 6920 206e
+0000040 | 6e45 6c67 7369 2c68 3220 3230 2d33 3930
+0000050 | 302d 2e35 4620 6e69 2064 6874 0a65 7075
+0000060 | 7420 206f 6164 6574 6f20 6972 6967 616e
+0000070 | 206c 685b 7265 5d65 6828 7474 7370 2f3a
+0000080 | 652f 2e6e 6977 696b 6570 6964 2e61 726f
+0000090 | 2f67 6977 696b 4d2f 7465 7361 6e79 6174
+00000a0 | 7463 6369 765f 7261 6169 6c62 2965 0a2e
+00000b0 | 230a 4d20 7465 7361 6e79 6174 7463 6369
+00000c0 | 7620 7261 6169 6c62 0a65 230a 2023 6f54
+00000d0 | 6c6f 0a73 460a 6f72 206d 6957 696b 6570
+00000e0 | 6964 2c61 7420 6568 6620 6572 2065 6e65
+00000f0 | 7963 6c63 706f 6465 6169 540a 6968 2073
+0000100 | 7261 6974 6c63 2065 7369 6120 6f62 7475
+0000110 | 6d20 7465 7361 6e79 6174 7463 6369 7620
+...
+```
+
+And like this when hexdumped with `-C`:
+
+```text
+Line Data Text
+======================================================================
+0000000 | 6f4e 6574 203a 6854 7369 6920 2073 6874 |Note: This is th|
+0000010 | 2065 6957 696b 6570 6964 2061 6170 6567 |e Wikipedia page|
+0000020 | 6620 726f 6d20 7465 7361 6e79 6174 7463 | for metasyntact|
+0000030 | 6369 7620 7261 6169 6c62 7365 6920 206e |ic variables in |
+0000040 | 6e45 6c67 7369 2c68 3220 3230 2d33 3930 |English, 2023-09|
+0000050 | 302d 2e35 4620 6e69 2064 6874 0a65 7075 |-05. Find the.up|
+0000060 | 7420 206f 6164 6574 6f20 6972 6967 616e | to date origina|
+0000070 | 206c 685b 7265 5d65 6828 7474 7370 2f3a |l [here](https:/|
+0000080 | 652f 2e6e 6977 696b 6570 6964 2e61 726f |/en.wikipedia.or|
+0000090 | 2f67 6977 696b 4d2f 7465 7361 6e79 6174 |g/wiki/Metasynta|
+00000a0 | 7463 6369 765f 7261 6169 6c62 2965 0a2e |ctic_variable)..|
+00000b0 | 230a 4d20 7465 7361 6e79 6174 7463 6369 |.# Metasyntactic|
+00000c0 | 7620 7261 6169 6c62 0a65 230a 2023 6f54 | variable..## To|
+00000d0 | 6c6f 0a73 460a 6f72 206d 6957 696b 6570 |ols..From Wikipe|
+00000e0 | 6964 2c61 7420 6568 6620 6572 2065 6e65 |dia, the free en|
+00000f0 | 7963 6c63 706f 6465 6169 540a 6968 2073 |cyclopedia.This |
...
```
+
+
+Hints
+
+
+
+
+
+
+Solution
+
+[Code Example](./src/hexdumper.py)
+
+
+
+### B. Packaging your hexdumper
+
+1. Install `pip`, on debian based systems you can do that with `apt-get install
+ python3-pip`.
diff --git a/src/caesar.py b/src/caesar.py
old mode 100644
new mode 100755
diff --git a/src/hexdumper.py b/src/hexdumper.py
new file mode 100755
index 0000000..c4604cb
--- /dev/null
+++ b/src/hexdumper.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+import argparse
+import os
+import sys
+
+# 2**30 bytes aka 1 Mebibyte
+MAX_SIZE: int = 0x100000
+
+
+
+def humanbytes(B):
+ """Return the given bytes as a human friendly KB, MB, GB, or TB string."""
+ B = float(B)
+ KB = float(1024)
+ MB = float(KB ** 2) # 1,048,576
+ GB = float(KB ** 3) # 1,073,741,824
+ TB = float(KB ** 4) # 1,099,511,627,776
+
+ if B < KB:
+ return '{0} {1}'.format(B,'Bytes' if 0 == B > 1 else 'Byte')
+ elif KB <= B < MB:
+ return '{0:.2f} KB'.format(B / KB)
+ elif MB <= B < GB:
+ return '{0:.2f} MB'.format(B / MB)
+ elif GB <= B < TB:
+ return '{0:.2f} GB'.format(B / GB)
+ elif TB <= B:
+ return '{0:.2f} TB'.format(B / TB)
+
+def main():
+ """Dump a file"""
+ # arg parsing
+ parser = argparse.ArgumentParser(
+ prog="hexer",
+ description="Dumps data as hex"
+ )
+ parser.add_argument("file")
+ parser.add_argument("-c", "--chars", action="store_true")
+ args = parser.parse_args()
+
+ # open file
+ try:
+ file = open(args.file, "rb")
+ except Exception as e:
+ print(f"Could not open file '{args.file}': {e}")
+ sys.exit(1)
+
+ # check if the file has a reasonable size to dump
+ if 0 != os.path.getsize(args.file) > MAX_SIZE:
+ print(f"""The file you are trying to dump is larger than 1M.\n\
+ Actual size: {humanbytes(os.path.getsize(args.file))}\nrefusing to dump""")
+ sys.exit(2)
+ # print header
+ if args.chars:
+ print("Line Data Text")
+ print('=' * 68)
+ else:
+ print(f"Line Data")
+ print('=' * 48)
+
+ # every line should contain 16 bytes, so we need a loop that get's 16 bytes
+ # and then works with them
+ next: bytes = bytes(16)
+ index: int = 0
+ while len(next) == 16:
+ next = file.read(16)
+ if len(next) == 0:
+ # no data left to read
+ break
+
+ line: str = f"{index:07x} | "
+
+ # actual hexdumping
+ for i in range(16):
+ if i % 2 == 0:
+ if len(next) > i+1:
+ line += f"{next[i]:02x}{next[i+1]:02x} "
+ elif len(next) > i:
+ line += f"{next[i]:02x} "
+ else:
+ line += " "
+ else: continue
+
+ # if chars is enabled, print chars
+ if args.chars:
+ line += "| "
+ for b in next:
+ # special case for newline
+ if b == 0x0a:
+ line+= '' # official unicode symbol representing newlines
+ # only print regular characters
+ elif b > 0x20 and b < 0x7e:
+ line += chr(b)
+ elif b == 0x20:
+ line += '\u2420'
+ else:
+ line += '.'
+
+ print(line)
+ index += 16
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/tasks/hexdumper-a.py b/src/tasks/hexdumper-a.py
deleted file mode 100755
index 7303f72..0000000
--- a/src/tasks/hexdumper-a.py
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env python3
-import sys
-
-def main():
- # parse args
-
-if __name__ == "__main__":
- main()