1use serde_json::{json, Map, Value};
32use std::fmt;
33
34pub const MAX_PER_DEPTH: u32 = 40;
37pub const MAX_PER_NODES: usize = 20_000;
39pub const MAX_UNFRAGMENTED: usize = 16_383;
41
42#[derive(Debug, Clone, Copy)]
43pub struct Range {
44 pub lb: Option<i64>,
45 pub ub: Option<i64>,
46 pub ext: bool,
47}
48
49#[derive(Debug, Clone, Copy)]
50pub struct Size {
51 pub lb: u32,
52 pub ub: Option<u32>,
53 pub ext: bool,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum CharKind {
58 Ia5,
59 Bmp,
60 Numeric,
61 Printable,
62 General,
65}
66
67#[derive(Debug)]
68pub struct Field {
69 pub name: &'static str,
70 pub ty: u16,
71 pub optional: bool,
72}
73
74#[derive(Debug)]
75pub enum Ty {
76 Null,
77 Boolean,
78 Oid,
79 Int(Range),
80 Enum {
81 root: &'static [&'static str],
82 ext: Option<&'static [&'static str]>,
83 },
84 Octets(Size),
85 Bits(Size),
86 Chars {
87 kind: CharKind,
88 size: Size,
89 alphabet: Option<&'static str>,
90 },
91 Seq {
92 root: &'static [Field],
93 ext: Option<&'static [Field]>,
94 },
95 Choice {
96 root: &'static [Field],
97 ext: Option<&'static [Field]>,
98 },
99 SeqOf {
100 size: Size,
101 item: u16,
102 },
103 Alias(u16),
104 Opaque(&'static str),
105}
106
107#[derive(Debug, Clone, PartialEq, Eq)]
109pub struct PerError(pub String);
110
111impl fmt::Display for PerError {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.write_str(&self.0)
114 }
115}
116
117impl std::error::Error for PerError {}
118
119pub type PerResult<T> = Result<T, PerError>;
120
121fn ty(index: u16) -> &'static Ty {
122 &super::schema::TYPES[index as usize]
123}
124
125fn bits_for_range(range: u64) -> u32 {
127 if range <= 1 {
128 0
129 } else {
130 64 - (range - 1).leading_zeros()
131 }
132}
133
134fn octets_for(value: u64) -> usize {
135 let bits = 64 - value.leading_zeros() as usize;
136 bits.div_ceil(8).max(1)
137}
138
139fn alphabet(kind: CharKind, from: Option<&'static str>) -> (Vec<u32>, u32) {
142 let mut chars: Vec<u32> = match (from, kind) {
143 (Some(a), _) => a.chars().map(|c| c as u32).collect(),
144 (None, CharKind::Numeric) => " 0123456789".chars().map(|c| c as u32).collect(),
145 (None, CharKind::Printable) => {
146 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?"
147 .chars()
148 .map(|c| c as u32)
149 .collect()
150 }
151 (None, CharKind::Ia5) => (0..128).collect(),
152 (None, CharKind::Bmp) => Vec::new(),
153 (None, CharKind::General) => (0..256).collect(),
154 };
155 chars.sort_unstable();
156 chars.dedup();
157 if kind == CharKind::Bmp && from.is_none() {
158 return (chars, 16);
159 }
160 if kind == CharKind::General {
161 return (chars, 8);
162 }
163 let n = chars.len() as u64;
164 let bits = bits_for_range(n);
165 let b = match bits {
167 0..=1 => bits,
168 2 => 2,
169 3..=4 => 4,
170 5..=8 => 8,
171 _ => 16,
172 };
173 (chars, b)
174}
175
176struct Reader<'a> {
181 data: &'a [u8],
182 pos: usize,
183}
184
185impl<'a> Reader<'a> {
186 fn remaining_bits(&self) -> usize {
187 self.data.len() * 8 - self.pos
188 }
189
190 fn align(&mut self) {
191 self.pos = self.pos.div_ceil(8) * 8;
192 if self.pos > self.data.len() * 8 {
193 self.pos = self.data.len() * 8;
194 }
195 }
196
197 fn bits(&mut self, n: u32, what: &str) -> PerResult<u64> {
198 if n > 64 {
199 return err(format!("{what}: {n}-bit field is wider than 64"));
200 }
201 if self.remaining_bits() < n as usize {
202 return err(format!(
203 "{what}: needs {n} bits, {} remain",
204 self.remaining_bits()
205 ));
206 }
207 let mut value = 0u64;
208 for _ in 0..n {
209 let byte = self.data[self.pos / 8];
210 let bit = (byte >> (7 - (self.pos % 8))) & 1;
211 value = (value << 1) | bit as u64;
212 self.pos += 1;
213 }
214 Ok(value)
215 }
216
217 fn octets(&mut self, n: usize, what: &str) -> PerResult<&'a [u8]> {
218 self.align();
219 let start = self.pos / 8;
220 if self.data.len() - start < n {
221 return err(format!(
222 "{what}: declares {n} octets, {} remain",
223 self.data.len() - start
224 ));
225 }
226 self.pos += n * 8;
227 Ok(&self.data[start..start + n])
228 }
229
230 fn octets_unaligned(&mut self, n: usize, what: &str) -> PerResult<Vec<u8>> {
231 if self.remaining_bits() < n * 8 {
232 return err(format!("{what}: declares {n} octets past the end"));
233 }
234 (0..n).map(|_| Ok(self.bits(8, what)? as u8)).collect()
235 }
236
237 fn whole(&mut self, range: u64, what: &str) -> PerResult<u64> {
239 match range {
240 0 | 1 => Ok(0),
241 r if r <= 255 => self.bits(bits_for_range(r), what),
242 256 => {
243 self.align();
244 self.bits(8, what)
245 }
246 r if r <= 65_536 => {
247 self.align();
248 self.bits(16, what)
249 }
250 r => {
251 let max_octets = octets_for(r - 1) as u64;
252 let len = self.bits(bits_for_range(max_octets), what)? + 1;
253 let raw = self.octets(len as usize, what)?;
254 Ok(raw.iter().fold(0u64, |acc, b| (acc << 8) | *b as u64))
255 }
256 }
257 }
258
259 fn general_length(&mut self, what: &str) -> PerResult<usize> {
260 self.align();
261 let first = self.bits(8, what)? as usize;
262 if first & 0x80 == 0 {
263 return Ok(first);
264 }
265 if first & 0xC0 == 0x80 {
266 let second = self.bits(8, what)? as usize;
267 return Ok(((first & 0x3F) << 8) | second);
268 }
269 err(format!(
270 "{what}: fragmented length (≥16384) is not accepted"
271 ))
272 }
273
274 fn normally_small(&mut self, what: &str) -> PerResult<u64> {
275 if self.bits(1, what)? == 1 {
276 return err(format!("{what}: normally-small value above 63"));
277 }
278 self.bits(6, what)
279 }
280
281 fn length(&mut self, size: Size, what: &str) -> PerResult<usize> {
283 if size.ext && self.bits(1, what)? == 1 {
284 return self.general_length(what);
285 }
286 let n = match size.ub {
287 Some(ub) if ub == size.lb => ub as usize,
288 Some(ub) if ub < 65_536 => {
289 size.lb as usize + self.whole((ub - size.lb) as u64 + 1, what)? as usize
290 }
291 _ => self.general_length(what)?,
292 };
293 if n < size.lb as usize || size.ub.is_some_and(|ub| n > ub as usize) {
294 return err(format!(
295 "{what}: size {n} outside {}..{:?}",
296 size.lb, size.ub
297 ));
298 }
299 Ok(n)
300 }
301
302 fn open_type(&mut self, what: &str) -> PerResult<&'a [u8]> {
303 let len = self.general_length(what)?;
304 self.octets(len, what)
305 }
306}
307
308#[derive(Default)]
309struct Writer {
310 data: Vec<u8>,
311 bit_len: usize,
312}
313
314impl Writer {
315 fn bits(&mut self, value: u64, n: u32) {
316 for i in (0..n).rev() {
317 let bit = ((value >> i) & 1) as u8;
318 if self.bit_len.is_multiple_of(8) {
319 self.data.push(0);
320 }
321 if bit == 1 {
322 let last = self.data.len() - 1;
323 self.data[last] |= 1 << (7 - (self.bit_len % 8));
324 }
325 self.bit_len += 1;
326 }
327 }
328
329 fn align(&mut self) {
330 self.bit_len = self.bit_len.div_ceil(8) * 8;
331 }
332
333 fn octets(&mut self, bytes: &[u8]) {
334 self.align();
335 self.data.extend_from_slice(bytes);
336 self.bit_len += bytes.len() * 8;
337 }
338
339 fn octets_unaligned(&mut self, bytes: &[u8]) {
340 for b in bytes {
341 self.bits(*b as u64, 8);
342 }
343 }
344
345 fn whole(&mut self, v: u64, range: u64) {
346 match range {
347 0 | 1 => {}
348 r if r <= 255 => self.bits(v, bits_for_range(r)),
349 256 => {
350 self.align();
351 self.bits(v, 8);
352 }
353 r if r <= 65_536 => {
354 self.align();
355 self.bits(v, 16);
356 }
357 r => {
358 let max_octets = octets_for(r - 1) as u64;
359 let len = octets_for(v);
360 self.bits(len as u64 - 1, bits_for_range(max_octets));
361 self.align();
362 for i in (0..len).rev() {
363 self.bits((v >> (8 * i)) & 0xFF, 8);
364 }
365 }
366 }
367 }
368
369 fn general_length(&mut self, n: usize, what: &str) -> PerResult<()> {
370 self.align();
371 if n < 128 {
372 self.bits(n as u64, 8);
373 } else if n <= MAX_UNFRAGMENTED {
374 self.bits(0x8000 | n as u64, 16);
375 } else {
376 return err(format!("{what}: {n} needs a fragmented length"));
377 }
378 Ok(())
379 }
380
381 fn normally_small(&mut self, v: u64, what: &str) -> PerResult<()> {
382 if v > 63 {
383 return err(format!("{what}: {v} is not a normally-small number"));
384 }
385 self.bits(0, 1);
386 self.bits(v, 6);
387 Ok(())
388 }
389
390 fn length(&mut self, n: usize, size: Size, what: &str) -> PerResult<()> {
391 let in_root = n >= size.lb as usize && size.ub.is_none_or(|ub| n <= ub as usize);
392 if !in_root {
393 return err(format!(
394 "{what}: size {n} outside {}..{:?}",
395 size.lb, size.ub
396 ));
397 }
398 if size.ext {
399 self.bits(0, 1);
400 }
401 match size.ub {
402 Some(ub) if ub == size.lb => {}
403 Some(ub) if ub < 65_536 => {
404 self.whole((n - size.lb as usize) as u64, (ub - size.lb) as u64 + 1)
405 }
406 _ => self.general_length(n, what)?,
407 }
408 Ok(())
409 }
410
411 fn open_type(&mut self, inner: &[u8], what: &str) -> PerResult<()> {
412 self.general_length(inner.len(), what)?;
413 self.octets(inner);
414 Ok(())
415 }
416
417 fn finish(mut self) -> Vec<u8> {
418 if self.data.is_empty() {
419 self.data.push(0);
420 }
421 self.data
422 }
423}
424
425fn err<T>(msg: impl Into<String>) -> PerResult<T> {
426 Err(PerError(msg.into()))
427}
428
429pub fn decode(root: u16, data: &[u8]) -> PerResult<Value> {
435 let mut nodes = 0usize;
436 decode_at(root, data, 0, &mut nodes)
437}
438
439fn decode_at(root: u16, data: &[u8], depth: u32, nodes: &mut usize) -> PerResult<Value> {
440 let mut d = Decoder {
441 r: Reader { data, pos: 0 },
442 nodes,
443 };
444 d.value(root, "", depth)
445}
446
447struct Decoder<'a, 'n> {
448 r: Reader<'a>,
449 nodes: &'n mut usize,
450}
451
452impl Decoder<'_, '_> {
453 fn value(&mut self, index: u16, path: &str, depth: u32) -> PerResult<Value> {
454 if depth > MAX_PER_DEPTH {
455 return err(format!("{path}: nested deeper than {MAX_PER_DEPTH}"));
456 }
457 *self.nodes += 1;
458 if *self.nodes > MAX_PER_NODES {
459 return err(format!("{path}: more than {MAX_PER_NODES} values"));
460 }
461 let what = if path.is_empty() {
462 super::schema::NAMES
463 .get(index as usize)
464 .copied()
465 .unwrap_or("value")
466 } else {
467 path
468 };
469 match ty(index) {
470 Ty::Alias(target) => self.value(*target, path, depth + 1),
471 Ty::Null => Ok(Value::Null),
472 Ty::Boolean => Ok(Value::Bool(self.r.bits(1, what)? == 1)),
473 Ty::Int(range) => self.integer(*range, what),
474 Ty::Enum { root, ext } => {
475 if ext.is_some() && self.r.bits(1, what)? == 1 {
476 let i = self.r.normally_small(what)? as usize;
477 return Ok(match ext.and_then(|e| e.get(i)) {
478 Some(name) => json!(name),
479 None => json!(format!("_unknown_{i}")),
480 });
481 }
482 let i = self.r.whole(root.len() as u64, what)? as usize;
483 root.get(i)
484 .map(|n| json!(n))
485 .ok_or_else(|| PerError(format!("{what}: enumeration index {i}")))
486 }
487 Ty::Octets(size) => {
488 let n = self.r.length(*size, what)?;
489 let fixed = !size.ext && size.ub == Some(size.lb);
490 let raw = if n == 0 {
491 Vec::new()
492 } else if fixed && n <= 2 {
493 self.r.octets_unaligned(n, what)?
494 } else {
495 self.r.octets(n, what)?.to_vec()
496 };
497 Ok(json!(hex::encode(raw)))
498 }
499 Ty::Bits(size) => {
500 let n = self.r.length(*size, what)?;
501 if n > self.r.remaining_bits() {
502 return err(format!("{what}: declares {n} bits past the end"));
503 }
504 let fixed = !size.ext && size.ub == Some(size.lb);
505 if n > 0 && !(fixed && n <= 16) {
506 self.r.align();
507 }
508 let mut s = String::with_capacity(n);
509 for _ in 0..n {
510 s.push(if self.r.bits(1, what)? == 1 { '1' } else { '0' });
511 }
512 Ok(json!(s))
513 }
514 Ty::Chars {
515 kind,
516 size,
517 alphabet: from,
518 } => self.chars(*kind, *size, *from, what),
519 Ty::Oid => {
520 let len = self.r.general_length(what)?;
521 let raw = self.r.octets(len, what)?;
522 Ok(json!(oid_to_string(raw).ok_or_else(|| PerError(
523 format!("{what}: malformed OBJECT IDENTIFIER")
524 ))?))
525 }
526 Ty::Seq { root, ext } => self.sequence(root, *ext, path, depth),
527 Ty::Choice { root, ext } => {
528 if ext.is_some() && self.r.bits(1, what)? == 1 {
529 let i = self.r.normally_small(what)? as usize;
530 let inner = self.r.open_type(what)?;
531 return match ext.and_then(|e| e.get(i)) {
532 Some(f) => {
533 let sub = join(path, f.name);
534 let v = self.open(f.ty, inner, &sub, depth)?;
535 Ok(json!({ f.name: v }))
536 }
537 None => Ok(json!({ "_unknown_extension": i })),
538 };
539 }
540 let i = self.r.whole(root.len() as u64, what)? as usize;
541 let f = root
542 .get(i)
543 .ok_or_else(|| PerError(format!("{what}: alternative {i}")))?;
544 let sub = join(path, f.name);
545 let v = self.value(f.ty, &sub, depth + 1)?;
546 Ok(json!({ f.name: v }))
547 }
548 Ty::SeqOf { size, item } => {
549 let n = self.r.length(*size, what)?;
550 if n > MAX_PER_NODES {
551 return err(format!("{what}: {n} elements"));
552 }
553 let mut out = Vec::with_capacity(n.min(64));
554 for i in 0..n {
555 let sub = format!("{path}[{i}]");
556 out.push(self.value(*item, &sub, depth + 1)?);
557 }
558 Ok(Value::Array(out))
559 }
560 Ty::Opaque(why) => err(format!("{what}: {why} is outside NetGet's PER subset")),
561 }
562 }
563
564 fn open(&mut self, index: u16, inner: &[u8], path: &str, depth: u32) -> PerResult<Value> {
565 let mut d = Decoder {
566 r: Reader {
567 data: inner,
568 pos: 0,
569 },
570 nodes: self.nodes,
571 };
572 d.value(index, path, depth + 1)
573 }
574
575 fn sequence(
576 &mut self,
577 root: &'static [Field],
578 ext: Option<&'static [Field]>,
579 path: &str,
580 depth: u32,
581 ) -> PerResult<Value> {
582 let what = if path.is_empty() { "sequence" } else { path };
583 let extended = ext.is_some() && self.r.bits(1, what)? == 1;
584 let optional = root.iter().filter(|f| f.optional).count();
585 let mut present = Vec::with_capacity(optional);
586 for _ in 0..optional {
587 present.push(self.r.bits(1, what)? == 1);
588 }
589 let mut obj = Map::new();
590 let mut opt = present.into_iter();
591 for f in root {
592 if f.optional && !opt.next().unwrap_or(false) {
593 continue;
594 }
595 let sub = join(path, f.name);
596 let v = self.value(f.ty, &sub, depth + 1)?;
597 obj.insert(f.name.to_string(), v);
598 }
599 if extended {
600 let n = self.r.normally_small(what)? as usize + 1;
601 let mut bitmap = Vec::with_capacity(n);
602 for _ in 0..n {
603 bitmap.push(self.r.bits(1, what)? == 1);
604 }
605 let additions = ext.unwrap_or(&[]);
606 for (i, on) in bitmap.into_iter().enumerate() {
607 if !on {
608 continue;
609 }
610 let inner = self.r.open_type(what)?;
611 let Some(f) = additions.get(i) else {
612 continue;
613 };
614 if let Ty::Opaque(_) = resolve(f.ty) {
615 obj.insert(f.name.to_string(), json!({"_opaque_octets": inner.len()}));
617 continue;
618 }
619 let sub = join(path, f.name);
620 let v = self.open(f.ty, inner, &sub, depth)?;
621 obj.insert(f.name.to_string(), v);
622 }
623 }
624 Ok(Value::Object(obj))
625 }
626
627 fn integer(&mut self, range: Range, what: &str) -> PerResult<Value> {
628 if range.ext && self.r.bits(1, what)? == 1 {
629 return self.unconstrained(what);
630 }
631 match (range.lb, range.ub) {
632 (Some(lb), Some(ub)) => {
633 let span = (ub - lb) as u64 + 1;
634 let v = self.r.whole(span, what)?;
635 let v = lb + v as i64;
636 if v > ub {
637 return err(format!("{what}: {v} is above {ub}"));
638 }
639 Ok(json!(v))
640 }
641 (Some(lb), None) => {
642 let len = self.r.general_length(what)?;
643 if len == 0 || len > 8 {
644 return err(format!("{what}: {len}-octet integer"));
645 }
646 let raw = self.r.octets(len, what)?;
647 let v = raw.iter().fold(0u64, |acc, b| (acc << 8) | *b as u64);
648 i64::try_from(v)
649 .ok()
650 .and_then(|v| lb.checked_add(v))
651 .map(|n| json!(n))
652 .ok_or_else(|| PerError(format!("{what}: {v} above {lb} does not fit")))
653 }
654 _ => self.unconstrained(what),
655 }
656 }
657
658 fn unconstrained(&mut self, what: &str) -> PerResult<Value> {
659 let len = self.r.general_length(what)?;
660 if len == 0 || len > 8 {
661 return err(format!("{what}: {len}-octet integer"));
662 }
663 let raw = self.r.octets(len, what)?;
664 let mut v: i64 = if raw[0] & 0x80 != 0 { -1 } else { 0 };
665 for b in raw {
666 v = (v << 8) | *b as i64;
667 }
668 Ok(json!(v))
669 }
670
671 fn chars(
672 &mut self,
673 kind: CharKind,
674 size: Size,
675 from: Option<&'static str>,
676 what: &str,
677 ) -> PerResult<Value> {
678 let (set, b) = alphabet(kind, from);
679 let n = self.r.length(size, what)?;
680 if n * b as usize > self.r.remaining_bits() {
681 return err(format!("{what}: {n} characters past the end"));
682 }
683 let fixed = !size.ext && size.ub == Some(size.lb);
684 let aligned = n > 0
685 && match size.ub {
686 Some(ub) if fixed => ub as usize * b as usize > 16,
687 Some(ub) => ub as usize * b as usize > 16,
688 None => true,
689 };
690 if aligned {
691 self.r.align();
692 }
693 let remap = set.last().is_some_and(|max| *max as u64 > (1u64 << b) - 1);
694 let mut s = String::with_capacity(n);
695 for _ in 0..n {
696 let raw = self.r.bits(b, what)? as u32;
697 let code = if remap {
698 *set.get(raw as usize)
699 .ok_or_else(|| PerError(format!("{what}: character index {raw}")))?
700 } else {
701 raw
702 };
703 if !set.is_empty() && !remap && set.binary_search(&code).is_err() {
704 return err(format!("{what}: character {code:#x} is not permitted"));
705 }
706 s.push(char::from_u32(code).unwrap_or('\u{fffd}'));
707 }
708 Ok(json!(s))
709 }
710}
711
712fn join(path: &str, name: &str) -> String {
713 if path.is_empty() {
714 name.to_string()
715 } else {
716 format!("{path}.{name}")
717 }
718}
719
720fn resolve(mut index: u16) -> &'static Ty {
723 for _ in 0..16 {
724 match ty(index) {
725 Ty::Alias(t) => index = *t,
726 other => return other,
727 }
728 }
729 ty(index)
730}
731
732pub fn oid_to_string(raw: &[u8]) -> Option<String> {
733 if raw.is_empty() || raw.len() > 64 {
734 return None;
735 }
736 let mut arcs: Vec<u64> = Vec::new();
737 let mut acc: u64 = 0;
738 let mut in_arc = false;
739 for b in raw {
740 if acc > (u64::MAX >> 8) {
741 return None;
742 }
743 acc = (acc << 7) | (*b & 0x7F) as u64;
744 in_arc = true;
745 if b & 0x80 == 0 {
746 if arcs.is_empty() {
747 let first = (acc / 40).min(2);
748 arcs.push(first);
749 arcs.push(acc - first * 40);
750 } else {
751 arcs.push(acc);
752 }
753 acc = 0;
754 in_arc = false;
755 }
756 }
757 if in_arc {
758 return None;
759 }
760 Some(
761 arcs.iter()
762 .map(|a| a.to_string())
763 .collect::<Vec<_>>()
764 .join("."),
765 )
766}
767
768pub fn oid_from_string(s: &str) -> Option<Vec<u8>> {
769 let arcs: Vec<u64> = s
770 .split('.')
771 .map(|a| a.parse().ok())
772 .collect::<Option<Vec<_>>>()?;
773 if arcs.len() < 2 || arcs[0] > 2 || (arcs[0] < 2 && arcs[1] >= 40) || arcs.len() > 32 {
774 return None;
775 }
776 let mut out = Vec::new();
777 let mut push = |mut v: u64| {
778 let mut tmp = vec![(v & 0x7F) as u8];
779 v >>= 7;
780 while v > 0 {
781 tmp.push(((v & 0x7F) as u8) | 0x80);
782 v >>= 7;
783 }
784 tmp.reverse();
785 out.extend(tmp);
786 };
787 push(arcs[0] * 40 + arcs[1]);
788 for a in &arcs[2..] {
789 push(*a);
790 }
791 Some(out)
792}
793
794pub fn encode(root: u16, value: &Value) -> PerResult<Vec<u8>> {
800 let mut w = Writer::default();
801 put(&mut w, root, value, "", 0)?;
802 Ok(w.finish())
803}
804
805fn put(w: &mut Writer, index: u16, v: &Value, path: &str, depth: u32) -> PerResult<()> {
806 if depth > MAX_PER_DEPTH {
807 return err(format!("{path}: nested deeper than {MAX_PER_DEPTH}"));
808 }
809 let what = if path.is_empty() {
810 super::schema::NAMES
811 .get(index as usize)
812 .copied()
813 .unwrap_or("value")
814 } else {
815 path
816 };
817 match ty(index) {
818 Ty::Alias(t) => put(w, *t, v, path, depth + 1),
819 Ty::Null => {
820 if !v.is_null() {
821 return err(format!("{what}: NULL takes null"));
822 }
823 Ok(())
824 }
825 Ty::Boolean => {
826 let b = v
827 .as_bool()
828 .ok_or_else(|| PerError(format!("{what}: expected a boolean")))?;
829 w.bits(b as u64, 1);
830 Ok(())
831 }
832 Ty::Int(range) => put_integer(w, *range, v, what),
833 Ty::Enum { root, ext } => {
834 let name = v
835 .as_str()
836 .ok_or_else(|| PerError(format!("{what}: expected an enumeration name")))?;
837 if let Some(i) = root.iter().position(|n| *n == name) {
838 if ext.is_some() {
839 w.bits(0, 1);
840 }
841 w.whole(i as u64, root.len() as u64);
842 return Ok(());
843 }
844 if let Some(i) = ext.and_then(|e| e.iter().position(|n| *n == name)) {
845 w.bits(1, 1);
846 return w.normally_small(i as u64, what);
847 }
848 err(format!("{what}: {name:?} is not one of {root:?}"))
849 }
850 Ty::Octets(size) => {
851 let raw = v
852 .as_str()
853 .and_then(|s| hex::decode(s).ok())
854 .ok_or_else(|| PerError(format!("{what}: expected hex octets")))?;
855 w.length(raw.len(), *size, what)?;
856 let fixed = !size.ext && size.ub == Some(size.lb);
857 if raw.is_empty() {
858 } else if fixed && raw.len() <= 2 {
859 w.octets_unaligned(&raw);
860 } else {
861 w.octets(&raw);
862 }
863 Ok(())
864 }
865 Ty::Bits(size) => {
866 let s = v
867 .as_str()
868 .filter(|s| s.chars().all(|c| c == '0' || c == '1'))
869 .ok_or_else(|| PerError(format!("{what}: expected a string of 0 and 1")))?;
870 w.length(s.len(), *size, what)?;
871 let fixed = !size.ext && size.ub == Some(size.lb);
872 if !s.is_empty() && !(fixed && s.len() <= 16) {
873 w.align();
874 }
875 for c in s.chars() {
876 w.bits((c == '1') as u64, 1);
877 }
878 Ok(())
879 }
880 Ty::Chars {
881 kind,
882 size,
883 alphabet: from,
884 } => {
885 let s = v
886 .as_str()
887 .ok_or_else(|| PerError(format!("{what}: expected a string")))?;
888 let (set, b) = alphabet(*kind, *from);
889 let codes: Vec<u32> = s.chars().map(|c| c as u32).collect();
890 for c in &codes {
891 let ok = if set.is_empty() {
892 *c <= 0xFFFF && !(0xD800..0xE000).contains(c)
893 } else {
894 set.binary_search(c).is_ok()
895 };
896 if !ok {
897 return err(format!(
898 "{what}: {:?} is not permitted in this string",
899 char::from_u32(*c).unwrap_or('?')
900 ));
901 }
902 }
903 let n = codes.len();
904 w.length(n, *size, what)?;
905 let fixed = !size.ext && size.ub == Some(size.lb);
906 let aligned = n > 0
907 && match size.ub {
908 Some(ub) if fixed => ub as usize * b as usize > 16,
909 Some(ub) => ub as usize * b as usize > 16,
910 None => true,
911 };
912 if aligned {
913 w.align();
914 }
915 let remap = set.last().is_some_and(|max| *max as u64 > (1u64 << b) - 1);
916 for c in codes {
917 let code = if remap {
918 set.binary_search(&c).unwrap_or(0) as u64
919 } else {
920 c as u64
921 };
922 w.bits(code, b);
923 }
924 Ok(())
925 }
926 Ty::Oid => {
927 let raw = v
928 .as_str()
929 .and_then(oid_from_string)
930 .ok_or_else(|| PerError(format!("{what}: expected a dotted OBJECT IDENTIFIER")))?;
931 w.general_length(raw.len(), what)?;
932 w.octets(&raw);
933 Ok(())
934 }
935 Ty::Seq { root, ext } => {
936 let obj = v
937 .as_object()
938 .ok_or_else(|| PerError(format!("{what}: expected an object")))?;
939 for key in obj.keys() {
940 let known = root.iter().any(|f| f.name == key)
941 || ext.is_some_and(|e| e.iter().any(|f| f.name == key));
942 if !known {
943 return err(format!("{what}: unknown field {key:?}"));
944 }
945 }
946 let additions: Vec<&Field> = ext
947 .map(|e| e.iter().filter(|f| obj.contains_key(f.name)).collect())
948 .unwrap_or_default();
949 if ext.is_some() {
950 w.bits(!additions.is_empty() as u64, 1);
951 }
952 for f in root.iter().filter(|f| f.optional) {
953 w.bits(obj.contains_key(f.name) as u64, 1);
954 }
955 for f in root.iter() {
956 match obj.get(f.name) {
957 Some(fv) => put(w, f.ty, fv, &join(path, f.name), depth + 1)?,
958 None if f.optional => {}
959 None => return err(format!("{what}: missing field {:?}", f.name)),
960 }
961 }
962 if let (Some(all), false) = (ext, additions.is_empty()) {
963 let last = all
966 .iter()
967 .rposition(|f| obj.contains_key(f.name))
968 .unwrap_or(0);
969 w.normally_small(last as u64, what)?;
970 for f in &all[..=last] {
971 w.bits(obj.contains_key(f.name) as u64, 1);
972 }
973 for f in &all[..=last] {
974 if let Some(fv) = obj.get(f.name) {
975 let mut inner = Writer::default();
976 put(&mut inner, f.ty, fv, &join(path, f.name), depth + 1)?;
977 w.open_type(&inner.finish(), what)?;
978 }
979 }
980 }
981 Ok(())
982 }
983 Ty::Choice { root, ext } => {
984 let obj = v
985 .as_object()
986 .filter(|o| o.len() == 1)
987 .ok_or_else(|| PerError(format!("{what}: a CHOICE is an object with one key")))?;
988 let (key, fv) = obj.iter().next().expect("one key");
989 if let Some(i) = root.iter().position(|f| f.name == key) {
990 if ext.is_some() {
991 w.bits(0, 1);
992 }
993 w.whole(i as u64, root.len() as u64);
994 return put(w, root[i].ty, fv, &join(path, key), depth + 1);
995 }
996 if let Some(i) = ext.and_then(|e| e.iter().position(|f| f.name == key)) {
997 let f = &ext.expect("checked")[i];
998 w.bits(1, 1);
999 w.normally_small(i as u64, what)?;
1000 let mut inner = Writer::default();
1001 put(&mut inner, f.ty, fv, &join(path, key), depth + 1)?;
1002 return w.open_type(&inner.finish(), what);
1003 }
1004 err(format!("{what}: {key:?} is not an alternative"))
1005 }
1006 Ty::SeqOf { size, item } => {
1007 let arr = v
1008 .as_array()
1009 .ok_or_else(|| PerError(format!("{what}: expected an array")))?;
1010 w.length(arr.len(), *size, what)?;
1011 for (i, e) in arr.iter().enumerate() {
1012 put(w, *item, e, &format!("{path}[{i}]"), depth + 1)?;
1013 }
1014 Ok(())
1015 }
1016 Ty::Opaque(why) => err(format!("{what}: NetGet cannot encode {why}")),
1017 }
1018}
1019
1020fn put_integer(w: &mut Writer, range: Range, v: &Value, what: &str) -> PerResult<()> {
1021 let n = v
1022 .as_i64()
1023 .ok_or_else(|| PerError(format!("{what}: expected an integer")))?;
1024 let in_root = range.lb.is_none_or(|lb| n >= lb) && range.ub.is_none_or(|ub| n <= ub);
1025 if !in_root {
1026 if !range.ext {
1027 return err(format!(
1028 "{what}: {n} outside {:?}..{:?}",
1029 range.lb, range.ub
1030 ));
1031 }
1032 w.bits(1, 1);
1033 return put_unconstrained(w, n, what);
1034 }
1035 if range.ext {
1036 w.bits(0, 1);
1037 }
1038 match (range.lb, range.ub) {
1039 (Some(lb), Some(ub)) => {
1040 w.whole((n - lb) as u64, (ub - lb) as u64 + 1);
1041 Ok(())
1042 }
1043 (Some(lb), None) => {
1044 let v = (n - lb) as u64;
1045 let len = octets_for(v);
1046 w.general_length(len, what)?;
1047 let bytes = v.to_be_bytes();
1048 w.octets(&bytes[8 - len..]);
1049 Ok(())
1050 }
1051 _ => put_unconstrained(w, n, what),
1052 }
1053}
1054
1055fn put_unconstrained(w: &mut Writer, n: i64, what: &str) -> PerResult<()> {
1056 let bytes = n.to_be_bytes();
1057 let mut start = 0;
1058 while start < 7 {
1059 let redundant = (bytes[start] == 0x00 && bytes[start + 1] & 0x80 == 0)
1060 || (bytes[start] == 0xFF && bytes[start + 1] & 0x80 != 0);
1061 if !redundant {
1062 break;
1063 }
1064 start += 1;
1065 }
1066 w.general_length(8 - start, what)?;
1067 w.octets(&bytes[start..]);
1068 Ok(())
1069}