Skip to main content

ass_renderer/pipeline/
validation.rs

1//! Tag parameter validation module
2
3#[cfg(feature = "nostd")]
4use alloc::{format, string::ToString};
5#[cfg(not(feature = "nostd"))]
6use std::string::ToString;
7
8use crate::utils::RenderError;
9
10/// Validate alignment value (1-9 for numpad positions)
11pub fn validate_alignment(value: u8) -> Result<u8, RenderError> {
12    if (1..=9).contains(&value) {
13        Ok(value)
14    } else {
15        Err(RenderError::InvalidScript(format!(
16            "Invalid alignment value: {value}. Must be 1-9"
17        )))
18    }
19}
20
21/// Validate wrap style (0-3)
22pub fn validate_wrap_style(value: u8) -> Result<u8, RenderError> {
23    if value <= 3 {
24        Ok(value)
25    } else {
26        Err(RenderError::InvalidScript(format!(
27            "Invalid wrap style: {value}. Must be 0-3"
28        )))
29    }
30}
31
32/// Validate drawing mode level (0-4)
33pub fn validate_drawing_mode(value: u8) -> Result<u8, RenderError> {
34    if value <= 4 {
35        Ok(value)
36    } else {
37        Err(RenderError::InvalidScript(format!(
38            "Invalid drawing mode: {value}. Must be 0-4"
39        )))
40    }
41}
42
43/// Validate font size (must be positive)
44pub fn validate_font_size(value: f32) -> Result<f32, RenderError> {
45    if value > 0.0 && value < 1000.0 {
46        Ok(value)
47    } else {
48        Err(RenderError::InvalidScript(format!(
49            "Invalid font size: {value}. Must be positive and reasonable"
50        )))
51    }
52}
53
54/// Validate scale percentage (0-1000%)
55pub fn validate_scale(value: f32) -> Result<f32, RenderError> {
56    if (0.0..=1000.0).contains(&value) {
57        Ok(value)
58    } else {
59        Err(RenderError::InvalidScript(format!(
60            "Invalid scale: {value}%. Must be 0-1000"
61        )))
62    }
63}
64
65/// Validate rotation angle (degrees)
66pub fn validate_rotation(value: f32) -> Result<f32, RenderError> {
67    // Normalize to 0-360 range
68    let normalized = value % 360.0;
69    Ok(if normalized < 0.0 {
70        normalized + 360.0
71    } else {
72        normalized
73    })
74}
75
76/// Validate border width (non-negative)
77pub fn validate_border_width(value: f32) -> Result<f32, RenderError> {
78    if (0.0..100.0).contains(&value) {
79        Ok(value)
80    } else {
81        Err(RenderError::InvalidScript(format!(
82            "Invalid border width: {value}. Must be non-negative"
83        )))
84    }
85}
86
87/// Validate blur amount (non-negative)
88pub fn validate_blur(value: f32) -> Result<f32, RenderError> {
89    if (0.0..100.0).contains(&value) {
90        Ok(value)
91    } else {
92        Err(RenderError::InvalidScript(format!(
93            "Invalid blur: {value}. Must be non-negative"
94        )))
95    }
96}
97
98/// Validate color array (BGRA format)
99pub fn validate_color(color: [u8; 4]) -> Result<[u8; 4], RenderError> {
100    // Colors are already in valid u8 range
101    Ok(color)
102}
103
104/// Validate alpha value (0-255)
105pub fn validate_alpha(value: u8) -> Result<u8, RenderError> {
106    // u8 is already in valid range
107    Ok(value)
108}
109
110/// Validate time in milliseconds
111pub fn validate_time_ms(value: u32) -> Result<u32, RenderError> {
112    // Allow any u32 value for time
113    Ok(value)
114}
115
116/// Validate karaoke duration (centiseconds)
117pub fn validate_karaoke_duration(value: u32) -> Result<u32, RenderError> {
118    if value < 100000 {
119        // Max ~16 minutes per syllable
120        Ok(value)
121    } else {
122        Err(RenderError::InvalidScript(format!(
123            "Invalid karaoke duration: {value} centiseconds"
124        )))
125    }
126}
127
128/// Validate position coordinates
129pub fn validate_position(x: f32, y: f32) -> Result<(f32, f32), RenderError> {
130    // Allow negative values for off-screen positioning
131    if x.is_finite() && y.is_finite() {
132        Ok((x, y))
133    } else {
134        Err(RenderError::InvalidScript(
135            "Invalid position: coordinates must be finite".to_string(),
136        ))
137    }
138}
139
140/// Validate clipping rectangle
141pub fn validate_clip_rect(
142    x1: f32,
143    y1: f32,
144    x2: f32,
145    y2: f32,
146) -> Result<(f32, f32, f32, f32), RenderError> {
147    if x1.is_finite() && y1.is_finite() && x2.is_finite() && y2.is_finite() {
148        // Ensure x2 > x1 and y2 > y1
149        let (x1, x2) = if x1 <= x2 { (x1, x2) } else { (x2, x1) };
150        let (y1, y2) = if y1 <= y2 { (y1, y2) } else { (y2, y1) };
151        Ok((x1, y1, x2, y2))
152    } else {
153        Err(RenderError::InvalidScript(
154            "Invalid clip rectangle: coordinates must be finite".to_string(),
155        ))
156    }
157}
158
159/// Validate font encoding (0-255, though only specific values are meaningful)
160pub fn validate_font_encoding(value: u8) -> Result<u8, RenderError> {
161    // Common encodings: 0 (ANSI), 1 (Default), 128 (Shift-JIS), 134 (GB2312), etc.
162    Ok(value)
163}
164
165/// Validate shear/perspective factor
166pub fn validate_shear(value: f32) -> Result<f32, RenderError> {
167    if (-2.0..=2.0).contains(&value) {
168        Ok(value)
169    } else {
170        Err(RenderError::InvalidScript(format!(
171            "Invalid shear factor: {value}. Should be between -2 and 2"
172        )))
173    }
174}
175
176/// Validate acceleration factor for transforms
177pub fn validate_acceleration(value: f32) -> Result<f32, RenderError> {
178    if value > 0.0 && value < 100.0 {
179        Ok(value)
180    } else {
181        Err(RenderError::InvalidScript(format!(
182            "Invalid acceleration: {value}. Must be positive"
183        )))
184    }
185}