tramex_tools/
asn1_parser.rs1#![allow(missing_docs)]
7
8use pest::Parser;
9use pest_derive::Parser;
10use serde_json::{Map, Value, json};
11
12#[derive(Parser)]
14#[grammar = "asn1.pest"]
15struct ASN1Parser;
16
17pub fn parse_asn1_to_json(input: &str) -> Result<Value, String> {
44 let pairs = ASN1Parser::parse(Rule::asn1_value, input).map_err(|e| format!("ASN.1 parse error: {}", e))?;
45
46 for pair in pairs {
47 if let Some(inner_pair) = pair.into_inner().next() {
48 return parse_value(inner_pair);
49 }
50 }
51
52 Err("No value found in ASN.1 input".to_string())
53}
54
55fn parse_value(pair: pest::iterators::Pair<Rule>) -> Result<Value, String> {
61 match pair.as_rule() {
62 Rule::sequence => parse_sequence(pair),
63 Rule::choice => parse_choice(pair),
64 Rule::hex_string => Ok(parse_hex_string(pair.as_str())),
65 Rule::bit_string => Ok(parse_bit_string(pair.as_str())),
66 Rule::null_value => Ok(Value::Null),
67 Rule::number => {
68 let num_str = pair.as_str();
69 if let Ok(num) = num_str.parse::<i64>() {
70 Ok(json!(num))
71 } else {
72 Ok(Value::String(num_str.to_string()))
73 }
74 }
75 Rule::identifier => Ok(Value::String(pair.as_str().to_string())),
76 Rule::value => {
77 if let Some(inner) = pair.into_inner().next() {
79 parse_value(inner)
80 } else {
81 Err("Empty value".to_string())
82 }
83 }
84 _ => Err(format!("Unexpected rule: {:?}", pair.as_rule())),
85 }
86}
87
88fn parse_sequence(pair: pest::iterators::Pair<Rule>) -> Result<Value, String> {
94 let mut map = Map::new();
95 let mut array_items = Vec::new();
96 let mut has_named_fields = false;
97 let mut has_bare_values = false;
98
99 for inner in pair.into_inner() {
100 if inner.as_rule() == Rule::element_list {
101 for element_pair in inner.into_inner() {
102 if element_pair.as_rule() == Rule::element {
103 let mut element_parts = element_pair.into_inner();
105 if let Some(first) = element_parts.next() {
106 match first.as_rule() {
107 Rule::named_field => {
108 has_named_fields = true;
110 let mut field_parts = first.into_inner();
111 if let (Some(key_pair), Some(value_pair)) = (field_parts.next(), field_parts.next()) {
112 let key = key_pair.as_str().to_string();
113 let value = parse_value(value_pair)?;
114 map.insert(key, value);
115 }
116 }
117 _ => {
118 has_bare_values = true;
120 let value = parse_value(first)?;
121 array_items.push(value);
122 }
123 }
124 }
125 }
126 }
127 }
128 }
129
130 if has_bare_values && !has_named_fields {
132 Ok(Value::Array(array_items))
134 } else if has_named_fields {
135 Ok(Value::Object(map))
137 } else {
138 Ok(Value::Object(Map::new()))
140 }
141}
142
143fn parse_choice(pair: pest::iterators::Pair<Rule>) -> Result<Value, String> {
149 let mut parts = pair.into_inner();
150
151 if let (Some(tag), Some(value)) = (parts.next(), parts.next()) {
152 let mut map = Map::new();
153 map.insert(tag.as_str().to_string(), parse_value(value)?);
154 Ok(Value::Object(map))
155 } else {
156 Err("Invalid choice format".to_string())
157 }
158}
159
160fn parse_hex_string(s: &str) -> Value {
162 let hex = s.trim_start_matches('\'').trim_end_matches("'H");
164
165 if hex.len() <= 16
167 && let Ok(num) = u64::from_str_radix(hex, 16)
168 {
169 return json!({
170 "hex": hex,
171 "decimal": num
172 });
173 }
174
175 Value::String(format!("0x{}", hex))
177}
178
179fn parse_bit_string(s: &str) -> Value {
181 let bits = s.trim_start_matches('\'').trim_end_matches("'B");
183
184 if bits.len() <= 64
186 && let Ok(num) = u64::from_str_radix(bits, 2)
187 {
188 return json!({
189 "bits": bits,
190 "decimal": num
191 });
192 }
193
194 Value::String(format!("0b{}", bits))
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_simple_sequence() {
204 let asn1 = r#"{
205 q-RxLevMin -70,
206 q-QualMin -20
207 }"#;
208
209 let result = parse_asn1_to_json(asn1);
210 assert!(result.is_ok());
211
212 let json = result.unwrap();
213 assert_eq!(json["q-RxLevMin"], -70);
214 assert_eq!(json["q-QualMin"], -20);
215 }
216
217 #[test]
218 fn test_hex_string() {
219 let asn1 = r#"{
220 trackingAreaCode '000065'H,
221 cellIdentity '001234501'H
222 }"#;
223
224 let result = parse_asn1_to_json(asn1);
225 assert!(result.is_ok());
226 }
227
228 #[test]
229 fn test_nested_sequence() {
230 let asn1 = r#"{
231 cellSelectionInfo {
232 q-RxLevMin -70,
233 q-QualMin -20
234 }
235 }"#;
236
237 let result = parse_asn1_to_json(asn1);
238 assert!(result.is_ok());
239
240 let json = result.unwrap();
241 assert!(json["cellSelectionInfo"].is_object());
242 }
243
244 #[test]
245 fn test_array() {
246 let asn1 = r#"{
247 {
248 0,
249 0,
250 1
251 }
252 }"#;
253
254 let result = parse_asn1_to_json(asn1);
255 assert!(result.is_ok());
256
257 let json = result.unwrap();
258 assert!(json.is_array());
259 }
260
261 #[test]
262 fn test_choice() {
263 let asn1 = r#"{
264 c1: systemInformationBlockType1: {
265 cellSelectionInfo {
266 q-RxLevMin -70
267 }
268 }
269 }"#;
270
271 let result = parse_asn1_to_json(asn1);
272 assert!(result.is_ok());
273 }
274
275 #[test]
276 fn test_null_value() {
277 let asn1 = r#"{
278 someField NULL
279 }"#;
280
281 let result = parse_asn1_to_json(asn1);
282 assert!(result.is_ok());
283
284 let json = result.unwrap();
285 assert!(json["someField"].is_null());
286 }
287
288 #[test]
289 fn test_bit_string() {
290 let asn1 = r#"{
291 monitoringSymbolsWithinSlot '10000000000000'B
292 }"#;
293
294 let result = parse_asn1_to_json(asn1);
295 assert!(result.is_ok());
296 }
297}