sim_lib_midi_smf/
limits.rs1#![forbid(unsafe_code)]
2
3use crate::{SmfError, SmfLimitKind};
4
5#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub struct SmfReadLimits {
13 pub max_file_bytes: usize,
15 pub max_header_bytes: usize,
17 pub max_tracks: usize,
19 pub max_track_bytes: usize,
21 pub max_events: usize,
23 pub max_event_payload_bytes: usize,
25 pub max_total_payload_bytes: usize,
27}
28
29impl Default for SmfReadLimits {
30 fn default() -> Self {
31 Self {
32 max_file_bytes: 64 * 1024 * 1024,
33 max_header_bytes: 1024,
34 max_tracks: 1024,
35 max_track_bytes: 16 * 1024 * 1024,
36 max_events: 1_000_000,
37 max_event_payload_bytes: 1024 * 1024,
38 max_total_payload_bytes: 16 * 1024 * 1024,
39 }
40 }
41}
42
43#[derive(Debug)]
44pub(crate) struct ReadBudget {
45 limits: SmfReadLimits,
46 events: usize,
47 payload_bytes: usize,
48}
49
50impl ReadBudget {
51 pub(crate) fn new(limits: SmfReadLimits) -> Self {
52 Self {
53 limits,
54 events: 0,
55 payload_bytes: 0,
56 }
57 }
58
59 pub(crate) fn claim_event(&mut self, offset: usize) -> Result<(), SmfError> {
60 let actual = self.events.checked_add(1).ok_or(SmfError::LimitExceeded {
61 offset,
62 kind: SmfLimitKind::EventCount,
63 actual: usize::MAX,
64 maximum: self.limits.max_events,
65 })?;
66 enforce_limit(
67 offset,
68 SmfLimitKind::EventCount,
69 actual,
70 self.limits.max_events,
71 )?;
72 self.events = actual;
73 Ok(())
74 }
75
76 pub(crate) fn claim_payload(&mut self, offset: usize, len: usize) -> Result<(), SmfError> {
77 enforce_limit(
78 offset,
79 SmfLimitKind::EventPayloadBytes,
80 len,
81 self.limits.max_event_payload_bytes,
82 )?;
83 let total = self
84 .payload_bytes
85 .checked_add(len)
86 .ok_or(SmfError::LimitExceeded {
87 offset,
88 kind: SmfLimitKind::TotalPayloadBytes,
89 actual: usize::MAX,
90 maximum: self.limits.max_total_payload_bytes,
91 })?;
92 enforce_limit(
93 offset,
94 SmfLimitKind::TotalPayloadBytes,
95 total,
96 self.limits.max_total_payload_bytes,
97 )?;
98 self.payload_bytes = total;
99 Ok(())
100 }
101}
102
103pub(crate) fn enforce_limit(
104 offset: usize,
105 kind: SmfLimitKind,
106 actual: usize,
107 maximum: usize,
108) -> Result<(), SmfError> {
109 if actual > maximum {
110 return Err(SmfError::LimitExceeded {
111 offset,
112 kind,
113 actual,
114 maximum,
115 });
116 }
117 Ok(())
118}