commit d84c216098da4ebfcb1c56642513d3985ae67662
parent e97cf6c27689ae457e28527b9df0cbe4d4ad52e1
Author: lash <dev@holbrook.no>
Date:   Sun, 25 Sep 2022 18:47:39 +0000
Enable multiple digest on biblatex import
Diffstat:
5 files changed, 84 insertions(+), 51 deletions(-)
diff --git a/src/biblatex.rs b/src/biblatex.rs
@@ -28,36 +28,7 @@ fn parse_digest(entry: &Entry) -> RecordDigest {
         },
     };
     let note_s = String::from_chunks(note).unwrap();
-    let mut digest_val = note_s.split(":");
-
-    //let mut digest = Vec::new();
-    let mut digest: RecordDigest = RecordDigest::Empty;
-
-    match digest_val.next() {
-        Some(v) => {
-//            if v == "sha512" {
-//                let digest_hex = digest_val.next().unwrap();
-//                let mut digest_imported = hex::decode(digest_hex).unwrap();
-//                digest.append(&mut digest_imported);
-//                debug!("parsed digest {}", hex::encode(&digest));
-//            }
-                match from_urn(v) {
-                    Ok(r) => {
-                        digest = r;
-                    },
-                    Err(e) => {
-                        debug!("note for entry {:?} is not a digest url", &entry);
-                    },
-                }
-        },
-        None => {},
-    };
-    
-//    if digest.len() == 0 {
-//        digest.resize(64, 0);
-//    }
-
-    digest
+    from_urn(note_s.as_str()).unwrap()
 }
 
 /// Read one or more metadata entries from the `bibtex` source.
@@ -76,10 +47,15 @@ pub fn read_all(mut r: impl Read, digests: &Vec<RecordDigest>) -> Result<Vec<Met
         },
         Err(e) => {
             error!("parse error for biblatex");
-            return Err(ParseError);
+            return Err(ParseError::new("Not a biblatex source"));
         },
     };
 
+    if bib.len() > 1 && digests.len() > 0 {
+        error!("more than one biblatex entry parsed while static digest provided");
+        return Err(ParseError::new("more than one biblatex entry parsed while static digest provided"));
+    }
+
     let mut rr: Vec<MetaData> = vec!();
 
     for e in bib.iter() {
@@ -97,6 +73,8 @@ pub fn read_all(mut r: impl Read, digests: &Vec<RecordDigest>) -> Result<Vec<Met
         });
 
         let mut use_digests: Vec<RecordDigest> = vec!();
+
+        // use clone instead
         let digest = parse_digest(&e);
         match digest {
             RecordDigest::Empty => {
@@ -113,13 +91,6 @@ pub fn read_all(mut r: impl Read, digests: &Vec<RecordDigest>) -> Result<Vec<Met
             RecordDigest::SwarmHash(r) => {
                 use_digests.push(RecordDigest::SwarmHash(r));
             },
-
-//            RecordDigest::Sha512(r) => {
-//                use_digests.push(digest);
-//            },
-//            RecordDigest::MD5(r) => {
-//                use_digests.push(digest);
-//            },
         }
 
         for v in digests {
@@ -128,6 +99,10 @@ pub fn read_all(mut r: impl Read, digests: &Vec<RecordDigest>) -> Result<Vec<Met
         let title = e.title().unwrap();
         let title_s = String::from_chunks(title).unwrap();
 
+        if use_digests.len() == 0 {
+            return Err(ParseError::new("no digests found")); 
+        }
+
         for dd in use_digests.into_iter() {
             let mut m = MetaData::new(title_s.as_str(), authors_s.as_str(), e.entry_type.clone(), dd, None);
 
@@ -160,6 +135,21 @@ mod tests {
     use env_logger;
 
     #[test]
+    fn test_embedded_digest() {
+       let biblatex_src = "@article{
+    foo,
+    title={bar},
+    author={Guybrush Threepwood},
+    note={sha512:f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7},
+}
+";
+        let digests = vec!();
+        let r = read_all(biblatex_src.as_bytes(), &digests).unwrap();
+
+    }
+
+
+    #[test]
     fn test_multi_digest() {
         let d_hex = "acbd18db4cc2f85cedef654fccc4a4d8";
         let d = digest::RecordDigest::MD5(hex::decode(d_hex).unwrap());
diff --git a/src/digest.rs b/src/digest.rs
@@ -41,6 +41,28 @@ impl Clone for RecordDigest {
     }
 }
 
+impl RecordDigest {
+    pub fn fingerprint(&self) -> Vec<u8> {
+        match self {
+            RecordDigest::Empty => {
+                return vec!();
+            },
+            RecordDigest::Sha512(v) => {
+                return v.to_vec();
+            },
+            RecordDigest::Sha256(v) => {
+                return v.to_vec();
+            },
+            RecordDigest::MD5(v) => {
+                return v.to_vec();
+            },
+            RecordDigest::SwarmHash(v) => {
+                return v.to_vec();
+            },
+        }
+    }
+}
+
 
 /// Create a [RecordDigest::Sha512](RecordDigest::Sha512) instance from the raw digest data.
 ///
@@ -48,7 +70,7 @@ impl Clone for RecordDigest {
 pub fn from_vec(v: Vec<u8>) -> Result<RecordDigest, ParseError> {
     let sz = Sha512::output_size();
     if v.len() != sz {
-        return Err(ParseError);
+        return Err(ParseError::new("invalid digest size"));
     }
     Ok(RecordDigest::Sha512(v))
 }
@@ -71,7 +93,7 @@ pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> {
                     vv
                 },
                 Err(e) => {
-                    return Err(ParseError);
+                    return Err(ParseError::new("invalid sha512 digest"));
                 },
             }
         },
@@ -81,7 +103,7 @@ pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> {
 
             let sz = Sha256::output_size();
             if digest.len() != sz {
-                return Err(ParseError);
+                return Err(ParseError::new("invalid sha256 digest"));
             }
 
             RecordDigest::Sha256(digest)
@@ -91,7 +113,7 @@ pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> {
             let digest = hex::decode(digest_hex).unwrap();
 
             if digest.len() != 16 {
-                return Err(ParseError);
+                return Err(ParseError::new("invalid md5 digest"));
             }
 
             RecordDigest::MD5(digest)
@@ -101,7 +123,7 @@ pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> {
             let digest = hex::decode(digest_hex).unwrap();
 
             if digest.len() != 32 {
-                return Err(ParseError);
+                return Err(ParseError::new("invalid bzz digest"));
             }
             
             RecordDigest::SwarmHash(digest)
@@ -110,7 +132,7 @@ pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> {
             RecordDigest::Empty
         },
         Some(_) => {
-            return Err(ParseError);
+            return Err(ParseError::new("unknown digest type"));
         },
         None => {
             RecordDigest::Empty
diff --git a/src/error.rs b/src/error.rs
@@ -1,3 +1,13 @@
 /// Used for any parsing error for any supported format.
 #[derive(Debug)]
-pub struct ParseError;
+pub struct ParseError {
+    pub detail: String,
+}
+
+impl ParseError {
+    pub fn new(s: &str) -> ParseError {
+        ParseError{
+            detail: String::from(s),
+        }
+    }
+}
diff --git a/src/meta.rs b/src/meta.rs
@@ -210,7 +210,9 @@ impl MetaData {
     }
 
     /// Returns the digest value of the media as a hex-encoded string.
-    pub fn fingerprint(&self) -> String {
+    ///
+    /// TODO: implememt in fmt for digest instead
+    pub fn urn(&self) -> String {
         match &self.digest {
             digest::RecordDigest::Empty => {
                 return String::new();
@@ -230,6 +232,13 @@ impl MetaData {
         }
     }
 
+
+    ///
+    pub fn fingerprint(&self) -> String {
+        let digest_fingerprint = self.digest.fingerprint();
+        return hex::encode(digest_fingerprint);
+    }
+
     /// Instantiate metadata from the extended attributes of the file in `filepath`.
     pub fn from_xattr(filepath: &path::Path) -> Result<MetaData, ParseError> {
 
@@ -253,7 +262,7 @@ impl MetaData {
                 v
             },
             Err(e) => {
-                return Err(ParseError{});
+                return Err(ParseError::new("title missing"));
             }
         };
         match title_src {
@@ -285,7 +294,7 @@ impl MetaData {
 
         let mut metadata = MetaData::new(title.as_str(), author.as_str(), typ, digest::RecordDigest::Sha512(digest), Some(filename));
         if !metadata.validate() {
-            return Err(ParseError{});
+            return Err(ParseError::new("invalid input"));
         }
 
         match xattr::get(filepath, "user.dcterms:subject") {
@@ -509,7 +518,8 @@ mod tests {
         let meta = MetaData::from_xattr(s).unwrap();
         assert_eq!(meta.dc.title, "Bitcoin: A Peer-to-Peer Electronic Cash System");
         assert_eq!(meta.dc.author, "Satoshi Nakamoto");
-        assert_eq!(meta.fingerprint(), String::from("sha512:2ac531ee521cf93f8419c2018f770fbb42c65396178e079a416e7038d3f9ab9fc2c35c4d838bc8b5dd68f4c13759fe9cdf90a46528412fefe1294cb26beabf4e"));
+        assert_eq!(meta.urn(), String::from("sha512:2ac531ee521cf93f8419c2018f770fbb42c65396178e079a416e7038d3f9ab9fc2c35c4d838bc8b5dd68f4c13759fe9cdf90a46528412fefe1294cb26beabf4e"));
+        assert_eq!(meta.fingerprint(), String::from("2ac531ee521cf93f8419c2018f770fbb42c65396178e079a416e7038d3f9ab9fc2c35c4d838bc8b5dd68f4c13759fe9cdf90a46528412fefe1294cb26beabf4e"));
     }
 
     #[test]
@@ -531,7 +541,8 @@ mod tests {
         let m_check = MetaData::from_xattr(fp).unwrap();
         assert_eq!(m_check.title(), "foo");
         assert_eq!(m_check.author(), "bar");
-        assert_eq!(m_check.fingerprint(), String::from("sha512:") + digest_hex);
+        assert_eq!(m_check.fingerprint(), digest_hex);
+        assert_eq!(m_check.urn(), String::from("sha512:") + digest_hex);
         assert_eq!(m_check.typ(), EntryType::Article);
         assert_eq!(m_check.subject().unwrap(), "baz");
         assert_eq!(m_check.mime().unwrap(), "foo/bar");
diff --git a/src/rdf.rs b/src/rdf.rs
@@ -233,7 +233,7 @@ pub fn read_all(r: impl Read) -> Result<Vec<MetaData>, ParseError> {
     });
     // TODO: should check validity of all records
     if rr[0].fingerprint() == "" {
-        return Err(ParseError);
+        return Err(ParseError::new("empty fingerprint"));
     }
     Ok(rr)
 }