<commit_before>//! Function layout.
//!
//! The order of extended basic blocks in a function and the order of instructions in an EBB is
//! determined by the `Layout` data structure defined in this module.

use entity_map::EntityMap;
use entities::{Ebb, NO_EBB, Inst, NO_INST};

/// The `Layout` struct determines the layout of EBBs and instructions in a function. It does not
/// contain definitions of instructions or EBBs, but depends on `Inst` and `Ebb` entity references
/// being defined elsewhere.
///
/// This data structure determines:
///
/// - The order of EBBs in the function.
/// - Which EBB contains a given instruction.
/// - The order of instructions with an EBB.
///
/// While data dependencies are not recorded, instruction ordering does affect control
/// dependencies, so part of the semantics of the program are determined by the layout.
///
pub struct Layout {
    // Linked list nodes for the layout order of EBBs Forms a doubly linked list, terminated in
    // both ends by NO_EBB.
    ebbs: EntityMap<Ebb, EbbNode>,

    // Linked list nodes for the layout order of instructions. Forms a double linked list per EBB,
    // terminated in both ends by NO_INST.
    insts: EntityMap<Inst, InstNode>,

    // First EBB in the layout order, or `NO_EBB` when no EBBs have been laid out.
    first_ebb: Ebb,

    // Last EBB in the layout order, or `NO_EBB` when no EBBs have been laid out.
    last_ebb: Ebb,
}

impl Layout {
    /// Create a new empty `Layout`.
    pub fn new() -> Layout {
        Layout {
            ebbs: EntityMap::new(),
            insts: EntityMap::new(),
            first_ebb: NO_EBB,
            last_ebb: NO_EBB,
        }
    }
}

/// Methods for laying out EBBs.
///
/// An unknown EBB starts out as *not inserted* in the EBB layout. The layout is a linear order of
/// inserted EBBs. Once an EBB has been inserted in the layout, instructions can be added. An EBB
/// can only be removed from the layout when it is empty.
///
/// Since every EBB must end with a terminator instruction which cannot fall through, the layout of
/// EBBs does not affect the semantics of the program.
///
impl Layout {
    /// Is `ebb` currently part of the layout?
    pub fn is_ebb_inserted(&self, ebb: Ebb) -> bool {
        ebb != self.first_ebb && self.ebbs.is_valid(ebb) && self.ebbs[ebb].prev == NO_EBB
    }

    /// Insert `ebb` as the last EBB in the layout.
    pub fn append_ebb(&mut self, ebb: Ebb) {
        assert!(!self.is_ebb_inserted(ebb),
                "Cannot append EBB that is already in the layout");
        let node = &mut self.ebbs[ebb];
        assert!(node.first_inst == NO_INST && node.last_inst == NO_INST);
        node.prev = self.last_ebb;
        node.next = NO_EBB;
        self.last_ebb = ebb;
    }

    /// Insert `ebb` in the layout before the existing EBB `before`.
    pub fn insert_ebb(&mut self, ebb: Ebb, before: Ebb) {
        assert!(!self.is_ebb_inserted(ebb),
                "Cannot insert EBB that is already in the layout");
        assert!(self.is_ebb_inserted(before),
                "EBB Insertion point not in the layout");
        let after = self.ebbs[before].prev;
        self.ebbs[ebb].next = before;
        self.ebbs[ebb].prev = after;
        self.ebbs[before].prev = ebb;
        if after != NO_EBB {
            self.ebbs[after].next = ebb;
        }
    }
}

#[derive(Clone, Debug, Default)]
struct EbbNode {
    prev: Ebb,
    next: Ebb,
    first_inst: Inst,
    last_inst: Inst,
}

/// Methods for arranging instructions.
///
/// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into
/// an EBB at a given position.
impl Layout {
    /// Get the EBB containing `inst`, or `None` if `inst` is not inserted in the layout.
    pub fn inst_ebb(&self, inst: Inst) -> Option<Ebb> {
        if self.insts.is_valid(inst) {
            let ebb = self.insts[inst].ebb;
            if ebb == NO_EBB {
                None
            } else {
                Some(ebb)
            }
        } else {
            None
        }
    }

    /// Append `inst` to the end of `ebb`.
    pub fn append_inst(&self, inst: Inst, ebb: Ebb) {
        assert_eq!(self.inst_ebb(inst), None);
        assert!(self.is_ebb_inserted(ebb),
                "Cannot append instructions to EBB not in layout");
        unimplemented!();
    }

    /// Insert `inst` before the instruction `before` in the same EBB.
    pub fn insert_inst(&self, inst: Inst, before: Inst) {
        assert_eq!(self.inst_ebb(inst), None);
        let ebb = self.inst_ebb(before)
            .expect("Instruction before insertion point not in the layout");
        assert!(ebb != NO_EBB);
        unimplemented!();
    }
}

#[derive(Clone, Debug, Default)]
struct InstNode {
    ebb: Ebb,
    prev: Inst,
    next: Inst,
}
<commit_msg>Add Layout::ebbs() and the corresponding iterator.<commit_after>//! Function layout.
//!
//! The order of extended basic blocks in a function and the order of instructions in an EBB is
//! determined by the `Layout` data structure defined in this module.

use std::iter::Iterator;
use entity_map::{EntityMap, EntityRef};
use entities::{Ebb, NO_EBB, Inst, NO_INST};

/// The `Layout` struct determines the layout of EBBs and instructions in a function. It does not
/// contain definitions of instructions or EBBs, but depends on `Inst` and `Ebb` entity references
/// being defined elsewhere.
///
/// This data structure determines:
///
/// - The order of EBBs in the function.
/// - Which EBB contains a given instruction.
/// - The order of instructions with an EBB.
///
/// While data dependencies are not recorded, instruction ordering does affect control
/// dependencies, so part of the semantics of the program are determined by the layout.
///
pub struct Layout {
    // Linked list nodes for the layout order of EBBs Forms a doubly linked list, terminated in
    // both ends by NO_EBB.
    ebbs: EntityMap<Ebb, EbbNode>,

    // Linked list nodes for the layout order of instructions. Forms a double linked list per EBB,
    // terminated in both ends by NO_INST.
    insts: EntityMap<Inst, InstNode>,

    // First EBB in the layout order, or `None` when no EBBs have been laid out.
    first_ebb: Option<Ebb>,

    // Last EBB in the layout order, or `None` when no EBBs have been laid out.
    last_ebb: Option<Ebb>,
}

impl Layout {
    /// Create a new empty `Layout`.
    pub fn new() -> Layout {
        Layout {
            ebbs: EntityMap::new(),
            insts: EntityMap::new(),
            first_ebb: None,
            last_ebb: None,
        }
    }
}

/// Methods for laying out EBBs.
///
/// An unknown EBB starts out as *not inserted* in the EBB layout. The layout is a linear order of
/// inserted EBBs. Once an EBB has been inserted in the layout, instructions can be added. An EBB
/// can only be removed from the layout when it is empty.
///
/// Since every EBB must end with a terminator instruction which cannot fall through, the layout of
/// EBBs does not affect the semantics of the program.
///
impl Layout {
    /// Is `ebb` currently part of the layout?
    pub fn is_ebb_inserted(&self, ebb: Ebb) -> bool {
        Some(ebb) == self.first_ebb || (self.ebbs.is_valid(ebb) && self.ebbs[ebb].prev != NO_EBB)
    }

    /// Insert `ebb` as the last EBB in the layout.
    pub fn append_ebb(&mut self, ebb: Ebb) {
        assert!(!self.is_ebb_inserted(ebb),
                "Cannot append EBB that is already in the layout");
        let node = &mut self.ebbs[ebb];
        assert!(node.first_inst == NO_INST && node.last_inst == NO_INST);
        node.prev = self.last_ebb.unwrap_or_default();
        node.next = NO_EBB;
        self.last_ebb = Some(ebb);
        if self.first_ebb.is_none() {
            self.first_ebb = Some(ebb);
        }
    }

    /// Insert `ebb` in the layout before the existing EBB `before`.
    pub fn insert_ebb(&mut self, ebb: Ebb, before: Ebb) {
        assert!(!self.is_ebb_inserted(ebb),
                "Cannot insert EBB that is already in the layout");
        assert!(self.is_ebb_inserted(before),
                "EBB Insertion point not in the layout");
        let after = self.ebbs[before].prev;
        self.ebbs[ebb].next = before;
        self.ebbs[ebb].prev = after;
        self.ebbs[before].prev = ebb;
        if after == NO_EBB {
            self.first_ebb = Some(ebb);
        } else {
            self.ebbs[after].next = ebb;
        }
    }

    /// Return an iterator over all EBBs in layout order.
    pub fn ebbs<'a>(&'a self) -> Ebbs<'a> {
        Ebbs {
            layout: self,
            next: self.first_ebb,
        }
    }
}

#[derive(Clone, Debug, Default)]
struct EbbNode {
    prev: Ebb,
    next: Ebb,
    first_inst: Inst,
    last_inst: Inst,
}

/// Iterate over EBBs in layout order. See `Layout::ebbs()`.
pub struct Ebbs<'a> {
    layout: &'a Layout,
    next: Option<Ebb>,
}

impl<'a> Iterator for Ebbs<'a> {
    type Item = Ebb;

    fn next(&mut self) -> Option<Ebb> {
        match self.next {
            Some(ebb) => {
                self.next = self.layout.ebbs[ebb].next.wrap();
                Some(ebb)
            }
            None => None,
        }
    }
}

/// Methods for arranging instructions.
///
/// An instruction starts out as *not inserted* in the layout. An instruction can be inserted into
/// an EBB at a given position.
impl Layout {
    /// Get the EBB containing `inst`, or `None` if `inst` is not inserted in the layout.
    pub fn inst_ebb(&self, inst: Inst) -> Option<Ebb> {
        if self.insts.is_valid(inst) {
            let ebb = self.insts[inst].ebb;
            if ebb == NO_EBB {
                None
            } else {
                Some(ebb)
            }
        } else {
            None
        }
    }

    /// Append `inst` to the end of `ebb`.
    pub fn append_inst(&self, inst: Inst, ebb: Ebb) {
        assert_eq!(self.inst_ebb(inst), None);
        assert!(self.is_ebb_inserted(ebb),
                "Cannot append instructions to EBB not in layout");
        unimplemented!();
    }

    /// Insert `inst` before the instruction `before` in the same EBB.
    pub fn insert_inst(&self, inst: Inst, before: Inst) {
        assert_eq!(self.inst_ebb(inst), None);
        let ebb = self.inst_ebb(before)
            .expect("Instruction before insertion point not in the layout");
        assert!(ebb != NO_EBB);
        unimplemented!();
    }
}

#[derive(Clone, Debug, Default)]
struct InstNode {
    ebb: Ebb,
    prev: Inst,
    next: Inst,
}

#[cfg(test)]
mod tests {
    use super::Layout;
    use entity_map::EntityRef;
    use entities::Ebb;

    #[test]
    fn insert_ebb() {
        let mut layout = Layout::new();
        let e0 = Ebb::new(0);
        let e1 = Ebb::new(1);
        let e2 = Ebb::new(2);

        {
            let imm = &layout;
            assert!(!imm.is_ebb_inserted(e0));
            assert!(!imm.is_ebb_inserted(e1));

            let v: Vec<Ebb> = layout.ebbs().collect();
            assert_eq!(v, []);
        }

        layout.append_ebb(e1);
        assert!(!layout.is_ebb_inserted(e0));
        assert!(layout.is_ebb_inserted(e1));
        assert!(!layout.is_ebb_inserted(e2));
        let v: Vec<Ebb> = layout.ebbs().collect();
        assert_eq!(v, [e1]);

        layout.insert_ebb(e2, e1);
        assert!(!layout.is_ebb_inserted(e0));
        assert!(layout.is_ebb_inserted(e1));
        assert!(layout.is_ebb_inserted(e2));
        let v: Vec<Ebb> = layout.ebbs().collect();
        assert_eq!(v, [e2, e1]);

        layout.insert_ebb(e0, e1);
        assert!(layout.is_ebb_inserted(e0));
        assert!(layout.is_ebb_inserted(e1));
        assert!(layout.is_ebb_inserted(e2));
        let v: Vec<Ebb> = layout.ebbs().collect();
        assert_eq!(v, [e2, e0, e1]);
    }
}
<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::iter::Iterator;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};
use std::path::{Component, Path};
use std::fs::File;
use std::io::prelude::*;
use mbtile_error::{InnerError, MBTileError};
use rustc_serialize::json::Json;
use std::convert;
use std::fmt;

#[derive(RustcDecodable, Debug)]
pub enum Command {
    Import,
    Export,
    Metadata,
}

#[derive(RustcDecodable, Debug, Clone, Copy)]
pub enum Scheme {
    Xyz,
    Tms,
    Wms,
    Ags,
}

impl fmt::Display for Scheme {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = match *self {
            Scheme::Xyz => "xyz",
            Scheme::Tms => "tms",
            Scheme::Wms => "wms",
            Scheme::Ags => "ags",
        };
        write!(f, "{}", res)
    }
}

#[derive(RustcDecodable, Debug, Clone, Copy)]
pub enum ImageFormat {
    Png,
    Jpg,
    Webp,
    Pbf,
}

fn mbtiles_connect(mbtiles_file: &Path) -> Result<Connection, MBTileError> {
    Ok(try_desc!(Connection::open(mbtiles_file),
                 format!("Can't connect to {:?}", mbtiles_file)))
}

fn optimize_connection(connection: &Connection) -> Result<(), MBTileError> {
    Ok(try_desc!(connection.execute_batch("
        PRAGMA synchronous=0;
        PRAGMA locking_mode=EXCLUSIVE;
        PRAGMA journal_mode=DELETE;
        "),
                 "Cannot execute sqlite optimization query"))
}

fn optimize_database(connection: &Connection) -> Result<(), MBTileError> {
    info!("SQLite analyse");
    try_desc!(connection.execute_batch("ANALYZE;"), "Can't analyze sqlite");
    info!("SQLite vacuum");
    try_desc!(connection.execute_batch("VACUUM;"), "Can't vacuum sqlite");
    Ok(())
}

fn mbtiles_setup(connection: &Connection) -> Result<(), MBTileError> {
    Ok(try_desc!(connection.execute_batch("
        CREATE TABLE tiles (
                zoom_level INTEGER,
                tile_column INTEGER,
                tile_row INTEGER,
                tile_data BLOB);
        CREATE TABLE metadata
            (name TEXT, value TEXT);
        CREATE TABLE grids (zoom_level INTEGER, tile_column INTEGER,
            tile_row INTEGER, grid BLOB);
        CREATE TABLE grid_data (zoom_level INTEGER, tile_column
            INTEGER, tile_row INTEGER, key_name TEXT, key_json TEXT);
        CREATE UNIQUE INDEX name ON metadata (name);
        CREATE UNIQUE INDEX tile_index ON tiles
            (zoom_level, tile_column, tile_row);
    "),
                 "Can't create schema"))
}

fn is_visible(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map_or(false, |s| !s.starts_with('.'))
}

fn get_extension(image_format: ImageFormat) -> &'static str {
    match image_format {
        ImageFormat::Jpg => "jpg",
        ImageFormat::Pbf => "pbf",
        ImageFormat::Png => "png",
        ImageFormat::Webp => "webp",
    }
}

fn insert_metadata(input: &Path, connection: &Connection) -> Result<(), MBTileError> {
    if input.is_file() {
        info!("metadata.json was not found");
        return Ok(());
    }
    let mut metadata_file = try_desc!(File::open(input.join("metadata.json")),
                                      "Can't open metadata.json");
    let mut buffer = String::new();
    try_desc!(metadata_file.read_to_string(&mut buffer),
              "metadata.json wasn't readable");
    // TODO: use try! add error type
    if let Ok(data) = Json::from_str(buffer.as_str()) {
        if data.is_object() {
            let obj = data.as_object().unwrap();
            for (key, value) in obj.iter() {
                try_desc!(connection.execute("insert into metadata (name, value) values ($1, $2)",
                                             &[key, &value.as_string().unwrap()]),
                          "Can't insert medata in database");
            }
        }
    }
    info!("metadata.json was restored");
    Ok(())
}

pub fn import(input: &Path,
              output: &Path,
              flag_scheme: Scheme,
              flag_image_format: ImageFormat,
              flag_grid_callback: String)
              -> Result<(), MBTileError> {
    info!("Importing disk to MBTiles");
    debug!("{:?} --> {:?}", &input, &output);
    if !input.is_dir() {
        return Err(MBTileError {
            message: "Can only import from a directory".to_owned(),
            inner_error: InnerError::None,
        });
    }
    let connection = try!(mbtiles_connect(output));
    try!(optimize_connection(&connection));
    try!(mbtiles_setup(&connection));
    try!(insert_metadata(&input, &connection));
    try!(walk_dir_image(&input,
                        flag_scheme,
                        flag_image_format,
                        flag_grid_callback,
                        &connection));
    debug!("tiles (and grids) inserted.");
    try!(optimize_database(&connection));
    Ok(())
}

fn flip_y(zoom: u32, y: u32) -> u32 {
    2u32.pow(zoom - 1) - y
}

fn walk_dir_image(input: &Path,
                  flag_scheme: Scheme,
                  flag_image_format: ImageFormat,
                  flag_grid_callback: String,
                  connection: &Connection)
                  -> Result<(), MBTileError> {
    let base_components_length = input.components().count();
    let dir_walker = WalkDir::new(input)
                         .follow_links(true)
                         .min_depth(1)
                         .max_depth(3)
                         .into_iter()
                         .filter_entry(is_visible);
    for entry_res in dir_walker {
        let entry = try_desc!(entry_res, "invalid entry");
        let entry_path = entry.path();
        if entry_path.is_dir() {
            // ignore directories
            continue;
        }
        let end_comp: Vec<Component> = entry_path.components()
                                                 .skip(base_components_length)
                                                 .collect();
        if end_comp.len() == 3 {
            parse_zoom_dir(end_comp[0], flag_scheme)
                .and_then(|zoom| {
                    parse_image_dir(end_comp[1], flag_scheme).and_then(|image_dir| {
                        parse_image_filename(end_comp[2], flag_scheme, flag_image_format)
                            .and_then(|image_filename| {
                                let (col, row) = match flag_scheme {
                                    Scheme::Ags => (image_filename, flip_y(zoom, image_dir)),
                                    Scheme::Xyz => (image_dir, flip_y(zoom, image_filename)),
                                    _ => (image_dir, image_filename),
                                };
                                info!("Zoom: {}, Col: {}, Row {}", zoom, col, row);
                                insert_image_sqlite(entry_path, zoom, col, row, &connection)
                            })
                    })
                })
                .unwrap_or_else(|err| error!("{}", err))
        }
        info!("{}", entry.path().display());
    }
    Ok(())
}

fn parse_comp(component: Component) -> Result<String, MBTileError> {
    if let Component::Normal(os_str) = component {
        os_str.to_str()
              .ok_or(MBTileError {
                  message: format!("Unvalid unicode path: {:?}", os_str),
                  inner_error: InnerError::None,
              })
              .map(|s| s.to_owned())
    } else {
        Err(MBTileError {
            message: format!("Can't read path component {:?}", component),
            inner_error: InnerError::None,
        })
    }
}

fn parse_zoom_dir(component: Component, flag_scheme: Scheme) -> Result<u32, MBTileError> {
    let mut zoom_string = try!(parse_comp(component));
    if let Scheme::Ags = flag_scheme {
        if !zoom_string.contains('L') {
            warn!("You appear to be using an ags scheme on an non-arcgis Server cache.");
        }
        zoom_string = zoom_string.replace("L", "");
    }
    Ok(try_desc!(zoom_string.parse::<u32>(),
                 "Can't parse component in integer format"))
}

fn parse_image_dir(component: Component, flag_scheme: Scheme) -> Result<u32, MBTileError> {
    let mut radix = 10u32;
    let mut x_string = try!(parse_comp(component));
    if let Scheme::Ags = flag_scheme {
        x_string = x_string.replace("R", "");
        radix = 16;
    }
    Ok(try_desc!(u32::from_str_radix(x_string.as_str(), radix),
                 "Can't parse component in integer format"))
}

fn parse_image_filename(component: Component,
                        flag_scheme: Scheme,
                        image_format: ImageFormat)
                        -> Result<u32, MBTileError> {
    let mut radix = 10u32;
    let mut x_string = try!(parse_comp(component));
    let mut x_part: String; //espace E0506 for s
    {
        let parts: Vec<&str> = x_string.split('.').collect();
        let filtered_extension = get_extension(image_format);
        if parts[1] == filtered_extension {
            x_part = parts[0].to_owned();
        } else {
            return Err(MBTileError {
                message: format!("The filtered extention {} is different than the path's \
                         extention {}",
                                 filtered_extension,
                                 parts[1]),
                inner_error: InnerError::None,
            });
        }
        if let Scheme::Ags = flag_scheme {
            x_part = x_string.replace("C", "");
            radix = 16;
        }
    }
    x_string = x_part;
    Ok(try_desc!(u32::from_str_radix(x_string.as_str(), radix),
                 "Can't parse component in integer format"))
}

fn insert_image_sqlite(image_path: &Path,
                       zoom: u32,
                       column: u32,
                       row: u32,
                       connection: &Connection)
                       -> Result<(), MBTileError> {
    let mut image_file = try_desc!(File::open(image_path),
                                   format!("Can't open {:?}", image_path));
    let mut buffer = Vec::new();
    try_desc!(image_file.read_to_end(&mut buffer),
              format!("Can't read file {:?}", image_path));
    try_desc!(connection.execute("insert into tiles (zoom_level,
                    tile_column, tile_row, tile_data) values
                    ($1, $2, $3, $4);",
                                 &[&(zoom as i64), &(column as i64), &(row as i64), &buffer]),
              format!("Can't insert {:?}", image_path));
    Ok(())
}

pub fn export(input: String,
              output: Option<String>,
              flag_scheme: Scheme,
              flag_image_format: ImageFormat,
              flag_grid_callback: String) {
    let input_path = Path::new(&input);
    if input_path.is_file() {
    } else {
        error!("Can only export from a file")
    }
}

pub fn metadata(input: String,
                output: Option<String>,
                flag_scheme: Scheme,
                flag_image_format: ImageFormat,
                flag_grid_callback: String) {
    let input_path = Path::new(&input);
    if input_path.is_file() {
    } else {
        error!("Can only dumps from a file")
    }
}
<commit_msg>fix flip_y computation error<commit_after>use rusqlite::Connection;
use std::iter::Iterator;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};
use std::path::{Component, Path};
use std::fs::File;
use std::io::prelude::*;
use mbtile_error::{InnerError, MBTileError};
use rustc_serialize::json::Json;
use std::convert;
use std::fmt;

#[derive(RustcDecodable, Debug)]
pub enum Command {
    Import,
    Export,
    Metadata,
}

#[derive(RustcDecodable, Debug, Clone, Copy)]
pub enum Scheme {
    Xyz,
    Tms,
    Wms,
    Ags,
}

impl fmt::Display for Scheme {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let res = match *self {
            Scheme::Xyz => "xyz",
            Scheme::Tms => "tms",
            Scheme::Wms => "wms",
            Scheme::Ags => "ags",
        };
        write!(f, "{}", res)
    }
}

#[derive(RustcDecodable, Debug, Clone, Copy)]
pub enum ImageFormat {
    Png,
    Jpg,
    Webp,
    Pbf,
}

fn mbtiles_connect(mbtiles_file: &Path) -> Result<Connection, MBTileError> {
    Ok(try_desc!(Connection::open(mbtiles_file),
                 format!("Can't connect to {:?}", mbtiles_file)))
}

fn optimize_connection(connection: &Connection) -> Result<(), MBTileError> {
    Ok(try_desc!(connection.execute_batch("
        PRAGMA synchronous=0;
        PRAGMA locking_mode=EXCLUSIVE;
        PRAGMA journal_mode=DELETE;
        "),
                 "Cannot execute sqlite optimization query"))
}

fn optimize_database(connection: &Connection) -> Result<(), MBTileError> {
    info!("SQLite analyse");
    try_desc!(connection.execute_batch("ANALYZE;"), "Can't analyze sqlite");
    info!("SQLite vacuum");
    try_desc!(connection.execute_batch("VACUUM;"), "Can't vacuum sqlite");
    Ok(())
}

fn mbtiles_setup(connection: &Connection) -> Result<(), MBTileError> {
    Ok(try_desc!(connection.execute_batch("
        CREATE TABLE tiles (
                zoom_level INTEGER,
                tile_column INTEGER,
                tile_row INTEGER,
                tile_data BLOB);
        CREATE TABLE metadata
            (name TEXT, value TEXT);
        CREATE TABLE grids (zoom_level INTEGER, tile_column INTEGER,
            tile_row INTEGER, grid BLOB);
        CREATE TABLE grid_data (zoom_level INTEGER, tile_column
            INTEGER, tile_row INTEGER, key_name TEXT, key_json TEXT);
        CREATE UNIQUE INDEX name ON metadata (name);
        CREATE UNIQUE INDEX tile_index ON tiles
            (zoom_level, tile_column, tile_row);
    "),
                 "Can't create schema"))
}

fn is_visible(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map_or(false, |s| !s.starts_with('.'))
}

fn get_extension(image_format: ImageFormat) -> &'static str {
    match image_format {
        ImageFormat::Jpg => "jpg",
        ImageFormat::Pbf => "pbf",
        ImageFormat::Png => "png",
        ImageFormat::Webp => "webp",
    }
}

fn insert_metadata(input: &Path, connection: &Connection) -> Result<(), MBTileError> {
    if input.is_file() {
        info!("metadata.json was not found");
        return Ok(());
    }
    let mut metadata_file = try_desc!(File::open(input.join("metadata.json")),
                                      "Can't open metadata.json");
    let mut buffer = String::new();
    try_desc!(metadata_file.read_to_string(&mut buffer),
              "metadata.json wasn't readable");
    // TODO: use try! add error type
    if let Ok(data) = Json::from_str(buffer.as_str()) {
        if data.is_object() {
            let obj = data.as_object().unwrap();
            for (key, value) in obj.iter() {
                try_desc!(connection.execute("insert into metadata (name, value) values ($1, $2)",
                                             &[key, &value.as_string().unwrap()]),
                          "Can't insert medata in database");
            }
        }
    }
    info!("metadata.json was restored");
    Ok(())
}

pub fn import(input: &Path,
              output: &Path,
              flag_scheme: Scheme,
              flag_image_format: ImageFormat,
              flag_grid_callback: String)
              -> Result<(), MBTileError> {
    info!("Importing disk to MBTiles");
    debug!("{:?} --> {:?}", &input, &output);
    if !input.is_dir() {
        return Err(MBTileError {
            message: "Can only import from a directory".to_owned(),
            inner_error: InnerError::None,
        });
    }
    let connection = try!(mbtiles_connect(output));
    try!(optimize_connection(&connection));
    try!(mbtiles_setup(&connection));
    try!(insert_metadata(&input, &connection));
    try!(walk_dir_image(&input,
                        flag_scheme,
                        flag_image_format,
                        flag_grid_callback,
                        &connection));
    debug!("tiles (and grids) inserted.");
    try!(optimize_database(&connection));
    Ok(())
}

fn flip_y(zoom: u32, y: u32) -> u32 {
    2u32.pow(zoom) -1 - y
}

fn walk_dir_image(input: &Path,
                  flag_scheme: Scheme,
                  flag_image_format: ImageFormat,
                  flag_grid_callback: String,
                  connection: &Connection)
                  -> Result<(), MBTileError> {
    let base_components_length = input.components().count();
    let dir_walker = WalkDir::new(input)
                         .follow_links(true)
                         .min_depth(1)
                         .max_depth(3)
                         .into_iter()
                         .filter_entry(is_visible);
    for entry_res in dir_walker {
        let entry = try_desc!(entry_res, "invalid entry");
        let entry_path = entry.path();
        if entry_path.is_dir() {
            // ignore directories
            continue;
        }
        let end_comp: Vec<Component> = entry_path.components()
                                                 .skip(base_components_length)
                                                 .collect();
        if end_comp.len() == 3 {
            parse_zoom_dir(end_comp[0], flag_scheme)
                .and_then(|zoom| {
                    parse_image_dir(end_comp[1], flag_scheme).and_then(|image_dir| {
                        parse_image_filename(end_comp[2], flag_scheme, flag_image_format)
                            .and_then(|image_filename| {
                                let (col, row) = match flag_scheme {
                                    Scheme::Ags => (image_filename, flip_y(zoom, image_dir)),
                                    Scheme::Xyz => (image_dir, flip_y(zoom, image_filename)),
                                    _ => (image_dir, image_filename),
                                };
                                info!("Zoom: {}, Col: {}, Row {}", zoom, col, row);
                                insert_image_sqlite(entry_path, zoom, col, row, &connection)
                            })
                    })
                })
                .unwrap_or_else(|err| error!("{}", err))
        }
        info!("{}", entry.path().display());
    }
    Ok(())
}

fn parse_comp(component: Component) -> Result<String, MBTileError> {
    if let Component::Normal(os_str) = component {
        os_str.to_str()
              .ok_or(MBTileError {
                  message: format!("Unvalid unicode path: {:?}", os_str),
                  inner_error: InnerError::None,
              })
              .map(|s| s.to_owned())
    } else {
        Err(MBTileError {
            message: format!("Can't read path component {:?}", component),
            inner_error: InnerError::None,
        })
    }
}

fn parse_zoom_dir(component: Component, flag_scheme: Scheme) -> Result<u32, MBTileError> {
    let mut zoom_string = try!(parse_comp(component));
    if let Scheme::Ags = flag_scheme {
        if !zoom_string.contains('L') {
            warn!("You appear to be using an ags scheme on an non-arcgis Server cache.");
        }
        zoom_string = zoom_string.replace("L", "");
    }
    Ok(try_desc!(zoom_string.parse::<u32>(),
                 "Can't parse component in integer format"))
}

fn parse_image_dir(component: Component, flag_scheme: Scheme) -> Result<u32, MBTileError> {
    let mut radix = 10u32;
    let mut x_string = try!(parse_comp(component));
    if let Scheme::Ags = flag_scheme {
        x_string = x_string.replace("R", "");
        radix = 16;
    }
    Ok(try_desc!(u32::from_str_radix(x_string.as_str(), radix),
                 "Can't parse component in integer format"))
}

fn parse_image_filename(component: Component,
                        flag_scheme: Scheme,
                        image_format: ImageFormat)
                        -> Result<u32, MBTileError> {
    let mut radix = 10u32;
    let mut x_string = try!(parse_comp(component));
    let mut x_part: String; //espace E0506 for s
    {
        let parts: Vec<&str> = x_string.split('.').collect();
        let filtered_extension = get_extension(image_format);
        if parts[1] == filtered_extension {
            x_part = parts[0].to_owned();
        } else {
            return Err(MBTileError {
                message: format!("The filtered extention {} is different than the path's \
                         extention {}",
                                 filtered_extension,
                                 parts[1]),
                inner_error: InnerError::None,
            });
        }
        if let Scheme::Ags = flag_scheme {
            x_part = x_string.replace("C", "");
            radix = 16;
        }
    }
    x_string = x_part;
    Ok(try_desc!(u32::from_str_radix(x_string.as_str(), radix),
                 "Can't parse component in integer format"))
}

fn insert_image_sqlite(image_path: &Path,
                       zoom: u32,
                       column: u32,
                       row: u32,
                       connection: &Connection)
                       -> Result<(), MBTileError> {
    let mut image_file = try_desc!(File::open(image_path),
                                   format!("Can't open {:?}", image_path));
    let mut buffer = Vec::new();
    try_desc!(image_file.read_to_end(&mut buffer),
              format!("Can't read file {:?}", image_path));
    try_desc!(connection.execute("insert into tiles (zoom_level,
                    tile_column, tile_row, tile_data) values
                    ($1, $2, $3, $4);",
                                 &[&(zoom as i64), &(column as i64), &(row as i64), &buffer]),
              format!("Can't insert {:?}", image_path));
    Ok(())
}

pub fn export(input: String,
              output: Option<String>,
              flag_scheme: Scheme,
              flag_image_format: ImageFormat,
              flag_grid_callback: String) {
    let input_path = Path::new(&input);
    if input_path.is_file() {
    } else {
        error!("Can only export from a file")
    }
}

pub fn metadata(input: String,
                output: Option<String>,
                flag_scheme: Scheme,
                flag_image_format: ImageFormat,
                flag_grid_callback: String) {
    let input_path = Path::new(&input);
    if input_path.is_file() {
    } else {
        error!("Can only dumps from a file")
    }
}
<|endoftext|>


<commit_before>use circular::Buffer;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::Read;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

fn main() {
    better_panic::install();
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let _id: u64 = ((seek.id[0] as u64) << 24)
                            | ((seek.id[1] as u64) << 16)
                            | ((seek.id[2] as u64) << 8)
                            | seek.id[3] as u64;

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!(
                            "|  + Seek position: {} size {}",
                            seek.position, position_size
                        );
                    }

                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    panic!(
                        "unexpected seek head, info or tracks element: {:?}",
                        element
                    );
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                    //eprintln!("got a cluster: {:#?}", c);
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    panic!(
                        "offset {:X?}: got unknown element: {:X?} {:#?}",
                        _consumed, id, data
                    );
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<commit_msg>more output in matroska info (#49)<commit_after>use circular::Buffer;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::Read;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

fn main() {
    better_panic::install();
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Document type: {}", header.doc_type);
            println!("|+ Document type version: {}", header.doc_type_version);
            println!(
                "|+ Document type read version: {}",
                header.doc_type_read_version
            );

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let _id: u64 = ((seek.id[0] as u64) << 24)
                            | ((seek.id[1] as u64) << 16)
                            | ((seek.id[2] as u64) << 8)
                            | seek.id[3] as u64;

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!(
                            "|  + Seek position: {} size {}",
                            seek.position, position_size
                        );
                    }

                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    panic!(
                        "unexpected seek head, info or tracks element: {:?}",
                        element
                    );
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                    //eprintln!("got a cluster: {:#?}", c);
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    panic!(
                        "offset {:X?}: got unknown element: {:X?} {:#?}",
                        _consumed, id, data
                    );
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::ptr;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;

use llvm::prelude::*;
use llvm::core::*;
use llvm::target_machine::*;
use llvm::target::*;
use ast::IntSize;
use target::Target;

unsafe fn create_target_machine() -> Result<(String, LLVMTargetMachineRef), String>
{
    let target_triple = LLVMGetDefaultTargetTriple();
    let target_triple_str = CStr::from_ptr(target_triple).to_str().expect("Invalid target triple");

    let mut target: LLVMTargetRef = ptr::null_mut();
    let mut error_message: *mut c_char = ptr::null_mut();
    if LLVMGetTargetFromTriple(target_triple, &mut target, &mut error_message) != 0 {
        let msg = CStr::from_ptr(error_message).to_str().expect("Invalid C string");
        let e = format!("Unable to get an LLVM target reference for {}: {}", target_triple_str, msg);
        LLVMDisposeMessage(error_message);
        LLVMDisposeMessage(target_triple);
        return Err(e);
    }

    let target_machine = LLVMCreateTargetMachine(
        target,
        target_triple,
        cstr!(""),
        cstr!(""),
        LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
        LLVMRelocMode::LLVMRelocPIC,
        LLVMCodeModel::LLVMCodeModelDefault,
    );

    LLVMDisposeMessage(target_triple);
    if target_machine.is_null() {
        let e = format!("Unable to get a LLVM target machine for {}", target_triple_str);
        return Err(e);
    }

    Ok((target_triple_str.into(), target_machine))
}

pub struct TargetMachine
{
    pub target_machine: LLVMTargetMachineRef,
    pub target_data: LLVMTargetDataRef,
    pub target: Target
}

impl TargetMachine
{
    pub unsafe fn new() -> Result<TargetMachine, String>
    {
        let (target_triplet, target_machine) = create_target_machine()?;
        let target_data = LLVMCreateTargetDataLayout(target_machine);
        let int_size = match LLVMPointerSize(target_data) {
            1 => IntSize::I8,
            2 => IntSize::I16,
            4 => IntSize::I32,
            8 => IntSize::I64,
            v => panic!("Not supported native integer size: {}", v),
        };

        Ok(TargetMachine{
            target_machine,
            target_data,
            target: Target::new(int_size, target_triplet)
        })
    }

    pub unsafe fn size_of_type(&self, typ: LLVMTypeRef) -> usize
    {
        LLVMStoreSizeOfType(self.target_data, typ) as usize
    }

    pub unsafe fn emit_to_file(&self, module: LLVMModuleRef, obj_file_name: &str) -> Result<(), String>
    {
        let mut error_message: *mut c_char = ptr::null_mut();
        let obj_file_name = CString::new(obj_file_name).expect("Invalid String");
        if LLVMTargetMachineEmitToFile(self.target_machine, module, obj_file_name.into_raw(), LLVMCodeGenFileType::LLVMObjectFile, &mut error_message) != 0 {
            let msg = CStr::from_ptr(error_message).to_str().expect("Invalid C string");
            let e = format!("Unable to create object file: {}", msg);
            LLVMDisposeMessage(error_message);
            return Err(e);
        }
        Ok(())
    }
}

impl Drop for TargetMachine
{
    fn drop(&mut self)
    {
        unsafe {
            LLVMDisposeTargetMachine(self.target_machine);
            LLVMDisposeTargetData(self.target_data);
        }
    }
}
<commit_msg>Fix use after free bug<commit_after>use std::ptr;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;

use llvm::prelude::*;
use llvm::core::*;
use llvm::target_machine::*;
use llvm::target::*;
use ast::IntSize;
use target::Target;

unsafe fn create_target_machine() -> Result<(String, LLVMTargetMachineRef), String>
{
    let target_triple = LLVMGetDefaultTargetTriple();
    let target_triple_str = CStr::from_ptr(target_triple).to_str().expect("Invalid target triple").to_owned();

    let mut target: LLVMTargetRef = ptr::null_mut();
    let mut error_message: *mut c_char = ptr::null_mut();
    if LLVMGetTargetFromTriple(target_triple, &mut target, &mut error_message) != 0 {
        let msg = CStr::from_ptr(error_message).to_str().expect("Invalid C string");
        let e = format!("Unable to get an LLVM target reference for {}: {}", target_triple_str, msg);
        LLVMDisposeMessage(error_message);
        LLVMDisposeMessage(target_triple);
        return Err(e);
    }

    let target_machine = LLVMCreateTargetMachine(
        target,
        target_triple,
        cstr!(""),
        cstr!(""),
        LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
        LLVMRelocMode::LLVMRelocPIC,
        LLVMCodeModel::LLVMCodeModelDefault,
    );

    LLVMDisposeMessage(target_triple);
    if target_machine.is_null() {
        let e = format!("Unable to get a LLVM target machine for {}", target_triple_str);
        return Err(e);
    }

    Ok((target_triple_str, target_machine))
}

pub struct TargetMachine
{
    pub target_machine: LLVMTargetMachineRef,
    pub target_data: LLVMTargetDataRef,
    pub target: Target
}

impl TargetMachine
{
    pub unsafe fn new() -> Result<TargetMachine, String>
    {
        let (target_triplet, target_machine) = create_target_machine()?;
        let target_data = LLVMCreateTargetDataLayout(target_machine);
        let int_size = match LLVMPointerSize(target_data) {
            1 => IntSize::I8,
            2 => IntSize::I16,
            4 => IntSize::I32,
            8 => IntSize::I64,
            v => panic!("Not supported native integer size: {}", v),
        };

        Ok(TargetMachine{
            target_machine,
            target_data,
            target: Target::new(int_size, target_triplet)
        })
    }

    pub unsafe fn size_of_type(&self, typ: LLVMTypeRef) -> usize
    {
        LLVMStoreSizeOfType(self.target_data, typ) as usize
    }

    pub unsafe fn emit_to_file(&self, module: LLVMModuleRef, obj_file_name: &str) -> Result<(), String>
    {
        let mut error_message: *mut c_char = ptr::null_mut();
        let obj_file_name = CString::new(obj_file_name).expect("Invalid String");
        if LLVMTargetMachineEmitToFile(self.target_machine, module, obj_file_name.into_raw(), LLVMCodeGenFileType::LLVMObjectFile, &mut error_message) != 0 {
            let msg = CStr::from_ptr(error_message).to_str().expect("Invalid C string");
            let e = format!("Unable to create object file: {}", msg);
            LLVMDisposeMessage(error_message);
            return Err(e);
        }
        Ok(())
    }
}

impl Drop for TargetMachine
{
    fn drop(&mut self)
    {
        unsafe {
            LLVMDisposeTargetMachine(self.target_machine);
            LLVMDisposeTargetData(self.target_data);
        }
    }
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

use super::register::{register_to_iced, Register};
use wasm_bindgen::prelude::*;

/// Memory operand passed to one of [`Instruction`]'s `create*()` constructor methods
///
/// [`Instruction`]: struct.Instruction.html
#[wasm_bindgen]
pub struct MemoryOperand(pub(crate) iced_x86_rust::MemoryOperand);

#[wasm_bindgen]
impl MemoryOperand {
	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(constructor)]
	pub fn new(
		base: Register, index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32,
		#[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::new(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleBcstSeg")]
	pub fn with_base_index_scale_bcst_seg(
		base: Register, index: Register, scale: u32, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_bcst_seg(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSizeBcstSeg")]
	pub fn with_base_displ_size_bcst_seg(
		base: Register, displacement: i32, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size_bcst_seg(
			register_to_iced(base),
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSizeBcstSeg")]
	pub fn with_index_scale_displ_size_bcst_seg(
		index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size_bcst_seg(
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplBcstSeg")]
	pub fn with_base_displ_bcst_seg(
		base: Register, displacement: i32, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_bcst_seg(register_to_iced(base), displacement, isBroadcast, register_to_iced(segmentPrefix)))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleDisplSize")]
	pub fn with_base_index_scale_displ_size(
		base: Register, index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_displ_size(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScale")]
	pub fn with_base_index_scale(base: Register, index: Register, scale: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale(register_to_iced(base), register_to_iced(index), scale))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndex")]
	pub fn with_base_index(base: Register, index: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index(register_to_iced(base), register_to_iced(index)))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSize")]
	pub fn with_base_displ_size(base: Register, displacement: i32, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size(register_to_iced(base), displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSize")]
	pub fn with_index_scale_displ_size(index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size(register_to_iced(index), scale, displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDispl")]
	pub fn with_base_displ(base: Register, displacement: i32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ(register_to_iced(base), displacement))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBase")]
	pub fn with_base(base: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base(register_to_iced(base)))
	}
}
<commit_msg>rustfmt<commit_after>/*
Copyright (C) 2018-2019 de4dot@gmail.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

use super::register::{register_to_iced, Register};
use wasm_bindgen::prelude::*;

/// Memory operand passed to one of [`Instruction`]'s `create*()` constructor methods
///
/// [`Instruction`]: struct.Instruction.html
#[wasm_bindgen]
pub struct MemoryOperand(pub(crate) iced_x86_rust::MemoryOperand);

#[wasm_bindgen]
impl MemoryOperand {
	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(constructor)]
	pub fn new(
		base: Register, index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32,
		#[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::new(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleBcstSeg")]
	pub fn with_base_index_scale_bcst_seg(
		base: Register, index: Register, scale: u32, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_bcst_seg(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSizeBcstSeg")]
	pub fn with_base_displ_size_bcst_seg(
		base: Register, displacement: i32, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size_bcst_seg(
			register_to_iced(base),
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSizeBcstSeg")]
	pub fn with_index_scale_displ_size_bcst_seg(
		index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32, #[allow(non_snake_case)] isBroadcast: bool,
		#[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size_bcst_seg(
			register_to_iced(index),
			scale,
			displacement,
			displSize,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `isBroadcast`: `true` if it's broadcasted memory (EVEX instructions)
	/// * `segmentPrefix`: Segment override or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplBcstSeg")]
	pub fn with_base_displ_bcst_seg(
		base: Register, displacement: i32, #[allow(non_snake_case)] isBroadcast: bool, #[allow(non_snake_case)] segmentPrefix: Register,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_bcst_seg(
			register_to_iced(base),
			displacement,
			isBroadcast,
			register_to_iced(segmentPrefix),
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScaleDisplSize")]
	pub fn with_base_index_scale_displ_size(
		base: Register, index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32,
	) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale_displ_size(
			register_to_iced(base),
			register_to_iced(index),
			scale,
			displacement,
			displSize,
		))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndexScale")]
	pub fn with_base_index_scale(base: Register, index: Register, scale: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index_scale(register_to_iced(base), register_to_iced(index), scale))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseIndex")]
	pub fn with_base_index(base: Register, index: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_index(register_to_iced(base), register_to_iced(index)))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDisplSize")]
	pub fn with_base_displ_size(base: Register, displacement: i32, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ_size(register_to_iced(base), displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `index`: Index register or [`Register.None`] (a [`Register`] value)
	/// * `scale`: Index register scale (1, 2, 4, or 8)
	/// * `displacement`: Memory displacement
	/// * `displSize`: 0 (no displ), 1 (16/32/64-bit, but use 2/4/8 if it doesn't fit in a `i8`), 2 (16-bit), 4 (32-bit) or 8 (64-bit)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createIndexScaleDisplSize")]
	pub fn with_index_scale_displ_size(index: Register, scale: u32, displacement: i32, #[allow(non_snake_case)] displSize: u32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_index_scale_displ_size(register_to_iced(index), scale, displacement, displSize))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	/// * `displacement`: Memory displacement
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBaseDispl")]
	pub fn with_base_displ(base: Register, displacement: i32) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base_displ(register_to_iced(base), displacement))
	}

	/// Constructor
	///
	/// # Arguments
	///
	/// * `base`: Base register or [`Register.None`] (a [`Register`] value)
	///
	/// [`Register`]: enum.Register.html
	/// [`Register.None`]: enum.Register.html#variant.None
	#[wasm_bindgen(js_name = "createBase")]
	pub fn with_base(base: Register) -> Self {
		Self(iced_x86_rust::MemoryOperand::with_base(register_to_iced(base)))
	}
}
<|endoftext|>