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:
parent
e64ae362ef
commit
56d36f2732
|
@ -345,7 +345,7 @@ impl ConvertedChart {
|
||||||
},
|
},
|
||||||
difficulty: beatmap::Difficulty {
|
difficulty: beatmap::Difficulty {
|
||||||
hp_drain_rate: config.hp_drain.map_from(self.difficulty.clone().into()),
|
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()),
|
overall_difficulty: config.accuracy.map_from(self.difficulty.clone().into()),
|
||||||
approach_rate: 8.0,
|
approach_rate: 8.0,
|
||||||
slider_multiplier: 0.64,
|
slider_multiplier: 0.64,
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::num;
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, LE};
|
use byteorder::{ReadBytesExt, LE};
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
|
@ -12,7 +13,7 @@ use thiserror::Error;
|
||||||
use crate::mini_parser::{MiniParser, MiniParserError};
|
use crate::mini_parser::{MiniParser, MiniParserError};
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
const MEASURE_LENGTH: i32 = 4096;
|
const MEASURE_LENGTH: f32 = 4096.0;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -21,7 +22,7 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
IOError(#[from] io::Error),
|
IOError(#[from] io::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
TryFromIntError(#[from] std::num::TryFromIntError),
|
TryFromIntError(#[from] num::TryFromIntError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
MiniParserError(#[from] MiniParserError),
|
MiniParserError(#[from] MiniParserError),
|
||||||
}
|
}
|
||||||
|
@ -29,7 +30,7 @@ pub enum Error {
|
||||||
/// Convert time offset to beats
|
/// Convert time offset to beats
|
||||||
/// time offset is the measure times MEASURE_LENGTH
|
/// time offset is the measure times MEASURE_LENGTH
|
||||||
fn measure_to_beats(metric: i32) -> f32 {
|
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)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
|
@ -385,7 +386,7 @@ impl SSQ {
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let length = cursor.read_i32::<LE>()? as usize;
|
let length: usize = cursor.read_i32::<LE>()?.try_into()?;
|
||||||
trace!("Found chunk (length {})", length);
|
trace!("Found chunk (length {})", length);
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
break;
|
break;
|
||||||
|
@ -401,7 +402,7 @@ impl SSQ {
|
||||||
match chunk_type {
|
match chunk_type {
|
||||||
1 => {
|
1 => {
|
||||||
debug!("Parsing tempo changes (ticks/s: {})", parameter);
|
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 => {
|
3 => {
|
||||||
debug!("Parsing step chunk ({})", Difficulty::from(parameter));
|
debug!("Parsing step chunk ({})", Difficulty::from(parameter));
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#![warn(clippy::cast_lossless)]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use(quickcheck)]
|
#[macro_use(quickcheck)]
|
||||||
extern crate quickcheck_macros;
|
extern crate quickcheck_macros;
|
||||||
|
|
|
@ -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 {
|
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)]
|
#[derive(ToPrimitive, Clone)]
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::io::{Cursor, Write};
|
use std::io::{Cursor, Write};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
const COEFFS: &[CoefSet] = &[
|
const COEFFS: &[CoefSet] = &[
|
||||||
|
@ -14,6 +16,12 @@ const COEFFS: &[CoefSet] = &[
|
||||||
(392, -232),
|
(392, -232),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("unable to create file of size {0} (larger than 2^32)")]
|
||||||
|
TooLarge(usize),
|
||||||
|
}
|
||||||
|
|
||||||
trait WaveChunk {
|
trait WaveChunk {
|
||||||
fn to_chunk(&self) -> Vec<u8>;
|
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");
|
debug!("Building file");
|
||||||
|
let length: u32 = data
|
||||||
|
.len()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| Error::TooLarge(data.len()))?;
|
||||||
|
|
||||||
let riff_header = RIFFHeader {
|
let riff_header = RIFFHeader {
|
||||||
file_size: 82 + data.len() as u32,
|
file_size: 82 + length,
|
||||||
};
|
};
|
||||||
|
|
||||||
let fact = WaveFact {
|
let fact = WaveFact {
|
||||||
length_samples: ((data.len() as u32 / format.n_block_align as u32)
|
length_samples: ((length / u32::from(format.n_block_align))
|
||||||
* ((format.n_block_align - (7 * format.n_channels)) * 8) as u32
|
* u32::from((format.n_block_align - (7 * format.n_channels)) * 8)
|
||||||
/ 4)
|
/ 4)
|
||||||
/ format.n_channels as u32,
|
/ u32::from(format.n_channels),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = Cursor::new(Vec::new());
|
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();
|
buf.write_all(&fact.to_chunk()).unwrap();
|
||||||
|
|
||||||
write!(buf, "data").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.write_all(data).unwrap();
|
||||||
|
|
||||||
buf.into_inner()
|
Ok(buf.into_inner())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::num;
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, LE};
|
use byteorder::{ReadBytesExt, LE};
|
||||||
use log::{debug, info, trace, warn};
|
use log::{debug, info, trace, warn};
|
||||||
|
@ -23,6 +24,10 @@ pub enum Error {
|
||||||
IOError(#[from] io::Error),
|
IOError(#[from] io::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
MiniParserError(#[from] MiniParserError),
|
MiniParserError(#[from] MiniParserError),
|
||||||
|
#[error(transparent)]
|
||||||
|
ADPCMError(#[from] adpcm::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
TryFromIntError(#[from] num::TryFromIntError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, FromPrimitive, Debug, PartialEq)]
|
#[derive(Clone, FromPrimitive, Debug, PartialEq)]
|
||||||
|
@ -60,11 +65,11 @@ impl TryInto<adpcm::WaveFormat> for Format {
|
||||||
return Err(Error::UnsupportedFormat(self.tag));
|
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 =
|
let n_samples_per_block =
|
||||||
(((n_block_align - (7 * self.channels)) * 8) / (4 * self.channels)) + 2;
|
(((n_block_align - (7 * self.channels)) * 8) / (4 * self.channels)) + 2;
|
||||||
let n_avg_bytes_per_sec =
|
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 {
|
Ok(adpcm::WaveFormat {
|
||||||
n_channels: self.channels,
|
n_channels: self.channels,
|
||||||
|
@ -113,8 +118,8 @@ impl Header {
|
||||||
let offset = cursor.read_u32::<LE>()?;
|
let offset = cursor.read_u32::<LE>()?;
|
||||||
let length = cursor.read_u32::<LE>()?;
|
let length = cursor.read_u32::<LE>()?;
|
||||||
segment_positions.push(SegmentPosition {
|
segment_positions.push(SegmentPosition {
|
||||||
offset: offset as usize,
|
offset: offset.try_into()?,
|
||||||
length: length as usize,
|
length: length.try_into()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Ok(Header { segment_positions })
|
Ok(Header { segment_positions })
|
||||||
|
@ -145,9 +150,9 @@ impl Info {
|
||||||
let _build_time = cursor.read_u32::<LE>()?;
|
let _build_time = cursor.read_u32::<LE>()?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
entry_count: entry_count as usize,
|
entry_count: entry_count.try_into()?,
|
||||||
name,
|
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 {
|
Ok(Self {
|
||||||
name: "".to_string(),
|
name: "".to_string(),
|
||||||
format: format.into(),
|
format: format.into(),
|
||||||
data_offset: data_offset as usize,
|
data_offset: data_offset.try_into()?,
|
||||||
data_length: data_length as usize,
|
data_length: data_length.try_into()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +269,10 @@ pub struct Sound<'a> {
|
||||||
impl Sound<'_> {
|
impl Sound<'_> {
|
||||||
pub fn to_wav(&self) -> Result<Vec<u8>, Error> {
|
pub fn to_wav(&self) -> Result<Vec<u8>, Error> {
|
||||||
match &self.format.tag {
|
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())),
|
_ => Err(Error::UnsupportedFormat(self.format.tag.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue