Avoid truncation

Error where truncation can occurr and prevent truncation in the future
by using `type::from()` (which checks for truncation) instead of `as
type` (which doesn’t).
This commit is contained in:
Simon Bruder 2020-06-27 19:43:50 +02:00
parent e64ae362ef
commit 56d36f2732
No known key found for this signature in database
GPG key ID: 6F03E0000CC5B62F
6 changed files with 47 additions and 23 deletions

View file

@ -345,7 +345,7 @@ impl ConvertedChart {
},
difficulty: beatmap::Difficulty {
hp_drain_rate: config.hp_drain.map_from(self.difficulty.clone().into()),
circle_size: self.difficulty.players as f32 * 4.0,
circle_size: f32::from(self.difficulty.players) * 4.0,
overall_difficulty: config.accuracy.map_from(self.difficulty.clone().into()),
approach_rate: 8.0,
slider_multiplier: 0.64,

View file

@ -4,6 +4,7 @@ use std::fmt;
use std::io;
use std::io::prelude::*;
use std::io::Cursor;
use std::num;
use byteorder::{ReadBytesExt, LE};
use log::{debug, info, trace, warn};
@ -12,7 +13,7 @@ use thiserror::Error;
use crate::mini_parser::{MiniParser, MiniParserError};
use crate::utils;
const MEASURE_LENGTH: i32 = 4096;
const MEASURE_LENGTH: f32 = 4096.0;
#[derive(Error, Debug)]
pub enum Error {
@ -21,7 +22,7 @@ pub enum Error {
#[error(transparent)]
IOError(#[from] io::Error),
#[error(transparent)]
TryFromIntError(#[from] std::num::TryFromIntError),
TryFromIntError(#[from] num::TryFromIntError),
#[error(transparent)]
MiniParserError(#[from] MiniParserError),
}
@ -29,7 +30,7 @@ pub enum Error {
/// Convert time offset to beats
/// time offset is the measure times MEASURE_LENGTH
fn measure_to_beats(metric: i32) -> f32 {
4.0 * metric as f32 / MEASURE_LENGTH as f32
4.0 * metric as f32 / MEASURE_LENGTH
}
#[derive(Debug, Clone, PartialEq, Default)]
@ -385,7 +386,7 @@ impl SSQ {
};
loop {
let length = cursor.read_i32::<LE>()? as usize;
let length: usize = cursor.read_i32::<LE>()?.try_into()?;
trace!("Found chunk (length {})", length);
if length == 0 {
break;
@ -401,7 +402,7 @@ impl SSQ {
match chunk_type {
1 => {
debug!("Parsing tempo changes (ticks/s: {})", parameter);
ssq.tempo_changes = TempoChanges::parse(parameter as i32, &data)?;
ssq.tempo_changes = TempoChanges::parse(parameter.into(), &data)?;
}
3 => {
debug!("Parsing step chunk ({})", Difficulty::from(parameter));

View file

@ -1,3 +1,5 @@
#![warn(clippy::cast_lossless)]
#[cfg(test)]
#[macro_use(quickcheck)]
extern crate quickcheck_macros;

View file

@ -29,7 +29,7 @@ fn assemble_hit_object_type(hit_object_type: u8, new_combo: bool, skip_combo_col
}
pub fn column_to_x(column: u8, columns: u8) -> OsuPixel {
((512 * column as OsuPixel + 256) / columns as OsuPixel) as OsuPixel
(512 * OsuPixel::from(column) + 256) / OsuPixel::from(columns)
}
#[derive(ToPrimitive, Clone)]

View file

@ -1,7 +1,9 @@
use std::convert::TryInto;
use std::io::{Cursor, Write};
use byteorder::{LittleEndian, WriteBytesExt};
use log::{debug, trace};
use thiserror::Error;
#[rustfmt::skip]
const COEFFS: &[CoefSet] = &[
@ -14,6 +16,12 @@ const COEFFS: &[CoefSet] = &[
(392, -232),
];
#[derive(Debug, Error)]
pub enum Error {
#[error("unable to create file of size {0} (larger than 2^32)")]
TooLarge(usize),
}
trait WaveChunk {
fn to_chunk(&self) -> Vec<u8>;
}
@ -87,17 +95,22 @@ impl WaveChunk for RIFFHeader {
}
}
pub fn build_wav(format: WaveFormat, data: &[u8]) -> Vec<u8> {
pub fn build_wav(format: WaveFormat, data: &[u8]) -> Result<Vec<u8>, Error> {
debug!("Building file");
let length: u32 = data
.len()
.try_into()
.map_err(|_| Error::TooLarge(data.len()))?;
let riff_header = RIFFHeader {
file_size: 82 + data.len() as u32,
file_size: 82 + length,
};
let fact = WaveFact {
length_samples: ((data.len() as u32 / format.n_block_align as u32)
* ((format.n_block_align - (7 * format.n_channels)) * 8) as u32
length_samples: ((length / u32::from(format.n_block_align))
* u32::from((format.n_block_align - (7 * format.n_channels)) * 8)
/ 4)
/ format.n_channels as u32,
/ u32::from(format.n_channels),
};
let mut buf = Cursor::new(Vec::new());
@ -110,8 +123,8 @@ pub fn build_wav(format: WaveFormat, data: &[u8]) -> Vec<u8> {
buf.write_all(&fact.to_chunk()).unwrap();
write!(buf, "data").unwrap();
buf.write_u32::<LittleEndian>(data.len() as u32).unwrap();
buf.write_u32::<LittleEndian>(length).unwrap();
buf.write_all(data).unwrap();
buf.into_inner()
Ok(buf.into_inner())
}

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::convert::TryInto;
use std::io;
use std::io::Cursor;
use std::num;
use byteorder::{ReadBytesExt, LE};
use log::{debug, info, trace, warn};
@ -23,6 +24,10 @@ pub enum Error {
IOError(#[from] io::Error),
#[error(transparent)]
MiniParserError(#[from] MiniParserError),
#[error(transparent)]
ADPCMError(#[from] adpcm::Error),
#[error(transparent)]
TryFromIntError(#[from] num::TryFromIntError),
}
#[derive(Clone, FromPrimitive, Debug, PartialEq)]
@ -60,11 +65,11 @@ impl TryInto<adpcm::WaveFormat> for Format {
return Err(Error::UnsupportedFormat(self.tag));
}
let n_block_align = (self.alignment as u16 + 22) * self.channels;
let n_block_align = (u16::from(self.alignment) + 22) * self.channels;
let n_samples_per_block =
(((n_block_align - (7 * self.channels)) * 8) / (4 * self.channels)) + 2;
let n_avg_bytes_per_sec =
(self.sample_rate / n_samples_per_block as u32) * n_block_align as u32;
(self.sample_rate / u32::from(n_samples_per_block)) * u32::from(n_block_align);
Ok(adpcm::WaveFormat {
n_channels: self.channels,
@ -113,8 +118,8 @@ impl Header {
let offset = cursor.read_u32::<LE>()?;
let length = cursor.read_u32::<LE>()?;
segment_positions.push(SegmentPosition {
offset: offset as usize,
length: length as usize,
offset: offset.try_into()?,
length: length.try_into()?,
})
}
Ok(Header { segment_positions })
@ -145,9 +150,9 @@ impl Info {
let _build_time = cursor.read_u32::<LE>()?;
Ok(Self {
entry_count: entry_count as usize,
entry_count: entry_count.try_into()?,
name,
entry_name_element_size: entry_name_element_size as usize,
entry_name_element_size: entry_name_element_size.try_into()?,
})
}
}
@ -181,8 +186,8 @@ impl Entry {
Ok(Self {
name: "".to_string(),
format: format.into(),
data_offset: data_offset as usize,
data_length: data_length as usize,
data_offset: data_offset.try_into()?,
data_length: data_length.try_into()?,
})
}
}
@ -264,7 +269,10 @@ pub struct Sound<'a> {
impl Sound<'_> {
pub fn to_wav(&self) -> Result<Vec<u8>, Error> {
match &self.format.tag {
FormatTag::ADPCM => Ok(adpcm::build_wav(self.format.clone().try_into()?, self.data)),
FormatTag::ADPCM => Ok(adpcm::build_wav(
self.format.clone().try_into()?,
self.data,
)?),
_ => Err(Error::UnsupportedFormat(self.format.tag.clone())),
}
}