summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRangi <remy.oukaour+rangi42@gmail.com>2020-09-16 12:15:10 -0400
committerRangi <remy.oukaour+rangi42@gmail.com>2020-09-16 12:15:10 -0400
commit331c9043d2d6d39cb71d4460de97f22fb5ebab3c (patch)
tree7e907694ae3fa085ebe9a63adb23024790e633a9
parent0f5510b72ea8843d54ffaaf1c70c24d271f5dc67 (diff)
tools/xor_compress revisions:
- C outputs bc run count to stdout - Python supports -v to output bc run count - Add Rust rewrite
-rw-r--r--tools/xor_compress.c2
-rw-r--r--tools/xor_compress.py25
-rw-r--r--tools/xor_compress.rs97
3 files changed, 119 insertions, 5 deletions
diff --git a/tools/xor_compress.c b/tools/xor_compress.c
index f186f05..48e5167 100644
--- a/tools/xor_compress.c
+++ b/tools/xor_compress.c
@@ -90,7 +90,7 @@ int write_compressed(const char *filename, unsigned char *data, size_t n, bool v
}
}
- if (verbose) fprintf(stderr, PROGRAM_NAME ": %s: ld bc, $%x\n", filename, runs);
+ if (verbose) printf(PROGRAM_NAME ": %s: ld bc, $%x\n", filename, runs);
fflush(f);
fclose(f);
diff --git a/tools/xor_compress.py b/tools/xor_compress.py
index b3bf317..015c80e 100644
--- a/tools/xor_compress.py
+++ b/tools/xor_compress.py
@@ -1,11 +1,22 @@
#!/usr/bin/env python3
-# Usage: ./xor_compress.py sources.bin... > dest.bin.xor
-
import sys
+sys.argv.pop(0)
+
+verbose = False
+if sys.argv and sys.argv[0] == '-v':
+ verbose = True
+ sys.argv.pop(0)
+
+if len(sys.argv) < 2:
+ print('Usage: xor_compress.py [-v] file... files.xor', file=sys.stderr)
+ exit(1)
+
+out_filename = sys.argv.pop()
+
data = bytearray()
-for filename in sys.argv[1:]:
+for filename in sys.argv:
with open(filename, 'rb') as f:
data.extend(f.read())
@@ -13,10 +24,12 @@ n = len(data)
output = bytearray()
v = 0x00
i = 0
+runs = 0
while i < n:
byte = data[i]
i += 1
+ runs += 1
if data[i] == v:
# Alternating (>= 0x80)
@@ -44,4 +57,8 @@ while i < n:
output.append(len(buffer) - 1)
output.extend(buffer)
-sys.stdout.buffer.write(output)
+with open(out_filename, 'wb') as f:
+ f.write(output)
+
+if verbose:
+ print('%s: ld bc, $%x' % (out_filename, runs))
diff --git a/tools/xor_compress.rs b/tools/xor_compress.rs
new file mode 100644
index 0000000..0d912ba
--- /dev/null
+++ b/tools/xor_compress.rs
@@ -0,0 +1,97 @@
+const PROGRAM_NAME: &str = "xor_compress";
+
+fn read_files(filenames: &[String]) -> Result<Vec<u8>, (&String, std::io::Error)> {
+ let mut data = Vec::new();
+ for filename in filenames.iter() {
+ match std::fs::read(filename) {
+ Ok(bytes) => data.extend(&bytes),
+ Err(err) => return Err((filename, err)),
+ }
+ }
+ Ok(data)
+}
+
+fn write_compressed(filename: &String, data: Vec<u8>) -> Result<u32, std::io::Error> {
+ let n = data.len();
+
+ let mut output = Vec::new();
+ let mut v = 0x00;
+ let mut i = 0;
+ let mut runs = 0;
+
+ while i < n {
+ let mut byte = data[i];
+ i += 1;
+ runs += 1;
+
+ if data[i] == v {
+ // Alternating (>= 0x80)
+ // Run stops at 0x80 bytes or when the values stop alternating
+ let mut size = 0;
+ while i < n && size < 0x80 && data[i] == (if size % 2 == 0 { v } else { byte }) {
+ size += 1;
+ i += 1;
+ }
+ output.push(size + 0x7f);
+ output.push(v ^ byte);
+ if size % 2 == 0 {
+ v = byte;
+ }
+ } else {
+ // Sequential (< 0x80)
+ // Run stops at 0x80 bytes or when the value two ahead is equal to v
+ let mut buffer = vec![v ^ byte];
+ while i < n {
+ v = byte;
+ if buffer.len() > 0x7f || (i + 1 < n && data[i + 1] == v) {
+ break;
+ }
+ byte = data[i];
+ buffer.push(v ^ byte);
+ i += 1;
+ }
+ output.push((buffer.len() - 1) as u8);
+ output.extend(buffer);
+ }
+ }
+
+ match std::fs::write(filename, &output[..]) {
+ Ok(()) => Ok(runs),
+ Err(err) => Err(err),
+ }
+}
+
+fn main() {
+ let mut args: Vec<String> = std::env::args().skip(1).collect();
+
+ let mut verbose = false;
+ if !args.is_empty() && args[0] == "-v" {
+ verbose = true;
+ args.remove(0);
+ }
+
+ if args.len() < 2 {
+ eprintln!("Usage: {} [-v] file... files.xor", PROGRAM_NAME);
+ std::process::exit(1);
+ }
+
+ let out_filename = args.pop().unwrap();
+ let data = match read_files(&args[..]) {
+ Ok(data) => data,
+ Err((filename, err)) => {
+ eprintln!("{}: {}: {}", PROGRAM_NAME, filename, err);
+ std::process::exit(err.raw_os_error().unwrap_or(1));
+ }
+ };
+ if !data.is_empty() {
+ match write_compressed(&out_filename, data) {
+ Ok(runs) => if verbose {
+ println!("{}: {}: ld bc, ${:x}", PROGRAM_NAME, out_filename, runs);
+ },
+ Err(err) => {
+ eprintln!("{}: {}: {}", PROGRAM_NAME, out_filename, err);
+ std::process::exit(err.raw_os_error().unwrap_or(1));
+ },
+ }
+ }
+}