1use std::cell::RefCell;
8use std::collections::HashMap;
9use std::fs::File;
10use std::io::Read;
11use std::path::Path;
12use std::sync::Arc;
13use indexmap::IndexMap;
14use crate::types::ObjectMap;
15
16use memmap2::Mmap;
17
18use crate::{Error, Result, Value, Schema, Union, Variant, Field, FieldType, TLType, MAGIC, HEADER_SIZE};
19
20const MAX_DECOMPRESSED_SIZE: usize = 256 * 1024 * 1024;
22
23const MAX_VARINT_BYTES: usize = 10;
25
26const MAX_DECODE_DEPTH: usize = 256;
29
30const MAX_COLLECTION_SIZE: usize = 1024 * 1024;
34
35fn read_u16_at(data: &[u8], offset: usize) -> Result<u16> {
37 let end = offset.checked_add(2)
38 .ok_or_else(|| Error::ParseError("offset overflow".into()))?;
39 if end > data.len() {
40 return Err(Error::ParseError(format!(
41 "read u16 out of bounds at offset {} (data len {})", offset, data.len()
42 )));
43 }
44 Ok(u16::from_le_bytes(data[offset..end].try_into().map_err(|_|
45 Error::ParseError(format!("u16 slice conversion failed at offset {}", offset))
46 )?))
47}
48
49fn read_u32_at(data: &[u8], offset: usize) -> Result<u32> {
51 let end = offset.checked_add(4)
52 .ok_or_else(|| Error::ParseError("offset overflow".into()))?;
53 if end > data.len() {
54 return Err(Error::ParseError(format!(
55 "read u32 out of bounds at offset {} (data len {})", offset, data.len()
56 )));
57 }
58 Ok(u32::from_le_bytes(data[offset..end].try_into().map_err(|_|
59 Error::ParseError(format!("u32 slice conversion failed at offset {}", offset))
60 )?))
61}
62
63fn read_u64_at(data: &[u8], offset: usize) -> Result<u64> {
65 let end = offset.checked_add(8)
66 .ok_or_else(|| Error::ParseError("offset overflow".into()))?;
67 if end > data.len() {
68 return Err(Error::ParseError(format!(
69 "read u64 out of bounds at offset {} (data len {})", offset, data.len()
70 )));
71 }
72 Ok(u64::from_le_bytes(data[offset..end].try_into().map_err(|_|
73 Error::ParseError(format!("u64 slice conversion failed at offset {}", offset))
74 )?))
75}
76
77enum DataSource {
79 Owned(Vec<u8>),
81 Mapped(Arc<Mmap>),
83}
84
85impl AsRef<[u8]> for DataSource {
86 fn as_ref(&self) -> &[u8] {
87 match self {
88 DataSource::Owned(v) => v.as_slice(),
89 DataSource::Mapped(m) => m.as_ref(),
90 }
91 }
92}
93
94pub struct Reader {
96 data: DataSource,
97 string_offsets: Vec<u32>,
98 string_lengths: Vec<u32>,
99 string_data_offset: usize,
100 pub schemas: Vec<Schema>,
101 schema_map: HashMap<String, usize>,
102 pub unions: Vec<Union>,
103 union_map: HashMap<String, usize>,
104 sections: IndexMap<String, SectionInfo>,
105 is_root_array: bool,
107 cache: RefCell<HashMap<String, Value>>,
109}
110
111#[allow(dead_code)]
112struct SectionInfo {
113 offset: u64,
114 size: u32,
115 uncompressed_size: u32,
116 schema_idx: i32,
117 tl_type: TLType,
118 compressed: bool,
119 is_array: bool,
120 item_count: u32,
121}
122
123impl Reader {
124 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
126 let mut file = File::open(path)?;
127 let mut data = Vec::new();
128 file.read_to_end(&mut data)?;
129 Self::from_bytes(data)
130 }
131
132 pub fn open_mmap<P: AsRef<Path>>(path: P) -> Result<Self> {
140 let file = File::open(path)?;
141 let mmap = unsafe { Mmap::map(&file)? };
142 Self::from_data_source(DataSource::Mapped(Arc::new(mmap)))
143 }
144
145 pub fn from_bytes(data: Vec<u8>) -> Result<Self> {
147 Self::from_data_source(DataSource::Owned(data))
148 }
149
150 fn from_data_source(data: DataSource) -> Result<Self> {
152 let bytes = data.as_ref();
153
154 if bytes.len() < HEADER_SIZE {
155 return Err(Error::InvalidMagic);
156 }
157 if &bytes[0..4] != MAGIC {
158 return Err(Error::InvalidMagic);
159 }
160
161 let major = read_u16_at(bytes, 4)?;
163 let minor = read_u16_at(bytes, 6)?;
164 if major != 2 {
165 return Err(Error::InvalidVersion { major, minor });
166 }
167
168 let flags = read_u32_at(bytes, 8)?;
170 let is_root_array = (flags & 0x02) != 0;
171
172 let str_off = read_u64_at(bytes, 16)? as usize;
173 let sch_off = read_u64_at(bytes, 24)? as usize;
174 let idx_off = read_u64_at(bytes, 32)? as usize;
175 let dat_off = read_u64_at(bytes, 40)? as usize;
176 let str_cnt = read_u32_at(bytes, 48)? as usize;
177 let sch_cnt = read_u32_at(bytes, 52)? as usize;
178 let sec_cnt = read_u32_at(bytes, 56)? as usize;
179
180 if str_off > bytes.len() || sch_off > bytes.len() || idx_off > bytes.len() || dat_off > bytes.len() {
182 return Err(Error::ParseError("header region offsets exceed file size".into()));
183 }
184
185 let str_header_end = str_off.checked_add(8)
187 .ok_or_else(|| Error::ParseError("string table offset overflow".into()))?;
188 if str_header_end > bytes.len() {
189 return Err(Error::ParseError("string table header out of bounds".into()));
190 }
191
192 let offsets_size = str_cnt.checked_mul(4)
193 .ok_or_else(|| Error::ParseError("string count overflow".into()))?;
194 let lengths_size = str_cnt.checked_mul(4)
195 .ok_or_else(|| Error::ParseError("string count overflow".into()))?;
196 let str_table_end = str_header_end
197 .checked_add(offsets_size)
198 .and_then(|v| v.checked_add(lengths_size))
199 .ok_or_else(|| Error::ParseError("string table size overflow".into()))?;
200 if str_table_end > bytes.len() {
201 return Err(Error::ParseError("string table out of bounds".into()));
202 }
203
204 let mut off = str_off + 8;
205 let string_offsets: Vec<u32> = (0..str_cnt)
206 .map(|i| read_u32_at(bytes, off + i * 4))
207 .collect::<Result<Vec<u32>>>()?;
208 off += offsets_size;
209 let string_lengths: Vec<u32> = (0..str_cnt)
210 .map(|i| read_u32_at(bytes, off + i * 4))
211 .collect::<Result<Vec<u32>>>()?;
212 let string_data_offset = off + lengths_size;
213
214 let union_cnt = if sch_off + 8 <= bytes.len() {
216 read_u16_at(bytes, sch_off + 6)? as usize
217 } else {
218 0
219 };
220
221 let mut reader = Self {
222 data,
223 string_offsets,
224 string_lengths,
225 string_data_offset,
226 schemas: Vec::new(),
227 schema_map: HashMap::new(),
228 unions: Vec::new(),
229 union_map: HashMap::new(),
230 sections: IndexMap::new(),
231 is_root_array,
232 cache: RefCell::new(HashMap::new()),
233 };
234
235 reader.parse_schemas(sch_off, sch_cnt)?;
236 if union_cnt > 0 {
237 reader.parse_unions(sch_off, sch_cnt, union_cnt)?;
238 }
239 reader.parse_index(idx_off, sec_cnt)?;
240
241 Ok(reader)
242 }
243
244 fn data(&self) -> &[u8] {
246 self.data.as_ref()
247 }
248
249 pub fn get_string(&self, idx: usize) -> Result<String> {
251 if idx >= self.string_offsets.len() {
252 return Err(Error::ParseError(format!("String index {} out of bounds", idx)));
253 }
254 let start = self.string_data_offset
255 .checked_add(self.string_offsets[idx] as usize)
256 .ok_or_else(|| Error::ParseError("string data offset overflow".into()))?;
257 let len = self.string_lengths[idx] as usize;
258 let end = start.checked_add(len)
259 .ok_or_else(|| Error::ParseError("string data range overflow".into()))?;
260 if end > self.data().len() {
261 return Err(Error::ParseError(format!(
262 "string data out of bounds: {}..{} exceeds file size {}", start, end, self.data().len()
263 )));
264 }
265 String::from_utf8(self.data()[start..end].to_vec())
266 .map_err(|_| Error::InvalidUtf8)
267 }
268
269 pub fn keys(&self) -> Vec<&str> {
271 self.sections.keys().map(|s| s.as_str()).collect()
272 }
273
274 pub fn is_root_array(&self) -> bool {
279 self.is_root_array
280 }
281
282 pub fn get(&self, key: &str) -> Result<Value> {
284 if let Some(cached) = self.cache.borrow().get(key) {
286 return Ok(cached.clone());
287 }
288
289 let section = self.sections.get(key)
290 .ok_or_else(|| Error::MissingField(key.to_string()))?;
291
292 let start = section.offset as usize;
293 let end = start.checked_add(section.size as usize)
294 .ok_or_else(|| Error::ParseError("section offset overflow".into()))?;
295 if end > self.data().len() {
296 return Err(Error::ParseError(format!(
297 "section '{}' data range {}..{} exceeds file size {}",
298 key, start, end, self.data().len()
299 )));
300 }
301
302 let data = if section.compressed {
303 decompress_data(&self.data()[start..end])?
304 } else {
305 self.data()[start..end].to_vec()
306 };
307
308 let mut cursor = Cursor::new(&data);
309
310 let result = if section.is_array && section.schema_idx >= 0 {
311 self.decode_struct_array(&mut cursor, section.schema_idx as usize, 0)?
312 } else {
313 match section.tl_type {
314 TLType::Array => self.decode_array(&mut cursor, 0)?,
315 TLType::Object => self.decode_object(&mut cursor, 0)?,
316 TLType::Struct => self.decode_struct(&mut cursor, 0)?,
317 TLType::Map => self.decode_map(&mut cursor, 0)?,
318 _ => self.decode_value(&mut cursor, section.tl_type, 0)?,
319 }
320 };
321
322 self.cache.borrow_mut().insert(key.to_string(), result.clone());
323 Ok(result)
324 }
325
326 pub fn clear_cache(&self) {
328 self.cache.borrow_mut().clear();
329 }
330
331 fn parse_schemas(&mut self, off: usize, count: usize) -> Result<()> {
332 if count == 0 {
333 return Ok(());
334 }
335
336 let data = self.data.as_ref();
337 let o = off.checked_add(8)
338 .ok_or_else(|| Error::ParseError("schema offset overflow".into()))?;
339
340 let offsets_size = count.checked_mul(4)
342 .ok_or_else(|| Error::ParseError("schema count overflow".into()))?;
343 let offsets_end = o.checked_add(offsets_size)
344 .ok_or_else(|| Error::ParseError("schema offsets overflow".into()))?;
345 if offsets_end > data.len() {
346 return Err(Error::ParseError("schema offset table out of bounds".into()));
347 }
348
349 let offsets: Vec<u32> = (0..count)
350 .map(|i| read_u32_at(data, o + i * 4))
351 .collect::<Result<Vec<u32>>>()?;
352 let start = offsets_end;
353
354 for i in 0..count {
355 let so = start.checked_add(offsets[i] as usize)
356 .ok_or_else(|| Error::ParseError("schema entry offset overflow".into()))?;
357
358 if so.checked_add(8).map_or(true, |end| end > data.len()) {
360 return Err(Error::ParseError(format!("schema entry {} out of bounds", i)));
361 }
362
363 let name_idx = read_u32_at(data, so)?;
364 let field_count = read_u16_at(data, so + 4)? as usize;
365
366 let name = self.get_string(name_idx as usize)?;
367 let mut schema = Schema::new(&name);
368
369 let mut fo = so + 8;
370 for fi in 0..field_count {
371 if fo.checked_add(8).map_or(true, |end| end > data.len()) {
373 return Err(Error::ParseError(format!(
374 "schema '{}' field {} out of bounds", name, fi
375 )));
376 }
377
378 let fname_idx = read_u32_at(data, fo)?;
379 let ftype = data[fo + 4];
380 let fflags = data[fo + 5];
381 let fextra = read_u16_at(data, fo + 6)?;
382
383 let fname = self.get_string(fname_idx as usize)?;
384 let tl_type = TLType::try_from(ftype)?;
385
386 let base = match tl_type {
387 TLType::Bool => "bool".to_string(),
388 TLType::Int8 => "int8".to_string(),
389 TLType::Int16 => "int16".to_string(),
390 TLType::Int32 => "int".to_string(),
391 TLType::Int64 => "int64".to_string(),
392 TLType::UInt8 => "uint8".to_string(),
393 TLType::UInt16 => "uint16".to_string(),
394 TLType::UInt32 => "uint".to_string(),
395 TLType::UInt64 => "uint64".to_string(),
396 TLType::Float32 => "float32".to_string(),
397 TLType::Float64 => "float".to_string(),
398 TLType::String => "string".to_string(),
399 TLType::Bytes => "bytes".to_string(),
400 TLType::Timestamp => "timestamp".to_string(),
401 TLType::Struct => {
402 if fextra != 0xFFFF {
404 self.get_string(fextra as usize)?
405 } else {
406 "object".to_string()
407 }
408 }
409 TLType::Tagged => {
410 if fextra != 0xFFFF {
412 self.get_string(fextra as usize)?
413 } else {
414 "tagged".to_string()
415 }
416 }
417 TLType::Object => "object".to_string(),
418 TLType::Tuple => "tuple".to_string(),
419 TLType::Map => "map".to_string(),
420 _ => "string".to_string(),
421 };
422
423 let mut field_type = FieldType::new(&base);
424 if fflags & 0x01 != 0 {
425 field_type.nullable = true;
426 }
427 if fflags & 0x02 != 0 {
428 field_type.is_array = true;
429 }
430
431 schema.fields.push(Field::new(fname, field_type));
432 fo += 8;
433 }
434
435 self.schema_map.insert(name, self.schemas.len());
436 self.schemas.push(schema);
437 }
438
439 Ok(())
440 }
441
442 fn parse_unions(&mut self, sch_off: usize, struct_count: usize, union_count: usize) -> Result<()> {
443 let data = self.data.as_ref();
444
445 let struct_offsets_start = sch_off.checked_add(8)
453 .ok_or_else(|| Error::ParseError("union region offset overflow".into()))?;
454 let struct_offsets_size = struct_count.checked_mul(4)
455 .ok_or_else(|| Error::ParseError("struct count overflow".into()))?;
456 let struct_data_start = struct_offsets_start.checked_add(struct_offsets_size)
457 .ok_or_else(|| Error::ParseError("struct data start overflow".into()))?;
458 let struct_data_size: usize = self.schemas.iter()
459 .map(|s| 8 + s.fields.len() * 8)
460 .sum();
461 let union_offsets_start = struct_data_start.checked_add(struct_data_size)
462 .ok_or_else(|| Error::ParseError("union offsets start overflow".into()))?;
463
464 let union_offsets_size = union_count.checked_mul(4)
466 .ok_or_else(|| Error::ParseError("union count overflow".into()))?;
467 let union_offsets_end = union_offsets_start.checked_add(union_offsets_size)
468 .ok_or_else(|| Error::ParseError("union offsets end overflow".into()))?;
469 if union_offsets_end > data.len() {
470 return Err(Error::ParseError("union offset table out of bounds".into()));
471 }
472
473 let union_offsets: Vec<u32> = (0..union_count)
475 .map(|i| read_u32_at(data, union_offsets_start + i * 4))
476 .collect::<Result<Vec<u32>>>()?;
477 let union_data_start = union_offsets_end;
478
479 for i in 0..union_count {
480 let uo = union_data_start.checked_add(union_offsets[i] as usize)
481 .ok_or_else(|| Error::ParseError("union entry offset overflow".into()))?;
482
483 if uo.checked_add(8).map_or(true, |end| end > data.len()) {
485 return Err(Error::ParseError(format!("union entry {} out of bounds", i)));
486 }
487
488 let name_idx = read_u32_at(data, uo)?;
489 let variant_count = read_u16_at(data, uo + 4)? as usize;
490 let name = self.get_string(name_idx as usize)?;
493 let mut union = Union::new(&name);
494
495 let mut vo = uo + 8;
496 for vi in 0..variant_count {
497 if vo.checked_add(8).map_or(true, |end| end > data.len()) {
499 return Err(Error::ParseError(format!(
500 "union '{}' variant {} out of bounds", name, vi
501 )));
502 }
503
504 let vname_idx = read_u32_at(data, vo)?;
505 let field_count = read_u16_at(data, vo + 4)? as usize;
506 let vname = self.get_string(vname_idx as usize)?;
509 let mut variant = Variant::new(&vname);
510
511 let mut fo = vo + 8;
512 for fi in 0..field_count {
513 if fo.checked_add(8).map_or(true, |end| end > data.len()) {
515 return Err(Error::ParseError(format!(
516 "union '{}' variant '{}' field {} out of bounds", name, vname, fi
517 )));
518 }
519
520 let fname_idx = read_u32_at(data, fo)?;
521 let ftype = data[fo + 4];
522 let fflags = data[fo + 5];
523 let fextra = read_u16_at(data, fo + 6)?;
524
525 let fname = self.get_string(fname_idx as usize)?;
526 let tl_type = TLType::try_from(ftype)?;
527
528 let base = match tl_type {
529 TLType::Bool => "bool".to_string(),
530 TLType::Int8 => "int8".to_string(),
531 TLType::Int16 => "int16".to_string(),
532 TLType::Int32 => "int".to_string(),
533 TLType::Int64 => "int64".to_string(),
534 TLType::UInt8 => "uint8".to_string(),
535 TLType::UInt16 => "uint16".to_string(),
536 TLType::UInt32 => "uint".to_string(),
537 TLType::UInt64 => "uint64".to_string(),
538 TLType::Float32 => "float32".to_string(),
539 TLType::Float64 => "float".to_string(),
540 TLType::String => "string".to_string(),
541 TLType::Bytes => "bytes".to_string(),
542 TLType::Timestamp => "timestamp".to_string(),
543 TLType::Struct => {
544 if fextra != 0xFFFF {
545 self.get_string(fextra as usize)?
546 } else {
547 "object".to_string()
548 }
549 }
550 TLType::Tagged => {
551 if fextra != 0xFFFF {
552 self.get_string(fextra as usize)?
553 } else {
554 "tagged".to_string()
555 }
556 }
557 TLType::Object => "object".to_string(),
558 TLType::Tuple => "tuple".to_string(),
559 TLType::Map => "map".to_string(),
560 _ => "string".to_string(),
561 };
562
563 let mut field_type = FieldType::new(&base);
564 if fflags & 0x01 != 0 { field_type.nullable = true; }
565 if fflags & 0x02 != 0 { field_type.is_array = true; }
566
567 variant.fields.push(Field::new(fname, field_type));
568 fo += 8;
569 }
570
571 union.variants.push(variant);
572 vo = fo;
573 }
574
575 self.union_map.insert(name, self.unions.len());
576 self.unions.push(union);
577 }
578
579 Ok(())
580 }
581
582 fn parse_index(&mut self, off: usize, count: usize) -> Result<()> {
583 let data = self.data.as_ref();
584 let mut o = off.checked_add(8)
585 .ok_or_else(|| Error::ParseError("index offset overflow".into()))?;
586
587 let index_size = count.checked_mul(32)
589 .ok_or_else(|| Error::ParseError("index count overflow".into()))?;
590 let index_end = o.checked_add(index_size)
591 .ok_or_else(|| Error::ParseError("index region overflow".into()))?;
592 if index_end > data.len() {
593 return Err(Error::ParseError("index table out of bounds".into()));
594 }
595
596 for _ in 0..count {
597 let key_idx = read_u32_at(data, o)?;
598 let offset = read_u64_at(data, o + 4)?;
599 let size = read_u32_at(data, o + 12)?;
600 let uncompressed = read_u32_at(data, o + 16)?;
601 let schema_idx = read_u16_at(data, o + 20)?;
602 let ptype = data[o + 22];
603 let flags = data[o + 23];
604 let item_count = read_u32_at(data, o + 24)?;
605
606 let key = self.get_string(key_idx as usize)?;
607
608 let sec_start = offset as usize;
610 let sec_end = sec_start.checked_add(size as usize)
611 .ok_or_else(|| Error::ParseError(format!(
612 "section '{}' offset overflow", key
613 )))?;
614 if sec_end > data.len() {
615 return Err(Error::ParseError(format!(
616 "section '{}' data range {}..{} exceeds file size {}",
617 key, sec_start, sec_end, data.len()
618 )));
619 }
620
621 self.sections.insert(key, SectionInfo {
622 offset,
623 size,
624 uncompressed_size: uncompressed,
625 schema_idx: if schema_idx == 0xFFFF { -1 } else { schema_idx as i32 },
626 tl_type: TLType::try_from(ptype)?,
627 compressed: flags & 0x01 != 0,
628 is_array: flags & 0x02 != 0,
629 item_count,
630 });
631 o += 32;
632 }
633
634 Ok(())
635 }
636
637 fn decode_struct_array(&self, cursor: &mut Cursor, schema_idx: usize, depth: usize) -> Result<Value> {
638 if depth > MAX_DECODE_DEPTH {
639 return Err(Error::ParseError("maximum decode nesting depth exceeded".into()));
640 }
641 let count = cursor.read_u32()?;
642 if count as usize > MAX_COLLECTION_SIZE {
643 return Err(Error::ParseError(format!(
644 "struct array element count {} exceeds limit of {}", count, MAX_COLLECTION_SIZE
645 )));
646 }
647 let _si = cursor.read_u16()?;
648 let bitmap_size = cursor.read_u16()? as usize;
649
650 if schema_idx >= self.schemas.len() {
651 return Err(Error::ParseError(format!(
652 "struct array schema index {} out of bounds ({} schemas available)",
653 schema_idx, self.schemas.len()
654 )));
655 }
656 let schema = &self.schemas[schema_idx];
657 let capacity = (count as usize).min(cursor.remaining()).min(MAX_COLLECTION_SIZE);
658 let mut result = Vec::with_capacity(capacity);
659
660 for _ in 0..count {
661 let mut bitmap = Vec::with_capacity(bitmap_size.min(cursor.remaining()));
662 for _ in 0..bitmap_size {
663 bitmap.push(cursor.read_u8()?);
664 }
665
666 let all_null = (0..schema.fields.len())
668 .all(|i| i / 8 < bitmap.len() && (bitmap[i / 8] & (1 << (i % 8))) != 0);
669
670 if all_null {
671 result.push(Value::Null);
672 } else {
673 let mut obj = ObjectMap::new();
674 for (i, field) in schema.fields.iter().enumerate() {
675 let is_null = i / 8 < bitmap.len() && (bitmap[i / 8] & (1 << (i % 8))) != 0;
676 if is_null {
677 if !field.field_type.nullable {
678 obj.insert(field.name.clone(), Value::Null);
679 }
680 } else {
681 let tl_type = if self.union_map.contains_key(&field.field_type.base) {
683 TLType::Tagged
684 } else {
685 field.field_type.to_tl_type()
686 };
687 obj.insert(field.name.clone(), self.decode_value(cursor, tl_type, depth + 1)?);
688 }
689 }
690 result.push(Value::Object(obj));
691 }
692 }
693
694 Ok(Value::Array(result))
695 }
696
697 fn decode_array(&self, cursor: &mut Cursor, depth: usize) -> Result<Value> {
698 if depth > MAX_DECODE_DEPTH {
699 return Err(Error::ParseError("maximum decode nesting depth exceeded".into()));
700 }
701 let count = cursor.read_u32()?;
702 if count == 0 {
703 return Ok(Value::Array(Vec::new()));
704 }
705 if count as usize > MAX_COLLECTION_SIZE {
706 return Err(Error::ParseError(format!(
707 "array element count {} exceeds limit of {}", count, MAX_COLLECTION_SIZE
708 )));
709 }
710
711 let elem_type = cursor.read_u8()?;
712 let capacity = (count as usize).min(cursor.remaining()).min(MAX_COLLECTION_SIZE);
713 let mut result = Vec::with_capacity(capacity);
714
715 if elem_type == 0xFF {
716 for _ in 0..count {
717 let t = TLType::try_from(cursor.read_u8()?)?;
718 result.push(self.decode_value(cursor, t, depth + 1)?);
719 }
720 } else {
721 let t = TLType::try_from(elem_type)?;
722 for _ in 0..count {
723 result.push(self.decode_value(cursor, t, depth + 1)?);
724 }
725 }
726
727 Ok(Value::Array(result))
728 }
729
730 fn decode_object(&self, cursor: &mut Cursor, depth: usize) -> Result<Value> {
731 if depth > MAX_DECODE_DEPTH {
732 return Err(Error::ParseError("maximum decode nesting depth exceeded".into()));
733 }
734 let count = cursor.read_u16()?;
735 let mut obj = ObjectMap::new();
736
737 for _ in 0..count {
738 let key_idx = cursor.read_u32()?;
739 let t = TLType::try_from(cursor.read_u8()?)?;
740 let key = self.get_string(key_idx as usize)?;
741 obj.insert(key, self.decode_value(cursor, t, depth + 1)?);
742 }
743
744 Ok(Value::Object(obj))
745 }
746
747 fn decode_struct(&self, cursor: &mut Cursor, depth: usize) -> Result<Value> {
748 if depth > MAX_DECODE_DEPTH {
749 return Err(Error::ParseError("maximum decode nesting depth exceeded".into()));
750 }
751 let schema_idx = cursor.read_u16()? as usize;
752 if schema_idx >= self.schemas.len() {
753 return Err(Error::ParseError(format!(
754 "struct schema index {} out of bounds ({} schemas available)",
755 schema_idx, self.schemas.len()
756 )));
757 }
758 let schema = &self.schemas[schema_idx];
759 let bitmap_size = (schema.fields.len() + 7) / 8;
760
761 let mut bitmap = Vec::with_capacity(bitmap_size.min(cursor.remaining()));
762 for _ in 0..bitmap_size {
763 bitmap.push(cursor.read_u8()?);
764 }
765
766 let mut obj = ObjectMap::new();
767 for (i, field) in schema.fields.iter().enumerate() {
768 let is_null = i / 8 < bitmap.len() && (bitmap[i / 8] & (1 << (i % 8))) != 0;
769 if is_null {
770 if !field.field_type.nullable {
773 obj.insert(field.name.clone(), Value::Null);
774 }
775 } else {
776 let tl_type = if self.union_map.contains_key(&field.field_type.base) {
778 TLType::Tagged
779 } else {
780 field.field_type.to_tl_type()
781 };
782 obj.insert(field.name.clone(), self.decode_value(cursor, tl_type, depth + 1)?);
783 }
784 }
785
786 Ok(Value::Object(obj))
787 }
788
789 fn decode_map(&self, cursor: &mut Cursor, depth: usize) -> Result<Value> {
790 if depth > MAX_DECODE_DEPTH {
791 return Err(Error::ParseError("maximum decode nesting depth exceeded".into()));
792 }
793 let count = cursor.read_u32()?;
794 if count as usize > MAX_COLLECTION_SIZE {
795 return Err(Error::ParseError(format!(
796 "map element count {} exceeds limit of {}", count, MAX_COLLECTION_SIZE
797 )));
798 }
799 let capacity = (count as usize).min(cursor.remaining()).min(MAX_COLLECTION_SIZE);
800 let mut pairs = Vec::with_capacity(capacity);
801
802 for _ in 0..count {
803 let key_type = TLType::try_from(cursor.read_u8()?)?;
804 let key = self.decode_value(cursor, key_type, depth + 1)?;
805 match &key {
807 Value::String(_) | Value::Int(_) | Value::UInt(_) => {}
808 _ => return Err(Error::ParseError(
809 format!("invalid map key type {:?}: map keys must be string, int, or uint", key.tl_type())
810 )),
811 }
812 let val_type = TLType::try_from(cursor.read_u8()?)?;
813 let val = self.decode_value(cursor, val_type, depth + 1)?;
814 pairs.push((key, val));
815 }
816
817 Ok(Value::Map(pairs))
818 }
819
820 fn decode_value(&self, cursor: &mut Cursor, tl_type: TLType, depth: usize) -> Result<Value> {
821 if depth > MAX_DECODE_DEPTH {
822 return Err(Error::ParseError("maximum decode nesting depth exceeded".into()));
823 }
824 Ok(match tl_type {
825 TLType::Null => Value::Null,
826 TLType::Bool => Value::Bool(cursor.read_u8()? != 0),
827 TLType::Int8 => Value::Int(cursor.read_i8()? as i64),
828 TLType::Int16 => Value::Int(cursor.read_i16()? as i64),
829 TLType::Int32 => Value::Int(cursor.read_i32()? as i64),
830 TLType::Int64 => Value::Int(cursor.read_i64()?),
831 TLType::UInt8 => Value::UInt(cursor.read_u8()? as u64),
832 TLType::UInt16 => Value::UInt(cursor.read_u16()? as u64),
833 TLType::UInt32 => Value::UInt(cursor.read_u32()? as u64),
834 TLType::UInt64 => Value::UInt(cursor.read_u64()?),
835 TLType::Float32 => Value::Float(cursor.read_f32()? as f64),
836 TLType::Float64 => Value::Float(cursor.read_f64()?),
837 TLType::String => {
838 let idx = cursor.read_u32()?;
839 Value::String(self.get_string(idx as usize)?)
840 }
841 TLType::Bytes => {
842 let len = cursor.read_varint()? as usize;
843 Value::Bytes(cursor.read_bytes(len)?)
844 }
845 TLType::Array => self.decode_array(cursor, depth)?,
846 TLType::Object => self.decode_object(cursor, depth)?,
847 TLType::Struct => self.decode_struct(cursor, depth)?,
848 TLType::Ref => {
849 let idx = cursor.read_u32()?;
850 Value::Ref(self.get_string(idx as usize)?)
851 }
852 TLType::Tagged => {
853 let tag_idx = cursor.read_u32()?;
854 let inner_type = TLType::try_from(cursor.read_u8()?)?;
855 let tag = self.get_string(tag_idx as usize)?;
856 let inner = self.decode_value(cursor, inner_type, depth + 1)?;
857 Value::Tagged(tag, Box::new(inner))
858 }
859 TLType::Map => self.decode_map(cursor, depth)?,
860 TLType::Timestamp => {
861 let ts = cursor.read_i64()?;
862 let tz = cursor.read_i16()?;
863 Value::Timestamp(ts, tz)
864 }
865 TLType::JsonNumber => {
866 let idx = cursor.read_u32()?;
867 Value::JsonNumber(self.get_string(idx as usize)?)
868 }
869 TLType::Tuple => {
870 self.decode_array(cursor, depth)?
872 }
873 })
874 }
875}
876
877struct Cursor<'a> {
879 data: &'a [u8],
880 pos: usize,
881}
882
883impl<'a> Cursor<'a> {
884 fn new(data: &'a [u8]) -> Self {
885 Self { data, pos: 0 }
886 }
887
888 fn remaining(&self) -> usize {
889 self.data.len().saturating_sub(self.pos)
890 }
891
892 fn check_bounds(&self, len: usize) -> Result<()> {
893 let end = self.pos.checked_add(len)
894 .ok_or_else(|| Error::ParseError("cursor position overflow".into()))?;
895 if end > self.data.len() {
896 return Err(Error::ParseError(format!(
897 "read out of bounds: pos={} len={} data_len={}", self.pos, len, self.data.len()
898 )));
899 }
900 Ok(())
901 }
902
903 fn read_u8(&mut self) -> Result<u8> {
904 self.check_bounds(1)?;
905 let v = self.data[self.pos];
906 self.pos += 1;
907 Ok(v)
908 }
909
910 fn read_i8(&mut self) -> Result<i8> {
911 Ok(self.read_u8()? as i8)
912 }
913
914 fn read_u16(&mut self) -> Result<u16> {
915 self.check_bounds(2)?;
916 let end = self.pos + 2; let v = u16::from_le_bytes(self.data[self.pos..end].try_into().map_err(|_|
918 Error::ParseError("u16 cursor conversion failed".into())
919 )?);
920 self.pos = end;
921 Ok(v)
922 }
923
924 fn read_i16(&mut self) -> Result<i16> {
925 Ok(self.read_u16()? as i16)
926 }
927
928 fn read_u32(&mut self) -> Result<u32> {
929 self.check_bounds(4)?;
930 let end = self.pos + 4;
931 let v = u32::from_le_bytes(self.data[self.pos..end].try_into().map_err(|_|
932 Error::ParseError("u32 cursor conversion failed".into())
933 )?);
934 self.pos = end;
935 Ok(v)
936 }
937
938 fn read_i32(&mut self) -> Result<i32> {
939 Ok(self.read_u32()? as i32)
940 }
941
942 fn read_u64(&mut self) -> Result<u64> {
943 self.check_bounds(8)?;
944 let end = self.pos + 8;
945 let v = u64::from_le_bytes(self.data[self.pos..end].try_into().map_err(|_|
946 Error::ParseError("u64 cursor conversion failed".into())
947 )?);
948 self.pos = end;
949 Ok(v)
950 }
951
952 fn read_i64(&mut self) -> Result<i64> {
953 Ok(self.read_u64()? as i64)
954 }
955
956 fn read_f32(&mut self) -> Result<f32> {
957 self.check_bounds(4)?;
958 let end = self.pos + 4;
959 let v = f32::from_le_bytes(self.data[self.pos..end].try_into().map_err(|_|
960 Error::ParseError("f32 cursor conversion failed".into())
961 )?);
962 self.pos = end;
963 Ok(v)
964 }
965
966 fn read_f64(&mut self) -> Result<f64> {
967 self.check_bounds(8)?;
968 let end = self.pos + 8;
969 let v = f64::from_le_bytes(self.data[self.pos..end].try_into().map_err(|_|
970 Error::ParseError("f64 cursor conversion failed".into())
971 )?);
972 self.pos = end;
973 Ok(v)
974 }
975
976 fn read_varint(&mut self) -> Result<u64> {
977 let mut result: u64 = 0;
978 let mut shift = 0;
979 for _ in 0..MAX_VARINT_BYTES {
980 let b = self.read_u8()?;
981 result |= ((b & 0x7F) as u64) << shift;
982 if b & 0x80 == 0 {
983 return Ok(result);
984 }
985 shift += 7;
986 }
987 Err(Error::ParseError("varint exceeds maximum length".into()))
988 }
989
990 fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>> {
991 self.check_bounds(len)?;
992 let end = self.pos.checked_add(len)
993 .ok_or_else(|| Error::ParseError("read_bytes offset overflow".into()))?;
994 let v = self.data[self.pos..end].to_vec();
995 self.pos = end;
996 Ok(v)
997 }
998}
999
1000fn decompress_data(data: &[u8]) -> Result<Vec<u8>> {
1001 use flate2::read::ZlibDecoder;
1002
1003 let decoder = ZlibDecoder::new(data);
1004 let mut limited = decoder.take((MAX_DECOMPRESSED_SIZE as u64) + 1);
1005 let mut result = Vec::new();
1006 limited.read_to_end(&mut result)
1007 .map_err(|_| Error::ParseError("Decompression failed".to_string()))?;
1008 if result.len() > MAX_DECOMPRESSED_SIZE {
1009 return Err(Error::ParseError(format!(
1010 "Decompressed data exceeds maximum size of {} bytes", MAX_DECOMPRESSED_SIZE
1011 )));
1012 }
1013 Ok(result)
1014}
1015
1016#[cfg(test)]
1017mod tests {
1018 use super::*;
1019 use crate::writer::Writer;
1020
1021 #[test]
1022 fn test_open_mmap() {
1023 let dir = std::env::temp_dir();
1025 let path = dir.join("test_reader_mmap.tlbx");
1026
1027 let mut w = Writer::new();
1028 w.add_section("val", &Value::Int(42), None).unwrap();
1029 w.write(&path, false).unwrap();
1030
1031 let r = Reader::open_mmap(&path).unwrap();
1032 assert_eq!(r.get("val").unwrap().as_int(), Some(42));
1033 std::fs::remove_file(&path).ok();
1034 }
1035
1036 #[test]
1037 fn test_open_regular() {
1038 let dir = std::env::temp_dir();
1039 let path = dir.join("test_reader_open.tlbx");
1040
1041 let mut w = Writer::new();
1042 w.add_section("greeting", &Value::String("hi".into()), None).unwrap();
1043 w.write(&path, false).unwrap();
1044
1045 let r = Reader::open(&path).unwrap();
1046 assert_eq!(r.get("greeting").unwrap().as_str(), Some("hi"));
1047 std::fs::remove_file(&path).ok();
1048 }
1049
1050 #[test]
1051 fn test_invalid_magic() {
1052 let result = Reader::from_bytes(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1053 assert!(result.is_err());
1054 }
1055
1056 #[test]
1057 fn test_too_short_data() {
1058 let result = Reader::from_bytes(vec![0; 10]);
1059 assert!(result.is_err());
1060 }
1061
1062 #[test]
1063 fn test_wrong_version() {
1064 let mut data = vec![0u8; 64];
1065 data[0] = b'T'; data[1] = b'L'; data[2] = b'F'; data[3] = b'X';
1067 data[4] = 3; data[5] = 0;
1069 let result = Reader::from_bytes(data);
1070 assert!(result.is_err());
1071 }
1072
1073 #[test]
1074 fn test_string_index_out_of_bounds() {
1075 let dir = std::env::temp_dir();
1076 let path = dir.join("test_str_oob.tlbx");
1077
1078 let mut w = Writer::new();
1079 w.add_section("x", &Value::Int(1), None).unwrap();
1080 w.write(&path, false).unwrap();
1081
1082 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1083 let result = r.get_string(9999);
1084 assert!(result.is_err());
1085 std::fs::remove_file(&path).ok();
1086 }
1087
1088 #[test]
1089 fn test_keys() {
1090 let dir = std::env::temp_dir();
1091 let path = dir.join("test_reader_keys.tlbx");
1092
1093 let mut w = Writer::new();
1094 w.add_section("alpha", &Value::Int(1), None).unwrap();
1095 w.add_section("beta", &Value::Int(2), None).unwrap();
1096 w.write(&path, false).unwrap();
1097
1098 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1099 let keys = r.keys();
1100 assert!(keys.contains(&"alpha"));
1101 assert!(keys.contains(&"beta"));
1102 std::fs::remove_file(&path).ok();
1103 }
1104
1105 #[test]
1106 fn test_missing_key() {
1107 let dir = std::env::temp_dir();
1108 let path = dir.join("test_reader_missing.tlbx");
1109
1110 let mut w = Writer::new();
1111 w.add_section("exists", &Value::Int(1), None).unwrap();
1112 w.write(&path, false).unwrap();
1113
1114 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1115 assert!(r.get("nonexistent").is_err());
1116 std::fs::remove_file(&path).ok();
1117 }
1118
1119 #[test]
1120 fn test_struct_section_roundtrip() {
1121 let dir = std::env::temp_dir();
1122 let path = dir.join("test_struct_section.tlbx");
1123
1124 let mut schema = Schema::new("Point");
1125 schema.add_field("x", FieldType::new("int"));
1126 schema.add_field("y", FieldType::new("int"));
1127
1128 let mut w = Writer::new();
1129 w.add_schema(schema.clone());
1130
1131 let mut obj1 = ObjectMap::new();
1132 obj1.insert("x".to_string(), Value::Int(10));
1133 obj1.insert("y".to_string(), Value::Int(20));
1134
1135 let mut obj2 = ObjectMap::new();
1136 obj2.insert("x".to_string(), Value::Int(30));
1137 obj2.insert("y".to_string(), Value::Null);
1138
1139 let arr = Value::Array(vec![Value::Object(obj1), Value::Object(obj2)]);
1140 w.add_section("points", &arr, Some(&schema)).unwrap();
1141 w.write(&path, false).unwrap();
1142
1143 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1144 assert!(!r.schemas.is_empty());
1145
1146 let points = r.get("points").unwrap();
1147 let items = points.as_array().unwrap();
1148 assert_eq!(items.len(), 2);
1149 let p1 = items[0].as_object().unwrap();
1150 assert_eq!(p1.get("x").unwrap().as_int(), Some(10));
1151 let p2 = items[1].as_object().unwrap();
1152 assert!(p2.get("y").unwrap().is_null());
1153 std::fs::remove_file(&path).ok();
1154 }
1155
1156 #[test]
1157 fn test_heterogeneous_array() {
1158 let dir = std::env::temp_dir();
1160 let path = dir.join("test_hetero_arr.tlbx");
1161
1162 let arr = Value::Array(vec![
1163 Value::Int(1),
1164 Value::String("hello".into()),
1165 Value::Bool(true),
1166 ]);
1167
1168 let mut w = Writer::new();
1169 w.add_section("mixed", &arr, None).unwrap();
1170 w.write(&path, false).unwrap();
1171
1172 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1173 let val = r.get("mixed").unwrap();
1174 let items = val.as_array().unwrap();
1175 assert_eq!(items.len(), 3);
1176 assert_eq!(items[0].as_int(), Some(1));
1177 assert_eq!(items[1].as_str(), Some("hello"));
1178 assert_eq!(items[2].as_bool(), Some(true));
1179 std::fs::remove_file(&path).ok();
1180 }
1181
1182 #[test]
1183 fn test_empty_array() {
1184 let dir = std::env::temp_dir();
1185 let path = dir.join("test_empty_arr.tlbx");
1186
1187 let mut w = Writer::new();
1188 w.add_section("empty", &Value::Array(vec![]), None).unwrap();
1189 w.write(&path, false).unwrap();
1190
1191 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1192 let val = r.get("empty").unwrap();
1193 let items = val.as_array().unwrap();
1194 assert_eq!(items.len(), 0);
1195 std::fs::remove_file(&path).ok();
1196 }
1197
1198 #[test]
1199 fn test_truncated_section_data() {
1200 let dir = std::env::temp_dir();
1202 let path = dir.join("test_truncated.tlbx");
1203
1204 let mut w = Writer::new();
1205 w.add_section("val", &Value::Int(42), None).unwrap();
1206 w.write(&path, false).unwrap();
1207
1208 let mut data = std::fs::read(&path).unwrap();
1210 data.truncate(data.len() - 1); let result = Reader::from_bytes(data);
1214 if let Ok(r) = result {
1215 let _ = r.get("val"); }
1218 std::fs::remove_file(&path).ok();
1219 }
1220
1221 #[test]
1222 fn test_cursor_bounds_checking() {
1223 let data = vec![1u8, 2];
1225 let mut cursor = Cursor::new(&data);
1226 assert!(cursor.read_u8().is_ok());
1227 assert!(cursor.read_u8().is_ok());
1228 assert!(cursor.read_u8().is_err()); let mut cursor2 = Cursor::new(&data);
1231 assert!(cursor2.read_u32().is_err()); let empty: Vec<u8> = vec![];
1234 let mut cursor3 = Cursor::new(&empty);
1235 assert!(cursor3.read_u8().is_err());
1236 assert!(cursor3.read_varint().is_err());
1237 }
1238
1239 #[test]
1240 fn test_varint_too_long() {
1241 let data = vec![0x80u8; 20];
1243 let mut cursor = Cursor::new(&data);
1244 assert!(cursor.read_varint().is_err());
1245 }
1246
1247 #[test]
1252 fn test_cache_returns_same_value() {
1253 use crate::Writer;
1254 let dir = std::env::temp_dir();
1255 let path = dir.join("test_cache_hit.tlbx");
1256
1257 let mut w = Writer::new();
1258 w.add_section("greeting", &crate::Value::String("hello".into()), None).unwrap();
1259 w.add_section("number", &crate::Value::Int(42), None).unwrap();
1260 w.write(&path, true).unwrap(); let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1263
1264 let v1 = r.get("greeting").unwrap();
1266 let v2 = r.get("greeting").unwrap();
1268 assert_eq!(v1, v2);
1269 assert_eq!(v1.as_str(), Some("hello"));
1270
1271 assert!(r.cache.borrow().contains_key("greeting"));
1273 assert!(!r.cache.borrow().contains_key("number")); let num = r.get("number").unwrap();
1277 assert_eq!(num.as_int(), Some(42));
1278 assert!(r.cache.borrow().contains_key("number"));
1279
1280 std::fs::remove_file(&path).ok();
1281 }
1282
1283 #[test]
1284 fn test_fuzz_crash_crafted_tlbx_2_no_panic() {
1285 let data: Vec<u8> = vec![
1287 0x54, 0x4C, 0x42, 0x58, 0x02, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1288 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1289 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1290 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
1291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1292 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1293 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1294 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
1297 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1300 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1301 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00,
1303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1304 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
1306 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
1307 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1308 ];
1309 let result = Reader::from_bytes(data);
1310 if let Ok(r) = result {
1311 for key in r.keys() {
1312 let _ = r.get(key); }
1314 }
1315 }
1316
1317 #[test]
1318 fn test_fuzz_oom_crafted_tlbx_no_panic() {
1319 let data: Vec<u8> = vec![
1323 0x54, 0x4C, 0x42, 0x58, 0x02, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
1324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1325 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1326 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00,
1327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1332 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00,
1336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4C,
1337 0x54, 0x26, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x23,
1338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1339 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
1340 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
1341 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
1342 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,
1343 0x00,
1344 ];
1345 let result = Reader::from_bytes(data);
1346 if let Ok(r) = result {
1347 for key in r.keys() {
1348 let _ = r.get(key); }
1350 }
1351 }
1352
1353 #[test]
1354 fn test_fuzz_oom_null_array_no_oom() {
1355 let data: Vec<u8> = vec![
1360 0x54, 0x4C, 0x42, 0x58, 0x02, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1362 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1363 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
1364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1366 ];
1368 let mut padded = data.clone();
1370 padded.resize(290, 0x00);
1371 padded.extend_from_slice(&[
1373 0x00, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]);
1383 padded.resize(335, 0x00);
1384
1385 let result = Reader::from_bytes(padded);
1386 if let Ok(r) = result {
1387 for key in r.keys() {
1388 let _ = r.get(key); }
1390 }
1391 }
1392
1393 #[test]
1394 fn test_fuzz_crash_crafted_tlbx_no_panic() {
1395 let data: Vec<u8> = vec![
1399 0x54, 0x4C, 0x42, 0x58, 0x02, 0x00, 0x0E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1400 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1401 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1402 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
1403 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1404 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1405 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1406 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
1407 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1408 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1410 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1411 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1412 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54,
1413 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1414 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1415 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1416 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00,
1417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00,
1418 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1419 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1420 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00,
1421 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1422 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1423 ];
1424 let result = Reader::from_bytes(data);
1425 if let Ok(r) = result {
1426 for key in r.keys() {
1427 let _ = r.get(key); }
1429 }
1430 }
1431
1432 #[test]
1433 fn test_clear_cache() {
1434 use crate::Writer;
1435 let dir = std::env::temp_dir();
1436 let path = dir.join("test_cache_clear.tlbx");
1437
1438 let mut w = Writer::new();
1439 w.add_section("val", &crate::Value::Int(99), None).unwrap();
1440 w.write(&path, false).unwrap();
1441
1442 let r = Reader::from_bytes(std::fs::read(&path).unwrap()).unwrap();
1443 let _ = r.get("val").unwrap();
1444 assert_eq!(r.cache.borrow().len(), 1);
1445
1446 r.clear_cache();
1447 assert_eq!(r.cache.borrow().len(), 0);
1448
1449 let v = r.get("val").unwrap();
1451 assert_eq!(v.as_int(), Some(99));
1452
1453 std::fs::remove_file(&path).ok();
1454 }
1455}