├── .gitignore ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── README.md └── src ├── bin ├── hex.rs ├── hexdump.rs └── strings.rs ├── bits.rs ├── convert.rs ├── lib.rs └── strings.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - nightly 4 | sudo: false 5 | notifications: 6 | email: false 7 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "binutils" 5 | version = "0.1.0" 6 | dependencies = [ 7 | "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", 8 | ] 9 | 10 | [[package]] 11 | name = "extra" 12 | version = "0.1.0" 13 | source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#cf213969493db8667052a591e32a1e26d43c4234" 14 | 15 | [metadata] 16 | "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "binutils" 3 | version = "0.1.0" 4 | authors = ["Ticki "] 5 | 6 | [[bin]] 7 | name = "strings" 8 | path = "src/bin/strings.rs" 9 | 10 | [[bin]] 11 | name = "hex" 12 | path = "src/bin/hex.rs" 13 | 14 | [[bin]] 15 | name = "hexdump" 16 | path = "src/bin/hexdump.rs" 17 | 18 | [dependencies.extra] 19 | git = "https://gitlab.redox-os.org/redox-os/libextra.git" 20 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Ticki 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redox OS binutils 2 | 3 | This repository contains UNIX utilities for dealing with binaries for Redox OS. 4 | 5 | [![Travis Build Status](https://travis-ci.org/redox-os/binutils.svg?branch=master)](https://travis-ci.org/redox-os/binutils) 6 | -------------------------------------------------------------------------------- /src/bin/hex.rs: -------------------------------------------------------------------------------- 1 | extern crate binutils; 2 | 3 | use std::env; 4 | use std::fs; 5 | use std::io::{self, Stderr, Write, Read}; 6 | 7 | use binutils::extra::option::OptionalExt; 8 | use binutils::extra::io::{WriteExt, fail}; 9 | use binutils::convert::{u8_to_hex, hex_to_u8, ascii_to_hex, hex_to_ascii}; 10 | 11 | const HELP: &'static [u8] = br#" 12 | NAME 13 | hex - read a binary file and output it in hexadecimal representation. 14 | SYNOPSIS 15 | hex [-h | --help] [-d | --decode] [FILE] 16 | DESCRIPTION 17 | This utility will read the file from the path given in the argument. If no argument is given, 'hex' will read from the standard input. The content of the file is then encoded/decoded in/from hexadecimal. 18 | 19 | In opposite to GNU Hexdump, 'hex' will treat the input as big endianness left-to-right byte stream. Furthermore, there is no stylistic representation, the output is just plain ASCII, with no spaces or new-lines for seperations. 20 | OPTIONS 21 | -h 22 | --help 23 | Print this manual page. 24 | -d 25 | --decode 26 | Decode hexadecimal. 27 | AUTHOR 28 | This program was written by Ticki. Bugs should be reported in the Github repository, 'redox-os/binutils'. 29 | COPYRIGHT 30 | Copyright (c) 2016 Ticki 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 33 | 34 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 35 | 36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | "#; 38 | 39 | fn encode(stdin: R, mut stdout: W, mut stderr: Stderr) { 40 | // Encode the input stream to hexadecimal output stream. 41 | 42 | for i in stdin.bytes() { 43 | let (a, b) = u8_to_hex(i.try(&mut stderr)); 44 | stdout.write(&[hex_to_ascii(a), hex_to_ascii(b)]).try(&mut stderr); 45 | } 46 | } 47 | 48 | fn decode(stdin: R, mut stdout: W, mut stderr: Stderr) { 49 | // Decode hexadecimal to base-256, raw byte stream. 50 | 51 | let mut iter = stdin.bytes(); 52 | loop { 53 | let i = if let Some(x) = iter.next() { 54 | x.try(&mut stderr) 55 | } else { 56 | break 57 | }; 58 | let j = if let Some(x) = iter.next() { 59 | x.try(&mut stderr) 60 | } else { 61 | break 62 | }; 63 | 64 | stdout.write(&[hex_to_u8((ascii_to_hex(i), ascii_to_hex(j)))]).try(&mut stderr); 65 | } 66 | } 67 | 68 | fn main() { 69 | let stdout = io::stdout(); 70 | let mut stdout = stdout.lock(); 71 | let mut stderr = io::stderr(); 72 | 73 | let mut args = env::args(); 74 | if args.len() > 2 { 75 | fail("too many arguments.", &mut stderr); 76 | } 77 | 78 | match args.nth(1) { 79 | None => encode(io::stdin(), stdout, stderr), 80 | Some(a) => match a.as_ref() { // MIR plz 81 | "-h" | "--help" => { 82 | stdout.writeln(HELP).try(&mut stderr); 83 | }, 84 | "-d" | "--decode" => { 85 | match args.next() { 86 | Some(f) => { 87 | let file = fs::File::open(f).try(&mut stderr); 88 | decode(file, stdout, stderr); 89 | }, 90 | None => { 91 | let stdin = io::stdin(); 92 | decode(stdin.lock(), stdout, stderr); 93 | }, 94 | } 95 | }, 96 | // Read from file instead of standard input. 97 | f => { 98 | let file = fs::File::open(f).try(&mut stderr); 99 | encode(file, stdout, stderr); 100 | }, 101 | }, 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/bin/hexdump.rs: -------------------------------------------------------------------------------- 1 | extern crate binutils; 2 | 3 | use std::env; 4 | use std::fs; 5 | use std::io::{self, Write, Read, Stderr}; 6 | use std::mem; 7 | 8 | use binutils::extra::option::OptionalExt; 9 | use binutils::extra::io::{WriteExt, fail}; 10 | use binutils::convert::{u8_to_hex, hex_to_u8, u32_byte_array, hex_to_ascii, ascii_to_hex}; 11 | use binutils::strings::IsPrintable; 12 | 13 | const HELP: &'static [u8] = br#" 14 | NAME 15 | hexdump - dump the hexidecimal representation of a byte stream. 16 | SYNOPSIS 17 | hexdump [-h | --help] [-r | --reverse] [FILE] 18 | DESCRIPTION 19 | This utility will dump the hexidecimal representation of a file or the standard input, in a stylized way. Hexdump utility behaves like 'xxd'. 20 | 21 | The first column signifies the address of the first byte on the line. Each line contains 16 bytes, grouped in groups of two bytes, sepereated by space. The last column contains the printable characters in the last 16 bytes. The non-printable characters are replaced by a '.'. 22 | OPTIONS 23 | -h 24 | --help 25 | Print this manual page. 26 | -r 27 | --reverse 28 | Do the reverse dump (consume the dump and output the bytes it defines). This is useful for usage within editors. 29 | AUTHOR 30 | This program was written by Ticki. Bugs should be reported in the Github repository, 'redox-os/binutils'. 31 | COPYRIGHT 32 | Copyright (c) 2016 Ticki 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 35 | 36 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 37 | 38 | Someone once read this. True story, bruh. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 41 | "#; 42 | 43 | /// Encode a single byte to the output stream 44 | fn encode_byte(stdin: &mut R, stdout: &mut W, stderr: &mut Stderr) -> Option { 45 | let byte = if let Some(x) = stdin.bytes().next() { 46 | x.try(&mut *stderr) 47 | } else { 48 | return None; 49 | }; 50 | 51 | // Convert the raw byte to hexadecimal 52 | let hex = u8_to_hex(byte); 53 | 54 | // Write it to stdout. 55 | stdout.write(&[hex_to_ascii(hex.0), hex_to_ascii(hex.1)]).try(stderr); 56 | 57 | Some(if byte.is_printable() { 58 | byte 59 | } else { 60 | // If it is non-printable, write `.` to char-buffer instead. 61 | b'.' 62 | }) 63 | } 64 | 65 | fn encode(mut stdin: R, mut stdout: W, mut stderr: Stderr) { 66 | let rem; 67 | // This is the char buffer. The last 16 byte column, which prints the printable characters. 68 | // The non-printable ones are replaced with `.`. 69 | let mut ascii: [u8; 16] = unsafe { mem::uninitialized() }; 70 | 71 | let mut line = 0; 72 | 73 | 'a: loop { 74 | // Iterate over the bytes in the line number times 16. 75 | for &b in u32_byte_array(line * 16).iter() { 76 | let hex = u8_to_hex(b); 77 | // Print this value to the first column (denoting the address of the first byte of the 78 | // line.) 79 | stdout.write(&[hex_to_ascii(hex.0), hex_to_ascii(hex.1)]).try(&mut stderr); 80 | } 81 | stdout.write(b": ").try(&mut stderr); 82 | 83 | // Now, we go over the actual data, printing it in hexadecimal. 84 | for n in 0..8 { 85 | // We add the char to the char buffer, and print it in two hex digits. 86 | ascii[n * 2] = if let Some(x) = encode_byte(&mut stdin, &mut stdout, &mut stderr) { 87 | x 88 | } else { 89 | // The end of the file is reached, set the remainder, which will later be used for 90 | // alignment of the last column. 91 | rem = n; 92 | break 'a; 93 | }; 94 | ascii[n * 2 + 1] = if let Some(x) = encode_byte(&mut stdin, &mut stdout, &mut stderr) { 95 | x 96 | } else { 97 | rem = n; 98 | break 'a; 99 | }; 100 | // Seperate every two hex digits by a space. 101 | stdout.write(b" ").try(&mut stderr); 102 | } 103 | 104 | stdout.write(b" ").try(&mut stderr); 105 | // Print the ASCII buffer at the end of the line. 106 | stdout.writeln(&ascii).try(&mut stderr); 107 | 108 | // Increment the line number. 109 | line += 1; 110 | } 111 | 112 | if rem != 0 { 113 | // We now align the last column using the remainder set before. 114 | for _ in 0..41 - rem * 5 { 115 | stdout.write(b" ").try(&mut stderr); 116 | } 117 | stdout.write(&ascii[..rem * 2]).try(&mut stderr); 118 | } 119 | 120 | stdout.write(b"\n").try(&mut stderr); 121 | } 122 | 123 | fn decode(stdin: R, mut stdout: W, mut stderr: Stderr) { 124 | let mut stdin = stdin.bytes().filter(|x| x.as_ref().ok() != Some(&b' ')); 125 | 126 | loop { 127 | // Skip the first column 128 | stdin.nth(8); 129 | // Process the inner 8 columns 130 | for _ in 0..16 { 131 | // The first hex digit to decode. 132 | let h1 = ascii_to_hex( 133 | if let Some(x) = stdin.next() { 134 | x.try(&mut stderr) 135 | } else { 136 | return; 137 | } 138 | ); 139 | // The second hex digit to decode. 140 | let h2 = ascii_to_hex( 141 | if let Some(x) = stdin.next() { 142 | x.try(&mut stderr) 143 | } else { 144 | return; 145 | } 146 | ); 147 | 148 | // Write the decoded, joined hex digits in binary form. 149 | stdout.write(&[hex_to_u8((h1, h2))]).try(&mut stderr); 150 | } 151 | 152 | // Skip the rest until newline. 153 | loop { 154 | if let Some(x) = stdin.next() { 155 | if x.try(&mut stderr) == b'\n' { 156 | break; 157 | } 158 | } else { 159 | return; 160 | } 161 | } 162 | } 163 | } 164 | 165 | fn main() { 166 | let stdout = io::stdout(); 167 | let mut stdout = stdout.lock(); 168 | let mut stderr = io::stderr(); 169 | 170 | let mut args = env::args(); 171 | 172 | // Arguments should be <= 2 173 | if args.len() > 2 { 174 | fail("too many arguments.", &mut stderr); 175 | } 176 | 177 | match args.nth(1) { 178 | None => encode(io::stdin(), stdout, stderr), 179 | Some(a) => match a.as_ref() { // MIR plz 180 | "-h" | "--help" => { 181 | // HEEEEEELP. 182 | stdout.writeln(HELP).try(&mut stderr); 183 | }, 184 | "-r" | "--reverse" => { 185 | match args.next() { 186 | // Decode. 187 | None => { 188 | let stdin = io::stdin(); 189 | decode(stdin.lock(), stdout, stderr); 190 | } 191 | // Encode. 192 | Some(f) => { 193 | let file = fs::File::open(f).try(&mut stderr); 194 | decode(file, stdout, stderr); 195 | } 196 | } 197 | }, 198 | // Read from a file, instead of standard input. 199 | f => { 200 | let file = fs::File::open(f).try(&mut stderr); 201 | encode(file, stdout, stderr); 202 | }, 203 | }, 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/bin/strings.rs: -------------------------------------------------------------------------------- 1 | extern crate binutils; 2 | 3 | use std::env; 4 | use std::fs; 5 | use std::io; 6 | 7 | use binutils::strings::read; 8 | use binutils::extra::option::OptionalExt; 9 | use binutils::extra::io::{WriteExt, fail}; 10 | 11 | const HELP: &'static [u8] = br#" 12 | NAME 13 | strings - inspect a binary file for strings of printable characters. 14 | SYNOPSIS 15 | strings [-h | --help] [FILE] 16 | DESCRIPTION 17 | This utility will read the file from the path given in the argument. If no argument is given, 'strings' will read from the standard input. The byte stream is then inspected for contiguous, printable ASCII characters of length 4 or more. These strings of printable characters are written to the standard output. Each contiguous strings are seperated by a newline (0x0A). 18 | 19 | This utility is useful for inspecting binary files for human readable information, to determine the contents. Note that all non-ASCII characters are treated as non-printable, due to the numerous false positives otherwise. 20 | 21 | This is a clone of GNU strings, though they differ in a number of ways. 22 | 23 | OPTIONS 24 | -h 25 | --help 26 | Print this manual page. 27 | AUTHOR 28 | This program was written by Ticki. Bugs should be reported in the Github repository, 'redox-os/binutils'. 29 | COPYRIGHT 30 | Copyright (c) 2016 Ticki 31 | 32 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 33 | 34 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 35 | 36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 | "#; 38 | 39 | fn main() { 40 | let stdout = io::stdout(); 41 | let mut stdout = stdout.lock(); 42 | let mut stderr = io::stderr(); 43 | let mut args = env::args(); 44 | 45 | if args.len() > 2 { 46 | fail("too many arguments.", &mut stderr); 47 | } 48 | 49 | match args.nth(1) { 50 | None => { 51 | let stdin = io::stdin(); 52 | read(stdin.lock(), stdout, stderr); 53 | } 54 | Some(a) => match a.as_ref() { 55 | "-h" | "--help" => { 56 | stdout.writeln(HELP).try(&mut stderr); 57 | }, 58 | f => { 59 | let file = fs::File::open(f).try(&mut stderr); 60 | read(file, stdout, stderr); 61 | } 62 | }, 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/bits.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Range; 2 | 3 | /// A trait for slicing integer's bits 4 | pub trait BitSlice : Sized { 5 | /// Slice an integer's bits by a range 6 | fn bit_slice(self, range: Range) -> Self; 7 | } 8 | 9 | impl BitSlice for u8 { 10 | fn bit_slice(self, range: Range) -> Self { 11 | self << range.start >> range.start >> (8 - range.end) 12 | } 13 | } 14 | 15 | #[test] 16 | fn bit_slice_test() { 17 | assert_eq!(0b10000100.bit_slice(1..2), 0); 18 | assert_eq!(0b10000100.bit_slice(0..2), 0b10); 19 | assert_eq!(0b10001110.bit_slice(4..8), 0b1110); 20 | assert_eq!(0b00001110.bit_slice(0..4), 0); 21 | assert_eq!(0b00001110.bit_slice(3..8), 0b1110); 22 | } 23 | -------------------------------------------------------------------------------- /src/convert.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | /// Convert a base 256 (byte) to a hexadecimal representation 4 | #[inline] 5 | pub fn u8_to_hex(from: u8) -> (u8, u8) { 6 | (from >> 4, from & 0b1111) 7 | } 8 | 9 | /// Convert two hexadecimal digits to a byte 10 | #[inline] 11 | pub fn hex_to_u8((a, b): (u8, u8)) -> u8 { 12 | (a << 4) + b 13 | } 14 | 15 | /// Convert an u32 to an byte array. This operation is safe. It is an noop on big-endianness 16 | #[inline] 17 | pub fn u32_byte_array(int: u32) -> [u8; 4] { 18 | // Safe 19 | // ((int >> (32 - 8 - n * 8)) & 255) as u8 20 | // or unsafe: 21 | unsafe { 22 | mem::transmute::<_, [u8; 4]>(int.to_be()) 23 | } 24 | } 25 | 26 | /// Convert hex to ascii 27 | #[inline] 28 | pub fn hex_to_ascii(b: u8) -> u8 { 29 | match b { 30 | 0...9 => b'0' + b, 31 | _ => b'a' - 10 + b, 32 | } 33 | } 34 | 35 | /// Convert ascii to hex 36 | #[inline] 37 | pub fn ascii_to_hex(b: u8) -> u8 { 38 | match b { 39 | b'0'...b'9' => b - b'0', 40 | _ => b - b'a' + 10, 41 | } 42 | } 43 | 44 | /// Convert a base 256 (byte) to an octal representation 45 | #[inline] 46 | pub fn u8_to_oct(from: u8) -> (u8, u8, u8) { 47 | (from >> 6, (from >> 3) & 0b111, from & 0b111) 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use super::*; 53 | 54 | #[test] 55 | fn test_hex_to_u8() { 56 | for i in 0..255 { 57 | assert_eq!(hex_to_u8(u8_to_hex(i)), i); 58 | } 59 | } 60 | 61 | #[test] 62 | fn test_hex2ascii() { 63 | assert_eq!(hex_to_ascii(0x0), b'0'); 64 | assert_eq!(hex_to_ascii(0x1), b'1'); 65 | assert_eq!(hex_to_ascii(0x2), b'2'); 66 | assert_eq!(hex_to_ascii(0x3), b'3'); 67 | assert_eq!(hex_to_ascii(0x4), b'4'); 68 | 69 | assert_eq!(hex_to_ascii(0xa), b'a'); 70 | assert_eq!(hex_to_ascii(0xb), b'b'); 71 | assert_eq!(hex_to_ascii(0xc), b'c'); 72 | } 73 | 74 | #[test] 75 | fn ascii2hex() { 76 | for i in 0..16 { 77 | assert_eq!(ascii_to_hex(hex_to_ascii(i)), i); 78 | } 79 | } 80 | 81 | #[test] 82 | fn test_hex() { 83 | for i in 0..16 { 84 | assert_eq!(u8_to_hex(i), (0, i)); 85 | } 86 | 87 | assert_eq!(u8_to_hex(0xDE), (0xD, 0xE)); 88 | assert_eq!(u8_to_hex(0xAD), (0xA, 0xD)); 89 | assert_eq!(u8_to_hex(0xBE), (0xB, 0xE)); 90 | assert_eq!(u8_to_hex(0xAF), (0xA, 0xF)); 91 | 92 | assert_eq!(u8_to_hex(0x12), (1, 2)); 93 | assert_eq!(u8_to_hex(0xA5), (0xA, 5)); 94 | assert_eq!(u8_to_hex(0x42), (4, 2)); 95 | } 96 | 97 | #[test] 98 | fn test_oct() { 99 | assert_eq!(u8_to_oct(0o102), (1, 0, 2)); 100 | assert_eq!(u8_to_oct(0o002), (0, 0, 2)); 101 | assert_eq!(u8_to_oct(0o000), (0, 0, 0)); 102 | assert_eq!(u8_to_oct(0o111), (1, 1, 1)); 103 | assert_eq!(u8_to_oct(0o277), (2, 7, 7)); 104 | } 105 | 106 | #[test] 107 | fn u32_byte() { 108 | for i in 0..255923 { 109 | assert_eq!(u32_byte_array(i)[3], (i & 255) as u8); 110 | assert_eq!(u32_byte_array(i)[0], (i >> (8 * 3)) as u8); 111 | for n in 0..4 { 112 | assert_eq!(u32_byte_array(i)[n], ((i >> (32 - 8 - n * 8)) & 255) as u8) 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Binutils: The distribution of utilities to process, read, and write binary files for the 2 | //! Redox operating system. 3 | 4 | // If this code works, it was written by Ticki. If it does not, I don't know who the hell wrote it 5 | // but it was definitively not me. Blame someone else. 6 | 7 | #![deny(missing_docs)] 8 | 9 | pub extern crate extra; 10 | 11 | /// Scan a byte stream for printable strings of 4 or more bytes. 12 | pub mod strings; 13 | 14 | /// Primitives for processing bits. 15 | pub mod bits; 16 | 17 | /// Converting between bases and endianesses 18 | pub mod convert; 19 | -------------------------------------------------------------------------------- /src/strings.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Write, Read, Stderr}; 2 | 3 | use extra::option::OptionalExt; 4 | 5 | /// A trait for characters/bytes that can be printable. 6 | pub trait IsPrintable { 7 | /// Is this character printable? 8 | fn is_printable(self) -> bool; 9 | } 10 | 11 | impl IsPrintable for u8 { 12 | #[inline] 13 | fn is_printable(self) -> bool { 14 | // TODO handle unicode. 15 | self >= 0x20 && self <= 0x7e 16 | } 17 | } 18 | 19 | /// A buffer tracking the previous printable characters. 20 | #[derive(Copy, Clone)] 21 | struct Trailing { 22 | chars: [u8; 4], 23 | current: usize, 24 | } 25 | 26 | // Wow, such premature, much optimization 27 | #[allow(dead_code)] // DAFUQ rustc? 28 | impl Trailing { 29 | #[inline] 30 | fn new() -> Trailing { 31 | Trailing { 32 | chars: [0; 4], 33 | current: 0, 34 | } 35 | } 36 | 37 | #[inline] 38 | fn set(&mut self, b: u8) -> bool { 39 | self.chars[self.current] = b; 40 | self.current += 1; 41 | 42 | self.is_complete() 43 | } 44 | 45 | #[inline] 46 | fn reset(&mut self) { 47 | self.current = 0; 48 | } 49 | 50 | #[inline] 51 | fn is_complete(self) -> bool { 52 | self.current == 4 53 | } 54 | 55 | #[inline] 56 | fn chars(self) -> [u8; 4] { 57 | self.chars 58 | } 59 | } 60 | 61 | /// Read a stream of bytes and output printable strings of length 4 or more seperated by 0x0A 62 | /// (NL) 63 | pub fn read(stdin: R, mut stdout: W, mut stderr: Stderr) { 64 | let mut trailing = Trailing::new(); 65 | 66 | for i in stdin.bytes() { 67 | let i = i.try(&mut stderr); 68 | 69 | if i.is_printable() { 70 | if trailing.is_complete() { 71 | stdout.write(&[i]).try(&mut stderr); 72 | } else if trailing.set(i) { 73 | stdout.write(&trailing.chars()).try(&mut stderr); 74 | } 75 | } else { 76 | if trailing.is_complete() { 77 | stdout.write(b"\n").try(&mut stderr); 78 | } 79 | trailing.reset(); 80 | } 81 | } 82 | } 83 | 84 | #[cfg(test)] 85 | mod test { 86 | use super::*; 87 | 88 | #[test] 89 | fn printable() { 90 | assert!(!b'\0'.is_printable()); 91 | assert!(!b'\t'.is_printable()); 92 | assert!(!b'\n'.is_printable()); 93 | assert!(!b'\r'.is_printable()); 94 | assert!(!b'\x1b'.is_printable()); 95 | assert!(b'a'.is_printable()); 96 | assert!(b'B'.is_printable()); 97 | assert!(b'x'.is_printable()); 98 | assert!(b'~'.is_printable()); 99 | } 100 | } 101 | --------------------------------------------------------------------------------