1pub use crate::artist::ArtistsReader;
2pub use crate::label::LabelsReader;
3pub use crate::master::MastersReader;
4pub use crate::release::ReleasesReader;
5use flate2::read::GzDecoder;
6use quick_xml::events::Event;
7use quick_xml::Error as XmlError;
8use std::fmt;
9use std::fs::File;
10use std::io::{BufRead, BufReader, Error as IoError};
11use std::path::Path;
12use thiserror::Error;
13
14pub type XmlReader = quick_xml::Reader<Box<dyn BufRead>>;
15
16pub fn get_xml_reader(path: &Path) -> Result<XmlReader, IoError> {
17 let file = File::open(path)?;
18 let gz = GzDecoder::new(file);
19 let reader: Box<dyn BufRead> = if gz.header().is_some() {
20 Box::new(BufReader::new(gz))
21 } else {
22 let file = File::open(path)?;
23 Box::new(BufReader::new(file))
24 };
25 Ok(quick_xml::Reader::from_reader(reader))
26}
27
28pub enum DiscogsReader {
29 Artists(Box<ArtistsReader>),
30 Labels(Box<LabelsReader>),
31 Masters(Box<MastersReader>),
32 Releases(Box<ReleasesReader>),
33}
34
35impl DiscogsReader {
36 pub fn from_path(path: &Path) -> Result<DiscogsReader, ReaderError> {
37 let mut xml_reader = get_xml_reader(path)?;
38 let mut buf = Vec::with_capacity(4096);
39 let start_event = loop {
40 match xml_reader.read_event_into(&mut buf)? {
41 Event::Start(ev) => break ev,
42 Event::Eof => return Err(ReaderError::NoStartTag),
43 _ => continue,
44 }
45 };
46 let reader = match start_event.name().as_ref() {
47 b"artists" => DiscogsReader::Artists(Box::new(ArtistsReader::new(xml_reader, buf))),
48 b"labels" => DiscogsReader::Labels(Box::new(LabelsReader::new(xml_reader, buf))),
49 b"masters" => DiscogsReader::Masters(Box::new(MastersReader::new(xml_reader, buf))),
50 b"releases" => DiscogsReader::Releases(Box::new(ReleasesReader::new(xml_reader, buf))),
51 _ => {
52 return Err(ReaderError::InvalidStartTag);
53 }
54 };
55 Ok(reader)
56 }
57}
58
59#[derive(Error, Debug)]
60pub enum ReaderError {
61 #[error(transparent)]
62 IoError(#[from] IoError),
63 #[error(transparent)]
64 XmlError(#[from] XmlError),
65 #[error("No start tag present in file")]
66 NoStartTag,
67 #[error("Invalid start tag present in file")]
68 InvalidStartTag,
69}
70
71impl fmt::Display for DiscogsReader {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 let name = match &self {
74 DiscogsReader::Artists(_) => "artists",
75 DiscogsReader::Labels(_) => "labels",
76 DiscogsReader::Masters(_) => "masters",
77 DiscogsReader::Releases(_) => "releases",
78 };
79 write!(f, "{name}")
80 }
81}