1use crate::encoding::DynEncoding;
2use crate::field::{DeletionFlag, FieldsInfo, DELETION_FLAG_SIZE};
3use crate::header::Header;
4use crate::memo::MemoReader;
5use crate::reading::{ReadingOptions, BACKLINK_SIZE, TERMINATOR_VALUE};
6use crate::writing::{write_header_parts, WritableAsDbaseField};
7use crate::ErrorKind::UnsupportedCodePage;
8use crate::{
9 Encoding, Error, ErrorKind, FieldConversionError, FieldIOError, FieldInfo, FieldIterator,
10 FieldValue, FieldWriter, ReadableRecord, TableInfo, WritableRecord,
11};
12use byteorder::ReadBytesExt;
13use std::fmt::{Debug, Formatter};
14use std::io::{Cursor, Read, Seek, SeekFrom, Write};
15use std::path::Path;
16
17pub type BufReadWriteFile = bufrw::BufReaderWriter<std::fs::File>;
18
19#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
21pub struct FieldIndex(pub usize);
22
23#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
25pub struct RecordIndex(pub usize);
26
27pub struct FieldRef<'a, T> {
32 file: &'a mut File<T>,
33 record_index: RecordIndex,
34 field_index: FieldIndex,
35}
36
37impl<T> Debug for FieldRef<'_, T> {
38 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39 f.debug_struct("FieldRef")
40 .field("record_index", &self.record_index)
41 .field("field_index", &self.field_index)
42 .finish()
43 }
44}
45
46impl<T> FieldRef<'_, T> {
47 fn position_in_source(&self) -> u64 {
48 let record_position = self
49 .file
50 .header
51 .record_position(self.record_index.0)
52 .unwrap() as u64;
53
54 record_position + self.position_in_record() as u64
55 }
56
57 fn position_in_record(&self) -> usize {
58 self.file
59 .fields_info
60 .field_position_in_record(self.field_index.0)
61 .expect("internal error: invalid field index")
62 }
63}
64
65impl<T> FieldRef<'_, T>
66where
67 T: Seek,
68{
69 fn seek_to_beginning(&mut self) -> Result<u64, FieldIOError> {
70 let field_info = &self.file.fields_info[self.field_index.0];
71
72 self.file
73 .inner
74 .seek(SeekFrom::Start(self.position_in_source()))
75 .map_err(|e| FieldIOError::new(ErrorKind::IoError(e), Some(field_info.clone())))
76 }
77}
78
79impl<T> FieldRef<'_, T>
80where
81 T: Seek + Read,
82{
83 pub fn read(&mut self) -> Result<FieldValue, Error> {
85 self.file
86 .ensure_record_has_been_read_into_buffer(self.record_index)?;
87
88 let field_info = &self.file.fields_info[self.field_index.0];
89
90 let start_pos = self.position_in_record();
91 let field_bytes = &mut self.file.record_data_buffer.get_mut()
92 [start_pos..start_pos + field_info.field_length as usize];
93
94 FieldValue::read_from(
95 field_bytes,
96 &mut self.file.memo_reader,
97 field_info,
98 &self.file.encoding,
99 self.file.options.character_trim,
100 )
101 .map_err(|e| {
102 Error::new(
103 FieldIOError::new(e, Some(field_info.clone())),
104 self.record_index.0,
105 )
106 })
107 }
108
109 pub fn read_as<ValueType>(&mut self) -> Result<ValueType, Error>
111 where
112 ValueType: TryFrom<FieldValue, Error = FieldConversionError>,
113 {
114 let value = self.read()?;
115
116 let converted_value = ValueType::try_from(value).map_err(|e| {
117 let field_info = &self.file.fields_info[self.field_index.0];
118 Error::new(
119 FieldIOError::new(ErrorKind::BadConversion(e), Some(field_info.clone())),
120 self.record_index.0,
121 )
122 })?;
123
124 Ok(converted_value)
125 }
126}
127
128impl<T> FieldRef<'_, T>
129where
130 T: Seek + Write,
131{
132 pub fn write<ValueType>(&mut self, value: &ValueType) -> Result<(), Error>
134 where
135 ValueType: WritableAsDbaseField,
136 {
137 self.file.file_position = self
138 .seek_to_beginning()
139 .map_err(|e| Error::new(e, self.record_index.0))?;
140
141 let field_info = &self.file.fields_info[self.field_index.0];
142
143 let start_pos = self.position_in_record();
144 let field_bytes = &mut self.file.record_data_buffer.get_mut()
145 [start_pos..start_pos + field_info.field_length as usize];
146 field_bytes.fill(0);
147
148 let mut cursor = Cursor::new(field_bytes);
152 value
153 .write_as(field_info, &self.file.encoding, &mut cursor)
154 .map_err(|e| {
155 Error::new(
156 FieldIOError::new(e, Some(field_info.clone())),
157 self.record_index.0,
158 )
159 })?;
160
161 let buffer = cursor.into_inner();
162
163 self.file.inner.write_all(buffer).map_err(|e| {
164 Error::new(
165 FieldIOError::new(ErrorKind::IoError(e), Some(field_info.clone())),
166 self.record_index.0,
167 )
168 })?;
169
170 self.file.file_position += buffer.len() as u64;
171
172 Ok(())
173 }
174}
175
176pub struct RecordRef<'a, T> {
184 file: &'a mut File<T>,
185 index: RecordIndex,
186}
187
188impl<T> Debug for RecordRef<'_, T> {
189 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190 f.debug_struct("RecordRef")
191 .field("index", &self.index)
192 .finish()
193 }
194}
195
196impl<T> RecordRef<'_, T> {
197 pub fn field(&mut self, index: FieldIndex) -> Option<FieldRef<'_, T>> {
198 if index.0 >= self.file.fields_info.len() {
199 return None;
200 }
201 Some(FieldRef {
202 file: self.file,
203 record_index: self.index,
204 field_index: index,
205 })
206 }
207
208 fn position_in_source(&self) -> u64 {
209 self.file.header.record_position(self.index.0).unwrap() as u64
210 }
211}
212
213impl<T> RecordRef<'_, T>
214where
215 T: Seek,
216{
217 pub fn seek_before_deletion_flag(&mut self) -> Result<u64, FieldIOError> {
218 self.file
219 .inner
220 .seek(SeekFrom::Start(self.position_in_source()))
221 .map_err(|e| FieldIOError::new(ErrorKind::IoError(e), None))
222 }
223}
224
225impl<T> RecordRef<'_, T>
226where
227 T: Read + Seek,
228{
229 pub fn is_deleted(&mut self) -> Result<bool, Error> {
234 self.file
235 .ensure_record_has_been_read_into_buffer(self.index)?;
236 let deletion_flag = DeletionFlag::from_byte(self.file.record_data_buffer.get_ref()[0]);
237
238 Ok(deletion_flag == DeletionFlag::Deleted)
239 }
240
241 pub fn read_field(&mut self, field_index: FieldIndex) -> Result<FieldValue, Error> {
245 let record_index = self.index.0;
246 let mut field = self
247 .field(field_index)
248 .ok_or_else(|| Error::new(FieldIOError::end_of_record(), record_index))?;
249 field.read()
250 }
251
252 pub fn read_field_as<ValueType>(&mut self, field_index: FieldIndex) -> Result<ValueType, Error>
256 where
257 ValueType: TryFrom<FieldValue, Error = FieldConversionError>,
258 {
259 let record_index = self.index.0;
260 let mut field = self
261 .field(field_index)
262 .ok_or_else(|| Error::new(FieldIOError::end_of_record(), record_index))?;
263 field.read_as()
264 }
265
266 pub fn read(&mut self) -> Result<crate::Record, Error> {
268 self.read_as()
269 }
270
271 pub fn read_as<R>(&mut self) -> Result<R, Error>
273 where
274 R: ReadableRecord,
275 {
276 self.file
277 .ensure_record_has_been_read_into_buffer(self.index)?;
278 self.file
279 .record_data_buffer
280 .set_position(DELETION_FLAG_SIZE as u64);
281 let mut field_iterator = FieldIterator {
282 source: &mut self.file.record_data_buffer,
283 fields_info: self.file.fields_info.iter().peekable(),
284 memo_reader: &mut self.file.memo_reader,
285 field_data_buffer: &mut self.file.field_data_buffer,
286 encoding: &self.file.encoding,
287 options: self.file.options,
288 };
289
290 R::read_using(&mut field_iterator).map_err(|error| Error::new(error, self.index.0))
291 }
292}
293
294impl<T> RecordRef<'_, T>
295where
296 T: Write + Seek,
297{
298 pub fn write_field<ValueType>(
302 &mut self,
303 field_index: FieldIndex,
304 value: &ValueType,
305 ) -> Result<(), Error>
306 where
307 ValueType: WritableAsDbaseField,
308 {
309 let record_index = self.index.0;
310 let mut field = self
311 .field(field_index)
312 .ok_or_else(|| Error::new(FieldIOError::end_of_record(), record_index))?;
313 field.write(value)
314 }
315
316 pub fn write<R>(&mut self, record: &R) -> Result<(), Error>
319 where
320 R: WritableRecord,
321 {
322 self.file.record_data_buffer.get_mut().fill(0);
323 self.file.record_data_buffer.get_mut()[0] = DeletionFlag::NotDeleted.to_byte();
324 self.file.record_data_buffer.set_position(1);
325
326 let mut field_writer = FieldWriter {
327 dst: &mut self.file.record_data_buffer,
328 fields_info: self.file.fields_info.iter().peekable(),
329 field_buffer: &mut Cursor::new(&mut self.file.field_data_buffer),
330 encoding: &self.file.encoding,
331 };
332
333 record
334 .write_using(&mut field_writer)
335 .map_err(|error| Error::new(error, self.index.0))?;
336
337 self.seek_before_deletion_flag()
338 .map_err(|error| Error::new(error, self.index.0))?;
339
340 self.file
341 .inner
342 .write_all(self.file.record_data_buffer.get_ref())
343 .map_err(|error| Error::io_error(error, self.index.0))?;
344
345 debug_assert_eq!(
347 self.file.file_position,
348 self.file.inner.stream_position().unwrap()
349 );
350
351 Ok(())
352 }
353}
354
355pub struct FileRecordIterator<'a, T> {
357 file: &'a mut File<T>,
358 current_record: RecordIndex,
359}
360
361impl<T> FileRecordIterator<'_, T>
362where
363 T: Seek + Read,
364{
365 pub fn next(&mut self) -> Option<RecordRef<'_, T>> {
368 let record_ref = self.file.record(self.current_record.0);
369 self.current_record.0 += usize::from(record_ref.is_some());
370 record_ref
371 }
372}
373
374#[derive(Debug)]
414pub struct File<T> {
415 pub(crate) inner: T,
416 memo_reader: Option<MemoReader<T>>,
417 pub(crate) header: Header,
418 pub(crate) fields_info: FieldsInfo,
419 pub(crate) encoding: DynEncoding,
420 record_data_buffer: Cursor<Vec<u8>>,
423 field_data_buffer: [u8; 255],
426 pub(crate) options: ReadingOptions,
427 file_position: u64,
431}
432
433impl<T> File<T> {
434 pub fn fields(&self) -> &[FieldInfo] {
436 self.fields_info.as_ref()
437 }
438
439 pub fn field_index(&self, name: &str) -> Option<FieldIndex> {
441 self.fields_info
442 .iter()
443 .position(|info| info.name.eq_ignore_ascii_case(name))
444 .map(FieldIndex)
445 }
446
447 pub fn num_records(&self) -> usize {
449 self.header.num_records as usize
450 }
451
452 pub fn set_options(&mut self, options: ReadingOptions) {
453 self.options = options;
454 }
455}
456
457impl<T: Read + Seek> File<T> {
458 pub fn open_with_encoding<E>(source: T, encoding: E) -> Result<Self, Error>
460 where
461 E: Encoding + 'static + Into<DynEncoding>,
462 {
463 Self::open_inner(source, Some(encoding))
464 }
465
466 pub fn open(source: T) -> Result<Self, Error> {
468 Self::open_inner(source, None::<DynEncoding>)
469 }
470
471 pub(crate) fn open_inner<E>(mut source: T, encoding: Option<E>) -> Result<Self, Error>
472 where
473 E: Encoding + 'static + Into<DynEncoding>,
474 {
475 let mut header =
476 Header::read_from(&mut source).map_err(|error| Error::io_error(error, 0))?;
477
478 let offset = if header.file_type.is_visual_fox_pro() {
479 if BACKLINK_SIZE > header.offset_to_first_record {
480 panic!("Invalid file");
481 }
482 header.offset_to_first_record - BACKLINK_SIZE
483 } else {
484 header.offset_to_first_record
485 };
486 let num_fields = (offset as usize - Header::SIZE - size_of::<u8>()) / FieldInfo::SIZE;
487
488 let encoding = match encoding {
490 Some(encoding) => encoding.into(),
491 None => header.code_page_mark.to_encoding().ok_or_else(|| {
492 let field_error =
493 FieldIOError::new(UnsupportedCodePage(header.code_page_mark), None);
494 Error::new(field_error, 0)
495 })?,
496 };
497
498 let fields_info =
499 FieldsInfo::read_from(&mut source, num_fields, &encoding).map_err(|error| Error {
500 record_num: 0,
501 field: None,
502 kind: error,
503 })?;
504
505 let terminator = source
506 .read_u8()
507 .map_err(|error| Error::io_error(error, 0))?;
508
509 debug_assert_eq!(terminator, TERMINATOR_VALUE);
510
511 source
512 .seek(SeekFrom::Start(u64::from(header.offset_to_first_record)))
513 .map_err(|error| Error::io_error(error, 0))?;
514
515 let record_size: usize = DELETION_FLAG_SIZE + fields_info.size_of_all_fields();
516 let record_data_buffer = Cursor::new(vec![0u8; record_size]);
517 header.size_of_record = record_size as u16;
520 Ok(Self {
523 inner: source,
524 memo_reader: None,
525 header,
526 fields_info,
527 encoding,
528 record_data_buffer,
529 field_data_buffer: [0u8; 255],
530 options: ReadingOptions::default(),
531 file_position: header.offset_to_first_record as u64,
532 })
533 }
534
535 pub fn record(&mut self, index: usize) -> Option<RecordRef<'_, T>> {
539 if index >= self.header.num_records as usize {
540 None
541 } else {
542 let record_ref = RecordRef {
543 file: self,
544 index: RecordIndex(index),
545 };
546 Some(record_ref)
547 }
548 }
549
550 pub fn records(&mut self) -> FileRecordIterator<'_, T> {
554 FileRecordIterator {
555 file: self,
556 current_record: RecordIndex(0),
557 }
558 }
559
560 fn ensure_record_has_been_read_into_buffer(
562 &mut self,
563 record_index: RecordIndex,
564 ) -> Result<bool, Error> {
565 let record_ref = RecordRef {
566 file: self,
567 index: record_index,
568 };
569 let start_of_record_pos = record_ref.position_in_source();
570 let end_of_record_pos = start_of_record_pos + u64::from(self.header.size_of_record);
571
572 if self.file_position > start_of_record_pos && self.file_position <= end_of_record_pos {
573 return Ok(false);
575 }
576
577 if start_of_record_pos != self.file_position {
578 self.file_position = self
581 .inner
582 .seek(SeekFrom::Start(start_of_record_pos))
583 .map_err(|e| Error::io_error(e, record_index.0))?;
584 }
585
586 self.inner
587 .read_exact(self.record_data_buffer.get_mut())
588 .map_err(|e| Error::io_error(e, record_index.0))?;
589 self.file_position += self.record_data_buffer.get_mut().len() as u64;
590 Ok(true)
591 }
592}
593
594impl<T: Write + Seek> File<T> {
595 pub fn create_new(mut dst: T, table_info: TableInfo) -> Result<Self, Error> {
596 write_header_parts(&mut dst, &table_info.header, &table_info.fields_info)?;
597 let record_size: usize = DELETION_FLAG_SIZE
598 + table_info
599 .fields_info
600 .iter()
601 .map(|i| i.field_length as usize)
602 .sum::<usize>();
603 let record_data_buffer = Cursor::new(vec![0u8; record_size]);
604 let file_position = table_info.header.offset_to_first_record as u64;
605 debug_assert_eq!(file_position, dst.stream_position().unwrap());
606 Ok(Self {
607 inner: dst,
608 memo_reader: None,
609 header: table_info.header,
610 fields_info: FieldsInfo {
611 inner: table_info.fields_info,
612 },
613 encoding: table_info.encoding,
614 record_data_buffer,
615 field_data_buffer: [0u8; 255],
616 options: ReadingOptions::default(),
617 file_position,
618 })
619 }
620
621 pub fn append_record<R>(&mut self, record: &R) -> Result<(), Error>
622 where
623 R: WritableRecord,
624 {
625 self.append_records(std::slice::from_ref(record))
626 }
627
628 pub fn append_records<R>(&mut self, records: &[R]) -> Result<(), Error>
629 where
630 R: WritableRecord,
631 {
632 assert!(
633 !self
634 .header
635 .num_records
636 .overflowing_add(records.len() as u32)
637 .1,
638 "Too many records (u32 overflow)"
639 );
640
641 let end_of_last_record = self.header.offset_to_first_record as u64
642 + (self.num_records() as u64 * self.header.size_of_record as u64);
643
644 self.inner
645 .seek(SeekFrom::Start(end_of_last_record))
646 .map_err(|error| Error::io_error(error, self.num_records()))?;
647
648 for record in records {
649 let current_record_index = self.header.num_records + 1;
650
651 let mut field_writer = FieldWriter {
652 dst: &mut self.inner,
653 fields_info: self.fields_info.iter().peekable(),
654 field_buffer: &mut Cursor::new(&mut self.field_data_buffer),
655 encoding: &self.encoding,
656 };
657
658 field_writer
659 .write_deletion_flag()
660 .map_err(|error| Error::io_error(error, current_record_index as usize))?;
661
662 record
663 .write_using(&mut field_writer)
664 .map_err(|error| Error::new(error, current_record_index as usize))?;
665
666 self.header.num_records = current_record_index;
667 }
668
669 self.sync_all()
670 .map_err(|error| Error::io_error(error, self.num_records()))?;
671
672 Ok(())
673 }
674
675 pub fn sync_all(&mut self) -> std::io::Result<()> {
676 let current_pos = self.inner.stream_position()?;
677 self.inner.seek(SeekFrom::Start(0))?;
678 self.header.write_to(&mut self.inner)?;
679 self.inner.seek(SeekFrom::Start(current_pos))?;
680 Ok(())
681 }
682}
683
684impl File<bufrw::BufReaderWriter<std::fs::File>> {
685 pub fn open_with_options<P: AsRef<Path>>(
686 path: P,
687 options: std::fs::OpenOptions,
688 ) -> Result<Self, Error> {
689 let file = options
690 .open(path)
691 .map_err(|error| Error::io_error(error, 0))?;
692 let source = bufrw::BufReaderWriter::new(file);
693 File::open(source)
694 }
695
696 pub fn open_read_only<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
698 let file = std::fs::File::open(path.as_ref()).map_err(|error| Error::io_error(error, 0))?;
699
700 let mut file = File::open(bufrw::BufReaderWriter::new(file))?;
701 if file.fields_info.at_least_one_field_is_memo() {
702 let p = path.as_ref();
703 let memo_type = file.header.file_type.supported_memo_type();
704 if let Some(mt) = memo_type {
705 let memo_path = p.with_extension(mt.extension());
706
707 let memo_file = std::fs::File::open(memo_path).map_err(|error| Error {
708 record_num: 0,
709 field: None,
710 kind: ErrorKind::ErrorOpeningMemoFile(error),
711 })?;
712
713 let memo_reader =
714 MemoReader::new(mt, bufrw::BufReaderWriter::new(memo_file)).unwrap();
715
716 file.memo_reader = Some(memo_reader);
717 }
718 }
719 Ok(file)
720 }
721
722 pub fn open_write_only<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
724 let mut options = std::fs::OpenOptions::new();
725 options
726 .read(false)
727 .write(true)
728 .create(false)
729 .truncate(false);
730
731 File::open_with_options(path, options)
732 }
733
734 pub fn open_read_write<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
736 let mut options = std::fs::OpenOptions::new();
737 options.read(true).write(true).create(false).truncate(false);
738
739 File::open_with_options(path, options)
740 }
741
742 pub fn create<P: AsRef<Path>>(path: P, table_info: TableInfo) -> Result<Self, Error> {
744 let file = std::fs::File::create(path).map_err(|error| Error::io_error(error, 0))?;
745
746 File::create_new(bufrw::BufReaderWriter::new(file), table_info)
747 }
748}
749
750#[cfg(test)]
751mod tests {
752 #[test]
753 fn ensure_record_has_been_read_into_buffer() {
754 let mut file = crate::File::open_read_only("tests/data/stations.dbf").unwrap();
755
756 {
757 let mut record = file.record(0).unwrap();
758 let _ = record.read_field(crate::FieldIndex(0)).unwrap();
759 assert!(!file
761 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(0))
762 .unwrap());
763 assert!(file
764 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(1))
765 .unwrap());
766 }
767
768 {
769 let mut record = file.record(4).unwrap();
770 let _ = record.read_field(crate::FieldIndex(3)).unwrap();
771 assert!(!file
773 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(4))
774 .unwrap());
775 assert!(file
776 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(1))
777 .unwrap());
778 }
779
780 {
782 let mut record = file.record(10).unwrap();
783 let value = record.read_field(crate::FieldIndex(2)).unwrap();
784 assert!(!record
786 .file
787 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(10))
788 .unwrap());
789 record.write_field(crate::FieldIndex(2), &value).unwrap();
790 assert!(!file
791 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(10))
792 .unwrap());
793 }
794 }
795}