<commit_before>use crate::{Crate, Error};
use std::{
    io,
    path::{Path, PathBuf},
};

/// Access to a "bare" git index that fetches files directly from the repo instead of local checkout
///
/// Uses Cargo's cache
pub struct BareIndex {
    path: PathBuf,
    pub url: String,
}

impl BareIndex {
    /// Creates a bare index from a provided URL, opening the same location on
    /// disk that cargo uses for that registry index.
    pub fn from_url(url: &str) -> Result<Self, Error> {
        let (dir_name, canonical_url) = url_to_local_dir(url)?;
        let mut path = home::cargo_home().unwrap_or_default();

        path.push("registry/index");
        path.push(dir_name);

        Ok(Self {
            path,
            url: canonical_url,
        })
    }

    /// Creates a bare index at the provided path with the specified repository URL.
    pub fn with_path(path: PathBuf, url: &str) -> Self {
        Self {
            path,
            url: url.to_owned(),
        }
    }

    /// Creates an index for the default crates.io registry, using the same
    /// disk location as cargo itself.
    pub fn new_cargo_default() -> Self {
        // UNWRAP: The default index git URL is known to safely convert to a path.
        Self::from_url(crate::INDEX_GIT_URL).unwrap()
    }

    /// Opens the local index, which acts as a kind of lock for source control
    /// operations
    pub fn open_or_clone(&self) -> Result<BareIndexRepo<'_>, Error> {
        BareIndexRepo::new(self)
    }
}

/// Self-referential struct where `Tree` borrows from `Repository`
struct UnsafeRepoTree {
    /// Warning: order of the fields is necessary for safety. `tree` must Drop before `repo`.
    tree: git2::Tree<'static>,
    repo: git2::Repository,
}

/// Opened instance of [`BareIndex`]
pub struct BareIndexRepo<'a> {
    inner: &'a BareIndex,
    head: git2::Oid,
    head_str: String,
    rt: UnsafeRepoTree,
}

impl<'a> BareIndexRepo<'a> {
    fn new(index: &'a BareIndex) -> Result<Self, Error> {
        let exists = git2::Repository::discover(&index.path)
            .map(|repository| {
                repository
                    .find_remote("origin")
                    .ok()
                    // Cargo creates a checkout without an origin set,
                    // so default to true in case of missing origin
                    .map_or(true, |remote| {
                        remote.url().map_or(true, |url| url == index.url)
                    })
            })
            .unwrap_or(false);

        if !exists {
            git2::build::RepoBuilder::new()
                .fetch_options(crate::fetch_opts())
                .bare(true)
                .clone(&index.url, &index.path)?;
        }

        let repo = git2::Repository::open(&index.path)?;
        let head = repo
            // Fallback to HEAD, as a fresh clone won't have a FETCH_HEAD
            .refname_to_id("FETCH_HEAD")
            .or_else(|_| repo.refname_to_id("HEAD"))?;
        let head_str = head.to_string();

        let tree = {
            let commit = repo.find_commit(head)?;
            let tree = commit.tree()?;

            // See `UnsafeRepoTree`
            unsafe { std::mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) }
        };

        Ok(Self {
            inner: index,
            head,
            head_str,
            rt: UnsafeRepoTree {
                repo,
                tree,
            },
        })
    }

    /// Fetches latest from the remote index repository. Note that using this
    /// method will mean no cache entries will be used, if a new commit is fetched
    /// from the repository, as their commit version will no longer match.
    pub fn retrieve(&mut self) -> Result<(), Error> {
        {
            let mut origin_remote = self
                .rt.repo
                .find_remote("origin")
                .or_else(|_| self.rt.repo.remote_anonymous(&self.inner.url))?;

            origin_remote.fetch(
                &["+refs/heads/*:refs/remotes/origin/*"],
                Some(&mut crate::fetch_opts()),
                None,
            )?;
        }

        let head = self
            .rt.repo
            .refname_to_id("FETCH_HEAD")
            .or_else(|_| self.rt.repo.refname_to_id("HEAD"))?;
        let head_str = head.to_string();

        let commit = self.rt.repo.find_commit(head)?;
        let tree = commit.tree()?;

        // See `UnsafeRepoTree`
        let tree = unsafe { std::mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) };

        self.head = head;
        self.head_str = head_str;
        self.rt.tree = tree;

        Ok(())
    }

    /// Reads a crate from the index, it will attempt to use a cached entry if
    /// one is available, otherwise it will fallback to reading the crate
    /// directly from the git blob containing the crate information.
    pub fn crate_(&self, name: &str) -> Option<Crate> {
        let rel_path = match crate::crate_name_to_relative_path(name) {
            Some(rp) => rp,
            None => return None,
        };

        // Attempt to load the .cache/ entry first, this is purely an acceleration
        // mechanism and can fail for a few reasons that are non-fatal
        {
            let mut cache_path = self.inner.path.join(".cache");
            cache_path.push(&rel_path);
            if let Ok(cache_bytes) = std::fs::read(&cache_path) {
                if let Ok(krate) = Crate::from_cache_slice(&cache_bytes, &self.head_str) {
                    return Some(krate);
                }
            }
        }

        // Fallback to reading the blob directly via git if we don't have a
        // valid cache entry
        self.krate_from_blob(&rel_path).ok()
    }

    fn krate_from_blob(&self, path: &str) -> Result<Crate, Error> {
        let entry = self.rt.tree.get_path(&Path::new(path))?;
        let object = entry.to_object(&self.rt.repo)?;
        let blob = object
            .as_blob()
            .ok_or_else(|| Error::Io(io::Error::new(io::ErrorKind::NotFound, path.to_owned())))?;

        Crate::from_slice(blob.content()).map_err(Error::Io)
    }
}

/// Converts a full url, eg https://github.com/rust-lang/crates.io-index, into
/// the root directory name where cargo itself will fetch it on disk
fn url_to_local_dir(url: &str) -> Result<(String, String), Error> {
    fn to_hex(num: u64) -> String {
        const CHARS: &[u8] = b"0123456789abcdef";

        let bytes = &[
            num as u8,
            (num >> 8) as u8,
            (num >> 16) as u8,
            (num >> 24) as u8,
            (num >> 32) as u8,
            (num >> 40) as u8,
            (num >> 48) as u8,
            (num >> 56) as u8,
        ];

        let mut output = vec![0u8; 16];

        let mut ind = 0;

        for &byte in bytes {
            output[ind] = CHARS[(byte >> 4) as usize];
            output[ind + 1] = CHARS[(byte & 0xf) as usize];

            ind += 2;
        }

        String::from_utf8(output).expect("valid utf-8 hex string")
    }

    #[allow(deprecated)]
    fn hash_u64(url: &str) -> u64 {
        use std::hash::{Hash, Hasher, SipHasher};

        let mut hasher = SipHasher::new_with_keys(0, 0);
        // Registry
        2usize.hash(&mut hasher);
        // Url
        url.hash(&mut hasher);
        hasher.finish()
    }

    // Ensure we have a registry or bare url
    let (url, scheme_ind) = {
        let scheme_ind = url
            .find("://")
            .ok_or_else(|| Error::Url(format!("'{}' is not a valid url", url)))?;

        let scheme_str = &url[..scheme_ind];
        if let Some(ind) = scheme_str.find('+') {
            if &scheme_str[..ind] != "registry" {
                return Err(Error::Url(format!("'{}' is not a valid registry url", url)));
            }

            (&url[ind + 1..], scheme_ind - ind - 1)
        } else {
            (url, scheme_ind)
        }
    };

    // Could use the Url crate for this, but it's simple enough and we don't
    // need to deal with every possible url (I hope...)
    let host = match url[scheme_ind + 3..].find('/') {
        Some(end) => &url[scheme_ind + 3..scheme_ind + 3 + end],
        None => &url[scheme_ind + 3..],
    };

    // cargo special cases github.com for reasons, so do the same
    let mut canonical = if host == "github.com" {
        url.to_lowercase()
    } else {
        url.to_owned()
    };

    // Chop off any query params/fragments
    if let Some(hash) = canonical.rfind('#') {
        canonical.truncate(hash);
    }

    if let Some(query) = canonical.rfind('?') {
        canonical.truncate(query);
    }

    let ident = to_hex(hash_u64(&canonical));

    if canonical.ends_with('/') {
        canonical.pop();
    }

    if canonical.ends_with(".git") {
        canonical.truncate(canonical.len() - 4);
    }

    Ok((format!("{}-{}", host, ident), canonical))
}

#[cfg(test)]
mod test {
    #[test]
    fn matches_cargo() {
        assert_eq!(
            super::url_to_local_dir(crate::INDEX_GIT_URL).unwrap(),
            (
                "github.com-1ecc6299db9ec823".to_owned(),
                crate::INDEX_GIT_URL.to_owned()
            )
        );

        // I've confirmed this also works with a custom registry, unfortunately
        // that one includes a secret key as part of the url which would allow
        // anyone to publish to the registry, so uhh...here's a fake one instead
        assert_eq!(
            super::url_to_local_dir(
                "https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git"
            )
            .unwrap(),
            (
                "dl.cloudsmith.io-ff79e51ddd2b38fd".to_owned(),
                "https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index".to_owned()
            )
        );

        // Ensure we actually strip off the irrelevant parts of a url, note that
        // the .git suffix is not part of the canonical url, but *is* used when hashing
        assert_eq!(
            super::url_to_local_dir(&format!(
                "registry+{}.git?one=1&two=2#fragment",
                crate::INDEX_GIT_URL
            ))
            .unwrap(),
            (
                "github.com-c786010fb7ef2e6e".to_owned(),
                crate::INDEX_GIT_URL.to_owned()
            )
        );
    }

    #[test]
    fn clones_bare_index() {
        use super::BareIndex;

        let tmp_dir = tempdir::TempDir::new("clones_bare_index").unwrap();

        let index = BareIndex::with_path(tmp_dir.path().to_owned(), crate::INDEX_GIT_URL);

        let mut repo = index
            .open_or_clone()
            .expect("Failed to clone crates.io index");

        fn test_sval(repo: &super::BareIndexRepo<'_>) {
            let krate = repo
                .crate_("sval")
                .expect("Could not find the crate sval in the index");

            let version = krate
                .versions()
                .iter()
                .find(|v| v.version() == "0.0.1")
                .expect("Version 0.0.1 of sval does not exist?");
            let dep_with_package_name = version
                .dependencies()
                .iter()
                .find(|d| d.name() == "serde_lib")
                .expect("sval does not have expected dependency?");
            assert_ne!(
                dep_with_package_name.name(),
                dep_with_package_name.package().unwrap()
            );
            assert_eq!(
                dep_with_package_name.crate_name(),
                dep_with_package_name.package().unwrap()
            );
        }

        test_sval(&repo);

        repo.retrieve().expect("Failed to fetch crates.io index");

        test_sval(&repo);
    }

    #[test]
    fn opens_bare_index() {
        use super::BareIndex;

        let tmp_dir = tempdir::TempDir::new("opens_bare_index").unwrap();

        let index = BareIndex::with_path(tmp_dir.path().to_owned(), crate::INDEX_GIT_URL);

        {
            let _ = index
                .open_or_clone()
                .expect("Failed to clone crates.io index");
        }

        let mut repo = index
            .open_or_clone()
            .expect("Failed to open crates.io index");

        fn test_sval(repo: &super::BareIndexRepo<'_>) {
            let krate = repo
                .crate_("sval")
                .expect("Could not find the crate sval in the index");

            let version = krate
                .versions()
                .iter()
                .find(|v| v.version() == "0.0.1")
                .expect("Version 0.0.1 of sval does not exist?");
            let dep_with_package_name = version
                .dependencies()
                .iter()
                .find(|d| d.name() == "serde_lib")
                .expect("sval does not have expected dependency?");
            assert_ne!(
                dep_with_package_name.name(),
                dep_with_package_name.package().unwrap()
            );
            assert_eq!(
                dep_with_package_name.crate_name(),
                dep_with_package_name.package().unwrap()
            );
        }

        test_sval(&repo);

        repo.retrieve().expect("Failed to fetch crates.io index");

        test_sval(&repo);
    }
}
<commit_msg>add a crates iterator on bare indexes<commit_after>use crate::{Crate, Error};
use std::{
    io,
    path::{Path, PathBuf},
};

/// Access to a "bare" git index that fetches files directly from the repo instead of local checkout
///
/// Uses Cargo's cache
pub struct BareIndex {
    path: PathBuf,
    pub url: String,
}

impl BareIndex {
    /// Creates a bare index from a provided URL, opening the same location on
    /// disk that cargo uses for that registry index.
    pub fn from_url(url: &str) -> Result<Self, Error> {
        let (dir_name, canonical_url) = url_to_local_dir(url)?;
        let mut path = home::cargo_home().unwrap_or_default();

        path.push("registry/index");
        path.push(dir_name);

        Ok(Self {
            path,
            url: canonical_url,
        })
    }

    /// Creates a bare index at the provided path with the specified repository URL.
    pub fn with_path(path: PathBuf, url: &str) -> Self {
        Self {
            path,
            url: url.to_owned(),
        }
    }

    /// Creates an index for the default crates.io registry, using the same
    /// disk location as cargo itself.
    pub fn new_cargo_default() -> Self {
        // UNWRAP: The default index git URL is known to safely convert to a path.
        Self::from_url(crate::INDEX_GIT_URL).unwrap()
    }

    /// Opens the local index, which acts as a kind of lock for source control
    /// operations
    pub fn open_or_clone(&self) -> Result<BareIndexRepo<'_>, Error> {
        BareIndexRepo::new(self)
    }
}

/// Self-referential struct where `Tree` borrows from `Repository`
struct UnsafeRepoTree {
    /// Warning: order of the fields is necessary for safety. `tree` must Drop before `repo`.
    tree: git2::Tree<'static>,
    repo: git2::Repository,
}

/// Opened instance of [`BareIndex`]
pub struct BareIndexRepo<'a> {
    inner: &'a BareIndex,
    head: git2::Oid,
    head_str: String,
    rt: UnsafeRepoTree,
}

impl<'a> BareIndexRepo<'a> {
    fn new(index: &'a BareIndex) -> Result<Self, Error> {
        let exists = git2::Repository::discover(&index.path)
            .map(|repository| {
                repository
                    .find_remote("origin")
                    .ok()
                    // Cargo creates a checkout without an origin set,
                    // so default to true in case of missing origin
                    .map_or(true, |remote| {
                        remote.url().map_or(true, |url| url == index.url)
                    })
            })
            .unwrap_or(false);

        if !exists {
            git2::build::RepoBuilder::new()
                .fetch_options(crate::fetch_opts())
                .bare(true)
                .clone(&index.url, &index.path)?;
        }

        let repo = git2::Repository::open(&index.path)?;
        let head = repo
            // Fallback to HEAD, as a fresh clone won't have a FETCH_HEAD
            .refname_to_id("FETCH_HEAD")
            .or_else(|_| repo.refname_to_id("HEAD"))?;
        let head_str = head.to_string();

        let tree = {
            let commit = repo.find_commit(head)?;
            let tree = commit.tree()?;

            // See `UnsafeRepoTree`
            unsafe { std::mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) }
        };

        Ok(Self {
            inner: index,
            head,
            head_str,
            rt: UnsafeRepoTree {
                repo,
                tree,
            },
        })
    }

    /// Fetches latest from the remote index repository. Note that using this
    /// method will mean no cache entries will be used, if a new commit is fetched
    /// from the repository, as their commit version will no longer match.
    pub fn retrieve(&mut self) -> Result<(), Error> {
        {
            let mut origin_remote = self
                .rt.repo
                .find_remote("origin")
                .or_else(|_| self.rt.repo.remote_anonymous(&self.inner.url))?;

            origin_remote.fetch(
                &["+refs/heads/*:refs/remotes/origin/*"],
                Some(&mut crate::fetch_opts()),
                None,
            )?;
        }

        let head = self
            .rt.repo
            .refname_to_id("FETCH_HEAD")
            .or_else(|_| self.rt.repo.refname_to_id("HEAD"))?;
        let head_str = head.to_string();

        let commit = self.rt.repo.find_commit(head)?;
        let tree = commit.tree()?;

        // See `UnsafeRepoTree`
        let tree = unsafe { std::mem::transmute::<git2::Tree<'_>, git2::Tree<'static>>(tree) };

        self.head = head;
        self.head_str = head_str;
        self.rt.tree = tree;

        Ok(())
    }

    /// Reads a crate from the index, it will attempt to use a cached entry if
    /// one is available, otherwise it will fallback to reading the crate
    /// directly from the git blob containing the crate information.
    pub fn crate_(&self, name: &str) -> Option<Crate> {
        let rel_path = match crate::crate_name_to_relative_path(name) {
            Some(rp) => rp,
            None => return None,
        };

        // Attempt to load the .cache/ entry first, this is purely an acceleration
        // mechanism and can fail for a few reasons that are non-fatal
        {
            let mut cache_path = self.inner.path.join(".cache");
            cache_path.push(&rel_path);
            if let Ok(cache_bytes) = std::fs::read(&cache_path) {
                if let Ok(krate) = Crate::from_cache_slice(&cache_bytes, &self.head_str) {
                    return Some(krate);
                }
            }
        }

        // Fallback to reading the blob directly via git if we don't have a
        // valid cache entry
        self.krate_from_blob(&rel_path).ok()
    }

    fn krate_from_blob(&self, path: &str) -> Result<Crate, Error> {
        let entry = self.rt.tree.get_path(&Path::new(path))?;
        let object = entry.to_object(&self.rt.repo)?;
        let blob = object
            .as_blob()
            .ok_or_else(|| Error::Io(io::Error::new(io::ErrorKind::NotFound, path.to_owned())))?;

        Crate::from_slice(blob.content()).map_err(Error::Io)
    }

    /// Retrieve an iterator over all the crates in the index.
    /// skips crates that can not be parsed.
    pub fn crates(&self) -> Crates<'_> {
        let tree = self.rt.tree.clone().into_object();
        Crates {
            stack: vec![tree],
            rt: &self.rt,
        }
    }
}

pub struct Crates<'a> {
    stack: Vec<git2::Object<'a>>,
    rt: &'a UnsafeRepoTree,
}

impl<'a> Iterator for Crates<'a> {
    type Item = Crate;

    fn next(&mut self) -> Option<Self::Item> {
        let last = self.stack.pop()?;
        if let Some(tree) = last.as_tree() {
            for entry in tree.iter().rev() {
                self.stack.push(entry.to_object(&self.rt.repo).unwrap());
            }
            return self.next();
        }
        last.as_blob()
            .and_then(|blob| Crate::from_slice(blob.content()).ok())
            .or_else(|| self.next())
    }
}

/// Converts a full url, eg https://github.com/rust-lang/crates.io-index, into
/// the root directory name where cargo itself will fetch it on disk
fn url_to_local_dir(url: &str) -> Result<(String, String), Error> {
    fn to_hex(num: u64) -> String {
        const CHARS: &[u8] = b"0123456789abcdef";

        let bytes = &[
            num as u8,
            (num >> 8) as u8,
            (num >> 16) as u8,
            (num >> 24) as u8,
            (num >> 32) as u8,
            (num >> 40) as u8,
            (num >> 48) as u8,
            (num >> 56) as u8,
        ];

        let mut output = vec![0u8; 16];

        let mut ind = 0;

        for &byte in bytes {
            output[ind] = CHARS[(byte >> 4) as usize];
            output[ind + 1] = CHARS[(byte & 0xf) as usize];

            ind += 2;
        }

        String::from_utf8(output).expect("valid utf-8 hex string")
    }

    #[allow(deprecated)]
    fn hash_u64(url: &str) -> u64 {
        use std::hash::{Hash, Hasher, SipHasher};

        let mut hasher = SipHasher::new_with_keys(0, 0);
        // Registry
        2usize.hash(&mut hasher);
        // Url
        url.hash(&mut hasher);
        hasher.finish()
    }

    // Ensure we have a registry or bare url
    let (url, scheme_ind) = {
        let scheme_ind = url
            .find("://")
            .ok_or_else(|| Error::Url(format!("'{}' is not a valid url", url)))?;

        let scheme_str = &url[..scheme_ind];
        if let Some(ind) = scheme_str.find('+') {
            if &scheme_str[..ind] != "registry" {
                return Err(Error::Url(format!("'{}' is not a valid registry url", url)));
            }

            (&url[ind + 1..], scheme_ind - ind - 1)
        } else {
            (url, scheme_ind)
        }
    };

    // Could use the Url crate for this, but it's simple enough and we don't
    // need to deal with every possible url (I hope...)
    let host = match url[scheme_ind + 3..].find('/') {
        Some(end) => &url[scheme_ind + 3..scheme_ind + 3 + end],
        None => &url[scheme_ind + 3..],
    };

    // cargo special cases github.com for reasons, so do the same
    let mut canonical = if host == "github.com" {
        url.to_lowercase()
    } else {
        url.to_owned()
    };

    // Chop off any query params/fragments
    if let Some(hash) = canonical.rfind('#') {
        canonical.truncate(hash);
    }

    if let Some(query) = canonical.rfind('?') {
        canonical.truncate(query);
    }

    let ident = to_hex(hash_u64(&canonical));

    if canonical.ends_with('/') {
        canonical.pop();
    }

    if canonical.ends_with(".git") {
        canonical.truncate(canonical.len() - 4);
    }

    Ok((format!("{}-{}", host, ident), canonical))
}

#[cfg(test)]
mod test {
    #[test]
    fn matches_cargo() {
        assert_eq!(
            super::url_to_local_dir(crate::INDEX_GIT_URL).unwrap(),
            (
                "github.com-1ecc6299db9ec823".to_owned(),
                crate::INDEX_GIT_URL.to_owned()
            )
        );

        // I've confirmed this also works with a custom registry, unfortunately
        // that one includes a secret key as part of the url which would allow
        // anyone to publish to the registry, so uhh...here's a fake one instead
        assert_eq!(
            super::url_to_local_dir(
                "https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git"
            )
            .unwrap(),
            (
                "dl.cloudsmith.io-ff79e51ddd2b38fd".to_owned(),
                "https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index".to_owned()
            )
        );

        // Ensure we actually strip off the irrelevant parts of a url, note that
        // the .git suffix is not part of the canonical url, but *is* used when hashing
        assert_eq!(
            super::url_to_local_dir(&format!(
                "registry+{}.git?one=1&two=2#fragment",
                crate::INDEX_GIT_URL
            ))
            .unwrap(),
            (
                "github.com-c786010fb7ef2e6e".to_owned(),
                crate::INDEX_GIT_URL.to_owned()
            )
        );
    }

    #[test]
    fn bare_iterator() {
        use super::BareIndex;

        let tmp_dir = tempdir::TempDir::new("bare_iterator").unwrap();

        let index = BareIndex::with_path(tmp_dir.path().to_owned(), crate::INDEX_GIT_URL);

        let repo = index
            .open_or_clone()
            .expect("Failed to clone crates.io index");

        let mut found_gcc_crate = false;

        for c in repo.crates() {
            if c.name() == "gcc" {
                found_gcc_crate = true;
            }
        }

        assert!(found_gcc_crate);
    }

    #[test]
    fn clones_bare_index() {
        use super::BareIndex;

        let tmp_dir = tempdir::TempDir::new("clones_bare_index").unwrap();

        let index = BareIndex::with_path(tmp_dir.path().to_owned(), crate::INDEX_GIT_URL);

        let mut repo = index
            .open_or_clone()
            .expect("Failed to clone crates.io index");

        fn test_sval(repo: &super::BareIndexRepo<'_>) {
            let krate = repo
                .crate_("sval")
                .expect("Could not find the crate sval in the index");

            let version = krate
                .versions()
                .iter()
                .find(|v| v.version() == "0.0.1")
                .expect("Version 0.0.1 of sval does not exist?");
            let dep_with_package_name = version
                .dependencies()
                .iter()
                .find(|d| d.name() == "serde_lib")
                .expect("sval does not have expected dependency?");
            assert_ne!(
                dep_with_package_name.name(),
                dep_with_package_name.package().unwrap()
            );
            assert_eq!(
                dep_with_package_name.crate_name(),
                dep_with_package_name.package().unwrap()
            );
        }

        test_sval(&repo);

        repo.retrieve().expect("Failed to fetch crates.io index");

        test_sval(&repo);
    }

    #[test]
    fn opens_bare_index() {
        use super::BareIndex;

        let tmp_dir = tempdir::TempDir::new("opens_bare_index").unwrap();

        let index = BareIndex::with_path(tmp_dir.path().to_owned(), crate::INDEX_GIT_URL);

        {
            let _ = index
                .open_or_clone()
                .expect("Failed to clone crates.io index");
        }

        let mut repo = index
            .open_or_clone()
            .expect("Failed to open crates.io index");

        fn test_sval(repo: &super::BareIndexRepo<'_>) {
            let krate = repo
                .crate_("sval")
                .expect("Could not find the crate sval in the index");

            let version = krate
                .versions()
                .iter()
                .find(|v| v.version() == "0.0.1")
                .expect("Version 0.0.1 of sval does not exist?");
            let dep_with_package_name = version
                .dependencies()
                .iter()
                .find(|d| d.name() == "serde_lib")
                .expect("sval does not have expected dependency?");
            assert_ne!(
                dep_with_package_name.name(),
                dep_with_package_name.package().unwrap()
            );
            assert_eq!(
                dep_with_package_name.crate_name(),
                dep_with_package_name.package().unwrap()
            );
        }

        test_sval(&repo);

        repo.retrieve().expect("Failed to fetch crates.io index");

        test_sval(&repo);
    }
}
<|endoftext|>


<commit_before>/// Represents an ASN.1 `BIT STRING`.
#[derive(Debug, PartialEq, Clone, Hash)]
pub struct BitString<'a> {
    data: &'a [u8],
    padding_bits: u8,
}

impl<'a> BitString<'a> {
    pub(crate) fn new(data: &'a [u8], padding_bits: u8) -> Option<BitString<'a>> {
        if padding_bits > 7 || (data.is_empty() && padding_bits != 0) {
            return None;
        }
        if padding_bits > 0 && data[data.len() - 1] & ((1 << padding_bits) - 1) != 0 {
            return None;
        }

        Some(BitString { data, padding_bits })
    }

    /// Returns a sequence of bytes representing the data in the `BIT STRING`. Padding bits will
    /// always be 0.
    pub fn as_bytes(&self) -> &'a [u8] {
        self.data
    }

    /// Returns the number of padding bits. Will always be in [0, 8).
    pub fn padding_bits(&self) -> u8 {
        self.padding_bits
    }

    /// Returns whether the requested bit is set. Padding bits will always return false and
    /// asking for bits that exceed the length of the bit string will also return false.
    pub fn has_bit_set(&self, n: usize) -> bool {
        let idx = n / 8;
        let v = 1 << (7 - (n & 0x07));
        if self.data.len() < (idx + 1) {
            false
        } else {
            self.data[idx] & v != 0
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::BitString;

    #[test]
    fn test_bitstring_new() {
        assert_eq!(BitString::new(b"abc", 8), None);
        assert_eq!(BitString::new(b"", 2), None);
        assert_eq!(BitString::new(b"\xff", 1), None);

        assert!(BitString::new(b"\xff", 0).is_some());
        assert!(BitString::new(b"\xfe", 1).is_some());
    }

    #[test]
    fn test_bitstring_as_bytes() {
        let bs = BitString::new(b"\xfe", 1).unwrap();
        assert_eq!(bs.as_bytes(), b"\xfe");
    }

    #[test]
    fn test_bitstring_padding_bits() {
        let bs = BitString::new(b"\xfe", 1).unwrap();
        assert_eq!(bs.padding_bits(), 1);
        let bs = BitString::new(b"\xe0", 5).unwrap();
        assert_eq!(bs.padding_bits(), 5);
    }

    #[test]
    fn test_bitstring_has_bit_set() {
        let bs = BitString::new(b"\x80", 0).unwrap();
        assert!(bs.has_bit_set(0));
        assert!(!bs.has_bit_set(1));
        assert!(!bs.has_bit_set(7));
        // An arbitrary bit much bigger than the underlying size of the bitfield
        assert!(!bs.has_bit_set(50));
        let bs = BitString::new(b"\xc0", 4).unwrap();
        // padding bits should always return false when asking if the bit is set
        assert!(bs.has_bit_set(0));
        assert!(bs.has_bit_set(1));
        assert!(!bs.has_bit_set(2));
        assert!(!bs.has_bit_set(3));
        assert!(!bs.has_bit_set(4));
        assert!(!bs.has_bit_set(5));
        assert!(!bs.has_bit_set(6));
        assert!(!bs.has_bit_set(7));
    }
}
<commit_msg>make BitString::new public (#204)<commit_after>/// Represents an ASN.1 `BIT STRING`.
#[derive(Debug, PartialEq, Clone, Hash)]
pub struct BitString<'a> {
    data: &'a [u8],
    padding_bits: u8,
}

impl<'a> BitString<'a> {
    pub fn new(data: &'a [u8], padding_bits: u8) -> Option<BitString<'a>> {
        if padding_bits > 7 || (data.is_empty() && padding_bits != 0) {
            return None;
        }
        if padding_bits > 0 && data[data.len() - 1] & ((1 << padding_bits) - 1) != 0 {
            return None;
        }

        Some(BitString { data, padding_bits })
    }

    /// Returns a sequence of bytes representing the data in the `BIT STRING`. Padding bits will
    /// always be 0.
    pub fn as_bytes(&self) -> &'a [u8] {
        self.data
    }

    /// Returns the number of padding bits. Will always be in [0, 8).
    pub fn padding_bits(&self) -> u8 {
        self.padding_bits
    }

    /// Returns whether the requested bit is set. Padding bits will always return false and
    /// asking for bits that exceed the length of the bit string will also return false.
    pub fn has_bit_set(&self, n: usize) -> bool {
        let idx = n / 8;
        let v = 1 << (7 - (n & 0x07));
        if self.data.len() < (idx + 1) {
            false
        } else {
            self.data[idx] & v != 0
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::BitString;

    #[test]
    fn test_bitstring_new() {
        assert_eq!(BitString::new(b"abc", 8), None);
        assert_eq!(BitString::new(b"", 2), None);
        assert_eq!(BitString::new(b"\xff", 1), None);

        assert!(BitString::new(b"\xff", 0).is_some());
        assert!(BitString::new(b"\xfe", 1).is_some());
    }

    #[test]
    fn test_bitstring_as_bytes() {
        let bs = BitString::new(b"\xfe", 1).unwrap();
        assert_eq!(bs.as_bytes(), b"\xfe");
    }

    #[test]
    fn test_bitstring_padding_bits() {
        let bs = BitString::new(b"\xfe", 1).unwrap();
        assert_eq!(bs.padding_bits(), 1);
        let bs = BitString::new(b"\xe0", 5).unwrap();
        assert_eq!(bs.padding_bits(), 5);
    }

    #[test]
    fn test_bitstring_has_bit_set() {
        let bs = BitString::new(b"\x80", 0).unwrap();
        assert!(bs.has_bit_set(0));
        assert!(!bs.has_bit_set(1));
        assert!(!bs.has_bit_set(7));
        // An arbitrary bit much bigger than the underlying size of the bitfield
        assert!(!bs.has_bit_set(50));
        let bs = BitString::new(b"\xc0", 4).unwrap();
        // padding bits should always return false when asking if the bit is set
        assert!(bs.has_bit_set(0));
        assert!(bs.has_bit_set(1));
        assert!(!bs.has_bit_set(2));
        assert!(!bs.has_bit_set(3));
        assert!(!bs.has_bit_set(4));
        assert!(!bs.has_bit_set(5));
        assert!(!bs.has_bit_set(6));
        assert!(!bs.has_bit_set(7));
    }
}
<|endoftext|>


<commit_before>fn main() {
    let haystack = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862];

    for reference in haystack.iter() {
        let item = *reference;

        let result = match item {
            42 | 132 => "hit!",
            _ => "miss",
        };

        if result == "hit!" {
            println!("{}: {}", item, result);
        }
    }
    println!("");

    let three = 0b11;
    let thirty = 0o36;
    let three_hundred = 0x12C;

    println!("{} {} {}", three, thirty, three_hundred);
    println!("{:b} {:b} {:b}", three, thirty, three_hundred);
    println!("{:o} {:o} {:o}", three, thirty, three_hundred);
    println!("{:x} {:x} {:x}", three, thirty, three_hundred);
    println!("");

    let twenty = 20;
    let twenty_one: i32 = twenty + 1;
    let floats_okay = 21.0;
    let one_million = 1_000_000;

    println!("{}; {}; {}; {}", twenty, twenty_one, floats_okay, one_million);
    println!("");

    let a = 10;
    let b: i32 = 20;

    let c = add(a, b);
    println!("a + b = {}", c);
}

fn add(i: i32, j: i32) -> i32 {
    i + j
}
<commit_msg>changed add function to use generics<commit_after>use std::ops::{Add};

fn main() {
    let (a, b) = (1.2, 3.4);
    let (x, y) = (10, 20);

    let c = add(a,b);
    let z = add(x, y);

    println!("{} + {} = {}", a, b, c);
    println!("{} + {} = {}", x, y, z);
    println!("");

    let haystack = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862];

    for reference in haystack.iter() {
        let item = *reference;

        let result = match item {
            42 | 132 => "hit!",
            _ => "miss",
        };

        if result == "hit!" {
            println!("{}: {}", item, result);
        }
    }
    println!("");

    let three = 0b11;
    let thirty = 0o36;
    let three_hundred = 0x12C;

    println!("{} {} {}", three, thirty, three_hundred);
    println!("{:b} {:b} {:b}", three, thirty, three_hundred);
    println!("{:o} {:o} {:o}", three, thirty, three_hundred);
    println!("{:x} {:x} {:x}", three, thirty, three_hundred);
    println!("");

    let twenty = 20;
    let twenty_one: i32 = twenty + 1;
    let floats_okay = 21.0;
    let one_million = 1_000_000;

    println!("{}; {}; {}; {}", twenty, twenty_one, floats_okay, one_million);
    println!("");

    let a = 10;
    let b: i32 = 20;

    let c = add(a, b);
    println!("a + b = {}", c);
}

fn add<T: Add<Output = T>>(i: T, j: T) -> T {
    i + j
}
<|endoftext|>


<commit_before>use term_painter::ToStyle;
use term_painter::Attr::*;
use std::fmt;
use std::io;
use std::process;

#[derive(Clone)]
pub struct SearchResult {
    pub title: String,
    pub score: String,
    pub number: String,
    pub genres: Vec<String>,
    pub year: String,
}

impl fmt::Display for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               Bold.paint(format!("{} ({})\n", &self.title, &self.year)));
        let mut stars = String::new();
        let score: f32 = self.score.parse::<f32>().unwrap();
        for i in 0..10 {
            if i < (score + 0.5) as i32 {
                stars.push_str("\u{2605}");
            } else {
                stars.push_str("\u{2606}");
            }
        }
        write!(f, "{}", &self.genres[0]);
        for genre in self.genres.clone().into_iter().skip(1) {
            write!(f, ", {}", genre);
        }
        write!(f,
               "\n{}, ({} bei {} Bewertungen)",
               stars,
               &self.score,
               &self.number)
    }
}

impl fmt::Debug for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n******",
               self.title,
               self.year,
               self.genres,
               self.score,
               self.number)
    }
}

pub fn output_result(results: Vec<SearchResult>) {
    let further = results.clone();
    for res in results.into_iter().take(3) {
        println!("{}", res);
    }
    for output in further.into_iter().skip(3) {
        let mut buffer = String::new();
        io::stdin().read_line(&mut buffer);
        if buffer != "q\n" {
            println!("{}", output);
        } else {
            process::exit(0);
        }
    }
}
<commit_msg>fixed unused results<commit_after>use term_painter::ToStyle;
use term_painter::Attr::*;
use std::fmt;
use std::io;
use std::process;

#[derive(Clone)]
pub struct SearchResult {
    pub title: String,
    pub score: String,
    pub number: String,
    pub genres: Vec<String>,
    pub year: String,
}

impl fmt::Display for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f,
                    "{}",
                    Bold.paint(format!("{} ({})\n", &self.title, &self.year))));
        let mut stars = String::new();
        let score: f32 = self.score.parse::<f32>().unwrap();
        for i in 0..10 {
            if i < (score + 0.5) as i32 {
                stars.push_str("\u{2605}");
            } else {
                stars.push_str("\u{2606}");
            }
        }
        try!(write!(f, "{}", &self.genres[0]));
        for genre in self.genres.clone().into_iter().skip(1) {
            try!(write!(f, ", {}", genre));
        }
        write!(f,
               "\n{}, ({} bei {} Bewertungen)",
               stars,
               &self.score,
               &self.number)
    }
}

impl fmt::Debug for SearchResult {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n******",
               self.title,
               self.year,
               self.genres,
               self.score,
               self.number)
    }
}

pub fn output_result(results: Vec<SearchResult>) {
    let further = results.clone();
    for res in results.into_iter().take(3) {
        println!("{}", res);
    }
    for output in further.into_iter().skip(3) {
        let mut buffer = String::new();
        io::stdin().read_line(&mut buffer);
        if buffer != "q\n" {
            println!("{}", output);
        } else {
            process::exit(0);
        }
    }
}
<|endoftext|>


<commit_before>//! Methods and structs that control the physical outputs and what they display.

mod output;

use std::sync::Mutex;

pub use self::output::Output;
use ::Session;
use utils::{wl_listener, wl_signal_add};

use wayland_sys::server;
use wlroots_sys::{wl_list, wlr_output, wlr_output_set_mode};
use std::os::raw::c_void;

lazy_static! {
    pub static ref OUTPUTS: Mutex<Vec<Output>> =
        Mutex::new(Vec::with_capacity(128));
}

/// Sets up the session so that it listens for and automatically manages adding
/// and removing outputs.
pub unsafe fn init(session: &mut Session) {
    let backend = &mut (*session.backend.0);

    // Set up output_add
    let mut output_add_listener = Box::new(wl_listener::new(output_add));
    wl_signal_add(&mut backend.events.output_add,
                  &mut *output_add_listener);

    // Set up output_remove
    let mut output_remove_listener = Box::new(wl_listener::new(output_remove));
    wl_signal_add(&mut backend.events.output_remove,
                  &mut *output_remove_listener);

    // Leak the link in the list that points to the static function.
    ::std::mem::forget(output_add_listener);
    ::std::mem::forget(output_remove_listener);
}

unsafe extern "C" fn output_add(listener: *mut server::wl_listener,
                                data: *mut c_void) {
    let mut outputs = OUTPUTS.lock().expect("OUTPUTS mutex has been poisoned");
    let output: &mut wlr_output = &mut *(data as *mut _);
    let cur_mode = (*(*output.modes).items) as *mut _;
    wlr_output_set_mode(output, cur_mode);
    outputs.push(Output::new(output as *mut _));
    println!("Added outputs: {:?}", outputs);
}

unsafe extern "C" fn output_remove(listener: *mut server::wl_listener,
                                   data: *mut c_void) {
    let mut outputs = OUTPUTS.lock().expect("OUTPUTS mutex has been poisoned");
    let output_ptr = data as *const wlr_output;
    outputs.retain(|output| output.inner as *const _ != output_ptr);
    println!("Removed outputs: {:?}", outputs);
}
<commit_msg>Added justification for unsafety of output::init<commit_after>//! Methods and structs that control the physical outputs and what they display.

mod output;

use std::sync::Mutex;

pub use self::output::Output;
use ::Session;
use utils::{wl_listener, wl_signal_add};

use wayland_sys::server;
use wlroots_sys::{wl_list, wlr_output, wlr_output_set_mode};
use std::os::raw::c_void;

lazy_static! {
    pub static ref OUTPUTS: Mutex<Vec<Output>> =
        Mutex::new(Vec::with_capacity(128));
}

// TODO Make this init part of some struct that consumes it and makes
// sure you can only call this once.

// TODO Also make sure this is definitely safe, pretty sure it is but we
// need to double check.

/// Sets up the session so that it listens for and automatically manages adding
/// and removing outputs.
///
/// # Unsafety
/// This should only be called once, otherwise there could be multiple
/// references to the same `wl_output`.
pub unsafe fn init(session: &mut Session) {
    let backend = &mut (*session.backend.0);

    // Set up output_add
    let mut output_add_listener = Box::new(wl_listener::new(output_add));
    wl_signal_add(&mut backend.events.output_add,
                  &mut *output_add_listener);

    // Set up output_remove
    let mut output_remove_listener = Box::new(wl_listener::new(output_remove));
    wl_signal_add(&mut backend.events.output_remove,
                  &mut *output_remove_listener);

    // Leak the link in the list that points to the static function.
    ::std::mem::forget(output_add_listener);
    ::std::mem::forget(output_remove_listener);
}

unsafe extern "C" fn output_add(listener: *mut server::wl_listener,
                                data: *mut c_void) {
    let mut outputs = OUTPUTS.lock().expect("OUTPUTS mutex has been poisoned");
    let output: &mut wlr_output = &mut *(data as *mut _);
    let cur_mode = (*(*output.modes).items) as *mut _;
    wlr_output_set_mode(output, cur_mode);
    outputs.push(Output::new(output as *mut _));
    println!("Added outputs: {:?}", outputs);
}

unsafe extern "C" fn output_remove(listener: *mut server::wl_listener,
                                   data: *mut c_void) {
    let mut outputs = OUTPUTS.lock().expect("OUTPUTS mutex has been poisoned");
    let output_ptr = data as *const wlr_output;
    outputs.retain(|output| output.inner as *const _ != output_ptr);
    println!("Removed outputs: {:?}", outputs);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::{Ipv4Addr, Ipv6Addr};

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_reserved: u8, // data offset field & reserved field
    control_bits: u8, // the first 5 bits are used; the rest is reserved
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    simple_no_options: u8, // XXX replace with something more complex later
    #[payload]
    payload: Vec<u8>
}

#[test]
fn tcp_header_ipv4_test() {
    use pnet::packet::ip::IpNextHeaderProtocols;
    use pnet::packet::ipv4::MutableIpv4Packet;

    const IPV4_HEADER_LEN: usize = 20;
    const TCP_HEADER_LEN: usize = 21;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV4_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let ipv4_source = Ipv4Addr::new(192, 168, 0, 1);
    let ipv4_destination = Ipv4Addr::new(192, 168, 0, 199);
    let next_level_protocol = IpNextHeaderProtocols::Tcp;
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_level_protocol(next_level_protocol);
        ip_header.set_source(ipv4_source);
        ip_header.set_destination(ipv4_destination);
    }

    // Set data
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[20..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x00,        // control bits
                      0x00, 0x00,  // window
                      0x00, 0x00,  // checksum
                      0x00, 0x00,  // urgent pointer
                      0x00];       // simple no tcp header options

    assert_eq!(&ref_packet[..], &packet[IPV4_HEADER_LEN .. IPV4_HEADER_LEN + TCP_HEADER_LEN]);
}

#[test]
fn tcp_header_ipv6_test() {
    use packet::ip::{IpNextHeaderProtocols};
    use packet::ipv6::{MutableIpv6Packet};

    const IPV6_HEADER_LEN: usize = 40;
    const TCP_HEADER_LEN: usize = 21;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV6_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let next_header = IpNextHeaderProtocols::Tcp;
    let ipv6_source = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    let ipv6_destination = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_header(next_header);
        ip_header.set_source(ipv6_source);
        ip_header.set_destination(ipv6_destination);
    }

    // Set data
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[IPV6_HEADER_LEN..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x00,        // control bits
                      0x00, 0x00,  // window
                      0x00, 0x00,  // checksum
                      0x00, 0x00,  // urgent pointer
                      0x00];       // simple no tcp header options

    assert_eq!(&ref_packet[..], &packet[IPV6_HEADER_LEN .. IPV6_HEADER_LEN + TCP_HEADER_LEN]);
}
<commit_msg>remove no-op tcp option from struct<commit_after>// Copyright (c) 2015 David Stainton <dstainton415@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! TCP packet abstraction

use packet::Packet;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::{Ipv4Addr, Ipv6Addr};

/// Represents a TCP Packet
#[packet]
pub struct Tcp {
    source: u16be,
    destination: u16be,
    sequence: u32be,
    acknowledgement: u32be,
    data_offset_reserved: u8, // data offset field & reserved field
    control_bits: u8, // the first 5 bits are used; the rest is reserved
    window: u16be,
    checksum: u16be,
    urgent_pointer: u16be,
    // 16+16+32+32+8+8+16+16+16 == 20
    #[payload]
    payload: Vec<u8>
}

#[test]
fn tcp_header_ipv4_test() {
    use pnet::packet::ip::IpNextHeaderProtocols;
    use pnet::packet::ipv4::MutableIpv4Packet;

    const IPV4_HEADER_LEN: usize = 20;
    const TCP_HEADER_LEN: usize = 20;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV4_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let ipv4_source = Ipv4Addr::new(192, 168, 0, 1);
    let ipv4_destination = Ipv4Addr::new(192, 168, 0, 199);
    let next_level_protocol = IpNextHeaderProtocols::Tcp;
    {
        let mut ip_header = MutableIpv4Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_level_protocol(next_level_protocol);
        ip_header.set_source(ipv4_source);
        ip_header.set_destination(ipv4_destination);
    }

    // Set data
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV4_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[20..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x00,        // control bits
                      0x00, 0x00,  // window
                      0x00, 0x00,  // checksum
                      0x00, 0x00  // urgent pointer
                      ];
                      //0x01, 0x01,  // simple no tcp header options
                      //0x01, 0x00];

    //[48, 57, 212, 49, 0, 0, 13, 128, 0, 0, 30, 119, 128, 0, 0, 0, 0, 0, 0, 0]`, right: `
    //[48, 57, 212, 49, 0, 0, 13, 128, 0, 0, 30, 119, 128, 0, 0, 0, 0, 0, 0, 0, 0]

    assert_eq!(&ref_packet[..], &packet[IPV4_HEADER_LEN .. IPV4_HEADER_LEN + TCP_HEADER_LEN]);
}

#[test]
fn tcp_header_ipv6_test() {
    use packet::ip::{IpNextHeaderProtocols};
    use packet::ipv6::{MutableIpv6Packet};

    const IPV6_HEADER_LEN: usize = 40;
    const TCP_HEADER_LEN: usize = 20;
    const PAYLOAD_LEN: usize = 4;

    let mut packet = [0u8; IPV6_HEADER_LEN + TCP_HEADER_LEN + PAYLOAD_LEN];

    let next_header = IpNextHeaderProtocols::Tcp;
    let ipv6_source = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    let ipv6_destination = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_next_header(next_header);
        ip_header.set_source(ipv6_source);
        ip_header.set_destination(ipv6_destination);
    }

    // Set data
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 0] = 't' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 1] = 'e' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 2] = 's' as u8;
    packet[IPV6_HEADER_LEN + TCP_HEADER_LEN + 3] = 't' as u8;

    {
        let mut tcp_header = MutableTcpPacket::new(&mut packet[IPV6_HEADER_LEN..]).unwrap();
        tcp_header.set_source(12345);
        assert_eq!(tcp_header.get_source(), 12345);

        tcp_header.set_destination(54321);
        assert_eq!(tcp_header.get_destination(), 54321);

        tcp_header.set_sequence(3456);
        assert_eq!(tcp_header.get_sequence(), 3456);

        tcp_header.set_acknowledgement(7799);
        assert_eq!(tcp_header.get_acknowledgement(), 7799);

        tcp_header.set_data_offset_reserved(0x80);
        assert_eq!(tcp_header.get_data_offset_reserved(), 0x80);
    }

    let ref_packet = [0x30, 0x39,  // source
                      0xd4, 0x31,  // destination
                      0x00, 0x00,  // sequence
                      0x0d, 0x80,
                      0x00, 0x00,  // acknowledgement
                      0x1e, 0x77,
                      0x80,        // header length + reserved
                      0x00,        // control bits
                      0x00, 0x00,  // window
                      0x00, 0x00,  // checksum
                      0x00, 0x00  // urgent pointer
                      ];
                      //0x01, 0x01,  // simple no tcp header options
                      //0x01, 0x00];

    assert_eq!(&ref_packet[..], &packet[IPV6_HEADER_LEN .. IPV6_HEADER_LEN + TCP_HEADER_LEN]);
}
<|endoftext|>


<commit_before>// Kevin Cantu
// hash function testing

use std;

fn splitfn(ss: str, sepf: block(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });

   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }

   ret vv;
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

// hash fn being mapped
fn djb(&&s: str) -> uint
{
    let u: uint = 5381u;
    for c: u8 in s { u *= 33u; u += c as uint; }
    ret u;
}

fn main ()
{
   let meow = word_of_god();
   hash_bench ("calling hash_bench()...   ", djb, meow);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// when BOTH of the following functions are compiled at opt level 1 instead of 0
// the program becomes SLOWER with optimization
fn word_of_god () -> [str]
{
   std::io::println ("Loading the lolcat bible...");
   let path = "../lolcat/LOLCatBible_2012-01-04.xml";
   let bible = std::io::read_whole_file (path);
   let bible_ = str::unsafe_from_bytes (result::get (bible));

   ret words(bible_) +
       vec::map(lines(bible_), {|ln| ln+ln+ln+ln});
}

fn hash_bench <TT> ( label: str, hashfn: native fn(&&str)->TT, data: [str] )
{
   let t0 = std::time::precise_time_s();
   let _v = vec::map(data, hashfn);
   let t1 = std::time::precise_time_s();

   std::io::println(label + #fmt("%06.3f sec", t1 - t0));
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

<commit_msg>removing the not-directly-related optimization debugging stuff<commit_after>// Kevin Cantu
// hash function testing

use std;
use bench;

fn splitfn(ss: str, sepf: block(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });

   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }

   ret vv;
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

// hash fn being mapped
fn djb(&&s: str) -> uint
{
    let u: uint = 5381u;
    for c: u8 in s { u *= 33u; u += c as uint; }
    ret u;
}

fn main ()
{
   let meow = word_of_god();
   hash_bench ("calling hash_bench()...   ", djb, meow);
}

<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! The client-side abstraction for multipart requests. Enabled with the `client` feature.
//!
//! Use this when sending POST requests with files to a server.
use mime::Mime;

use std::borrow::Cow;
use std::fs::File;
use std::io;
use std::io::prelude::*;

use std::path::Path;

#[cfg(feature = "hyper")]
pub mod hyper;

pub mod lazy;

mod sized;

pub use self::sized::SizedRequest;

const BOUNDARY_LEN: usize = 16;

macro_rules! map_self {
    ($selff:expr, $try:expr) => (
        match $try {
            Ok(_) => Ok($selff),
            Err(err) => Err(err.into()),
        }
    )
}

/// The entry point of the client-side multipart API.
///
/// Though they perform I/O, the `.write_*()` methods do not return `io::Result<_>` in order to
/// facilitate method chaining. Upon the first error, all subsequent API calls will be no-ops until
/// `.send()` is called, at which point the error will be reported.
pub struct Multipart<S> {
    writer: MultipartWriter<'static, S>,
}

impl Multipart<()> {
    /// Create a new `Multipart` to wrap a request.
    ///
    /// ## Returns Error
    /// If `req.open_stream()` returns an error.
    pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Stream>, R::Error> {
        let (boundary, stream) = open_stream(req, None)?;

        Ok(Multipart {
            writer: MultipartWriter::new(stream, boundary),
        })
    }
}

impl<S: HttpStream> Multipart<S> {
    /// Write a text field to this multipart request.
    /// `name` and `val` can be either owned `String` or `&str`.
    ///
    /// ## Errors
    /// If something went wrong with the HTTP stream.
    pub fn write_text<N: AsRef<str>, V: AsRef<str>>(&mut self, name: N, val: V) -> Result<&mut Self, S::Error> {
        map_self!(self, self.writer.write_text(name.as_ref(), val.as_ref()))
    }

    /// Open a file pointed to by `path` and write its contents to the multipart request,
    /// supplying its filename and guessing its `Content-Type` from its extension.
    ///
    /// If you want to set these values manually, or use another type that implements `Read`,
    /// use `.write_stream()`.
    ///
    /// `name` can be either `String` or `&str`, and `path` can be `PathBuf` or `&Path`.
    ///
    /// ## Errors
    /// If there was a problem opening the file (was a directory or didn't exist),
    /// or if something went wrong with the HTTP stream.
    pub fn write_file<N: AsRef<str>, P: AsRef<Path>>(&mut self, name: N, path: P) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();
        let path = path.as_ref();

        map_self!(self, self.writer.write_file(name, path))
    }

    /// Write a byte stream to the multipart request as a file field, supplying `filename` if given,
    /// and `content_type` if given or `"application/octet-stream"` if not.
    ///
    /// `name` can be either `String` or `&str`, and `read` can take the `Read` by-value or
    /// with an `&mut` borrow.
    ///
    /// ## Warning
    /// The given `Read` **must** be able to read to EOF (end of file/no more data), meaning
    /// `Read::read()` returns `Ok(0)`. If it never returns EOF it will be read to infinity
    /// and the request will never be completed.
    ///
    /// When using `SizedRequest` this also can cause out-of-control memory usage as the
    /// multipart data has to be written to an in-memory buffer so its size can be calculated.
    ///
    /// Use `Read::take()` if you wish to send data from a `Read`
    /// that will never return EOF otherwise.
    ///
    /// ## Errors
    /// If the reader returned an error, or if something went wrong with the HTTP stream.
    // RFC: How to format this declaration?
    pub fn write_stream<N: AsRef<str>, St: Read>(
        &mut self, name: N, stream: &mut St, filename: Option<&str>, content_type: Option<Mime>
    ) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();

        map_self!(self, self.writer.write_stream(stream, name, filename, content_type))
    }

    /// Finalize the request and return the response from the server, or the last error if set.
    pub fn send(self) -> Result<S::Response, S::Error> {
        self.writer.finish().map_err(io::Error::into).and_then(|body| body.finish())
    }
}

impl<R: HttpRequest> Multipart<SizedRequest<R>>
where <R::Stream as HttpStream>::Error: From<R::Error> {
    /// Create a new `Multipart` using the `SizedRequest` wrapper around `req`.
    pub fn from_request_sized(req: R) -> Result<Self, R::Error> {
        Multipart::from_request(SizedRequest::from_request(req))
    }
}

/// A trait describing an HTTP request that can be used to send multipart data.
pub trait HttpRequest {
    /// The HTTP stream type that can be opend by this request, to which the multipart data will be
    /// written.
    type Stream: HttpStream;
    /// The error type for this request.
    /// Must be compatible with `io::Error` as well as `Self::HttpStream::Error`
    type Error: From<io::Error> + Into<<Self::Stream as HttpStream>::Error>;

    /// Set the `Content-Type` header to `multipart/form-data` and supply the `boundary` value.
    /// If `content_len` is given, set the `Content-Length` header to its value.
    ///
    /// Return `true` if any and all sanity checks passed and the stream is ready to be opened,
    /// or `false` otherwise.
    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool;

    /// Open the request stream and return it or any error otherwise.
    fn open_stream(self) -> Result<Self::Stream, Self::Error>;
}

/// A trait describing an open HTTP stream that can be written to.
pub trait HttpStream: Write {
    /// The request type that opened this stream.
    type Request: HttpRequest;
    /// The response type that will be returned after the request is completed.
    type Response;
    /// The error type for this stream.
    /// Must be compatible with `io::Error` as well as `Self::Request::Error`.
    type Error: From<io::Error> + From<<Self::Request as HttpRequest>::Error>;

    /// Finalize and close the stream and return the response object, or any error otherwise.
    fn finish(self) -> Result<Self::Response, Self::Error>;
}

impl HttpRequest for () {
    type Stream = io::Sink;
    type Error = io::Error;

    fn apply_headers(&mut self, _: &str, _: Option<u64>) -> bool { true }
    fn open_stream(self) -> Result<Self::Stream, Self::Error> { Ok(io::sink()) }
}

impl HttpStream for io::Sink {
    type Request = ();
    type Response = ();
    type Error = io::Error;

    fn finish(self) -> Result<Self::Response, Self::Error> { Ok(()) }
}

fn gen_boundary() -> String {
    ::random_alphanumeric(BOUNDARY_LEN)
}

fn open_stream<R: HttpRequest>(mut req: R, content_len: Option<u64>) -> Result<(String, R::Stream), R::Error> {
    let boundary = gen_boundary();
    req.apply_headers(&boundary, content_len);
    req.open_stream().map(|stream| (boundary, stream))
}

struct MultipartWriter<'a, W> {
    inner: W,
    boundary: Cow<'a, str>,
    data_written: bool,
}

impl<'a, W: Write> MultipartWriter<'a, W> {
    fn new<B: Into<Cow<'a, str>>>(inner: W, boundary: B) -> Self {
        MultipartWriter {
            inner,
            boundary: boundary.into(),
            data_written: false,
        }
    }

    fn write_boundary(&mut self) -> io::Result<()> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        write!(self.inner, "--{}\r\n", self.boundary)
    }

    fn write_text(&mut self, name: &str, text: &str) -> io::Result<()> {
        chain_result! {
            self.write_field_headers(name, None, None),
            self.inner.write_all(text.as_bytes())
        }
    }

    fn write_file(&mut self, name: &str, path: &Path) -> io::Result<()> {
        let (content_type, filename) = mime_filename(path);
        let mut file = File::open(path)?;
        self.write_stream(&mut file, name, filename, Some(content_type))
    }

    fn write_stream<S: Read>(&mut self, stream: &mut S, name: &str, filename: Option<&str>, content_type: Option<Mime>) -> io::Result<()> {
        // This is necessary to make sure it is interpreted as a file on the server end.
        let content_type = Some(content_type.unwrap_or_else(::mime_guess::octet_stream));

        chain_result! {
            self.write_field_headers(name, filename, content_type),
            io::copy(stream, &mut self.inner),
            Ok(())
        }
    }

    fn write_field_headers(&mut self, name: &str, filename: Option<&str>, content_type: Option<Mime>)
    -> io::Result<()> {
        chain_result! {
            // Write the first boundary, or the boundary for the previous field.
            self.write_boundary(),
            { self.data_written = true; Ok(()) },
            write!(self.inner, "Content-Disposition: form-data; name=\"{}\"", name),
            filename.map(|filename| write!(self.inner, "; filename=\"{}\"", filename))
                .unwrap_or(Ok(())),
            content_type.map(|content_type| write!(self.inner, "\r\nContent-Type: {}", content_type))
                .unwrap_or(Ok(())),
            self.inner.write_all(b"\r\n\r\n")
        }
    }

    fn finish(mut self) -> io::Result<W> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        // always write the closing boundary, even for empty bodies
        write!(self.inner, "--{}--\r\n", self.boundary)?;
        Ok(self.inner)
    }
}

fn mime_filename(path: &Path) -> (Mime, Option<&str>) {
    let content_type = ::mime_guess::guess_mime_type(path);
    let filename = opt_filename(path);
    (content_type, filename)
}

fn opt_filename(path: &Path) -> Option<&str> {
    path.file_name().and_then(|filename| filename.to_str())
}
<commit_msg>client: add note about trailing CRLF<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! The client-side abstraction for multipart requests. Enabled with the `client` feature.
//!
//! Use this when sending POST requests with files to a server.
use mime::Mime;

use std::borrow::Cow;
use std::fs::File;
use std::io;
use std::io::prelude::*;

use std::path::Path;

#[cfg(feature = "hyper")]
pub mod hyper;

pub mod lazy;

mod sized;

pub use self::sized::SizedRequest;

const BOUNDARY_LEN: usize = 16;

macro_rules! map_self {
    ($selff:expr, $try:expr) => (
        match $try {
            Ok(_) => Ok($selff),
            Err(err) => Err(err.into()),
        }
    )
}

/// The entry point of the client-side multipart API.
///
/// Though they perform I/O, the `.write_*()` methods do not return `io::Result<_>` in order to
/// facilitate method chaining. Upon the first error, all subsequent API calls will be no-ops until
/// `.send()` is called, at which point the error will be reported.
pub struct Multipart<S> {
    writer: MultipartWriter<'static, S>,
}

impl Multipart<()> {
    /// Create a new `Multipart` to wrap a request.
    ///
    /// ## Returns Error
    /// If `req.open_stream()` returns an error.
    pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Stream>, R::Error> {
        let (boundary, stream) = open_stream(req, None)?;

        Ok(Multipart {
            writer: MultipartWriter::new(stream, boundary),
        })
    }
}

impl<S: HttpStream> Multipart<S> {
    /// Write a text field to this multipart request.
    /// `name` and `val` can be either owned `String` or `&str`.
    ///
    /// ## Errors
    /// If something went wrong with the HTTP stream.
    pub fn write_text<N: AsRef<str>, V: AsRef<str>>(&mut self, name: N, val: V) -> Result<&mut Self, S::Error> {
        map_self!(self, self.writer.write_text(name.as_ref(), val.as_ref()))
    }

    /// Open a file pointed to by `path` and write its contents to the multipart request,
    /// supplying its filename and guessing its `Content-Type` from its extension.
    ///
    /// If you want to set these values manually, or use another type that implements `Read`,
    /// use `.write_stream()`.
    ///
    /// `name` can be either `String` or `&str`, and `path` can be `PathBuf` or `&Path`.
    ///
    /// ## Errors
    /// If there was a problem opening the file (was a directory or didn't exist),
    /// or if something went wrong with the HTTP stream.
    pub fn write_file<N: AsRef<str>, P: AsRef<Path>>(&mut self, name: N, path: P) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();
        let path = path.as_ref();

        map_self!(self, self.writer.write_file(name, path))
    }

    /// Write a byte stream to the multipart request as a file field, supplying `filename` if given,
    /// and `content_type` if given or `"application/octet-stream"` if not.
    ///
    /// `name` can be either `String` or `&str`, and `read` can take the `Read` by-value or
    /// with an `&mut` borrow.
    ///
    /// ## Warning
    /// The given `Read` **must** be able to read to EOF (end of file/no more data), meaning
    /// `Read::read()` returns `Ok(0)`. If it never returns EOF it will be read to infinity
    /// and the request will never be completed.
    ///
    /// When using `SizedRequest` this also can cause out-of-control memory usage as the
    /// multipart data has to be written to an in-memory buffer so its size can be calculated.
    ///
    /// Use `Read::take()` if you wish to send data from a `Read`
    /// that will never return EOF otherwise.
    ///
    /// ## Errors
    /// If the reader returned an error, or if something went wrong with the HTTP stream.
    // RFC: How to format this declaration?
    pub fn write_stream<N: AsRef<str>, St: Read>(
        &mut self, name: N, stream: &mut St, filename: Option<&str>, content_type: Option<Mime>
    ) -> Result<&mut Self, S::Error> {
        let name = name.as_ref();

        map_self!(self, self.writer.write_stream(stream, name, filename, content_type))
    }

    /// Finalize the request and return the response from the server, or the last error if set.
    pub fn send(self) -> Result<S::Response, S::Error> {
        self.writer.finish().map_err(io::Error::into).and_then(|body| body.finish())
    }
}

impl<R: HttpRequest> Multipart<SizedRequest<R>>
where <R::Stream as HttpStream>::Error: From<R::Error> {
    /// Create a new `Multipart` using the `SizedRequest` wrapper around `req`.
    pub fn from_request_sized(req: R) -> Result<Self, R::Error> {
        Multipart::from_request(SizedRequest::from_request(req))
    }
}

/// A trait describing an HTTP request that can be used to send multipart data.
pub trait HttpRequest {
    /// The HTTP stream type that can be opend by this request, to which the multipart data will be
    /// written.
    type Stream: HttpStream;
    /// The error type for this request.
    /// Must be compatible with `io::Error` as well as `Self::HttpStream::Error`
    type Error: From<io::Error> + Into<<Self::Stream as HttpStream>::Error>;

    /// Set the `Content-Type` header to `multipart/form-data` and supply the `boundary` value.
    /// If `content_len` is given, set the `Content-Length` header to its value.
    ///
    /// Return `true` if any and all sanity checks passed and the stream is ready to be opened,
    /// or `false` otherwise.
    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool;

    /// Open the request stream and return it or any error otherwise.
    fn open_stream(self) -> Result<Self::Stream, Self::Error>;
}

/// A trait describing an open HTTP stream that can be written to.
pub trait HttpStream: Write {
    /// The request type that opened this stream.
    type Request: HttpRequest;
    /// The response type that will be returned after the request is completed.
    type Response;
    /// The error type for this stream.
    /// Must be compatible with `io::Error` as well as `Self::Request::Error`.
    type Error: From<io::Error> + From<<Self::Request as HttpRequest>::Error>;

    /// Finalize and close the stream and return the response object, or any error otherwise.
    fn finish(self) -> Result<Self::Response, Self::Error>;
}

impl HttpRequest for () {
    type Stream = io::Sink;
    type Error = io::Error;

    fn apply_headers(&mut self, _: &str, _: Option<u64>) -> bool { true }
    fn open_stream(self) -> Result<Self::Stream, Self::Error> { Ok(io::sink()) }
}

impl HttpStream for io::Sink {
    type Request = ();
    type Response = ();
    type Error = io::Error;

    fn finish(self) -> Result<Self::Response, Self::Error> { Ok(()) }
}

fn gen_boundary() -> String {
    ::random_alphanumeric(BOUNDARY_LEN)
}

fn open_stream<R: HttpRequest>(mut req: R, content_len: Option<u64>) -> Result<(String, R::Stream), R::Error> {
    let boundary = gen_boundary();
    req.apply_headers(&boundary, content_len);
    req.open_stream().map(|stream| (boundary, stream))
}

struct MultipartWriter<'a, W> {
    inner: W,
    boundary: Cow<'a, str>,
    data_written: bool,
}

impl<'a, W: Write> MultipartWriter<'a, W> {
    fn new<B: Into<Cow<'a, str>>>(inner: W, boundary: B) -> Self {
        MultipartWriter {
            inner,
            boundary: boundary.into(),
            data_written: false,
        }
    }

    fn write_boundary(&mut self) -> io::Result<()> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        write!(self.inner, "--{}\r\n", self.boundary)
    }

    fn write_text(&mut self, name: &str, text: &str) -> io::Result<()> {
        chain_result! {
            self.write_field_headers(name, None, None),
            self.inner.write_all(text.as_bytes())
        }
    }

    fn write_file(&mut self, name: &str, path: &Path) -> io::Result<()> {
        let (content_type, filename) = mime_filename(path);
        let mut file = File::open(path)?;
        self.write_stream(&mut file, name, filename, Some(content_type))
    }

    fn write_stream<S: Read>(&mut self, stream: &mut S, name: &str, filename: Option<&str>, content_type: Option<Mime>) -> io::Result<()> {
        // This is necessary to make sure it is interpreted as a file on the server end.
        let content_type = Some(content_type.unwrap_or_else(::mime_guess::octet_stream));

        chain_result! {
            self.write_field_headers(name, filename, content_type),
            io::copy(stream, &mut self.inner),
            Ok(())
        }
    }

    fn write_field_headers(&mut self, name: &str, filename: Option<&str>, content_type: Option<Mime>)
    -> io::Result<()> {
        chain_result! {
            // Write the first boundary, or the boundary for the previous field.
            self.write_boundary(),
            { self.data_written = true; Ok(()) },
            write!(self.inner, "Content-Disposition: form-data; name=\"{}\"", name),
            filename.map(|filename| write!(self.inner, "; filename=\"{}\"", filename))
                .unwrap_or(Ok(())),
            content_type.map(|content_type| write!(self.inner, "\r\nContent-Type: {}", content_type))
                .unwrap_or(Ok(())),
            self.inner.write_all(b"\r\n\r\n")
        }
    }

    fn finish(mut self) -> io::Result<W> {
        if self.data_written {
            self.inner.write_all(b"\r\n")?;
        }

        // always write the closing boundary, even for empty bodies
        // trailing CRLF is optional but Actix requires it due to a naive implementation:
        // https://github.com/actix/actix-web/issues/598
        write!(self.inner, "--{}--\r\n", self.boundary)?;
        Ok(self.inner)
    }
}

fn mime_filename(path: &Path) -> (Mime, Option<&str>) {
    let content_type = ::mime_guess::guess_mime_type(path);
    let filename = opt_filename(path);
    (content_type, filename)
}

fn opt_filename(path: &Path) -> Option<&str> {
    path.file_name().and_then(|filename| filename.to_str())
}
<|endoftext|>


<commit_before>//!  Decoding of DDS images
//!
//!  DDS (DirectDraw Surface) is a container format for storing DXT (S3TC) compressed images.
//!
//!  # Related Links
//!  * <https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide> - Description of the DDS format.

use std::io::Read;
use std::{error, fmt};

use bytemuck::bytes_of;
use byteorder::{LittleEndian, ReadBytesExt};

#[allow(deprecated)]
use crate::codecs::dxt::{DxtDecoder, DxtReader, DxtVariant};
use crate::color::ColorType;
use crate::error::{
    DecodingError, ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageFormat};

/// Errors that can occur during decoding and parsing a DDS image
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum DecoderError {
    /// Wrong DDS channel width
    PixelFormatSizeInvalid(u32),
    /// Wrong DDS header size
    HeaderSizeInvalid(u32),
    /// Wrong DDS header flags
    HeaderFlagsInvalid(u32),

    /// DDS "DDS " signature invalid or missing
    DdsSignatureInvalid,
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DecoderError::PixelFormatSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS PixelFormat size: {}", s))
            }
            DecoderError::HeaderSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS header size: {}", s))
            }
            DecoderError::HeaderFlagsInvalid(fs) => {
                f.write_fmt(format_args!("Invalid DDS header flags: {:#010X}", fs))
            }
            DecoderError::DdsSignatureInvalid => f.write_str("DDS signature not found"),
        }
    }
}

impl From<DecoderError> for ImageError {
    fn from(e: DecoderError) -> ImageError {
        ImageError::Decoding(DecodingError::new(ImageFormat::Dds.into(), e))
    }
}

impl error::Error for DecoderError {}

/// Header used by DDS image files
#[derive(Debug)]
struct Header {
    flags: u32,
    height: u32,
    width: u32,
    pitch_or_linear_size: u32,
    depth: u32,
    mipmap_count: u32,
    pixel_format: PixelFormat,
    caps: u32,
    caps2: u32,
}

/// DDS pixel format
#[derive(Debug)]
struct PixelFormat {
    flags: u32,
    fourcc: [u8; 4],
    rgb_bit_count: u32,
    r_bit_mask: u32,
    g_bit_mask: u32,
    b_bit_mask: u32,
    a_bit_mask: u32,
}

impl PixelFormat {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 32 {
            return Err(DecoderError::PixelFormatSizeInvalid(size).into());
        }

        Ok(Self {
            flags: r.read_u32::<LittleEndian>()?,
            fourcc: {
                let mut v = [0; 4];
                r.read_exact(&mut v)?;
                v
            },
            rgb_bit_count: r.read_u32::<LittleEndian>()?,
            r_bit_mask: r.read_u32::<LittleEndian>()?,
            g_bit_mask: r.read_u32::<LittleEndian>()?,
            b_bit_mask: r.read_u32::<LittleEndian>()?,
            a_bit_mask: r.read_u32::<LittleEndian>()?,
        })
    }
}

impl Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 124 {
            return Err(DecoderError::HeaderSizeInvalid(size).into());
        }

        const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
        const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x800000;
        let flags = r.read_u32::<LittleEndian>()?;
        if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
            return Err(DecoderError::HeaderFlagsInvalid(flags).into());
        }

        let height = r.read_u32::<LittleEndian>()?;
        let width = r.read_u32::<LittleEndian>()?;
        let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
        let depth = r.read_u32::<LittleEndian>()?;
        let mipmap_count = r.read_u32::<LittleEndian>()?;
        // Skip `dwReserved1`
        {
            let mut skipped = [0; 4 * 11];
            r.read_exact(&mut skipped)?;
        }
        let pixel_format = PixelFormat::from_reader(r)?;
        let caps = r.read_u32::<LittleEndian>()?;
        let caps2 = r.read_u32::<LittleEndian>()?;
        // Skip `dwCaps3`, `dwCaps4`, `dwReserved2` (unused)
        {
            let mut skipped = [0; 4 + 4 + 4];
            r.read_exact(&mut skipped)?;
        }

        Ok(Self {
            flags,
            height,
            width,
            pitch_or_linear_size,
            depth,
            mipmap_count,
            pixel_format,
            caps,
            caps2,
        })
    }
}

/// The representation of a DDS decoder
pub struct DdsDecoder<R: Read> {
    #[allow(deprecated)]
    inner: DxtDecoder<R>,
}

impl<R: Read> DdsDecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(mut r: R) -> ImageResult<Self> {
        let mut magic = [0; 4];
        r.read_exact(&mut magic)?;
        if magic != b"DDS "[..] {
            return Err(DecoderError::DdsSignatureInvalid.into());
        }

        let header = Header::from_reader(&mut r)?;

        if header.pixel_format.flags & 0x4 != 0 {
            #[allow(deprecated)]
            let variant = match &header.pixel_format.fourcc {
                b"DXT1" => DxtVariant::DXT1,
                b"DXT3" => DxtVariant::DXT3,
                b"DXT5" => DxtVariant::DXT5,
                fourcc => {
                    return Err(ImageError::Unsupported(
                        UnsupportedError::from_format_and_kind(
                            ImageFormat::Dds.into(),
                            UnsupportedErrorKind::GenericFeature(format!(
                                "DDS FourCC {:?}",
                                fourcc
                            )),
                        ),
                    ))
                }
            };

            #[allow(deprecated)]
            let bytes_per_pixel = variant.color_type().bytes_per_pixel();

            if crate::utils::check_dimension_overflow(
                header.width,
                header.height,
                bytes_per_pixel,
            ) {
                return Err(ImageError::Unsupported(
                    UnsupportedError::from_format_and_kind(
                        ImageFormat::Dds.into(),
                        UnsupportedErrorKind::GenericFeature(format!(
                            "Image dimensions ({}x{}) are too large",
                            header.width, header.height
                        )),
                    ),
                ));
            }

            #[allow(deprecated)]
            let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
            Ok(Self { inner })
        } else {
            // For now, supports only DXT variants
            Err(ImageError::Unsupported(
                UnsupportedError::from_format_and_kind(
                    ImageFormat::Dds.into(),
                    UnsupportedErrorKind::Format(ImageFormatHint::Name("DDS".to_string())),
                ),
            ))
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for DdsDecoder<R> {
    #[allow(deprecated)]
    type Reader = DxtReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.inner.dimensions()
    }

    fn color_type(&self) -> ColorType {
        self.inner.color_type()
    }

    fn scanline_bytes(&self) -> u64 {
        self.inner.scanline_bytes()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        self.inner.into_reader()
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        self.inner.read_image(buf)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn dimension_overflow() {
        // A DXT1 header set to 0xFFFF_FFFC width and height (the highest u32%4 == 0)
        let header = vec![
            0x44, 0x44, 0x53, 0x20, 0x7C, 0x0, 0x0, 0x0, 0x7, 0x10, 0x8, 0x0, 0xFC, 0xFF, 0xFF,
            0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x0, 0xC0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
            0x0, 0x49, 0x4D, 0x41, 0x47, 0x45, 0x4D, 0x41, 0x47, 0x49, 0x43, 0x4B, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
            0x4, 0x0, 0x0, 0x0, 0x44, 0x58, 0x54, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        ];

        assert!(DdsDecoder::new(&header[..]).is_err());
    }
}
<commit_msg>Fix formatting and unused warning<commit_after>//!  Decoding of DDS images
//!
//!  DDS (DirectDraw Surface) is a container format for storing DXT (S3TC) compressed images.
//!
//!  # Related Links
//!  * <https://docs.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide> - Description of the DDS format.

use std::io::Read;
use std::{error, fmt};

use byteorder::{LittleEndian, ReadBytesExt};

#[allow(deprecated)]
use crate::codecs::dxt::{DxtDecoder, DxtReader, DxtVariant};
use crate::color::ColorType;
use crate::error::{
    DecodingError, ImageError, ImageFormatHint, ImageResult, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageFormat};

/// Errors that can occur during decoding and parsing a DDS image
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum DecoderError {
    /// Wrong DDS channel width
    PixelFormatSizeInvalid(u32),
    /// Wrong DDS header size
    HeaderSizeInvalid(u32),
    /// Wrong DDS header flags
    HeaderFlagsInvalid(u32),

    /// DDS "DDS " signature invalid or missing
    DdsSignatureInvalid,
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DecoderError::PixelFormatSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS PixelFormat size: {}", s))
            }
            DecoderError::HeaderSizeInvalid(s) => {
                f.write_fmt(format_args!("Invalid DDS header size: {}", s))
            }
            DecoderError::HeaderFlagsInvalid(fs) => {
                f.write_fmt(format_args!("Invalid DDS header flags: {:#010X}", fs))
            }
            DecoderError::DdsSignatureInvalid => f.write_str("DDS signature not found"),
        }
    }
}

impl From<DecoderError> for ImageError {
    fn from(e: DecoderError) -> ImageError {
        ImageError::Decoding(DecodingError::new(ImageFormat::Dds.into(), e))
    }
}

impl error::Error for DecoderError {}

/// Header used by DDS image files
#[derive(Debug)]
struct Header {
    flags: u32,
    height: u32,
    width: u32,
    pitch_or_linear_size: u32,
    depth: u32,
    mipmap_count: u32,
    pixel_format: PixelFormat,
    caps: u32,
    caps2: u32,
}

/// DDS pixel format
#[derive(Debug)]
struct PixelFormat {
    flags: u32,
    fourcc: [u8; 4],
    rgb_bit_count: u32,
    r_bit_mask: u32,
    g_bit_mask: u32,
    b_bit_mask: u32,
    a_bit_mask: u32,
}

impl PixelFormat {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 32 {
            return Err(DecoderError::PixelFormatSizeInvalid(size).into());
        }

        Ok(Self {
            flags: r.read_u32::<LittleEndian>()?,
            fourcc: {
                let mut v = [0; 4];
                r.read_exact(&mut v)?;
                v
            },
            rgb_bit_count: r.read_u32::<LittleEndian>()?,
            r_bit_mask: r.read_u32::<LittleEndian>()?,
            g_bit_mask: r.read_u32::<LittleEndian>()?,
            b_bit_mask: r.read_u32::<LittleEndian>()?,
            a_bit_mask: r.read_u32::<LittleEndian>()?,
        })
    }
}

impl Header {
    fn from_reader(r: &mut dyn Read) -> ImageResult<Self> {
        let size = r.read_u32::<LittleEndian>()?;
        if size != 124 {
            return Err(DecoderError::HeaderSizeInvalid(size).into());
        }

        const REQUIRED_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x1000;
        const VALID_FLAGS: u32 = 0x1 | 0x2 | 0x4 | 0x8 | 0x1000 | 0x20000 | 0x80000 | 0x800000;
        let flags = r.read_u32::<LittleEndian>()?;
        if flags & (REQUIRED_FLAGS | !VALID_FLAGS) != REQUIRED_FLAGS {
            return Err(DecoderError::HeaderFlagsInvalid(flags).into());
        }

        let height = r.read_u32::<LittleEndian>()?;
        let width = r.read_u32::<LittleEndian>()?;
        let pitch_or_linear_size = r.read_u32::<LittleEndian>()?;
        let depth = r.read_u32::<LittleEndian>()?;
        let mipmap_count = r.read_u32::<LittleEndian>()?;
        // Skip `dwReserved1`
        {
            let mut skipped = [0; 4 * 11];
            r.read_exact(&mut skipped)?;
        }
        let pixel_format = PixelFormat::from_reader(r)?;
        let caps = r.read_u32::<LittleEndian>()?;
        let caps2 = r.read_u32::<LittleEndian>()?;
        // Skip `dwCaps3`, `dwCaps4`, `dwReserved2` (unused)
        {
            let mut skipped = [0; 4 + 4 + 4];
            r.read_exact(&mut skipped)?;
        }

        Ok(Self {
            flags,
            height,
            width,
            pitch_or_linear_size,
            depth,
            mipmap_count,
            pixel_format,
            caps,
            caps2,
        })
    }
}

/// The representation of a DDS decoder
pub struct DdsDecoder<R: Read> {
    #[allow(deprecated)]
    inner: DxtDecoder<R>,
}

impl<R: Read> DdsDecoder<R> {
    /// Create a new decoder that decodes from the stream `r`
    pub fn new(mut r: R) -> ImageResult<Self> {
        let mut magic = [0; 4];
        r.read_exact(&mut magic)?;
        if magic != b"DDS "[..] {
            return Err(DecoderError::DdsSignatureInvalid.into());
        }

        let header = Header::from_reader(&mut r)?;

        if header.pixel_format.flags & 0x4 != 0 {
            #[allow(deprecated)]
            let variant = match &header.pixel_format.fourcc {
                b"DXT1" => DxtVariant::DXT1,
                b"DXT3" => DxtVariant::DXT3,
                b"DXT5" => DxtVariant::DXT5,
                fourcc => {
                    return Err(ImageError::Unsupported(
                        UnsupportedError::from_format_and_kind(
                            ImageFormat::Dds.into(),
                            UnsupportedErrorKind::GenericFeature(format!(
                                "DDS FourCC {:?}",
                                fourcc
                            )),
                        ),
                    ))
                }
            };

            #[allow(deprecated)]
            let bytes_per_pixel = variant.color_type().bytes_per_pixel();

            if crate::utils::check_dimension_overflow(header.width, header.height, bytes_per_pixel)
            {
                return Err(ImageError::Unsupported(
                    UnsupportedError::from_format_and_kind(
                        ImageFormat::Dds.into(),
                        UnsupportedErrorKind::GenericFeature(format!(
                            "Image dimensions ({}x{}) are too large",
                            header.width, header.height
                        )),
                    ),
                ));
            }

            #[allow(deprecated)]
            let inner = DxtDecoder::new(r, header.width, header.height, variant)?;
            Ok(Self { inner })
        } else {
            // For now, supports only DXT variants
            Err(ImageError::Unsupported(
                UnsupportedError::from_format_and_kind(
                    ImageFormat::Dds.into(),
                    UnsupportedErrorKind::Format(ImageFormatHint::Name("DDS".to_string())),
                ),
            ))
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for DdsDecoder<R> {
    #[allow(deprecated)]
    type Reader = DxtReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.inner.dimensions()
    }

    fn color_type(&self) -> ColorType {
        self.inner.color_type()
    }

    fn scanline_bytes(&self) -> u64 {
        self.inner.scanline_bytes()
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        self.inner.into_reader()
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        self.inner.read_image(buf)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn dimension_overflow() {
        // A DXT1 header set to 0xFFFF_FFFC width and height (the highest u32%4 == 0)
        let header = vec![
            0x44, 0x44, 0x53, 0x20, 0x7C, 0x0, 0x0, 0x0, 0x7, 0x10, 0x8, 0x0, 0xFC, 0xFF, 0xFF,
            0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x0, 0xC0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0,
            0x0, 0x49, 0x4D, 0x41, 0x47, 0x45, 0x4D, 0x41, 0x47, 0x49, 0x43, 0x4B, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
            0x4, 0x0, 0x0, 0x0, 0x44, 0x58, 0x54, 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        ];

        assert!(DdsDecoder::new(&header[..]).is_err());
    }
}
<|endoftext|>