<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut visitCount: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {

        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            //Gets the contents of the 2nd /, so as to check if it is an empty path or not.
            let splitArray: ~[&str] = request_str.split(' ').collect();
            let path = splitArray[1].slice_from(1).to_owned();
            let testVal = ~"/";
            //println!("{}", path);

            println(format!("Received request :\n{:s}", request_str));

            //println!("{}", std::str::eq(&path, &testVal));

            if (std::str::eq(&path, &testVal)) {
                let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
                stream.write(response.as_bytes());
            }
            else {
                let filePath = Path::new(path);
                let mut msg_file = File::open(&filePath);
                let msg_bytes: ~[u8] = msg_file.read_to_end();
                stream.write(msg_bytes);
            };
            println!("Connection terminates.");
            unsafe {
                visitCount = visitCount + 1;
                println!("This page has been called {} time(s).", visitCount);
            }
        }
    }
}
<commit_msg>Commit with zhttpto.rs 98% complete. All that is left to do is to prevent directorys other than where the server started.<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;
static mut visitCount: int = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {

        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            //Gets the contents of the 2nd /, so as to check if it is an empty path or not.
            let splitArray: ~[&str] = request_str.split(' ').collect();
            let path = splitArray[1].slice_from(1).to_owned();
            let testVal = ~"";
            println!("{}", path);

            //Obtain, potentially, the last four characters in the string to check if they are html
            let borrowedPath = path.clone();
            let size = path.len();
            let HTMLTestVal = ~"html";
            let mut isHTML = ~"N/A";
            if(size > 4) {
               isHTML = borrowedPath.slice_from(size-4).to_owned();
            };

            println(format!("Received request :\n{:s}", request_str));

            if (std::str::eq(&path, &testVal)) {
                let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
                stream.write(response.as_bytes());
            }
            else if(std::str::eq(&isHTML, &HTMLTestVal)) {
                let filePath = Path::new(path);
                let mut msg_file = File::open(&filePath);
                let msg_bytes: ~[u8] = msg_file.read_to_end();
                stream.write(msg_bytes);
            }
            else {
                let response: ~str =
                format!("HTTP/1.1 403 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>403 Forbidden</title>

 Forbidden

 You don't have permission to access /{:s}

                 \r\n", path);
                stream.write(response.as_bytes());
            };
            println!("Connection terminates.");
            unsafe {
                visitCount = visitCount + 1;
                println!("This page has been called {} time(s).", visitCount);
            }
        }
    }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, ReadBytesExt};
use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Seek, SeekFrom};
use std::marker::PhantomData;
use std::{error, fmt, mem};

use crate::color::ColorType;
use crate::error::{DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind};
use crate::image::{self, ImageDecoder, ImageFormat};

use self::InnerDecoder::*;
use crate::bmp::BmpDecoder;
use crate::png::PngDecoder;

// http://www.w3.org/TR/PNG-Structure.html
// The first eight bytes of a PNG file always contain the following (decimal) values:
const PNG_SIGNATURE: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];

/// Errors that can occur during decoding and parsing an ICO image or one of its enclosed images.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum DecoderError {
    /// The ICO directory is empty
    NoEntries,
    /// The number of color planes (0 or 1), or the horizontal coordinate of the hotspot for CUR files too big.
    IcoEntryTooManyPlanesOrHotspot,
    /// The bit depth (may be 0 meaning unspecified), or the vertical coordinate of the hotspot for CUR files too big.
    IcoEntryTooManyBitsPerPixelOrHotspot,

    /// The entry is in PNG format and specified a length that is shorter than PNG header.
    PngShorterThanHeader,
    /// The enclosed PNG is not in RGBA, which is invalid: https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473/.
    PngNotRgba,

    /// The optional mask row, containing 1 bit per pixel, padded to 4 bytes, was too short for this image.
    BmpIcoMaskTooShortForImage,

    /// The dimensions specified by the entry does not match the dimensions in the header of the enclosed image.
    ImageEntryDimensionMismatch {
        /// The mismatched subimage's type
        format: IcoEntryImageFormat,
        /// The dimensions specified by the entry
        entry: (u16, u16),
        /// The dimensions of the image itself
        image: (u32, u32)
    },
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DecoderError::NoEntries =>
                f.write_str("ICO directory contains no image"),
            DecoderError::IcoEntryTooManyPlanesOrHotspot =>
                f.write_str("ICO image entry has too many color planes or too large hotspot value"),
            DecoderError::IcoEntryTooManyBitsPerPixelOrHotspot =>
                f.write_str("ICO image entry has too many bits per pixel or too large hotspot value"),
            DecoderError::PngShorterThanHeader =>
                f.write_str("Entry specified a length that is shorter than PNG header!"),
            DecoderError::PngNotRgba =>
                f.write_str("The PNG is not in RGBA format!"),
            DecoderError::BmpIcoMaskTooShortForImage =>
                f.write_str("ICO mask too short for the image"),
            DecoderError::ImageEntryDimensionMismatch { format, entry, image } =>
                f.write_fmt(format_args!("Entry{:?} and {}{:?} dimensions do not match!", entry, format, image)),
        }
    }
}

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

impl error::Error for DecoderError {}

/// The image formats an ICO may contain
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum IcoEntryImageFormat {
    /// PNG in ARGB
    Png,
    /// BMP with optional alpha mask
    Bmp,
}

impl fmt::Display for IcoEntryImageFormat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(match self {
            IcoEntryImageFormat::Png => "PNG",
            IcoEntryImageFormat::Bmp => "BMP",
        })
    }
}

impl Into<ImageFormat> for IcoEntryImageFormat {
    fn into(self) -> ImageFormat {
        match self {
            IcoEntryImageFormat::Png => ImageFormat::Png,
            IcoEntryImageFormat::Bmp => ImageFormat::Bmp,
        }
    }
}

/// An ico decoder
pub struct IcoDecoder<R: Read> {
    selected_entry: DirEntry,
    inner_decoder: InnerDecoder<R>,
}

enum InnerDecoder<R: Read> {
    BMP(BmpDecoder<R>),
    PNG(PngDecoder<R>),
}

#[derive(Clone, Copy, Default)]
struct DirEntry {
    width: u8,
    height: u8,
    color_count: u8,
    reserved: u8,

    num_color_planes: u16,
    bits_per_pixel: u16,

    image_length: u32,
    image_offset: u32,
}

impl<R: Read + Seek> IcoDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(mut r: R) -> ImageResult<IcoDecoder<R>> {
        let entries = read_entries(&mut r)?;
        let entry = best_entry(entries)?;
        let decoder = entry.decoder(r)?;

        Ok(IcoDecoder {
            selected_entry: entry,
            inner_decoder: decoder,
        })
    }
}

fn read_entries<R: Read>(r: &mut R) -> ImageResult<Vec<DirEntry>> {
    let _reserved = r.read_u16::<LittleEndian>()?;
    let _type = r.read_u16::<LittleEndian>()?;
    let count = r.read_u16::<LittleEndian>()?;
    (0..count).map(|_| read_entry(r)).collect()
}

fn read_entry<R: Read>(r: &mut R) -> ImageResult<DirEntry> {
    let mut entry = DirEntry::default();

    entry.width = r.read_u8()?;
    entry.height = r.read_u8()?;
    entry.color_count = r.read_u8()?;
    // Reserved value (not used)
    entry.reserved = r.read_u8()?;

    // This may be either the number of color planes (0 or 1), or the horizontal coordinate
    // of the hotspot for CUR files.
    entry.num_color_planes = r.read_u16::<LittleEndian>()?;
    if entry.num_color_planes > 256 {
        return Err(DecoderError::IcoEntryTooManyPlanesOrHotspot.into());
    }

    // This may be either the bit depth (may be 0 meaning unspecified),
    // or the vertical coordinate of the hotspot for CUR files.
    entry.bits_per_pixel = r.read_u16::<LittleEndian>()?;
    if entry.bits_per_pixel > 256 {
        return Err(DecoderError::IcoEntryTooManyBitsPerPixelOrHotspot.into());
    }

    entry.image_length = r.read_u32::<LittleEndian>()?;
    entry.image_offset = r.read_u32::<LittleEndian>()?;

    Ok(entry)
}

/// Find the entry with the highest (color depth, size).
fn best_entry(mut entries: Vec<DirEntry>) -> ImageResult<DirEntry> {
    let mut best = entries.pop().ok_or(DecoderError::NoEntries)?;

    let mut best_score = (
        best.bits_per_pixel,
        u32::from(best.real_width()) * u32::from(best.real_height()),
    );

    for entry in entries {
        let score = (
            entry.bits_per_pixel,
            u32::from(entry.real_width()) * u32::from(entry.real_height()),
        );
        if score > best_score {
            best = entry;
            best_score = score;
        }
    }
    Ok(best)
}

impl DirEntry {
    fn real_width(&self) -> u16 {
        match self.width {
            0 => 256,
            w => u16::from(w),
        }
    }

    fn real_height(&self) -> u16 {
        match self.height {
            0 => 256,
            h => u16::from(h),
        }
    }

    fn matches_dimensions(&self, width: u32, height: u32) -> bool {
        u32::from(self.real_width()) == width && u32::from(self.real_height()) == height
    }

    fn seek_to_start<R: Read + Seek>(&self, r: &mut R) -> ImageResult<()> {
        r.seek(SeekFrom::Start(u64::from(self.image_offset)))?;
        Ok(())
    }

    fn is_png<R: Read + Seek>(&self, r: &mut R) -> ImageResult<bool> {
        self.seek_to_start(r)?;

        // Read the first 8 bytes to sniff the image.
        let mut signature = [0u8; 8];
        r.read_exact(&mut signature)?;

        Ok(signature == PNG_SIGNATURE)
    }

    fn decoder<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
        let is_png = self.is_png(&mut r)?;
        self.seek_to_start(&mut r)?;

        if is_png {
            Ok(PNG(PngDecoder::new(r)?))
        } else {
            Ok(BMP(BmpDecoder::new_with_ico_format(r)?))
        }
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct IcoReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for IcoReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for IcoDecoder<R> {
    type Reader = IcoReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        match self.inner_decoder {
            BMP(ref decoder) => decoder.dimensions(),
            PNG(ref decoder) => decoder.dimensions(),
        }
    }

    fn color_type(&self) -> ColorType {
        match self.inner_decoder {
            BMP(ref decoder) => decoder.color_type(),
            PNG(ref decoder) => decoder.color_type(),
        }
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(IcoReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
        match self.inner_decoder {
            PNG(decoder) => {
                if self.selected_entry.image_length < PNG_SIGNATURE.len() as u32 {
                    return Err(DecoderError::PngShorterThanHeader.into());
                }

                // Check if the image dimensions match the ones in the image data.
                let (width, height) = decoder.dimensions();
                if !self.selected_entry.matches_dimensions(width, height) {
                    return Err(DecoderError::ImageEntryDimensionMismatch {
                        format: IcoEntryImageFormat::Png,
                        entry: (self.selected_entry.real_width(), self.selected_entry.real_height()),
                        image: (width, height)
                    }.into());
                }

                // Embedded PNG images can only be of the 32BPP RGBA format.
                // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473/
                if decoder.color_type() != ColorType::Rgba8 {
                    return Err(DecoderError::PngNotRgba.into());
                }

                decoder.read_image(buf)
            }
            BMP(mut decoder) => {
                let (width, height) = decoder.dimensions();
                if !self.selected_entry.matches_dimensions(width, height) {
                    return Err(DecoderError::ImageEntryDimensionMismatch {
                        format: IcoEntryImageFormat::Bmp,
                        entry: (self.selected_entry.real_width(), self.selected_entry.real_height()),
                        image: (width, height)
                    }.into());
                }

                // The ICO decoder needs an alpha channel to apply the AND mask.
                if decoder.color_type() != ColorType::Rgba8 {
                    return Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
                        ImageFormat::Bmp.into(),
                        UnsupportedErrorKind::Color(decoder.color_type().into()),
                    )));
                }

                decoder.read_image_data(buf)?;

                // If there's an AND mask following the image, read and apply it.
                let r = decoder.reader();
                let mask_start = r.seek(SeekFrom::Current(0))?;
                let mask_end =
                    u64::from(self.selected_entry.image_offset + self.selected_entry.image_length);

                if mask_end > mask_start {
                    // A mask row contains 1 bit per pixel, padded to 4 bytes.
                    let mask_row_bytes = ((width + 31) / 32) * 4;
                    let expected_length = u64::from(mask_row_bytes) * u64::from(height);

                    let actual_length = mask_end - mask_start;

                    if actual_length < expected_length {
                        return Err(DecoderError::BmpIcoMaskTooShortForImage.into());
                    }

                    for y in 0..height {
                        let mut x = 0;
                        for _ in 0..mask_row_bytes {
                            // Apply the bits of each byte until we reach the end of the row.
                            let mask_byte = r.read_u8()?;
                            for bit in (0..8).rev() {
                                if x >= width {
                                    break;
                                }
                                if mask_byte & (1 << bit) != 0 {
                                    // Set alpha channel to transparent.
                                    buf[((height - y - 1) * width + x) as usize * 4 + 3] = 0;
                                }
                                x += 1;
                            }
                        }
                    }
                }
                Ok(())
            }
        }
    }
}
<commit_msg>Add a comment and more precise check for ICO mask<commit_after>use byteorder::{LittleEndian, ReadBytesExt};
use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Seek, SeekFrom};
use std::marker::PhantomData;
use std::{error, fmt, mem};

use crate::color::ColorType;
use crate::error::{DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind};
use crate::image::{self, ImageDecoder, ImageFormat};

use self::InnerDecoder::*;
use crate::bmp::BmpDecoder;
use crate::png::PngDecoder;

// http://www.w3.org/TR/PNG-Structure.html
// The first eight bytes of a PNG file always contain the following (decimal) values:
const PNG_SIGNATURE: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];

/// Errors that can occur during decoding and parsing an ICO image or one of its enclosed images.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum DecoderError {
    /// The ICO directory is empty
    NoEntries,
    /// The number of color planes (0 or 1), or the horizontal coordinate of the hotspot for CUR files too big.
    IcoEntryTooManyPlanesOrHotspot,
    /// The bit depth (may be 0 meaning unspecified), or the vertical coordinate of the hotspot for CUR files too big.
    IcoEntryTooManyBitsPerPixelOrHotspot,

    /// The entry is in PNG format and specified a length that is shorter than PNG header.
    PngShorterThanHeader,
    /// The enclosed PNG is not in RGBA, which is invalid: https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473/.
    PngNotRgba,

    /// This could be replaced with some error about the image_length in the header, or potentially merged with ImageEntryDimensionMismatch
    #[allow(dead_code)]
    #[deprecated = "There is no encoding for the length of the mask or flat to indicate its presence, so this error was reporting a different error than it claimed"]
    BmpIcoMaskTooShortForImage,

    /// The dimensions specified by the entry does not match the dimensions in the header of the enclosed image.
    ImageEntryDimensionMismatch {
        /// The mismatched subimage's type
        format: IcoEntryImageFormat,
        /// The dimensions specified by the entry
        entry: (u16, u16),
        /// The dimensions of the image itself
        image: (u32, u32)
    },
}

impl fmt::Display for DecoderError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DecoderError::NoEntries =>
                f.write_str("ICO directory contains no image"),
            DecoderError::IcoEntryTooManyPlanesOrHotspot =>
                f.write_str("ICO image entry has too many color planes or too large hotspot value"),
            DecoderError::IcoEntryTooManyBitsPerPixelOrHotspot =>
                f.write_str("ICO image entry has too many bits per pixel or too large hotspot value"),
            DecoderError::PngShorterThanHeader =>
                f.write_str("Entry specified a length that is shorter than PNG header!"),
            DecoderError::PngNotRgba =>
                f.write_str("The PNG is not in RGBA format!"),
            #[allow(deprecated)]
            DecoderError::BmpIcoMaskTooShortForImage =>
                f.write_str("ICO mask too short for the image"),
            DecoderError::ImageEntryDimensionMismatch { format, entry, image } =>
                f.write_fmt(format_args!("Entry{:?} and {}{:?} dimensions do not match!", entry, format, image)),
        }
    }
}

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

impl error::Error for DecoderError {}

/// The image formats an ICO may contain
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum IcoEntryImageFormat {
    /// PNG in ARGB
    Png,
    /// BMP with optional alpha mask
    Bmp,
}

impl fmt::Display for IcoEntryImageFormat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(match self {
            IcoEntryImageFormat::Png => "PNG",
            IcoEntryImageFormat::Bmp => "BMP",
        })
    }
}

impl Into<ImageFormat> for IcoEntryImageFormat {
    fn into(self) -> ImageFormat {
        match self {
            IcoEntryImageFormat::Png => ImageFormat::Png,
            IcoEntryImageFormat::Bmp => ImageFormat::Bmp,
        }
    }
}

/// An ico decoder
pub struct IcoDecoder<R: Read> {
    selected_entry: DirEntry,
    inner_decoder: InnerDecoder<R>,
}

enum InnerDecoder<R: Read> {
    BMP(BmpDecoder<R>),
    PNG(PngDecoder<R>),
}

#[derive(Clone, Copy, Default)]
struct DirEntry {
    width: u8,
    height: u8,
    color_count: u8,
    reserved: u8,

    num_color_planes: u16,
    bits_per_pixel: u16,

    image_length: u32,
    image_offset: u32,
}

impl<R: Read + Seek> IcoDecoder<R> {
    /// Create a new decoder that decodes from the stream ```r```
    pub fn new(mut r: R) -> ImageResult<IcoDecoder<R>> {
        let entries = read_entries(&mut r)?;
        let entry = best_entry(entries)?;
        let decoder = entry.decoder(r)?;

        Ok(IcoDecoder {
            selected_entry: entry,
            inner_decoder: decoder,
        })
    }
}

fn read_entries<R: Read>(r: &mut R) -> ImageResult<Vec<DirEntry>> {
    let _reserved = r.read_u16::<LittleEndian>()?;
    let _type = r.read_u16::<LittleEndian>()?;
    let count = r.read_u16::<LittleEndian>()?;
    (0..count).map(|_| read_entry(r)).collect()
}

fn read_entry<R: Read>(r: &mut R) -> ImageResult<DirEntry> {
    let mut entry = DirEntry::default();

    entry.width = r.read_u8()?;
    entry.height = r.read_u8()?;
    entry.color_count = r.read_u8()?;
    // Reserved value (not used)
    entry.reserved = r.read_u8()?;

    // This may be either the number of color planes (0 or 1), or the horizontal coordinate
    // of the hotspot for CUR files.
    entry.num_color_planes = r.read_u16::<LittleEndian>()?;
    if entry.num_color_planes > 256 {
        return Err(DecoderError::IcoEntryTooManyPlanesOrHotspot.into());
    }

    // This may be either the bit depth (may be 0 meaning unspecified),
    // or the vertical coordinate of the hotspot for CUR files.
    entry.bits_per_pixel = r.read_u16::<LittleEndian>()?;
    if entry.bits_per_pixel > 256 {
        return Err(DecoderError::IcoEntryTooManyBitsPerPixelOrHotspot.into());
    }

    entry.image_length = r.read_u32::<LittleEndian>()?;
    entry.image_offset = r.read_u32::<LittleEndian>()?;

    Ok(entry)
}

/// Find the entry with the highest (color depth, size).
fn best_entry(mut entries: Vec<DirEntry>) -> ImageResult<DirEntry> {
    let mut best = entries.pop().ok_or(DecoderError::NoEntries)?;

    let mut best_score = (
        best.bits_per_pixel,
        u32::from(best.real_width()) * u32::from(best.real_height()),
    );

    for entry in entries {
        let score = (
            entry.bits_per_pixel,
            u32::from(entry.real_width()) * u32::from(entry.real_height()),
        );
        if score > best_score {
            best = entry;
            best_score = score;
        }
    }
    Ok(best)
}

impl DirEntry {
    fn real_width(&self) -> u16 {
        match self.width {
            0 => 256,
            w => u16::from(w),
        }
    }

    fn real_height(&self) -> u16 {
        match self.height {
            0 => 256,
            h => u16::from(h),
        }
    }

    fn matches_dimensions(&self, width: u32, height: u32) -> bool {
        u32::from(self.real_width()) == width && u32::from(self.real_height()) == height
    }

    fn seek_to_start<R: Read + Seek>(&self, r: &mut R) -> ImageResult<()> {
        r.seek(SeekFrom::Start(u64::from(self.image_offset)))?;
        Ok(())
    }

    fn is_png<R: Read + Seek>(&self, r: &mut R) -> ImageResult<bool> {
        self.seek_to_start(r)?;

        // Read the first 8 bytes to sniff the image.
        let mut signature = [0u8; 8];
        r.read_exact(&mut signature)?;

        Ok(signature == PNG_SIGNATURE)
    }

    fn decoder<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
        let is_png = self.is_png(&mut r)?;
        self.seek_to_start(&mut r)?;

        if is_png {
            Ok(PNG(PngDecoder::new(r)?))
        } else {
            Ok(BMP(BmpDecoder::new_with_ico_format(r)?))
        }
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct IcoReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for IcoReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for IcoDecoder<R> {
    type Reader = IcoReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        match self.inner_decoder {
            BMP(ref decoder) => decoder.dimensions(),
            PNG(ref decoder) => decoder.dimensions(),
        }
    }

    fn color_type(&self) -> ColorType {
        match self.inner_decoder {
            BMP(ref decoder) => decoder.color_type(),
            PNG(ref decoder) => decoder.color_type(),
        }
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(IcoReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
        match self.inner_decoder {
            PNG(decoder) => {
                if self.selected_entry.image_length < PNG_SIGNATURE.len() as u32 {
                    return Err(DecoderError::PngShorterThanHeader.into());
                }

                // Check if the image dimensions match the ones in the image data.
                let (width, height) = decoder.dimensions();
                if !self.selected_entry.matches_dimensions(width, height) {
                    return Err(DecoderError::ImageEntryDimensionMismatch {
                        format: IcoEntryImageFormat::Png,
                        entry: (self.selected_entry.real_width(), self.selected_entry.real_height()),
                        image: (width, height)
                    }.into());
                }

                // Embedded PNG images can only be of the 32BPP RGBA format.
                // https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473/
                if decoder.color_type() != ColorType::Rgba8 {
                    return Err(DecoderError::PngNotRgba.into());
                }

                decoder.read_image(buf)
            }
            BMP(mut decoder) => {
                let (width, height) = decoder.dimensions();
                if !self.selected_entry.matches_dimensions(width, height) {
                    return Err(DecoderError::ImageEntryDimensionMismatch {
                        format: IcoEntryImageFormat::Bmp,
                        entry: (self.selected_entry.real_width(), self.selected_entry.real_height()),
                        image: (width, height)
                    }.into());
                }

                // The ICO decoder needs an alpha channel to apply the AND mask.
                if decoder.color_type() != ColorType::Rgba8 {
                    return Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
                        ImageFormat::Bmp.into(),
                        UnsupportedErrorKind::Color(decoder.color_type().into()),
                    )));
                }

                decoder.read_image_data(buf)?;

                // If there's an AND mask following the image, read and apply it.
                let r = decoder.reader();
                let image_end = r.seek(SeekFrom::Current(0))?;
                let data_end =
                    u64::from(self.selected_entry.image_offset + self.selected_entry.image_length);

                // A mask row contains 1 bit per pixel, padded to 4 bytes.
                let mask_row_bytes = ((width + 31) / 32) * 4;
                let mask_length = u64::from(mask_row_bytes) * u64::from(height);

                // data_end should be either exactly mask_start + mask_length. or exactly mask_start.
                // Only attempt to parse the mask if it exactly matches the first case. This allows
                // leniant parsing of ico files with an incorrect image_length that don't match the
                // second case either.

                // Support for this leniency varies across other libraries, for example as of this
                // comment Firefox is strict about image_length while Chrome and GIMP are not.
                if data_end == image_end + mask_length {
                    for y in 0..height {
                        let mut x = 0;
                        for _ in 0..mask_row_bytes {
                            // Apply the bits of each byte until we reach the end of the row.
                            let mask_byte = r.read_u8()?;
                            for bit in (0..8).rev() {
                                if x >= width {
                                    break;
                                }
                                if mask_byte & (1 << bit) != 0 {
                                    // Set alpha channel to transparent.
                                    buf[((height - y - 1) * width + x) as usize * 4 + 3] = 0;
                                }
                                x += 1;
                            }
                        }
                    }
                }
                Ok(())
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[deny(missing_docs)]

extern crate gfx_core as core;
extern crate gfx_device_gl as device_gl;
extern crate glutin;

use core::{format, handle, texture};
use core::memory::Typed;
use device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example
///
/// ```no_run
/// extern crate gfx_core;
/// extern crate gfx_device_gl;
/// extern crate gfx_window_glutin;
/// extern crate glutin;
///
/// use gfx_core::format::{DepthStencil, Rgba8};
///
/// fn main() {
///     let builder = glutin::WindowBuilder::new().with_title("Example".to_string());
///     let (window, device, factory, rtv, stv) =
///         gfx_window_glutin::init::<Rgba8, DepthStencil>(builder);
///
///     // your code
/// }
/// ```
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Typed::new(color_view), Typed::new(ds_view))
}

/// Initialize with an existing Glutin window.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example (using Piston to create the window)
///
/// ```no_run
/// extern crate piston;
/// extern crate glutin_window;
/// extern crate gfx_window_glutin;
///
/// // Create window with Piston
/// let settings = piston::window::WindowSettings::new("Example", [800, 600]);
/// let mut glutin_window = glutin_window::GlutinWindow::new(&settings).unwrap();
///
/// // Initialise gfx
/// let (mut device, mut factory, main_color, main_depth) =
///     gfx_window_glutin::init_existing::<ColorFormat, DepthFormat>(&glutin_window.window);
///
/// let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
/// ```
pub fn init_existing<Cf, Df>(window: &glutin::Window) ->
            (device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (device, factory, color_view, ds_view) = init_existing_raw(window, Cf::get_format(), Df::get_format());
    (device, factory, Typed::new(color_view), Typed::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> texture::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as texture::NumSamples;
    ((width as f32 * window.hidpi_factor()) as texture::Size, (height as f32 * window.hidpi_factor()) as texture::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    let (device, factory, color_view, ds_view) = init_existing_raw(&window, color_format, ds_format);

    (window, device, factory, color_view, ds_view)
}

/// Initialize with an existing Glutin window. Raw version.
pub fn init_existing_raw(window: &glutin::Window,
                color_format: format::Format, ds_format: format::Format) ->
                (device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    unsafe { window.make_current().unwrap() };
    let (device, factory) = device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(window);
    let (color_view, ds_view) = device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);

    // done
    (device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Typed::new(cv);
        *ds_view = Typed::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: texture::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<commit_msg>Do not attempt to compile or run piston example due to missing dependency<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[deny(missing_docs)]

extern crate gfx_core as core;
extern crate gfx_device_gl as device_gl;
extern crate glutin;

use core::{format, handle, texture};
use core::memory::Typed;
use device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example
///
/// ```no_run
/// extern crate gfx_core;
/// extern crate gfx_device_gl;
/// extern crate gfx_window_glutin;
/// extern crate glutin;
///
/// use gfx_core::format::{DepthStencil, Rgba8};
///
/// fn main() {
///     let builder = glutin::WindowBuilder::new().with_title("Example".to_string());
///     let (window, device, factory, rtv, stv) =
///         gfx_window_glutin::init::<Rgba8, DepthStencil>(builder);
///
///     // your code
/// }
/// ```
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Typed::new(color_view), Typed::new(ds_view))
}

/// Initialize with an existing Glutin window.
/// Generically parametrized version over the main framebuffer format.
///
/// # Example (using Piston to create the window)
///
/// ```rust,ignore
/// extern crate piston;
/// extern crate glutin_window;
/// extern crate gfx_window_glutin;
///
/// // Create window with Piston
/// let settings = piston::window::WindowSettings::new("Example", [800, 600]);
/// let mut glutin_window = glutin_window::GlutinWindow::new(&settings).unwrap();
///
/// // Initialise gfx
/// let (mut device, mut factory, main_color, main_depth) =
///     gfx_window_glutin::init_existing::<ColorFormat, DepthFormat>(&glutin_window.window);
///
/// let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
/// ```
pub fn init_existing<Cf, Df>(window: &glutin::Window) ->
            (device_gl::Device, device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let (device, factory, color_view, ds_view) = init_existing_raw(window, Cf::get_format(), Df::get_format());
    (device, factory, Typed::new(color_view), Typed::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> texture::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as texture::NumSamples;
    ((width as f32 * window.hidpi_factor()) as texture::Size, (height as f32 * window.hidpi_factor()) as texture::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    let (device, factory, color_view, ds_view) = init_existing_raw(&window, color_format, ds_format);

    (window, device, factory, color_view, ds_view)
}

/// Initialize with an existing Glutin window. Raw version.
pub fn init_existing_raw(window: &glutin::Window,
                color_format: format::Format, ds_format: format::Format) ->
                (device_gl::Device, device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    unsafe { window.make_current().unwrap() };
    let (device, factory) = device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(window);
    let (color_view, ds_view) = device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);

    // done
    (device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Typed::new(cv);
        *ds_view = Typed::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: texture::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<|endoftext|>


<commit_before>//! Plugin which loads secrets from `config/secrets.yml` and adds them to a
//! project.

use docker_compose::v2 as dc;
use serde_yaml;
use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;

use plugins;
use plugins::transform::Operation;
use plugins::transform::{Plugin as TransformPlugin, PluginNew};
use project::Project;
use util::Error;

#[cfg(feature = "serde_macros")]
include!(concat!("secrets_config.in.rs"));
#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/plugins/transform/secrets_config.rs"));

/// Loads a `config/secrets.yml` file and merges in into a project.
#[derive(Debug)]
pub struct Plugin {
    /// Our `config/secrets.yml` YAML file, parsed and read into memory.
    config: Config,
}

impl Plugin {
    /// Get the path to this plugin's config file.
    fn config_path(project: &Project) -> PathBuf {
        project.root_dir().join("config/secrets.yml")
    }
}

impl TransformPlugin for Plugin {
    fn name(&self) -> &'static str {
        "secrets"
    }

    fn transform(&self,
                 _op: Operation,
                 ctx: &plugins::Context,
                 file: &mut dc::File)
                 -> Result<(), Error> {

        let append_container =
            |service: &mut dc::Service, pods: &BTreeMap<_, PodSecrets>, name| {
                let opt_env = pods.get(ctx.pod.name()).and_then(|p| p.get(name));
                if let Some(env) = opt_env {
                    service.environment.append(&mut env.clone());
                }
            };

        for (name, mut service) in &mut file.services {
            service.environment.append(&mut self.config.common.clone());
            append_container(&mut service, &self.config.pods, name);
            if let Some(ovr) = self.config.overrides.get(ctx.ovr.name()) {
                service.environment.append(&mut ovr.common.clone());
                append_container(&mut service, &ovr.pods, name);
            }
        }
        Ok(())
    }
}

impl PluginNew for Plugin {
    /// Should we enable this plugin for this project?
    fn should_enable_for(project: &Project) -> Result<bool, Error> {
        let path = Self::config_path(project);
        Ok(path.exists())
    }

    /// Create a new plugin.
    fn new(project: &Project) -> Result<Self, Error> {
        let f = try!(fs::File::open(&Self::config_path(project)));
        let config = try!(serde_yaml::from_reader(f));
        Ok(Plugin { config: config })
    }
}

#[test]
fn enabled_for_projects_with_config_file() {
    use env_logger;
    let _ = env_logger::init();
    let proj1 = Project::from_example("hello").unwrap();
    assert!(!Plugin::should_enable_for(&proj1).unwrap());
    let proj2 = Project::from_example("rails_hello").unwrap();
    assert!(Plugin::should_enable_for(&proj2).unwrap());
}

#[test]
fn injects_secrets_into_containers() {
    use env_logger;
    let _ = env_logger::init();
    let proj = Project::from_example("rails_hello").unwrap();
    let plugin = Plugin::new(&proj).unwrap();

    let ovr = proj.ovr("production").unwrap();
    let frontend = proj.pod("frontend").unwrap();
    let ctx = plugins::Context::new(&proj, ovr, frontend);
    let mut file = frontend.merged_file(ovr).unwrap();
    plugin.transform(Operation::Output, &ctx, &mut file).unwrap();
    let web = file.services.get("web").unwrap();
    assert_eq!(web.environment.get("GLOBAL_PASSWORD").expect("has GLOBAL_PASSWORD"),
               "more magic");
    assert_eq!(web.environment.get("SOME_PASSWORD").expect("has SOME_PASSWORD"),
               "production secret");
}
<commit_msg>secrets: Rename imported traits more consistently<commit_after>//! Plugin which loads secrets from `config/secrets.yml` and adds them to a
//! project.

use docker_compose::v2 as dc;
use serde_yaml;
use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;

use plugins;
use plugins::transform::Operation;
use plugins::transform::{Plugin as PluginTransform, PluginNew};
use project::Project;
use util::Error;

#[cfg(feature = "serde_macros")]
include!(concat!("secrets_config.in.rs"));
#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/plugins/transform/secrets_config.rs"));

/// Loads a `config/secrets.yml` file and merges in into a project.
#[derive(Debug)]
pub struct Plugin {
    /// Our `config/secrets.yml` YAML file, parsed and read into memory.
    config: Config,
}

impl Plugin {
    /// Get the path to this plugin's config file.
    fn config_path(project: &Project) -> PathBuf {
        project.root_dir().join("config/secrets.yml")
    }
}

impl PluginTransform for Plugin {
    fn name(&self) -> &'static str {
        "secrets"
    }

    fn transform(&self,
                 _op: Operation,
                 ctx: &plugins::Context,
                 file: &mut dc::File)
                 -> Result<(), Error> {

        let append_container =
            |service: &mut dc::Service, pods: &BTreeMap<_, PodSecrets>, name| {
                let opt_env = pods.get(ctx.pod.name()).and_then(|p| p.get(name));
                if let Some(env) = opt_env {
                    service.environment.append(&mut env.clone());
                }
            };

        for (name, mut service) in &mut file.services {
            service.environment.append(&mut self.config.common.clone());
            append_container(&mut service, &self.config.pods, name);
            if let Some(ovr) = self.config.overrides.get(ctx.ovr.name()) {
                service.environment.append(&mut ovr.common.clone());
                append_container(&mut service, &ovr.pods, name);
            }
        }
        Ok(())
    }
}

impl PluginNew for Plugin {
    /// Should we enable this plugin for this project?
    fn should_enable_for(project: &Project) -> Result<bool, Error> {
        let path = Self::config_path(project);
        Ok(path.exists())
    }

    /// Create a new plugin.
    fn new(project: &Project) -> Result<Self, Error> {
        let f = try!(fs::File::open(&Self::config_path(project)));
        let config = try!(serde_yaml::from_reader(f));
        Ok(Plugin { config: config })
    }
}

#[test]
fn enabled_for_projects_with_config_file() {
    use env_logger;
    let _ = env_logger::init();
    let proj1 = Project::from_example("hello").unwrap();
    assert!(!Plugin::should_enable_for(&proj1).unwrap());
    let proj2 = Project::from_example("rails_hello").unwrap();
    assert!(Plugin::should_enable_for(&proj2).unwrap());
}

#[test]
fn injects_secrets_into_containers() {
    use env_logger;
    let _ = env_logger::init();
    let proj = Project::from_example("rails_hello").unwrap();
    let plugin = Plugin::new(&proj).unwrap();

    let ovr = proj.ovr("production").unwrap();
    let frontend = proj.pod("frontend").unwrap();
    let ctx = plugins::Context::new(&proj, ovr, frontend);
    let mut file = frontend.merged_file(ovr).unwrap();
    plugin.transform(Operation::Output, &ctx, &mut file).unwrap();
    let web = file.services.get("web").unwrap();
    assert_eq!(web.environment.get("GLOBAL_PASSWORD").expect("has GLOBAL_PASSWORD"),
               "more magic");
    assert_eq!(web.environment.get("SOME_PASSWORD").expect("has SOME_PASSWORD"),
               "production secret");
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::{HashMap, HashSet};

use crate::{
    conversion::{
        analysis::{depth_first::depth_first, pod::PodAnalysis},
        api::{Api, CppVisibility, FuncToConvert, SpecialMemberKind},
    },
    types::QualifiedName,
};

use super::{
    implicit_constructor_rules::{
        determine_implicit_constructors, ExplicitItemsFound, ImplicitConstructorsNeeded,
    },
    FnAnalysis, FnKind, FnPhase, MethodKind, ReceiverMutability, TraitMethodKind,
};

#[derive(Hash, Eq, PartialEq)]
enum ExplicitKind {
    MoveConstructor,
    ConstCopyConstructor,
    NonConstCopyConstructor,
    OtherConstructor,
    Destructor,
    CopyAssignmentOperator,
    MoveAssignmentOperator,
    DeletedOrInaccessibleCopyConstructor,
    DeletedOrInaccessibleDestructor,
}

#[derive(Hash, Eq, PartialEq)]
struct ExplicitFound {
    ty: QualifiedName,
    kind: ExplicitKind,
}

/// If a type has explicit constructors, bindgen will generate corresponding
/// constructor functions, which we'll have already converted to make_unique methods.
/// For types with implicit constructors, we synthesize them here.
/// It is tempting to make this a separate analysis phase, to be run later than
/// the function analysis; but that would make the code much more complex as it
/// would need to output a `FnAnalysisBody`. By running it as part of this phase
/// we can simply generate the sort of thing bindgen generates, then ask
/// the existing code in this phase to figure out what to do with it.
pub(super) fn find_missing_constructors(
    apis: &[Api<FnPhase>],
) -> HashMap<QualifiedName, ImplicitConstructorsNeeded> {
    let explicits = find_explicit_items(apis);
    let mut implicit_constructors_needed = HashMap::new();
    for api in depth_first(apis) {
        if let Api::Struct {
            name,
            analysis: PodAnalysis {
                bases, field_types, ..
            },
            ..
        } = api
        {
            let name = &name.name;
            let find = |kind: ExplicitKind| -> bool {
                explicits.contains(&ExplicitFound {
                    ty: name.clone(),
                    kind,
                })
            };
            let any_bases_or_fields_lack_const_copy_constructors =
                bases.iter().chain(field_types.iter()).any(|qn| {
                    let has_explicit = explicits.contains(&ExplicitFound {
                        ty: qn.clone(),
                        kind: ExplicitKind::ConstCopyConstructor,
                    });
                    let has_implicit = implicit_constructors_needed
                        .get(qn)
                        .map(|imp: &ImplicitConstructorsNeeded| imp.copy_constructor_taking_const_t)
                        .unwrap_or_default();
                    !has_explicit && !has_implicit
                });
            let any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors =
                bases.iter().chain(field_types.iter()).any(|qn| {
                    explicits.contains(&ExplicitFound {
                        ty: qn.clone(),
                        kind: ExplicitKind::DeletedOrInaccessibleCopyConstructor,
                    })
                });
            let any_bases_have_deleted_or_inaccessible_destructors = bases.iter().any(|qn| {
                explicits.contains(&ExplicitFound {
                    ty: qn.clone(),
                    kind: ExplicitKind::DeletedOrInaccessibleDestructor,
                })
            });
            let explicit_items_found = ExplicitItemsFound {
                move_constructor: find(ExplicitKind::MoveConstructor),
                copy_constructor: find(ExplicitKind::ConstCopyConstructor)
                    || find(ExplicitKind::NonConstCopyConstructor),
                any_other_constructor: find(ExplicitKind::OtherConstructor),
                any_bases_or_fields_lack_const_copy_constructors,
                any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors,
                any_bases_have_deleted_or_inaccessible_destructors,
                destructor: find(ExplicitKind::Destructor),
                copy_assignment_operator: find(ExplicitKind::CopyAssignmentOperator),
                move_assignment_operator: find(ExplicitKind::MoveAssignmentOperator),
            };
            let implicits = determine_implicit_constructors(explicit_items_found);
            implicit_constructors_needed.insert(name.clone(), implicits);
        }
    }
    implicit_constructors_needed
}

fn find_explicit_items(apis: &[Api<FnPhase>]) -> HashSet<ExplicitFound> {
    apis.iter()
        .filter_map(|api| match api {
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind: FnKind::Method(self_ty, MethodKind::Constructor),
                        ..
                    },
                ..
            } => Some(ExplicitFound {
                ty: self_ty.clone(),
                kind: ExplicitKind::OtherConstructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::MoveConstructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                ..
            } => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::MoveConstructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::Destructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                fun,
                ..
            } if is_deleted_or_inaccessible(fun) => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::DeletedOrInaccessibleDestructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::Destructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                ..
            } => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::Destructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::CopyConstructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                fun,
                ..
            } if is_deleted_or_inaccessible(fun) => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::DeletedOrInaccessibleCopyConstructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::CopyConstructor,
                                impl_for,
                                ..
                            },
                        param_details,
                        ..
                    },
                ..
            } => {
                let receiver_mutability = &param_details
                    .iter()
                    .next()
                    .unwrap()
                    .self_type
                    .as_ref()
                    .unwrap()
                    .1;
                let kind = match receiver_mutability {
                    ReceiverMutability::Const => ExplicitKind::ConstCopyConstructor,
                    ReceiverMutability::Mutable => ExplicitKind::NonConstCopyConstructor,
                };
                Some(ExplicitFound {
                    ty: impl_for.clone(),
                    kind,
                })
            }
            Api::Function {
                fun,
                analysis:
                    FnAnalysis {
                        kind: FnKind::Method(self_ty, ..),
                        ..
                    },
                ..
            } if matches!(
                fun.special_member,
                Some(SpecialMemberKind::AssignmentOperator)
            ) =>
            {
                let is_move_assignment_operator = !fun.references.rvalue_ref_params.is_empty();
                Some(ExplicitFound {
                    ty: self_ty.clone(),
                    kind: if is_move_assignment_operator {
                        ExplicitKind::MoveAssignmentOperator
                    } else {
                        ExplicitKind::CopyAssignmentOperator
                    },
                })
            }
            _ => None,
        })
        .collect()
}

fn is_deleted_or_inaccessible(fun: &FuncToConvert) -> bool {
    fun.cpp_vis == CppVisibility::Private || fun.is_deleted
}
<commit_msg>Fixing spotting some items<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::{HashMap, HashSet};

use crate::{
    conversion::{
        analysis::{depth_first::depth_first, pod::PodAnalysis},
        api::{Api, CppVisibility, FuncToConvert, SpecialMemberKind},
    },
    types::QualifiedName,
};

use super::{
    implicit_constructor_rules::{
        determine_implicit_constructors, ExplicitItemsFound, ImplicitConstructorsNeeded,
    },
    FnAnalysis, FnKind, FnPhase, MethodKind, ReceiverMutability, TraitMethodKind,
};

#[derive(Hash, Eq, PartialEq)]
enum ExplicitKind {
    MoveConstructor,
    ConstCopyConstructor,
    NonConstCopyConstructor,
    OtherConstructor,
    Destructor,
    CopyAssignmentOperator,
    MoveAssignmentOperator,
    DeletedOrInaccessibleCopyConstructor,
    DeletedOrInaccessibleDestructor,
}

#[derive(Hash, Eq, PartialEq)]
struct ExplicitFound {
    ty: QualifiedName,
    kind: ExplicitKind,
}

/// If a type has explicit constructors, bindgen will generate corresponding
/// constructor functions, which we'll have already converted to make_unique methods.
/// For types with implicit constructors, we synthesize them here.
/// It is tempting to make this a separate analysis phase, to be run later than
/// the function analysis; but that would make the code much more complex as it
/// would need to output a `FnAnalysisBody`. By running it as part of this phase
/// we can simply generate the sort of thing bindgen generates, then ask
/// the existing code in this phase to figure out what to do with it.
pub(super) fn find_missing_constructors(
    apis: &[Api<FnPhase>],
) -> HashMap<QualifiedName, ImplicitConstructorsNeeded> {
    let explicits = find_explicit_items(apis);
    let mut implicit_constructors_needed = HashMap::new();
    for api in depth_first(apis) {
        if let Api::Struct {
            name,
            analysis: PodAnalysis {
                bases, field_types, ..
            },
            ..
        } = api
        {
            let name = &name.name;
            let find = |kind: ExplicitKind| -> bool {
                explicits.contains(&ExplicitFound {
                    ty: name.clone(),
                    kind,
                })
            };
            let any_bases_or_fields_lack_const_copy_constructors =
                bases.iter().chain(field_types.iter()).any(|qn| {
                    let has_explicit = explicits.contains(&ExplicitFound {
                        ty: qn.clone(),
                        kind: ExplicitKind::ConstCopyConstructor,
                    });
                    let has_implicit = implicit_constructors_needed
                        .get(qn)
                        .map(|imp: &ImplicitConstructorsNeeded| imp.copy_constructor_taking_const_t)
                        .unwrap_or_default();
                    !has_explicit && !has_implicit
                });
            let any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors =
                bases.iter().chain(field_types.iter()).any(|qn| {
                    explicits.contains(&ExplicitFound {
                        ty: qn.clone(),
                        kind: ExplicitKind::DeletedOrInaccessibleCopyConstructor,
                    })
                });
            let any_bases_have_deleted_or_inaccessible_destructors = bases.iter().any(|qn| {
                explicits.contains(&ExplicitFound {
                    ty: qn.clone(),
                    kind: ExplicitKind::DeletedOrInaccessibleDestructor,
                })
            });
            let explicit_items_found = ExplicitItemsFound {
                move_constructor: find(ExplicitKind::MoveConstructor),
                copy_constructor: find(ExplicitKind::ConstCopyConstructor)
                    || find(ExplicitKind::NonConstCopyConstructor)
                    || find(ExplicitKind::DeletedOrInaccessibleCopyConstructor),
                any_other_constructor: find(ExplicitKind::OtherConstructor),
                any_bases_or_fields_lack_const_copy_constructors,
                any_bases_or_fields_have_deleted_or_inaccessible_copy_constructors,
                any_bases_have_deleted_or_inaccessible_destructors,
                destructor: find(ExplicitKind::Destructor)
                    || find(ExplicitKind::DeletedOrInaccessibleDestructor),
                copy_assignment_operator: find(ExplicitKind::CopyAssignmentOperator),
                move_assignment_operator: find(ExplicitKind::MoveAssignmentOperator),
            };
            let implicits = determine_implicit_constructors(explicit_items_found);
            implicit_constructors_needed.insert(name.clone(), implicits);
        }
    }
    implicit_constructors_needed
}

fn find_explicit_items(apis: &[Api<FnPhase>]) -> HashSet<ExplicitFound> {
    apis.iter()
        .filter_map(|api| match api {
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind: FnKind::Method(self_ty, MethodKind::Constructor),
                        ..
                    },
                ..
            } => Some(ExplicitFound {
                ty: self_ty.clone(),
                kind: ExplicitKind::OtherConstructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::MoveConstructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                ..
            } => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::MoveConstructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::Destructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                fun,
                ..
            } if is_deleted_or_inaccessible(fun) => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::DeletedOrInaccessibleDestructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::Destructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                ..
            } => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::Destructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::CopyConstructor,
                                impl_for,
                                ..
                            },
                        ..
                    },
                fun,
                ..
            } if is_deleted_or_inaccessible(fun) => Some(ExplicitFound {
                ty: impl_for.clone(),
                kind: ExplicitKind::DeletedOrInaccessibleCopyConstructor,
            }),
            Api::Function {
                analysis:
                    FnAnalysis {
                        kind:
                            FnKind::TraitMethod {
                                kind: TraitMethodKind::CopyConstructor,
                                impl_for,
                                ..
                            },
                        param_details,
                        ..
                    },
                ..
            } => {
                let receiver_mutability = &param_details
                    .iter()
                    .next()
                    .unwrap()
                    .self_type
                    .as_ref()
                    .unwrap()
                    .1;
                let kind = match receiver_mutability {
                    ReceiverMutability::Const => ExplicitKind::ConstCopyConstructor,
                    ReceiverMutability::Mutable => ExplicitKind::NonConstCopyConstructor,
                };
                Some(ExplicitFound {
                    ty: impl_for.clone(),
                    kind,
                })
            }
            Api::Function {
                fun,
                analysis:
                    FnAnalysis {
                        kind: FnKind::Method(self_ty, ..),
                        ..
                    },
                ..
            } if matches!(
                fun.special_member,
                Some(SpecialMemberKind::AssignmentOperator)
            ) =>
            {
                let is_move_assignment_operator = !fun.references.rvalue_ref_params.is_empty();
                Some(ExplicitFound {
                    ty: self_ty.clone(),
                    kind: if is_move_assignment_operator {
                        ExplicitKind::MoveAssignmentOperator
                    } else {
                        ExplicitKind::CopyAssignmentOperator
                    },
                })
            }
            _ => None,
        })
        .collect()
}

fn is_deleted_or_inaccessible(fun: &FuncToConvert) -> bool {
    fun.cpp_vis == CppVisibility::Private || fun.is_deleted
}
<|endoftext|>


<commit_before>use serialization::Serializable;
use abomonation::{Abomonation, encode, decode};
// use columnar::Columnar;

impl<T: Abomonation+Clone> Serializable for T {
    fn encode(typed: Self, bytes: &mut Vec<u8>) {
        encode(&vec![typed], bytes);
    }
    fn decode(bytes: &mut [u8]) -> Result<Self, &mut [u8]> {
        let result = if let Ok(result) = decode::<T>(bytes) { Ok(result[0].clone()) } else { Err(()) };
        if let Ok(result) = result { Ok(result) } else { Err (bytes) }
    }
}
<commit_msg>updated for new abomonation interface<commit_after>use serialization::Serializable;
use abomonation::{Abomonation, encode, decode};
// use columnar::Columnar;

impl<T: Abomonation+Clone> Serializable for T {
    fn encode(typed: Self, bytes: &mut Vec<u8>) {
        encode(&typed, bytes);
    }
    fn decode(bytes: &mut [u8]) -> Result<Self, &mut [u8]> {
        let result = if let Ok(result) = decode::<T>(bytes) { Ok(result.clone()) } else { Err(()) };
        if let Ok(result) = result { Ok(result) } else { Err (bytes) }
    }
}
<|endoftext|>


<commit_before>use std::result;

use crate::common::*;
use crate::symbol::constants::*;
use crate::FallibleIterator;

/// An iterator over binary annotations used by `S_INLINESITE`
pub struct BinaryAnnotationsIter<'t> {
    buffer: &'t [u8],
}

impl<'t> BinaryAnnotationsIter<'t> {
    /// Initializes the iterator by parsing the buffer contents.
    pub fn new(buffer: &'t [u8]) -> BinaryAnnotationsIter<'t> {
        BinaryAnnotationsIter { buffer }
    }

    fn pop_front(&mut self) -> Result<u8> {
        let (first, rest) = self.buffer.split_first().ok_or(Error::UnexpectedEof)?;
        self.buffer = rest;
        Ok(*first)
    }

    fn get_compressed_annotation(&mut self) -> Result<u32> {
        let b1 = u32::from(self.pop_front()?);
        if (b1 & 0x80) == 0 {
            return Ok(b1);
        }
        let b2 = u32::from(self.pop_front()?);
        if (b1 & 0xc0) == 0x80 {
            return Ok((b1 & 0x3f) << 8 | b2);
        }
        let b3 = u32::from(self.pop_front()?);
        let b4 = u32::from(self.pop_front()?);
        if (b1 & 0xe0) == 0xc0 {
            return Ok(((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4);
        }
        Err(Error::SymbolTooShort)
    }
}

fn decode_signed_operand(value: u32) -> i32 {
    if value & 1 != 0 {
        -((value >> 1) as i32)
    } else {
        (value >> 1) as i32
    }
}

impl<'t> FallibleIterator for BinaryAnnotationsIter<'t> {
    type Item = BinaryAnnotation;
    type Error = Error;

    fn next(&mut self) -> result::Result<Option<Self::Item>, Self::Error> {
        if self.buffer.is_empty() {
            return Ok(None);
        }
        Ok(Some(
            match BinaryAnnotationOpcode::from(self.get_compressed_annotation()?) {
                // invalid opcodes mark the end of the stream.
                BinaryAnnotationOpcode::Invalid => {
                    self.buffer = &[][..];
                    return Ok(None);
                }
                BinaryAnnotationOpcode::CodeOffset => {
                    BinaryAnnotation::CodeOffset(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeCodeOffsetBase => {
                    BinaryAnnotation::ChangeCodeOffsetBase(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeCodeOffset => {
                    BinaryAnnotation::ChangeCodeOffset(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeCodeLength => {
                    BinaryAnnotation::ChangeCodeLength(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeFile => {
                    BinaryAnnotation::ChangeFile(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeLineOffset => BinaryAnnotation::ChangeLineOffset(
                    decode_signed_operand(self.get_compressed_annotation()?),
                ),
                BinaryAnnotationOpcode::ChangeLineEndDelta => {
                    BinaryAnnotation::ChangeLineEndDelta(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeRangeKind => {
                    BinaryAnnotation::ChangeRangeKind(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeColumnStart => {
                    BinaryAnnotation::ChangeColumnStart(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeColumnEndDelta => {
                    BinaryAnnotation::ChangeColumnEndDelta(decode_signed_operand(
                        self.get_compressed_annotation()?,
                    ))
                }
                BinaryAnnotationOpcode::ChangeCodeOffsetAndLineOffset => {
                    let annotation = self.get_compressed_annotation()?;
                    BinaryAnnotation::ChangeCodeOffsetAndLineOffset(
                        decode_signed_operand(annotation >> 4),
                        decode_signed_operand(annotation & 0xf),
                    )
                }
                BinaryAnnotationOpcode::ChangeCodeLengthAndCodeOffset => {
                    BinaryAnnotation::ChangeCodeLengthAndCodeOffset(
                        self.get_compressed_annotation()?,
                        self.get_compressed_annotation()?,
                    )
                }
                BinaryAnnotationOpcode::ChangeColumnEnd => {
                    BinaryAnnotation::ChangeColumnEnd(self.get_compressed_annotation()?)
                }
            },
        ))
    }
}

/// Represents a parsed `BinaryAnnotation`.
///
/// Binary annotations are used by `S_INLINESITE` to encode opcodes for how to
/// evaluate the state changes for inline information.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BinaryAnnotation {
    CodeOffset(u32),
    ChangeCodeOffsetBase(u32),
    ChangeCodeOffset(u32),
    ChangeCodeLength(u32),
    ChangeFile(u32),
    ChangeLineOffset(i32),
    ChangeLineEndDelta(u32),
    ChangeRangeKind(u32),
    ChangeColumnStart(u32),
    ChangeColumnEndDelta(i32),
    ChangeCodeOffsetAndLineOffset(i32, i32),
    ChangeCodeLengthAndCodeOffset(u32, u32),
    ChangeColumnEnd(u32),
}

#[test]
fn test_binary_annotation_iter() {
    let inp = b"\x0b\x03\x06\n\x03\x08\x06\x06\x03-\x06\x08\x03\x07\x0br\x06\x06\x0c\x03\x07\x06\x0f\x0c\x06\x05\x00\x00";
    let items = BinaryAnnotationsIter::new(inp).collect::<Vec<_>>().unwrap();
    assert_eq!(
        items,
        vec![
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(0, -1),
            BinaryAnnotation::ChangeLineOffset(5),
            BinaryAnnotation::ChangeCodeOffset(8),
            BinaryAnnotation::ChangeLineOffset(3),
            BinaryAnnotation::ChangeCodeOffset(45),
            BinaryAnnotation::ChangeLineOffset(4),
            BinaryAnnotation::ChangeCodeOffset(7),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(-3, 1),
            BinaryAnnotation::ChangeLineOffset(3),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(3, 7),
            BinaryAnnotation::ChangeLineOffset(-7),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(6, 5)
        ]
    );

    let inp = b"\x03P\x06\x0e\x03\x0c\x06\x04\x032\x06\x06\x03T\x0b#\x0b\\\x0bC\x0b/\x06\x04\x0c-\t\x03;\x06\x1d\x0c\x05\x06\x00\x00";
    let items = BinaryAnnotationsIter::new(inp).collect::<Vec<_>>().unwrap();
    assert_eq!(
        items,
        vec![
            BinaryAnnotation::ChangeCodeOffset(80),
            BinaryAnnotation::ChangeLineOffset(7),
            BinaryAnnotation::ChangeCodeOffset(12),
            BinaryAnnotation::ChangeLineOffset(2),
            BinaryAnnotation::ChangeCodeOffset(50),
            BinaryAnnotation::ChangeLineOffset(3),
            BinaryAnnotation::ChangeCodeOffset(84),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(1, -1),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(-2, 6),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(2, -1),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(1, -7),
            BinaryAnnotation::ChangeLineOffset(2),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(45, 9),
            BinaryAnnotation::ChangeCodeOffset(59),
            BinaryAnnotation::ChangeLineOffset(-14),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(5, 6),
        ]
    );
}
<commit_msg>Changed error<commit_after>use std::result;

use crate::common::*;
use crate::symbol::constants::*;
use crate::FallibleIterator;

/// An iterator over binary annotations used by `S_INLINESITE`
pub struct BinaryAnnotationsIter<'t> {
    buffer: &'t [u8],
}

impl<'t> BinaryAnnotationsIter<'t> {
    /// Initializes the iterator by parsing the buffer contents.
    pub fn new(buffer: &'t [u8]) -> BinaryAnnotationsIter<'t> {
        BinaryAnnotationsIter { buffer }
    }

    fn pop_front(&mut self) -> Result<u8> {
        let (first, rest) = self.buffer.split_first().ok_or(Error::UnexpectedEof)?;
        self.buffer = rest;
        Ok(*first)
    }

    fn get_compressed_annotation(&mut self) -> Result<u32> {
        let b1 = u32::from(self.pop_front()?);
        if (b1 & 0x80) == 0 {
            return Ok(b1);
        }
        let b2 = u32::from(self.pop_front()?);
        if (b1 & 0xc0) == 0x80 {
            return Ok((b1 & 0x3f) << 8 | b2);
        }
        let b3 = u32::from(self.pop_front()?);
        let b4 = u32::from(self.pop_front()?);
        if (b1 & 0xe0) == 0xc0 {
            return Ok(((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4);
        }
        Err(Error::UnexpectedEof)
    }
}

fn decode_signed_operand(value: u32) -> i32 {
    if value & 1 != 0 {
        -((value >> 1) as i32)
    } else {
        (value >> 1) as i32
    }
}

impl<'t> FallibleIterator for BinaryAnnotationsIter<'t> {
    type Item = BinaryAnnotation;
    type Error = Error;

    fn next(&mut self) -> result::Result<Option<Self::Item>, Self::Error> {
        if self.buffer.is_empty() {
            return Ok(None);
        }
        Ok(Some(
            match BinaryAnnotationOpcode::from(self.get_compressed_annotation()?) {
                // invalid opcodes mark the end of the stream.
                BinaryAnnotationOpcode::Invalid => {
                    self.buffer = &[][..];
                    return Ok(None);
                }
                BinaryAnnotationOpcode::CodeOffset => {
                    BinaryAnnotation::CodeOffset(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeCodeOffsetBase => {
                    BinaryAnnotation::ChangeCodeOffsetBase(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeCodeOffset => {
                    BinaryAnnotation::ChangeCodeOffset(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeCodeLength => {
                    BinaryAnnotation::ChangeCodeLength(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeFile => {
                    BinaryAnnotation::ChangeFile(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeLineOffset => BinaryAnnotation::ChangeLineOffset(
                    decode_signed_operand(self.get_compressed_annotation()?),
                ),
                BinaryAnnotationOpcode::ChangeLineEndDelta => {
                    BinaryAnnotation::ChangeLineEndDelta(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeRangeKind => {
                    BinaryAnnotation::ChangeRangeKind(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeColumnStart => {
                    BinaryAnnotation::ChangeColumnStart(self.get_compressed_annotation()?)
                }
                BinaryAnnotationOpcode::ChangeColumnEndDelta => {
                    BinaryAnnotation::ChangeColumnEndDelta(decode_signed_operand(
                        self.get_compressed_annotation()?,
                    ))
                }
                BinaryAnnotationOpcode::ChangeCodeOffsetAndLineOffset => {
                    let annotation = self.get_compressed_annotation()?;
                    BinaryAnnotation::ChangeCodeOffsetAndLineOffset(
                        decode_signed_operand(annotation >> 4),
                        decode_signed_operand(annotation & 0xf),
                    )
                }
                BinaryAnnotationOpcode::ChangeCodeLengthAndCodeOffset => {
                    BinaryAnnotation::ChangeCodeLengthAndCodeOffset(
                        self.get_compressed_annotation()?,
                        self.get_compressed_annotation()?,
                    )
                }
                BinaryAnnotationOpcode::ChangeColumnEnd => {
                    BinaryAnnotation::ChangeColumnEnd(self.get_compressed_annotation()?)
                }
            },
        ))
    }
}

/// Represents a parsed `BinaryAnnotation`.
///
/// Binary annotations are used by `S_INLINESITE` to encode opcodes for how to
/// evaluate the state changes for inline information.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum BinaryAnnotation {
    CodeOffset(u32),
    ChangeCodeOffsetBase(u32),
    ChangeCodeOffset(u32),
    ChangeCodeLength(u32),
    ChangeFile(u32),
    ChangeLineOffset(i32),
    ChangeLineEndDelta(u32),
    ChangeRangeKind(u32),
    ChangeColumnStart(u32),
    ChangeColumnEndDelta(i32),
    ChangeCodeOffsetAndLineOffset(i32, i32),
    ChangeCodeLengthAndCodeOffset(u32, u32),
    ChangeColumnEnd(u32),
}

#[test]
fn test_binary_annotation_iter() {
    let inp = b"\x0b\x03\x06\n\x03\x08\x06\x06\x03-\x06\x08\x03\x07\x0br\x06\x06\x0c\x03\x07\x06\x0f\x0c\x06\x05\x00\x00";
    let items = BinaryAnnotationsIter::new(inp).collect::<Vec<_>>().unwrap();
    assert_eq!(
        items,
        vec![
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(0, -1),
            BinaryAnnotation::ChangeLineOffset(5),
            BinaryAnnotation::ChangeCodeOffset(8),
            BinaryAnnotation::ChangeLineOffset(3),
            BinaryAnnotation::ChangeCodeOffset(45),
            BinaryAnnotation::ChangeLineOffset(4),
            BinaryAnnotation::ChangeCodeOffset(7),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(-3, 1),
            BinaryAnnotation::ChangeLineOffset(3),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(3, 7),
            BinaryAnnotation::ChangeLineOffset(-7),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(6, 5)
        ]
    );

    let inp = b"\x03P\x06\x0e\x03\x0c\x06\x04\x032\x06\x06\x03T\x0b#\x0b\\\x0bC\x0b/\x06\x04\x0c-\t\x03;\x06\x1d\x0c\x05\x06\x00\x00";
    let items = BinaryAnnotationsIter::new(inp).collect::<Vec<_>>().unwrap();
    assert_eq!(
        items,
        vec![
            BinaryAnnotation::ChangeCodeOffset(80),
            BinaryAnnotation::ChangeLineOffset(7),
            BinaryAnnotation::ChangeCodeOffset(12),
            BinaryAnnotation::ChangeLineOffset(2),
            BinaryAnnotation::ChangeCodeOffset(50),
            BinaryAnnotation::ChangeLineOffset(3),
            BinaryAnnotation::ChangeCodeOffset(84),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(1, -1),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(-2, 6),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(2, -1),
            BinaryAnnotation::ChangeCodeOffsetAndLineOffset(1, -7),
            BinaryAnnotation::ChangeLineOffset(2),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(45, 9),
            BinaryAnnotation::ChangeCodeOffset(59),
            BinaryAnnotation::ChangeLineOffset(-14),
            BinaryAnnotation::ChangeCodeLengthAndCodeOffset(5, 6),
        ]
    );
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// Don't fail if we encounter a NonZero<*T> where T is an unsized type

#![feature(unique)]

use std::ptr::Unique;

fn main() {
    let mut a = [0u8; 5];
    let b: Option<Unique<[u8]>> = unsafe { Some(Unique::new_unchecked(&mut a)) };
    match b {
        Some(_) => println!("Got `Some`"),
        None => panic!("Unexpected `None`"),
    }
}
<commit_msg>Use safe conversion instead of unsafe constructor in issue-23433 test<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// Don't fail if we encounter a NonZero<*T> where T is an unsized type

#![feature(unique)]

use std::ptr::Unique;

fn main() {
    let mut a = [0u8; 5];
    let b: Option<Unique<[u8]>> = Some(Unique::from(&mut a));
    match b {
        Some(_) => println!("Got `Some`"),
        None => panic!("Unexpected `None`"),
    }
}
<|endoftext|>