1#![forbid(unsafe_code)]
2
3use crate::{ProtocolError, Result};
4
5pub const TNS_MAX_SHORT_LENGTH: usize = 252;
6pub const TNS_LONG_LENGTH_INDICATOR: u8 = 0xfe;
7pub const TNS_NULL_LENGTH_INDICATOR: u8 = 0xff;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum PacketLengthWidth {
11 Legacy16,
12 Large32,
13}
14
15#[derive(Clone, Debug, Default, Eq, PartialEq)]
16pub struct TtcWriter {
17 bytes: Vec<u8>,
18 seq_num: u8,
19}
20
21impl TtcWriter {
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn with_capacity(capacity: usize) -> Self {
34 Self {
35 bytes: Vec::with_capacity(capacity),
36 seq_num: 0,
37 }
38 }
39
40 pub fn into_bytes(self) -> Vec<u8> {
41 self.bytes
42 }
43
44 pub fn write_u8(&mut self, value: u8) {
45 self.bytes.push(value);
46 }
47
48 pub fn write_u16be(&mut self, value: u16) {
49 self.bytes.extend_from_slice(&value.to_be_bytes());
50 }
51
52 pub fn write_u16le(&mut self, value: u16) {
53 self.bytes.extend_from_slice(&value.to_le_bytes());
54 }
55
56 pub fn write_u32be(&mut self, value: u32) {
57 self.bytes.extend_from_slice(&value.to_be_bytes());
58 }
59
60 pub fn write_u64be(&mut self, value: u64) {
61 self.bytes.extend_from_slice(&value.to_be_bytes());
62 }
63
64 pub fn write_ub2(&mut self, value: u16) {
65 if value == 0 {
66 self.write_u8(0);
67 } else if value <= u16::from(u8::MAX) {
68 self.write_u8(1);
69 self.write_u8(value as u8);
70 } else {
71 self.write_u8(2);
72 self.write_u16be(value);
73 }
74 }
75
76 pub fn write_ub4(&mut self, value: u32) {
77 if value == 0 {
78 self.write_u8(0);
79 } else if value <= u32::from(u8::MAX) {
80 self.write_u8(1);
81 self.write_u8(value as u8);
82 } else if value <= u32::from(u16::MAX) {
83 self.write_u8(2);
84 self.write_u16be(value as u16);
85 } else {
86 self.write_u8(4);
87 self.write_u32be(value);
88 }
89 }
90
91 pub fn write_ub8(&mut self, value: u64) {
92 if value == 0 {
93 self.write_u8(0);
94 } else if value <= u64::from(u8::MAX) {
95 self.write_u8(1);
96 self.write_u8(value as u8);
97 } else if value <= u64::from(u16::MAX) {
98 self.write_u8(2);
99 self.write_u16be(value as u16);
100 } else if value <= u64::from(u32::MAX) {
101 self.write_u8(4);
102 self.write_u32be(value as u32);
103 } else {
104 self.write_u8(8);
105 self.write_u64be(value);
106 }
107 }
108
109 pub fn write_seq_num(&mut self) {
110 self.seq_num = self.seq_num.wrapping_add(1);
111 if self.seq_num == 0 {
112 self.seq_num = 1;
113 }
114 self.write_u8(self.seq_num);
115 }
116
117 pub fn write_raw(&mut self, value: &[u8]) {
118 self.bytes.extend_from_slice(value);
119 }
120
121 pub fn write_bytes_with_length(&mut self, value: &[u8]) -> Result<()> {
122 if value.len() <= TNS_MAX_SHORT_LENGTH {
123 self.write_u8(value.len() as u8);
124 self.write_raw(value);
125 return Ok(());
126 }
127 self.write_u8(TNS_LONG_LENGTH_INDICATOR);
128 for chunk in value.chunks(32_767) {
129 self.write_ub4(u32::try_from(chunk.len()).map_err(|_| {
130 ProtocolError::InvalidPacketLength {
131 length: chunk.len(),
132 minimum: 0,
133 }
134 })?);
135 self.write_raw(chunk);
136 }
137 self.write_ub4(0);
138 Ok(())
139 }
140
141 pub fn write_bytes_with_two_lengths(&mut self, value: Option<&[u8]>) -> Result<()> {
142 match value {
143 Some(bytes) => {
144 self.write_ub4(u32::try_from(bytes.len()).map_err(|_| {
145 ProtocolError::InvalidPacketLength {
146 length: bytes.len(),
147 minimum: 0,
148 }
149 })?);
150 if !bytes.is_empty() {
151 self.write_bytes_with_length(bytes)?;
152 }
153 }
154 None => self.write_ub4(0),
155 }
156 Ok(())
157 }
158
159 pub fn write_str_two_lengths(&mut self, value: &str) -> Result<()> {
160 self.write_bytes_with_two_lengths(Some(value.as_bytes()))
161 }
162
163 pub fn write_sb4(&mut self, value: i32) {
168 let (sign, magnitude) = if value < 0 {
169 (0x80u8, value.unsigned_abs())
170 } else {
171 (0u8, value as u32)
172 };
173 if magnitude == 0 {
174 self.write_u8(0);
175 } else if magnitude <= u32::from(u8::MAX) {
176 self.write_u8(1 | sign);
177 self.write_u8(magnitude as u8);
178 } else if magnitude <= u32::from(u16::MAX) {
179 self.write_u8(2 | sign);
180 self.write_u16be(magnitude as u16);
181 } else {
182 self.write_u8(4 | sign);
183 self.write_u32be(magnitude);
184 }
185 }
186
187 pub fn write_keyword_value_pair(
191 &mut self,
192 text_value: Option<&[u8]>,
193 binary_value: Option<&[u8]>,
194 keyword: u16,
195 ) -> Result<()> {
196 self.write_bytes_with_two_lengths(text_value)?;
197 self.write_bytes_with_two_lengths(binary_value)?;
198 self.write_ub2(keyword);
199 Ok(())
200 }
201
202 pub fn write_function_code(&mut self, function_code: u8) {
203 self.write_u8(crate::thin::TNS_MSG_TYPE_FUNCTION);
204 self.write_u8(function_code);
205 self.write_seq_num();
206 }
207
208 pub fn write_function_code_with_seq(&mut self, function_code: u8, seq_num: u8) {
209 self.write_u8(crate::thin::TNS_MSG_TYPE_FUNCTION);
210 self.write_u8(function_code);
211 self.write_u8(seq_num);
212 }
213}
214
215pub trait BoundedReader {
242 fn remaining(&self) -> usize;
245
246 fn alloc_count_checked(&self, count: usize, min_bytes_per_elem: usize) -> Result<usize> {
256 let per_elem = min_bytes_per_elem.max(1);
257 match count.checked_mul(per_elem) {
258 Some(needed) if needed <= self.remaining() => Ok(count),
259 _ => Err(ProtocolError::TtcDecode(
260 "declared element count exceeds remaining buffer",
261 )),
262 }
263 }
264
265 fn with_capacity_bounded<T>(&self, count: usize, min_bytes_per_elem: usize) -> Vec<T> {
273 let per_elem = min_bytes_per_elem.max(1);
274 Vec::with_capacity(count.min(self.remaining() / per_elem))
275 }
276}
277
278#[derive(Clone, Debug)]
279pub struct TtcReader<'a> {
280 bytes: &'a [u8],
281 pos: usize,
282}
283
284impl BoundedReader for TtcReader<'_> {
285 fn remaining(&self) -> usize {
286 TtcReader::remaining(self)
287 }
288}
289
290#[derive(Clone, Debug, PartialEq, Eq)]
294pub enum BorrowedBytes<'a> {
295 Null,
297 Slice(&'a [u8]),
299 Chunked(Vec<u8>),
302}
303
304impl<'a> TtcReader<'a> {
305 pub fn new(bytes: &'a [u8]) -> Self {
306 Self { bytes, pos: 0 }
307 }
308
309 pub fn remaining(&self) -> usize {
310 self.bytes.len().saturating_sub(self.pos)
311 }
312
313 pub fn position(&self) -> usize {
314 self.pos
315 }
316
317 pub fn remaining_slice(&self) -> &[u8] {
318 &self.bytes[self.pos.min(self.bytes.len())..]
319 }
320
321 pub fn peek_u8(&self) -> Result<u8> {
322 self.bytes
323 .get(self.pos)
324 .copied()
325 .ok_or(ProtocolError::TtcDecode("missing u8"))
326 }
327
328 pub fn read_u8(&mut self) -> Result<u8> {
329 let value = *self
330 .bytes
331 .get(self.pos)
332 .ok_or(ProtocolError::TtcDecode("missing u8"))?;
333 self.pos += 1;
334 Ok(value)
335 }
336
337 pub fn read_i8(&mut self) -> Result<i8> {
338 Ok(self.read_u8()? as i8)
339 }
340
341 pub fn read_u16be(&mut self) -> Result<u16> {
342 let bytes = self.read_raw(2)?;
343 Ok(u16::from_be_bytes(
344 bytes
345 .try_into()
346 .map_err(|_| ProtocolError::TtcDecode("invalid u16"))?,
347 ))
348 }
349
350 pub fn read_u16le(&mut self) -> Result<u16> {
351 let bytes = self.read_raw(2)?;
352 Ok(u16::from_le_bytes(
353 bytes
354 .try_into()
355 .map_err(|_| ProtocolError::TtcDecode("invalid u16"))?,
356 ))
357 }
358
359 pub fn read_u32be(&mut self) -> Result<u32> {
360 let bytes = self.read_raw(4)?;
361 Ok(u32::from_be_bytes(
362 bytes
363 .try_into()
364 .map_err(|_| ProtocolError::TtcDecode("invalid u32"))?,
365 ))
366 }
367
368 pub fn read_raw(&mut self, len: usize) -> Result<&'a [u8]> {
369 let end = self
370 .pos
371 .checked_add(len)
372 .ok_or(ProtocolError::TtcDecode("read offset overflow"))?;
373 let bytes = self
374 .bytes
375 .get(self.pos..end)
376 .ok_or(ProtocolError::TtcDecode("truncated TTC payload"))?;
377 self.pos = end;
378 Ok(bytes)
379 }
380
381 pub fn skip(&mut self, len: usize) -> Result<()> {
382 self.read_raw(len).map(|_| ())
383 }
384
385 pub fn read_ub2(&mut self) -> Result<u16> {
386 let len = self.read_u8()?;
387 match len {
388 0 => Ok(0),
389 1 => Ok(u16::from(self.read_u8()?)),
390 2 => self.read_u16be(),
391 _ => Err(ProtocolError::TtcDecode("invalid ub2 length")),
392 }
393 }
394
395 pub fn read_ub4(&mut self) -> Result<u32> {
396 let len = self.read_u8()?;
397 if len == 0 {
398 return Ok(0);
399 }
400 if len > 4 {
401 return Err(ProtocolError::TtcDecode("invalid ub4 length"));
402 }
403 let mut value = 0u32;
404 for byte in self.read_raw(usize::from(len))? {
405 value = (value << 8) | u32::from(*byte);
406 }
407 Ok(value)
408 }
409
410 pub fn read_sb4(&mut self) -> Result<i32> {
411 let len = self.read_u8()?;
412 let is_negative = len & 0x80 != 0;
413 let len = len & 0x7f;
414 if len == 0 {
415 return Ok(0);
416 }
417 if len > 4 {
418 return Err(ProtocolError::TtcDecode("invalid sb4 length"));
419 }
420 let mut value = 0u32;
427 for byte in self.read_raw(usize::from(len))? {
428 value = (value << 8) | u32::from(*byte);
429 }
430 let value = value as i32;
431 Ok(if is_negative {
432 value.wrapping_neg()
433 } else {
434 value
435 })
436 }
437
438 pub fn read_sb8(&mut self) -> Result<i64> {
439 let len = self.read_u8()?;
440 let is_negative = len & 0x80 != 0;
441 let len = len & 0x7f;
442 if len == 0 {
443 return Ok(0);
444 }
445 if len > 8 {
446 return Err(ProtocolError::TtcDecode("invalid sb8 length"));
447 }
448 let mut value = 0u64;
451 for byte in self.read_raw(usize::from(len))? {
452 value = (value << 8) | u64::from(*byte);
453 }
454 let value = value as i64;
455 Ok(if is_negative {
456 value.wrapping_neg()
457 } else {
458 value
459 })
460 }
461
462 pub fn read_ub8(&mut self) -> Result<u64> {
463 let len = self.read_u8()?;
464 if len == 0 {
465 return Ok(0);
466 }
467 if len > 8 {
468 return Err(ProtocolError::TtcDecode("invalid ub8 length"));
469 }
470 let mut value = 0u64;
471 for byte in self.read_raw(usize::from(len))? {
472 value = (value << 8) | u64::from(*byte);
473 }
474 Ok(value)
475 }
476
477 pub fn read_bytes_borrowed(&mut self) -> Result<BorrowedBytes<'a>> {
488 let len = self.read_u8()?;
489 if len == TNS_LONG_LENGTH_INDICATOR {
490 let mut out = Vec::new();
491 loop {
492 let chunk_len = self.read_ub4()?;
493 if chunk_len == 0 {
494 break;
495 }
496 let chunk = self.read_raw(chunk_len as usize)?;
497 out.extend_from_slice(chunk);
498 }
499 Ok(BorrowedBytes::Chunked(out))
500 } else if len == 0 || len == TNS_NULL_LENGTH_INDICATOR {
501 Ok(BorrowedBytes::Null)
502 } else {
503 Ok(BorrowedBytes::Slice(self.read_raw(usize::from(len))?))
504 }
505 }
506
507 pub fn skip_bytes_field(&mut self) -> Result<()> {
512 let len = self.read_u8()?;
513 if len == TNS_LONG_LENGTH_INDICATOR {
514 loop {
515 let chunk_len = self.read_ub4()?;
516 if chunk_len == 0 {
517 break;
518 }
519 self.skip(chunk_len as usize)?;
520 }
521 Ok(())
522 } else if len == 0 || len == TNS_NULL_LENGTH_INDICATOR {
523 Ok(())
524 } else {
525 self.skip(usize::from(len))
526 }
527 }
528
529 pub fn read_bytes(&mut self) -> Result<Option<Vec<u8>>> {
530 let len = self.read_u8()?;
531 if len == TNS_LONG_LENGTH_INDICATOR {
532 let mut out = Vec::new();
533 loop {
534 let chunk_len = self.read_ub4()?;
535 if chunk_len == 0 {
536 break;
537 }
538 let chunk = self.read_raw(chunk_len as usize)?;
539 out.extend_from_slice(chunk);
540 }
541 Ok(Some(out))
542 } else if len == 0 || len == TNS_NULL_LENGTH_INDICATOR {
543 Ok(None)
544 } else {
545 Ok(Some(self.read_raw(usize::from(len))?.to_vec()))
546 }
547 }
548
549 pub fn read_bytes_with_length(&mut self) -> Result<Option<Vec<u8>>> {
550 let len =
551 usize::try_from(self.read_ub4()?).map_err(|_| ProtocolError::InvalidPacketLength {
552 length: usize::MAX,
553 minimum: 0,
554 })?;
555 if len == 0 {
556 return Ok(None);
557 }
558 let value_start = self.pos;
559 match self.read_bytes() {
560 Ok(Some(bytes)) if bytes.len() == len => Ok(Some(bytes)),
561 Ok(_) | Err(_) => {
562 self.pos = value_start;
563 Ok(Some(self.read_raw(len)?.to_vec()))
564 }
565 }
566 }
567
568 pub fn read_string_with_length(&mut self) -> Result<Option<String>> {
569 let Some(bytes) = self.read_bytes_with_length()? else {
570 return Ok(None);
571 };
572 String::from_utf8(bytes)
573 .map(Some)
574 .map_err(|_| ProtocolError::TtcDecode("server sent non-UTF8 string"))
575 }
576
577 pub fn read_string(&mut self) -> Result<Option<String>> {
578 let Some(bytes) = self.read_bytes()? else {
579 return Ok(None);
580 };
581 String::from_utf8(bytes)
582 .map(Some)
583 .map_err(|_| ProtocolError::TtcDecode("server sent non-UTF8 string"))
584 }
585}
586
587pub fn encode_packet(
588 packet_type: u8,
589 packet_flags: u8,
590 data_flags: Option<u16>,
591 payload: &[u8],
592 width: PacketLengthWidth,
593) -> Result<Vec<u8>> {
594 let data_flags_len = usize::from(data_flags.is_some()) * 2;
595 let length = crate::packet::TNS_HEADER_LEN + data_flags_len + payload.len();
596 let mut out = Vec::with_capacity(length);
597 match width {
598 PacketLengthWidth::Legacy16 => {
599 let wire_length =
600 u16::try_from(length).map_err(|_| ProtocolError::PacketTooLarge { length })?;
601 out.extend_from_slice(&wire_length.to_be_bytes());
602 out.extend_from_slice(&0u16.to_be_bytes());
603 }
604 PacketLengthWidth::Large32 => {
605 let wire_length =
606 u32::try_from(length).map_err(|_| ProtocolError::PacketTooLarge { length })?;
607 out.extend_from_slice(&wire_length.to_be_bytes());
608 }
609 }
610 out.push(packet_type);
611 out.push(packet_flags);
612 out.extend_from_slice(&0u16.to_be_bytes());
613 if let Some(flags) = data_flags {
614 out.extend_from_slice(&flags.to_be_bytes());
615 }
616 out.extend_from_slice(payload);
617 Ok(out)
618}
619
620#[cfg(test)]
621mod tests {
622 use super::*;
623
624 #[test]
631 fn alloc_count_checked_errs_when_count_exceeds_remaining() {
632 let bytes = [0u8; 4];
636 let reader = TtcReader::new(&bytes);
637 assert!(reader.alloc_count_checked(u32::MAX as usize, 8).is_err());
638 assert!(reader.alloc_count_checked(usize::MAX, 8).is_err());
640 }
641
642 #[test]
643 fn alloc_count_checked_ok_when_count_fits() {
644 let bytes = [0u8; 16];
646 let reader = TtcReader::new(&bytes);
647 assert_eq!(
648 reader.alloc_count_checked(2, 8).expect("fits"),
649 2,
650 "a count whose bytes fit must pass through unchanged"
651 );
652 assert_eq!(reader.alloc_count_checked(0, 0).expect("zero"), 0);
655 }
656
657 #[test]
658 fn with_capacity_bounded_caps_preallocation_but_still_grows() {
659 let bytes = [0u8; 8];
661 let reader = TtcReader::new(&bytes);
662 let v: Vec<u32> = reader.with_capacity_bounded(u32::MAX as usize, 4);
663 assert_eq!(
665 v.capacity(),
666 2,
667 "pre-allocation must be capped by remaining"
668 );
669 let mut v = v;
672 for i in 0..100u32 {
673 v.push(i);
674 }
675 assert_eq!(v.len(), 100);
676 }
677
678 #[test]
679 fn with_capacity_bounded_uses_full_count_when_buffer_is_large() {
680 let bytes = [0u8; 400];
683 let reader = TtcReader::new(&bytes);
684 let v: Vec<u32> = reader.with_capacity_bounded(10, 4);
685 assert_eq!(v.capacity(), 10);
686 }
687
688 #[test]
693 fn sb4_sb8_negate_overflow_does_not_panic() {
694 let bytes = [0x84u8, 0x80, 0x00, 0x00, 0x00];
696 let mut reader = TtcReader::new(&bytes);
697 assert_eq!(reader.read_sb4().expect("sb4 must not panic"), i32::MIN);
698
699 let bytes8 = [0x88u8, 0x80, 0, 0, 0, 0, 0, 0, 0];
701 let mut reader8 = TtcReader::new(&bytes8);
702 assert_eq!(reader8.read_sb8().expect("sb8 must not panic"), i64::MIN);
703 }
704
705 #[test]
708 fn sb4_decodes_representative_values() {
709 let cases: [(&[u8], i32); 4] = [
711 (&[0x00], 0),
712 (&[0x01, 0x2a], 42),
713 (&[0x81, 0x2a], -42),
714 (&[0x02, 0x01, 0x00], 256),
715 ];
716 for (bytes, expected) in cases {
717 let mut reader = TtcReader::new(bytes);
718 assert_eq!(
719 reader.read_sb4().expect("sb4 decode"),
720 expected,
721 "{bytes:?}"
722 );
723 }
724 }
725
726 #[test]
727 fn ub4_round_trips_representative_values() {
728 for value in [0, 1, 255, 256, 65_535, 65_536, u32::MAX] {
729 let mut writer = TtcWriter::new();
730 writer.write_ub4(value);
731 let bytes = writer.into_bytes();
732 let mut reader = TtcReader::new(&bytes);
733 assert_eq!(reader.read_ub4().expect("ub4 should decode"), value);
734 assert_eq!(reader.remaining(), 0);
735 }
736 }
737
738 #[test]
745 fn read_bytes_borrowed_borrows_short_values_and_owns_chunked() {
746 let short = [0x03u8, b'a', b'b', b'c'];
748 let mut reader = TtcReader::new(&short);
749 match reader.read_bytes_borrowed().expect("short decode") {
750 BorrowedBytes::Slice(slice) => assert_eq!(slice, b"abc"),
751 other => panic!("expected borrowed slice, got {other:?}"),
752 }
753 assert_eq!(reader.remaining(), 0);
754
755 let null = [TNS_NULL_LENGTH_INDICATOR];
757 let mut reader = TtcReader::new(&null);
758 assert!(matches!(
759 reader.read_bytes_borrowed().expect("null decode"),
760 BorrowedBytes::Null
761 ));
762
763 let zero = [0x00u8];
765 let mut reader = TtcReader::new(&zero);
766 assert!(matches!(
767 reader.read_bytes_borrowed().expect("zero decode"),
768 BorrowedBytes::Null
769 ));
770
771 let mut writer = TtcWriter::new();
773 writer
774 .write_bytes_with_length(&vec![0x5au8; 600]) .expect("chunked encode");
776 let long = writer.into_bytes();
777 let mut reader = TtcReader::new(&long);
778 match reader.read_bytes_borrowed().expect("chunked decode") {
779 BorrowedBytes::Chunked(bytes) => assert_eq!(bytes, vec![0x5au8; 600]),
780 other => panic!("expected owned chunked bytes, got {other:?}"),
781 }
782 assert_eq!(reader.remaining(), 0);
783 }
784
785 #[test]
786 fn bytes_with_length_accepts_nested_ttc_bytes() {
787 let mut writer = TtcWriter::new();
788 writer
789 .write_bytes_with_two_lengths(Some(b"abc"))
790 .expect("bytes should encode");
791 let bytes = writer.into_bytes();
792 let mut reader = TtcReader::new(&bytes);
793 assert_eq!(
794 reader
795 .read_bytes_with_length()
796 .expect("bytes should decode"),
797 Some(b"abc".to_vec())
798 );
799 assert_eq!(reader.remaining(), 0);
800 }
801
802 #[test]
803 fn bytes_with_length_accepts_direct_payload_bytes() {
804 let bytes = [1, 3, b'a', b'b', b'c'];
805 let mut reader = TtcReader::new(&bytes);
806 assert_eq!(
807 reader
808 .read_bytes_with_length()
809 .expect("bytes should decode"),
810 Some(b"abc".to_vec())
811 );
812 assert_eq!(reader.remaining(), 0);
813 }
814
815 #[test]
816 fn data_packet_uses_four_byte_length_when_negotiated() {
817 let packet = encode_packet(
818 6,
819 0,
820 Some(0),
821 &[0x03, 0x93, 0x01],
822 PacketLengthWidth::Large32,
823 )
824 .expect("packet should encode");
825 assert_eq!(&packet[..10], &[0, 0, 0, 13, 6, 0, 0, 0, 0, 0]);
826 }
827}