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 Error, ErrorKind, FieldConversionError, FieldIOError, FieldInfo, FieldIterator, FieldValue,
10 FieldWriter, ReadableRecord, TableInfo, WritableRecord,
11};
12use byteorder::ReadBytesExt;
13use std::fmt::{Debug, Formatter};
14use std::io::{BufReader, BufWriter, Cursor, Read, Seek, SeekFrom, Write};
15use std::path::Path;
16
17pub struct BufReadWriteFile {
18 input: BufReader<std::fs::File>,
19 output: BufWriter<std::fs::File>,
20}
21
22impl BufReadWriteFile {
23 fn new(file: std::fs::File) -> std::io::Result<Self> {
24 let input = BufReader::new(file.try_clone()?);
25 let output = BufWriter::new(file);
26
27 Ok(Self { input, output })
28 }
29}
30
31impl Read for BufReadWriteFile {
32 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
33 self.input.read(buf)
34 }
35}
36
37impl Write for BufReadWriteFile {
38 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
39 self.output.write(buf)
40 }
41
42 fn flush(&mut self) -> std::io::Result<()> {
43 self.output.flush()
44 }
45}
46
47impl Seek for BufReadWriteFile {
48 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
49 self.output.seek(pos)?;
50 self.input.seek(pos)
51 }
52}
53
54#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
56pub struct FieldIndex(pub usize);
57
58#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
60pub struct RecordIndex(pub usize);
61
62pub struct FieldRef<'a, T> {
67 file: &'a mut File<T>,
68 record_index: RecordIndex,
69 field_index: FieldIndex,
70}
71
72impl<'a, T> Debug for FieldRef<'a, T> {
73 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
74 f.debug_struct("FieldRef")
75 .field("record_index", &self.record_index)
76 .field("field_index", &self.field_index)
77 .finish()
78 }
79}
80
81impl<'a, T> FieldRef<'a, T> {
82 fn position_in_source(&self) -> u64 {
83 let record_position = self
84 .file
85 .header
86 .record_position(self.record_index.0)
87 .unwrap() as u64;
88
89 record_position + self.position_in_record() as u64
90 }
91
92 fn position_in_record(&self) -> usize {
93 self.file
94 .fields_info
95 .field_position_in_record(self.field_index.0)
96 .expect("internal error: invalid field index")
97 }
98}
99
100impl<'a, T> FieldRef<'a, T>
101where
102 T: Seek,
103{
104 fn seek_to_beginning(&mut self) -> Result<u64, FieldIOError> {
105 let field_info = &self.file.fields_info[self.field_index.0];
106
107 self.file
108 .inner
109 .seek(SeekFrom::Start(self.position_in_source()))
110 .map_err(|e| FieldIOError::new(ErrorKind::IoError(e), Some(field_info.clone())))
111 }
112}
113
114impl<'a, T> FieldRef<'a, T>
115where
116 T: Seek + Read,
117{
118 pub fn read(&mut self) -> Result<FieldValue, Error> {
120 self.file
121 .ensure_record_has_been_read_into_buffer(self.record_index)?;
122
123 let field_info = &self.file.fields_info[self.field_index.0];
124
125 let start_pos = self.position_in_record();
126 let field_bytes = &mut self.file.record_data_buffer.get_mut()
127 [start_pos..start_pos + field_info.field_length as usize];
128
129 FieldValue::read_from(
130 field_bytes,
131 &mut self.file.memo_reader,
132 field_info,
133 &self.file.encoding,
134 self.file.options.character_trim,
135 )
136 .map_err(|e| {
137 Error::new(
138 FieldIOError::new(e, Some(field_info.clone())),
139 self.record_index.0,
140 )
141 })
142 }
143
144 pub fn read_as<ValueType>(&mut self) -> Result<ValueType, Error>
146 where
147 ValueType: TryFrom<FieldValue, Error = FieldConversionError>,
148 {
149 let value = self.read()?;
150
151 let converted_value = ValueType::try_from(value).map_err(|e| {
152 let field_info = &self.file.fields_info[self.field_index.0];
153 Error::new(
154 FieldIOError::new(ErrorKind::BadConversion(e), Some(field_info.clone())),
155 self.record_index.0,
156 )
157 })?;
158
159 Ok(converted_value)
160 }
161}
162
163impl<'a, T> FieldRef<'a, T>
164where
165 T: Seek + Write,
166{
167 pub fn write<ValueType>(&mut self, value: &ValueType) -> Result<(), Error>
169 where
170 ValueType: WritableAsDbaseField,
171 {
172 self.file.file_position = self
173 .seek_to_beginning()
174 .map_err(|e| Error::new(e, self.record_index.0))?;
175
176 let field_info = &self.file.fields_info[self.field_index.0];
177
178 let start_pos = self.position_in_record();
179 let field_bytes = &mut self.file.record_data_buffer.get_mut()
180 [start_pos..start_pos + field_info.field_length as usize];
181 field_bytes.fill(0);
182
183 let mut cursor = Cursor::new(field_bytes);
187 value
188 .write_as(field_info, &self.file.encoding, &mut cursor)
189 .map_err(|e| {
190 Error::new(
191 FieldIOError::new(e, Some(field_info.clone())),
192 self.record_index.0,
193 )
194 })?;
195
196 let buffer = cursor.into_inner();
197
198 self.file.inner.write_all(buffer).map_err(|e| {
199 Error::new(
200 FieldIOError::new(ErrorKind::IoError(e), Some(field_info.clone())),
201 self.record_index.0,
202 )
203 })?;
204
205 self.file.file_position += buffer.len() as u64;
206
207 Ok(())
208 }
209}
210
211pub struct RecordRef<'a, T> {
219 file: &'a mut File<T>,
220 index: RecordIndex,
221}
222
223impl<'a, T> Debug for RecordRef<'a, T> {
224 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
225 f.debug_struct("RecordRef")
226 .field("index", &self.index)
227 .finish()
228 }
229}
230
231impl<'a, T> RecordRef<'a, T> {
232 pub fn field<'b>(&'b mut self, index: FieldIndex) -> Option<FieldRef<'b, T>> {
233 if index.0 >= self.file.fields_info.len() {
234 return None;
235 }
236 Some(FieldRef {
237 file: self.file,
238 record_index: self.index,
239 field_index: index,
240 })
241 }
242
243 fn position_in_source(&self) -> u64 {
244 self.file.header.record_position(self.index.0).unwrap() as u64
245 }
246}
247
248impl<'a, T> RecordRef<'a, T>
249where
250 T: Seek,
251{
252 pub fn seek_before_deletion_flag(&mut self) -> Result<u64, FieldIOError> {
253 self.file
254 .inner
255 .seek(SeekFrom::Start(self.position_in_source()))
256 .map_err(|e| FieldIOError::new(ErrorKind::IoError(e), None))
257 }
258}
259
260impl<'a, T> RecordRef<'a, T>
261where
262 T: Read + Seek,
263{
264 pub fn is_deleted(&mut self) -> Result<bool, Error> {
269 self.file
270 .ensure_record_has_been_read_into_buffer(self.index)?;
271 let deletion_flag = DeletionFlag::from_byte(self.file.record_data_buffer.get_ref()[0]);
272
273 Ok(deletion_flag == DeletionFlag::Deleted)
274 }
275
276 pub fn read_field(&mut self, field_index: FieldIndex) -> Result<FieldValue, Error> {
280 let record_index = self.index.0;
281 let mut field = self
282 .field(field_index)
283 .ok_or_else(|| Error::new(FieldIOError::end_of_record(), record_index))?;
284 field.read()
285 }
286
287 pub fn read_field_as<ValueType>(&mut self, field_index: FieldIndex) -> Result<ValueType, Error>
291 where
292 ValueType: TryFrom<FieldValue, Error = FieldConversionError>,
293 {
294 let record_index = self.index.0;
295 let mut field = self
296 .field(field_index)
297 .ok_or_else(|| Error::new(FieldIOError::end_of_record(), record_index))?;
298 field.read_as()
299 }
300
301 pub fn read(&mut self) -> Result<crate::Record, Error> {
303 self.read_as()
304 }
305
306 pub fn read_as<R>(&mut self) -> Result<R, Error>
308 where
309 R: ReadableRecord,
310 {
311 self.file
312 .ensure_record_has_been_read_into_buffer(self.index)?;
313 self.file
314 .record_data_buffer
315 .set_position(DELETION_FLAG_SIZE as u64);
316 let mut field_iterator = FieldIterator {
317 source: &mut self.file.record_data_buffer,
318 fields_info: self.file.fields_info.iter().peekable(),
319 memo_reader: &mut self.file.memo_reader,
320 field_data_buffer: &mut self.file.field_data_buffer,
321 encoding: &self.file.encoding,
322 options: self.file.options,
323 };
324
325 R::read_using(&mut field_iterator).map_err(|error| Error::new(error, self.index.0))
326 }
327}
328
329impl<'a, T> RecordRef<'a, T>
330where
331 T: Write + Seek,
332{
333 pub fn write_field<ValueType>(
337 &mut self,
338 field_index: FieldIndex,
339 value: &ValueType,
340 ) -> Result<(), Error>
341 where
342 ValueType: WritableAsDbaseField,
343 {
344 let record_index = self.index.0;
345 let mut field = self
346 .field(field_index)
347 .ok_or_else(|| Error::new(FieldIOError::end_of_record(), record_index))?;
348 field.write(value)
349 }
350
351 pub fn write<R>(&mut self, record: &R) -> Result<(), Error>
354 where
355 R: WritableRecord,
356 {
357 self.file.record_data_buffer.get_mut().fill(0);
358 self.file.record_data_buffer.get_mut()[0] = DeletionFlag::NotDeleted.to_byte();
359 self.file.record_data_buffer.set_position(1);
360
361 let mut field_writer = FieldWriter {
362 dst: &mut self.file.record_data_buffer,
363 fields_info: self.file.fields_info.iter().peekable(),
364 field_buffer: &mut Cursor::new(&mut self.file.field_data_buffer),
365 encoding: &self.file.encoding,
366 };
367
368 record
369 .write_using(&mut field_writer)
370 .map_err(|error| Error::new(error, self.index.0))?;
371
372 self.seek_before_deletion_flag()
373 .map_err(|error| Error::new(error, self.index.0))?;
374
375 self.file
376 .inner
377 .write_all(self.file.record_data_buffer.get_ref())
378 .map_err(|error| Error::io_error(error, self.index.0))?;
379
380 debug_assert_eq!(
382 self.file.file_position,
383 self.file.inner.stream_position().unwrap()
384 );
385
386 Ok(())
387 }
388}
389
390pub struct FileRecordIterator<'a, T> {
392 file: &'a mut File<T>,
393 current_record: RecordIndex,
394}
395
396impl<'a, T> FileRecordIterator<'a, T>
397where
398 T: Seek + Read,
399{
400 pub fn next<'s>(&'s mut self) -> Option<RecordRef<'s, T>> {
403 let record_ref = self.file.record(self.current_record.0);
404 if let Some(_) = record_ref {
405 self.current_record.0 += 1
406 }
407 record_ref
408 }
409}
410
411pub struct File<T> {
451 pub(crate) inner: T,
452 memo_reader: Option<MemoReader<T>>,
453 pub(crate) header: Header,
454 pub(crate) fields_info: FieldsInfo,
455 pub(crate) encoding: DynEncoding,
456 record_data_buffer: Cursor<Vec<u8>>,
459 field_data_buffer: [u8; 255],
462 pub(crate) options: ReadingOptions,
463 file_position: u64,
467}
468
469impl<T> File<T> {
470 pub fn fields(&self) -> &[FieldInfo] {
472 self.fields_info.as_ref()
473 }
474
475 pub fn field_index(&self, name: &str) -> Option<FieldIndex> {
477 self.fields_info
478 .iter()
479 .position(|info| info.name.eq_ignore_ascii_case(name))
480 .map(FieldIndex)
481 }
482
483 pub fn num_records(&self) -> usize {
485 self.header.num_records as usize
486 }
487
488 pub fn set_options(&mut self, options: ReadingOptions) {
489 self.options = options;
490 }
491}
492
493impl<T: Read + Seek> File<T> {
494 pub fn open(mut source: T) -> Result<Self, Error> {
496 let mut header =
497 Header::read_from(&mut source).map_err(|error| Error::io_error(error, 0))?;
498
499 let offset = if header.file_type.is_visual_fox_pro() {
500 if BACKLINK_SIZE > header.offset_to_first_record {
501 panic!("Invalid file");
502 }
503 header.offset_to_first_record - BACKLINK_SIZE
504 } else {
505 header.offset_to_first_record
506 };
507 let num_fields =
508 (offset as usize - Header::SIZE - std::mem::size_of::<u8>()) / FieldInfo::SIZE;
509
510 let fields_info =
511 FieldsInfo::read_from(&mut source, num_fields).map_err(|error| Error {
512 record_num: 0,
513 field: None,
514 kind: error,
515 })?;
516
517 let terminator = source
518 .read_u8()
519 .map_err(|error| Error::io_error(error, 0))?;
520
521 debug_assert_eq!(terminator, TERMINATOR_VALUE);
522
523 source
524 .seek(SeekFrom::Start(u64::from(header.offset_to_first_record)))
525 .map_err(|error| Error::io_error(error, 0))?;
526
527 let encoding = header.code_page_mark.to_encoding().ok_or_else(|| {
528 let field_error = FieldIOError::new(UnsupportedCodePage(header.code_page_mark), None);
529 Error::new(field_error, 0)
530 })?;
531
532 let record_size: usize = DELETION_FLAG_SIZE + fields_info.size_of_all_fields();
533 let record_data_buffer = Cursor::new(vec![0u8; record_size]);
534 header.size_of_record = record_size as u16;
537 Ok(Self {
540 inner: source,
541 memo_reader: None,
542 header,
543 fields_info,
544 encoding,
545 record_data_buffer,
546 field_data_buffer: [0u8; 255],
547 options: ReadingOptions::default(),
548 file_position: header.offset_to_first_record as u64,
549 })
550 }
551
552 pub fn record(&mut self, index: usize) -> Option<RecordRef<'_, T>> {
556 if index >= self.header.num_records as usize {
557 None
558 } else {
559 let record_ref = RecordRef {
560 file: self,
561 index: RecordIndex(index),
562 };
563 Some(record_ref)
564 }
565 }
566
567 pub fn records(&mut self) -> FileRecordIterator<'_, T> {
571 FileRecordIterator {
572 file: self,
573 current_record: RecordIndex(0),
574 }
575 }
576
577 fn ensure_record_has_been_read_into_buffer(
579 &mut self,
580 record_index: RecordIndex,
581 ) -> Result<bool, Error> {
582 let record_ref = RecordRef {
583 file: self,
584 index: record_index,
585 };
586 let start_of_record_pos = record_ref.position_in_source();
587 let end_of_record_pos = start_of_record_pos + u64::from(self.header.size_of_record);
588
589 if self.file_position > start_of_record_pos && self.file_position <= end_of_record_pos {
590 return Ok(false);
592 }
593
594 if start_of_record_pos != self.file_position {
595 self.file_position = self
598 .inner
599 .seek(SeekFrom::Start(start_of_record_pos))
600 .map_err(|e| Error::io_error(e, record_index.0))?;
601 }
602
603 self.inner
604 .read_exact(self.record_data_buffer.get_mut())
605 .map_err(|e| Error::io_error(e, record_index.0))?;
606 self.file_position += self.record_data_buffer.get_mut().len() as u64;
607 Ok(true)
608 }
609}
610
611impl<T: Write + Seek> File<T> {
612 pub fn create_new(mut dst: T, table_info: TableInfo) -> Result<Self, Error> {
613 write_header_parts(&mut dst, &table_info.header, &table_info.fields_info)?;
614 let record_size: usize = DELETION_FLAG_SIZE
615 + table_info
616 .fields_info
617 .iter()
618 .map(|i| i.field_length as usize)
619 .sum::<usize>();
620 let record_data_buffer = Cursor::new(vec![0u8; record_size]);
621 let file_position = table_info.header.offset_to_first_record as u64;
622 debug_assert_eq!(file_position, dst.stream_position().unwrap());
623 Ok(Self {
624 inner: dst,
625 memo_reader: None,
626 header: table_info.header,
627 fields_info: FieldsInfo {
628 inner: table_info.fields_info,
629 },
630 encoding: table_info.encoding,
631 record_data_buffer,
632 field_data_buffer: [0u8; 255],
633 options: ReadingOptions::default(),
634 file_position,
635 })
636 }
637
638 pub fn append_record<R>(&mut self, record: &R) -> Result<(), Error>
639 where
640 R: WritableRecord,
641 {
642 self.append_records(std::slice::from_ref(record))
643 }
644
645 pub fn append_records<R>(&mut self, records: &[R]) -> Result<(), Error>
646 where
647 R: WritableRecord,
648 {
649 assert_eq!(
650 self.header
651 .num_records
652 .overflowing_add(records.len() as u32)
653 .1,
654 false,
655 "Too many records (u32 overflow)"
656 );
657
658 let end_of_last_record = self.header.offset_to_first_record as u64
659 + (self.num_records() as u64 * self.header.size_of_record as u64);
660
661 self.inner
662 .seek(SeekFrom::Start(end_of_last_record))
663 .map_err(|error| Error::io_error(error, self.num_records()))?;
664
665 for record in records {
666 let current_record_index = self.header.num_records + 1;
667
668 let mut field_writer = FieldWriter {
669 dst: &mut self.inner,
670 fields_info: self.fields_info.iter().peekable(),
671 field_buffer: &mut Cursor::new(&mut self.field_data_buffer),
672 encoding: &self.encoding,
673 };
674
675 field_writer
676 .write_deletion_flag()
677 .map_err(|error| Error::io_error(error, current_record_index as usize))?;
678
679 record
680 .write_using(&mut field_writer)
681 .map_err(|error| Error::new(error, current_record_index as usize))?;
682
683 self.header.num_records = current_record_index;
684 }
685
686 self.sync_all()
687 .map_err(|error| Error::io_error(error, self.num_records()))?;
688
689 Ok(())
690 }
691
692 pub fn sync_all(&mut self) -> std::io::Result<()> {
693 let current_pos = self.inner.stream_position()?;
694 self.inner.seek(SeekFrom::Start(0))?;
695 self.header.write_to(&mut self.inner)?;
696 self.inner.seek(SeekFrom::Start(current_pos))?;
697 Ok(())
698 }
699}
700
701impl File<BufReadWriteFile> {
702 pub fn open_with_options<P: AsRef<Path>>(
703 path: P,
704 options: std::fs::OpenOptions,
705 ) -> Result<Self, Error> {
706 let file = options
707 .open(path)
708 .map_err(|error| Error::io_error(error, 0))?;
709 File::open(BufReadWriteFile::new(file).unwrap())
710 }
711
712 pub fn open_read_only<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
714 let file = std::fs::File::open(path.as_ref()).map_err(|error| Error::io_error(error, 0))?;
715
716 let mut file = File::open(BufReadWriteFile::new(file).unwrap())?;
717 if file.fields_info.at_least_one_field_is_memo() {
718 let p = path.as_ref();
719 let memo_type = file.header.file_type.supported_memo_type();
720 if let Some(mt) = memo_type {
721 let memo_path = p.with_extension(mt.extension());
722
723 let memo_file = std::fs::File::open(memo_path).map_err(|error| Error {
724 record_num: 0,
725 field: None,
726 kind: ErrorKind::ErrorOpeningMemoFile(error),
727 })?;
728
729 let memo_reader = BufReadWriteFile::new(memo_file)
730 .and_then(|memo_file| MemoReader::new(mt, memo_file))
731 .map_err(|error| Error::io_error(error, 0))?;
732
733 file.memo_reader = Some(memo_reader);
734 }
735 }
736 Ok(file)
737 }
738
739 pub fn open_write_only<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
741 let mut options = std::fs::OpenOptions::new();
742 options
743 .read(false)
744 .write(true)
745 .create(false)
746 .truncate(false);
747
748 File::open_with_options(path, options)
749 }
750
751 pub fn open_read_write<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
753 let mut options = std::fs::OpenOptions::new();
754 options.read(true).write(true).create(false).truncate(false);
755
756 File::open_with_options(path, options)
757 }
758
759 pub fn create<P: AsRef<Path>>(path: P, table_info: TableInfo) -> Result<Self, Error> {
761 let file = std::fs::File::create(path).map_err(|error| Error::io_error(error, 0))?;
762
763 File::create_new(BufReadWriteFile::new(file).unwrap(), table_info)
764 }
765}
766
767#[cfg(test)]
768mod tests {
769 #[test]
770 fn ensure_record_has_been_read_into_buffer() {
771 let mut file = crate::File::open_read_only("tests/data/stations.dbf").unwrap();
772
773 {
774 let mut record = file.record(0).unwrap();
775 let _ = record.read_field(crate::FieldIndex(0)).unwrap();
776 assert!(!file
778 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(0))
779 .unwrap());
780 assert!(file
781 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(1))
782 .unwrap());
783 }
784
785 {
786 let mut record = file.record(4).unwrap();
787 let _ = record.read_field(crate::FieldIndex(3)).unwrap();
788 assert!(!file
790 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(4))
791 .unwrap());
792 assert!(file
793 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(1))
794 .unwrap());
795 }
796
797 {
799 let mut record = file.record(10).unwrap();
800 let value = record.read_field(crate::FieldIndex(2)).unwrap();
801 assert!(!record
803 .file
804 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(10))
805 .unwrap());
806 record.write_field(crate::FieldIndex(2), &value).unwrap();
807 assert!(!file
808 .ensure_record_has_been_read_into_buffer(crate::RecordIndex(10))
809 .unwrap());
810 }
811 }
812}