-
Notifications
You must be signed in to change notification settings - Fork 17
58 separate db format #59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,15 @@ | ||
| use std::collections::BTreeMap; | ||
| use std::error::Error; | ||
| use std::fs; | ||
| use std::path::{Path, PathBuf}; | ||
|
|
||
| use serde::{Deserialize, Serialize}; | ||
|
|
||
| use crate::app::App; | ||
| use crate::hex::{blocks::ColoredBlock, comment::Comment, hex_view::HexView}; | ||
|
|
||
| impl App { | ||
| pub fn save_database(&self) -> Result<(), Box<dyn Error>> { | ||
| let toml_string = toml::to_string_pretty(&self.hex_view)?; | ||
| let target_dir: &Path = Path::new(&self.file_info.path) | ||
| .parent() | ||
| .unwrap_or(Path::new(".")); | ||
|
|
@@ -23,6 +26,10 @@ impl App { | |
| return Ok(()); | ||
| } | ||
|
|
||
| // serialize after checking for empty | ||
| let db = hex_view_to_db(&self.hex_view); | ||
| let toml_string = toml::to_string_pretty(&db)?; | ||
|
|
||
| // try target's path or else current directory | ||
| fs::write(&target_db, &toml_string).or_else(|_| fs::write(&cwd_db, &toml_string))?; | ||
|
|
||
|
|
@@ -36,10 +43,127 @@ impl App { | |
| let target_db: PathBuf = target_dir.join(&cwd_db); | ||
| let data = fs::read_to_string(&cwd_db).or_else(|_| fs::read_to_string(&target_db))?; | ||
|
|
||
| // TODO: Although we're only interested in comments and bookmarks, other fields might | ||
| // be loaded if they are defined in the TOML file. How to prevent that? | ||
| self.hex_view = toml::from_str(&data)?; | ||
| self.hex_view.editing_hex = true; // otherwise it defaults to false if a .dz6 file exists for the target | ||
| let db = toml::from_str::<Database>(&data)?; | ||
| self.hex_view = hex_view_from_db(db); | ||
| Ok(()) | ||
| } | ||
| } | ||
|
|
||
| #[derive(Debug, Serialize, Deserialize, PartialEq)] | ||
| pub struct Database { | ||
| // blocks are ByteBlock structs -- ranges with different colors | ||
| pub blocks: Vec<DbColoredBlock>, | ||
| pub bookmarks: Vec<usize>, | ||
|
|
||
| // `comment_name_list` is used to show comments in Names list | ||
| // and also on the conversion from selected item on the list | ||
| // to file offset passed to goto() | ||
| pub comment_name_list: Vec<DbComment>, | ||
|
|
||
| // TODO: comments and comment_name_list are redundant, we should only store one of them | ||
| // but to avoid breaking existing .dz6 files, we will keep both for now | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for thinking about it! Currently, there's no way an user can create a name, so maybe in the future we can build this list (for the Names window) from |
||
| // The `comments` format is more compact and doesn't require a new type | ||
| // so maybe later we default to using only it | ||
| pub comments: BTreeMap<usize, String>, | ||
|
merces marked this conversation as resolved.
|
||
| } | ||
|
|
||
| #[derive(Debug, Serialize, Deserialize, PartialEq)] | ||
| pub struct DbComment { | ||
| pub offset: usize, | ||
| pub comment: String, | ||
| } | ||
|
|
||
| #[derive(Debug, Serialize, Deserialize, PartialEq)] | ||
| pub struct DbColoredBlock { | ||
| pub start: usize, | ||
| pub end: usize, | ||
| pub bg_color: u32, | ||
| pub fg_color: u32, | ||
| } | ||
|
|
||
| fn hex_view_from_db(db: Database) -> HexView { | ||
| HexView { | ||
| blocks: db.blocks.into_iter().map(colored_block_from_db).collect(), | ||
| bookmarks: db.bookmarks, | ||
| comment_name_list: db | ||
| .comment_name_list | ||
| .into_iter() | ||
| .map(comment_from_db) | ||
| .collect(), | ||
| comments: db.comments.into_iter().collect(), | ||
| editing_hex: true, // otherwise it defaults to false if a .dz6 file exists for the target | ||
| ..Default::default() | ||
| } | ||
| } | ||
| fn colored_block_from_db(db_block: DbColoredBlock) -> ColoredBlock { | ||
| ColoredBlock { | ||
| start: db_block.start, | ||
| end: db_block.end, | ||
| bg_color: db_block.bg_color, | ||
| fg_color: db_block.fg_color, | ||
| } | ||
| } | ||
| fn comment_from_db(db_comment: DbComment) -> Comment { | ||
| Comment { | ||
| offset: db_comment.offset, | ||
| comment: db_comment.comment, | ||
| } | ||
| } | ||
|
|
||
| /// HexView to Database conversion, | ||
| /// takes a reference because we don't want to consume the live HexView that is | ||
| /// being used in the app. | ||
| fn hex_view_to_db(hex_view: &HexView) -> Database { | ||
| Database { | ||
| blocks: hex_view.blocks.iter().map(colored_block_to_db).collect(), | ||
| bookmarks: hex_view.bookmarks.clone(), | ||
| comment_name_list: hex_view | ||
| .comment_name_list | ||
| .iter() | ||
| .map(comment_to_db) | ||
| .collect(), | ||
| comments: hex_view | ||
| .comments | ||
| .iter() | ||
| .map(|(k, v)| (*k, v.clone())) | ||
| .collect(), | ||
| } | ||
| } | ||
| fn colored_block_to_db(block: &ColoredBlock) -> DbColoredBlock { | ||
| DbColoredBlock { | ||
| start: block.start, | ||
| end: block.end, | ||
| bg_color: block.bg_color, | ||
| fg_color: block.fg_color, | ||
| } | ||
| } | ||
| fn comment_to_db(comment: &Comment) -> DbComment { | ||
| DbComment { | ||
| offset: comment.offset, | ||
| comment: comment.comment.clone(), | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
| use pretty_assertions::assert_eq; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a pretty neat library for tests that will color the parts that are different when assert_eq fails.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Neat indeed! Should we use it in other tests too?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no big downside to using it. but I usually only use it when a test fails and I have a hard time figuring out why. In this case the serialization test was failing because the comments map sometimes serialized in different orders. it was hard to see what was different so I added the pretty_assertion. |
||
|
|
||
| #[test] | ||
| fn test_database_round_trip() { | ||
| // db file generated with the hexview serialization | ||
| let db_file = "test_data/db.toml"; | ||
| let db_str = fs::read_to_string(db_file).expect("Failed to read test database file"); | ||
|
|
||
| let db: Database = toml::from_str(&db_str).expect("Failed to deserialize database"); | ||
|
|
||
| // tests that we don't drop any data from the original file and don't add any | ||
| let serialized = toml::to_string_pretty(&db).expect("Failed to serialize database"); | ||
| assert_eq!(db_str, serialized); | ||
|
|
||
| // tests that we can deserialize the serialized string and get the same data back | ||
| let re_deserialized: Database = | ||
| toml::from_str(&serialized).expect("Failed to deserialize database"); | ||
| assert_eq!(db, re_deserialized); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| bookmarks = [ | ||
| 288, | ||
| 325, | ||
| ] | ||
|
|
||
| [[blocks]] | ||
| start = 16 | ||
| end = 21 | ||
| bg_color = 446956584 | ||
| fg_color = 2910089301 | ||
|
|
||
| [[blocks]] | ||
| start = 128 | ||
| end = 134 | ||
| bg_color = 3843912424 | ||
| fg_color = 2232455935 | ||
|
|
||
| [[blocks]] | ||
| start = 182 | ||
| end = 214 | ||
| bg_color = 4160309102 | ||
| fg_color = 4169677532 | ||
|
|
||
| [[comment_name_list]] | ||
| offset = 21 | ||
| comment = " one comment" | ||
|
|
||
| [[comment_name_list]] | ||
| offset = 101 | ||
| comment = "comment" | ||
|
|
||
| [comments] | ||
| 21 = " one comment" | ||
| 101 = "comment" |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, I can't remember why I decided to store both of them. I think my line of thought was that the user could add a name to an offset so this name could be shown when code references it. For example:
jmp 0x401000could be shown asjmp destinationif the user set the namedestinationto 0x401000, but this only makes sense in a disassembly view, which we don't have yet. Also, even when names and comments are two different vectors, we can still show the elements from both of them in a single Names window, but store them separately in the database and build thecomment_name_listfromcommentsandnamesin the future. Alternatively, perhaps we can get rid ofcomment_name_listentirely and build this list when the Names window is shown? Just thoughts. :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to store just one of them and derive the data of the other one.
I will make a PR the "deprecates" the comment_name_list from the database.
The idea is that we stop reading from it but we still write to it. That way at least for a while the current version can still create DBs for previous versions. then after a few releases we remove the field for good.
(I am probably overly paranoid with this "forward" and "backwards" compatability stuff)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created the MR for it:
#63
I decide to only make it "backwards" compatible, not forward compatible. I explain it in the other MR.