Compare commits
10 Commits
386c2a5d27
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 73bf2c538c | |||
| 00638fca6e | |||
| 1c1721b861 | |||
| ae6c6e371b | |||
| 097d6a973c | |||
| 4650e84111 | |||
| 6350f421a1 | |||
| 156710ec53 | |||
| 3871a1dcb7 | |||
| c86504ea95 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,4 +10,3 @@ Cargo.lock
|
|||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
||||||
|
|||||||
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'address_book'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=address_book",
|
||||||
|
"--package=address_book"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "address_book",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in executable 'address_book'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--bin=address_book",
|
||||||
|
"--package=address_book"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "address_book",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "address_book"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jon Janzen <jon@endofeternity.ca>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
db = { path = "db" }
|
||||||
47
README.md
47
README.md
@@ -1,3 +1,48 @@
|
|||||||
# binary_address_book
|
# binary_address_book
|
||||||
|
|
||||||
binary address book from text manipulation chapter
|
binary address book from text manipulation chapter
|
||||||
|
|
||||||
|
# Address Book Fields
|
||||||
|
Things to store
|
||||||
|
1. First name(s)
|
||||||
|
2. Last name
|
||||||
|
3. Street Address
|
||||||
|
4. City
|
||||||
|
5. State/Province
|
||||||
|
6. Post Code
|
||||||
|
7. Phone Number
|
||||||
|
8. Extra
|
||||||
|
|
||||||
|
There can be any number of extras
|
||||||
|
|
||||||
|
# Binary Format
|
||||||
|
|
||||||
|
The binary format for the address book starts with a DB Header. Immediately following the DB Header is the first record header. Each record header is followed by the number of field headers indicated by the field count.
|
||||||
|
|
||||||
|
## DB Header
|
||||||
|
|
||||||
|
1. Magic 0xDB
|
||||||
|
2. u4 major
|
||||||
|
3. u4 minor version
|
||||||
|
4. u16 reserved
|
||||||
|
3. u32 record count
|
||||||
|
|
||||||
|
## Record Header
|
||||||
|
|
||||||
|
1. u8 field count
|
||||||
|
2. u8 length - not including header
|
||||||
|
3. u16 crc16-arc - not including header
|
||||||
|
|
||||||
|
022094A6
|
||||||
|
|
||||||
|
## Field
|
||||||
|
Hex
|
||||||
|
0100034a6f6e020006fa616e78a656e
|
||||||
|
```
|
||||||
|
Field 1 - First Name(s)
|
||||||
|
Length 3
|
||||||
|
Jon
|
||||||
|
Field 2 - Last Name
|
||||||
|
Length 6
|
||||||
|
Janzen
|
||||||
|
```
|
||||||
9
binary_loader/Cargo.toml
Normal file
9
binary_loader/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "binary_loader"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jon Janzen <jon@endofeternity.ca>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
94
binary_loader/src/lib.rs
Normal file
94
binary_loader/src/lib.rs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
pub fn load_high_u4(raw: &u8) -> u8 {
|
||||||
|
(raw & 0xF0) >> 4
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_low_u4(raw: &u8) -> u8 {
|
||||||
|
raw & 0x0F
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_u8(raw: &u8) -> u8 {
|
||||||
|
raw & 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_u16(raw: &[u8]) -> u16 {
|
||||||
|
let temp: u16 = raw[0].into();
|
||||||
|
let mut value: u16 = temp << 8;
|
||||||
|
let temp: u16 = raw[1].into();
|
||||||
|
value |= temp;
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_u32(raw: &[u8]) -> u32 {
|
||||||
|
let temp: u32 = raw[0].into();
|
||||||
|
let mut value: u32 = temp << 24;
|
||||||
|
let temp: u32 = raw[1].into();
|
||||||
|
value |= temp << 16;
|
||||||
|
let temp: u32 = raw[2].into();
|
||||||
|
value |= temp << 8;
|
||||||
|
let temp: u32 = raw[3].into();
|
||||||
|
value |= temp;
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_0() {
|
||||||
|
assert_eq!(0, load_u32(&[0, 0, 0, 0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_1() {
|
||||||
|
assert_eq!(1, load_u32(&[0, 0, 0, 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_big() {
|
||||||
|
let my_arr = [1, 0, 0, 2, 1, 1];
|
||||||
|
let slice = &my_arr[0..4];
|
||||||
|
assert_eq!(0x01000002, load_u32(&slice));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_low_u4() {
|
||||||
|
assert_eq!(0x07, load_low_u4(&0x07));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_low_u4_with_high_data() {
|
||||||
|
assert_eq!(0x03, load_low_u4(&0x13));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_low_u4_with_only_high_data() {
|
||||||
|
assert_eq!(0x00, load_low_u4(&0x30));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_high_u4() {
|
||||||
|
assert_eq!(0x07, load_high_u4(&0x70));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_high_u4_with_low_data() {
|
||||||
|
assert_eq!(0x01, load_high_u4(&0x13));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_high_u4_with_only_low_data() {
|
||||||
|
assert_eq!(0x00, load_high_u4(&0x03));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_u8() {
|
||||||
|
assert_eq!(0x43, load_u8(&0x43));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_load_u16() {
|
||||||
|
let my_arr = [0x34, 0x23];
|
||||||
|
assert_eq!(0x3423, load_u16(&my_arr));
|
||||||
|
}
|
||||||
|
}
|
||||||
10
db/Cargo.toml
Normal file
10
db/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "db"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Jon Janzen <jon@endofeternity.ca>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
binary_loader = { path = "../binary_loader" }
|
||||||
98
db/src/lib.rs
Normal file
98
db/src/lib.rs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
use binary_loader;
|
||||||
|
|
||||||
|
struct DBHeader {
|
||||||
|
magic: u8,
|
||||||
|
major_version: u8, // actually u4 in data
|
||||||
|
minor_version: u8, // actually u4 in data
|
||||||
|
reserved: u16,
|
||||||
|
record_count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DBHeader {
|
||||||
|
fn from(raw: &[u8]) -> DBHeader {
|
||||||
|
DBHeader {
|
||||||
|
magic: binary_loader::load_u8(&raw[0]),
|
||||||
|
major_version: binary_loader::load_high_u4(&raw[1]),
|
||||||
|
minor_version: binary_loader::load_low_u4(&raw[1]),
|
||||||
|
reserved: binary_loader::load_u16(&raw[2..4]),
|
||||||
|
record_count: binary_loader::load_u32(&raw[4..8]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RecordHeader {
|
||||||
|
field_count: u8,
|
||||||
|
length: u8,
|
||||||
|
crc: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecordHeader {
|
||||||
|
fn from(raw: &[u8]) -> RecordHeader {
|
||||||
|
RecordHeader {
|
||||||
|
field_count: binary_loader::load_u8(&raw[0]),
|
||||||
|
length: binary_loader::load_u8(&raw[1]),
|
||||||
|
crc: binary_loader::load_u16(&raw[2..4]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Field {
|
||||||
|
field_type: u8,
|
||||||
|
length: u16,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field {
|
||||||
|
fn from(raw: &[u8]) -> Field {
|
||||||
|
let length = binary_loader::load_u16(&raw[1..3]);
|
||||||
|
let mut lsize: usize = length.into();
|
||||||
|
lsize += 3;
|
||||||
|
let value = String::from_utf8_lossy(&raw[3..lsize]).to_string();
|
||||||
|
println!("{}", value);
|
||||||
|
println!("{}", lsize);
|
||||||
|
Field {
|
||||||
|
field_type: binary_loader::load_u8(&raw[0]),
|
||||||
|
length: length,
|
||||||
|
value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
assert_eq!(2 + 2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_empty_db_header() {
|
||||||
|
let header = [0xDB, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||||
|
let db_header = DBHeader::from(&header);
|
||||||
|
assert_eq!(db_header.magic, 0xDB);
|
||||||
|
assert_eq!(db_header.major_version, 0);
|
||||||
|
assert_eq!(db_header.minor_version, 1);
|
||||||
|
assert_eq!(db_header.reserved, 0);
|
||||||
|
assert_eq!(db_header.record_count, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_record_header() {
|
||||||
|
let header: [u8; 4] = [0x3, 0x45, 0x12, 0x34];
|
||||||
|
let record_header = RecordHeader::from(&header);
|
||||||
|
assert_eq!(record_header.field_count, 3);
|
||||||
|
assert_eq!(record_header.length, 0x45);
|
||||||
|
assert_eq!(record_header.crc, 0x1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_field() {
|
||||||
|
let field: [u8; 6] = [0x01, 0x00, 0x03, 0x4a, 0x6f, 0x6e];
|
||||||
|
let field = Field::from(&field);
|
||||||
|
assert_eq!(0x01, field.field_type);
|
||||||
|
assert_eq!(3, field.length);
|
||||||
|
assert_eq!(String::from("Jon"), field.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/main.rs
Normal file
3
src/main.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user