|
|
@ -1,11 +1,10 @@ |
|
|
|
|
|
|
|
use slug::slugify; |
|
|
|
use std::env; |
|
|
|
use std::env; |
|
|
|
use xml::{Event, Parser}; |
|
|
|
|
|
|
|
use std::fs::File; |
|
|
|
use std::fs::File; |
|
|
|
use std::io::prelude::*; |
|
|
|
use std::io::prelude::*; |
|
|
|
use std::path::Path; |
|
|
|
use std::path::Path; |
|
|
|
use std::vec::Vec; |
|
|
|
use std::vec::Vec; |
|
|
|
use slug::slugify; |
|
|
|
use xml::{Event, Parser}; |
|
|
|
use base64::decode; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
#[derive(Debug)] |
|
|
|
enum CurrentTag { |
|
|
|
enum CurrentTag { |
|
|
@ -14,7 +13,7 @@ enum CurrentTag { |
|
|
|
Resource, |
|
|
|
Resource, |
|
|
|
ResourceData, |
|
|
|
ResourceData, |
|
|
|
ResourceAttributes, |
|
|
|
ResourceAttributes, |
|
|
|
ResourceAttributesFilename |
|
|
|
ResourceAttributesFilename, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
#[derive(Debug)] |
|
|
@ -22,42 +21,69 @@ struct State { |
|
|
|
tag: Option<CurrentTag>, |
|
|
|
tag: Option<CurrentTag>, |
|
|
|
title: Option<String>, |
|
|
|
title: Option<String>, |
|
|
|
filename: Option<String>, |
|
|
|
filename: Option<String>, |
|
|
|
data: Vec<u8> |
|
|
|
data: Vec<u8>, |
|
|
|
|
|
|
|
content: Vec<u8>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl State { |
|
|
|
impl State { |
|
|
|
pub fn new() -> Self { |
|
|
|
pub fn new() -> Self { |
|
|
|
Self { tag: None, title: None, filename: None, data: Vec::new() } |
|
|
|
Self { |
|
|
|
|
|
|
|
tag: None, |
|
|
|
|
|
|
|
title: None, |
|
|
|
|
|
|
|
filename: None, |
|
|
|
|
|
|
|
data: Vec::new(), |
|
|
|
|
|
|
|
content: Vec::new(), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn with_title(self, title:String) -> Self { |
|
|
|
pub fn with_title(self, title: String) -> Self { |
|
|
|
Self { title: Some(title.to_string()), |
|
|
|
Self { |
|
|
|
..self } |
|
|
|
title: Some(title.to_string()), |
|
|
|
|
|
|
|
..self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn with_filename(self, filename: String) -> Self { |
|
|
|
pub fn with_filename(self, filename: String) -> Self { |
|
|
|
Self { filename: Some(filename), |
|
|
|
Self { |
|
|
|
..self } |
|
|
|
filename: Some(filename), |
|
|
|
|
|
|
|
..self |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn with_tag(self, tag: CurrentTag) -> Self { |
|
|
|
|
|
|
|
Self { |
|
|
|
|
|
|
|
tag: Some(tag), |
|
|
|
|
|
|
|
..self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn with_tag(self, tag:CurrentTag) -> Self { |
|
|
|
pub fn with_data(self, data: Vec<u8>) -> Self { |
|
|
|
Self { tag: Some(tag), |
|
|
|
Self { data: data, ..self } |
|
|
|
..self } |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn with_data(self, data:Vec<u8>) -> Self { |
|
|
|
pub fn with_content(self, content: Vec<u8>) -> Self { |
|
|
|
Self { data: data, |
|
|
|
Self { |
|
|
|
..self } |
|
|
|
content: content, |
|
|
|
|
|
|
|
..self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn remove_tag(self) -> Self { |
|
|
|
pub fn remove_tag(self) -> Self { |
|
|
|
Self { tag: None, |
|
|
|
Self { tag: None, ..self } |
|
|
|
..self } |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn remove_data(self) -> Self { |
|
|
|
pub fn remove_data(self) -> Self { |
|
|
|
Self { data: Vec::new(), |
|
|
|
Self { |
|
|
|
..self } |
|
|
|
data: Vec::new(), |
|
|
|
|
|
|
|
..self |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn remove_content(self) -> Self { |
|
|
|
|
|
|
|
Self { |
|
|
|
|
|
|
|
content: Vec::new(), |
|
|
|
|
|
|
|
..self |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -76,7 +102,7 @@ fn open_tag(current_state: State, tag: &str) -> State { |
|
|
|
"resource-attributes" => current_state.with_tag(CurrentTag::ResourceAttributes), |
|
|
|
"resource-attributes" => current_state.with_tag(CurrentTag::ResourceAttributes), |
|
|
|
"file-name" => current_state.with_tag(CurrentTag::ResourceAttributesFilename), |
|
|
|
"file-name" => current_state.with_tag(CurrentTag::ResourceAttributesFilename), |
|
|
|
"note" => State::new(), |
|
|
|
"note" => State::new(), |
|
|
|
_ => current_state |
|
|
|
_ => current_state, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -93,59 +119,73 @@ fn dump_resource(current_state: &State) -> () { |
|
|
|
target.write_all(&content).unwrap(); |
|
|
|
target.write_all(&content).unwrap(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn dump_note_contents(current_state: &State) -> () { |
|
|
|
|
|
|
|
let filename = Path::new("data") |
|
|
|
|
|
|
|
.join(current_state.title.as_ref().unwrap()) |
|
|
|
|
|
|
|
.join("content.md"); |
|
|
|
|
|
|
|
let mut target = File::create(filename).unwrap(); |
|
|
|
|
|
|
|
target.write_all(¤t_state.content).unwrap(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn close_tag(current_state: State, tag: &str) -> State { |
|
|
|
fn close_tag(current_state: State, tag: &str) -> State { |
|
|
|
match tag { |
|
|
|
match tag { |
|
|
|
"resource" => { |
|
|
|
"resource" => { |
|
|
|
dump_resource(¤t_state); |
|
|
|
dump_resource(¤t_state); |
|
|
|
current_state.remove_data() |
|
|
|
current_state.remove_data() |
|
|
|
}, |
|
|
|
}, |
|
|
|
_ => current_state.remove_tag() |
|
|
|
"content" => { |
|
|
|
|
|
|
|
dump_note_contents(¤t_state); |
|
|
|
|
|
|
|
current_state.remove_content() |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
_ => current_state.remove_tag(), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn main() { |
|
|
|
fn main() { |
|
|
|
let args:Vec<_> = env::args().collect(); |
|
|
|
let args: Vec<_> = env::args().collect(); |
|
|
|
if args.len() != 2 { |
|
|
|
if args.len() != 2 { |
|
|
|
println!("Required: filename."); |
|
|
|
println!("Required: filename."); |
|
|
|
std::process::exit(2); |
|
|
|
std::process::exit(2); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let filename = &args[1]; |
|
|
|
let filename = &args[1]; |
|
|
|
|
|
|
|
|
|
|
|
println!("Will process {}", filename); |
|
|
|
println!("Will process {}", filename); |
|
|
|
|
|
|
|
|
|
|
|
// Need to find a way to load small chunks and feed it to the parser while parsing.
|
|
|
|
// Need to find a way to load small chunks and feed it to the parser while parsing.
|
|
|
|
// (E.g., load 1024 bytes, feed it to the parser and, if the parser can't continue,
|
|
|
|
// (E.g., load 1024 bytes, feed it to the parser and, if the parser can't continue,
|
|
|
|
// feed more data, till the end of file).
|
|
|
|
// feed more data, till the end of file).
|
|
|
|
let mut file = File::open(filename).unwrap(); |
|
|
|
let mut file = File::open(filename).unwrap(); |
|
|
|
let mut contents = String::new(); |
|
|
|
let mut contents = String::new(); |
|
|
|
file.read_to_string(&mut contents).unwrap(); |
|
|
|
file.read_to_string(&mut contents).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
let mut parser = Parser::new(); |
|
|
|
let mut parser = Parser::new(); |
|
|
|
parser.feed_str(&contents); |
|
|
|
parser.feed_str(&contents); |
|
|
|
|
|
|
|
|
|
|
|
parser.fold(State::new(), {|state:State, element| { |
|
|
|
parser.fold(State::new(), { |
|
|
|
println!("State: {:?}", state); |
|
|
|
|state: State, element| { |
|
|
|
|
|
|
|
println!("State: {:?}", state); |
|
|
|
match element.unwrap() { |
|
|
|
|
|
|
|
Event::ElementStart(tag) => open_tag(state, tag.name.as_ref()), |
|
|
|
match element.unwrap() { |
|
|
|
Event::ElementEnd(tag) => close_tag(state, tag.name.as_ref()), |
|
|
|
Event::ElementStart(tag) => open_tag(state, tag.name.as_ref()), |
|
|
|
Event::Characters(data) => { |
|
|
|
Event::ElementEnd(tag) => close_tag(state, tag.name.as_ref()), |
|
|
|
match state.tag { |
|
|
|
Event::Characters(data) => { |
|
|
|
Some(CurrentTag::Title) => state.with_title(create_note_storage(&data)), |
|
|
|
match state.tag { |
|
|
|
Some(CurrentTag::ResourceData) => state.with_data( |
|
|
|
Some(CurrentTag::Title) => state.with_title(create_note_storage(&data)), |
|
|
|
data |
|
|
|
Some(CurrentTag::ResourceData) => state.with_data( |
|
|
|
.into_bytes() |
|
|
|
data.into_bytes() |
|
|
|
.iter() |
|
|
|
.iter() |
|
|
|
.filter(|&x| *x != 13 && *x != 10) // remove new lines, it is base 64, after all
|
|
|
|
.filter(|&x| *x != 13 && *x != 10) // remove new lines, it is base 64, after all
|
|
|
|
.map(|&x| x) |
|
|
|
.map(|&x| x) |
|
|
|
.collect() |
|
|
|
.collect(), |
|
|
|
), |
|
|
|
), |
|
|
|
Some(CurrentTag::ResourceAttributesFilename) => state.with_filename(data), |
|
|
|
Some(CurrentTag::Content) => state.with_content(data.into_bytes()), |
|
|
|
_ => state |
|
|
|
Some(CurrentTag::ResourceAttributesFilename) => state.with_filename(data), |
|
|
|
|
|
|
|
_ => state, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
_ => state, |
|
|
|
_ => state |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|