tiberius/tds/codec/column_data/
plp.rs

1use crate::sql_read_bytes::SqlReadBytes;
2
3// Decode a partially length-prefixed type.
4pub(crate) async fn decode<R>(src: &mut R, len: usize) -> crate::Result<Option<Vec<u8>>>
5where
6    R: SqlReadBytes + Unpin,
7{
8    match len {
9        // Fixed size
10        len if len < 0xffff => {
11            let len = src.read_u16_le().await? as u64;
12
13            match len {
14                // NULL
15                0xffff => Ok(None),
16                _ => {
17                    let mut data = Vec::with_capacity(len as usize);
18
19                    for _ in 0..len {
20                        data.push(src.read_u8().await?);
21                    }
22
23                    Ok(Some(data))
24                }
25            }
26        }
27        // Unknown size, length-prefixed blobs
28        _ => {
29            let len = src.read_u64_le().await?;
30
31            let mut data = match len {
32                // NULL
33                0xffffffffffffffff => return Ok(None),
34                // Unknown size
35                0xfffffffffffffffe => Vec::new(),
36                // Known size
37                _ => Vec::with_capacity(len as usize),
38            };
39
40            let mut chunk_data_left = 0;
41
42            loop {
43                if chunk_data_left == 0 {
44                    // We have no chunk. Start a new one.
45                    let chunk_size = src.read_u32_le().await? as usize;
46
47                    if chunk_size == 0 {
48                        break; // found a sentinel, we're done
49                    } else {
50                        chunk_data_left = chunk_size
51                    }
52                } else {
53                    // Just read a byte
54                    let byte = src.read_u8().await?;
55                    chunk_data_left -= 1;
56
57                    data.push(byte);
58                }
59            }
60
61            Ok(Some(data))
62        }
63    }
64}