private void FillVFPFields(Stream fs, DbfHeader header, DatabaseTable dbTable) { const int fieldSize = 32; header.Fields = new List <DbfField>(); fs.Seek(32, SeekOrigin.Begin); var fieldBuf = bufferPool.Rent(fieldSize); var index = 0; int nullFieldIndex = -1; while (fs.Read(fieldBuf, 0, fieldSize) != 0 && fieldBuf[0] != FieldDescriptorTerminator) { var field = new VfpField { Name = encoding.GetString(fieldBuf, 0, 10).TrimEnd('\0'), Type = (char)fieldBuf[11], Displacement = BTOI(fieldBuf, 12), Length = fieldBuf[16], DecimalCount = fieldBuf[17], Flags = (DbfFieldFlags)fieldBuf[18], NextAutoIncrement = BTOI(fieldBuf, 19), AutoIncrementStep = fieldBuf[23], Index = index, VarLengthSizeIndex = -1, NullFieldIndex = -1, }; if (field.Type == 'V' || field.Type == 'Q') { nullFieldIndex++; field.VarLengthSizeIndex = nullFieldIndex; } if ((field.Flags & DbfFieldFlags.Null) != 0) { nullFieldIndex++; field.NullFieldIndex = nullFieldIndex; } Buffer.BlockCopy(fieldBuf, 24, field.Reserved24To31 = new byte[8], 0, 8); if (dbTable != null && dbTable.Fields.Count > index) { field.Name = dbTable.Fields[index].Name; } header.Fields.Add(field); index++; } bufferPool.Return(fieldBuf); }
private void FillBacklink(Stream fs, DbfHeader header) { const int maxBacklinkLengh = 263; fs.Seek(header.HeaderSize - maxBacklinkLengh, SeekOrigin.Begin); var fieldBuf = bufferPool.Rent(maxBacklinkLengh); var read = fs.Read(fieldBuf, 0, maxBacklinkLengh); var backlinkLength = read; if (read != 0) { var nullIdx = GetIndexOf(fieldBuf, 0, 0); if (nullIdx != -1) { backlinkLength = nullIdx; } } header.Backlink = encoding.GetString(fieldBuf, 0, backlinkLength); bufferPool.Return(fieldBuf); }
public DbfHeader GetHeader() { var header = new DbfHeader(); using (var fs = OpenReadOnly()) { header.Type = (DbfType)fs.ReadByte(); fs.Position = 4; header.RecordCount = fs.ReadInt(); header.HeaderSize = fs.ReadShort(); header.RecordLength = fs.ReadShort(); header.FileSize = fs.Length; fs.Position = 28; header.Flags = (DbfHeaderFlags)fs.ReadByte(); switch (header.Type) { case DbfType.VisualFoxPro: case DbfType.VisualFoxProAutoInc: case DbfType.VisualFoxProVar: DatabaseTable dbTable = null; if ((header.Flags & DbfHeaderFlags.DBC) == 0) { FillBacklink(fs, header); if (!string.IsNullOrEmpty(header.Backlink)) { var db = Database.FromDbf(new Dbf(Path.Combine(Path.GetDirectoryName(dbfPath), header.Backlink))); dbTable = db.Tables.Find(t => t.Name.Equals(Path.GetFileNameWithoutExtension(dbfPath), StringComparison.OrdinalIgnoreCase)); } } FillVFPFields(fs, header, dbTable); break; default: throw new NotSupportedException($"Field Data for DBF-Type {header.Type} is not supported."); } } return(header); }
public DbfReader(Dbf dbf, Encoding textEncoding) { DbfTypeMap.Add('C', (i, b, f, e) => { if (f.Length == 1) { return(e.GetString(b)[0]); } return(e.GetString(b).TrimEnd('\0')); }); DbfTypeMap.Add('M', (i, b, f, e) => BitConverter.ToInt32(b)); DbfTypeMap.Add('W', (i, b, f, e) => BitConverter.ToInt32(b)); DbfTypeMap.Add('G', (i, b, f, e) => BitConverter.ToInt32(b)); DbfTypeMap.Add('Y', (i, b, f, e) => BitConverter.ToInt64(b) / 10000m); // Stored as int64 with 4 implicit decimal places DbfTypeMap.Add('D', (i, b, f, e) => { var dateStr = e.GetString(b).Trim(); return(dateStr == "" ? DateTime.MinValue : DateTime.ParseExact(dateStr, "yyyyMMdd", null)); }); DbfTypeMap.Add('T', (i, b, f, e) => JulianDateHelper.FromULongBuffer(b)); DbfTypeMap.Add('N', (i, b, f, e) => { var numStr = e.GetString(b).Trim(); if (f.DecimalCount == 0) { if (f.Length < 3) { if (numStr == "") { return((byte)0); } return(byte.Parse(numStr)); } else if (f.Length < 5) { if (numStr == "") { return((short)0); } return(short.Parse(numStr)); } else if (f.Length < 10) { if (numStr == "") { return((int)0); } return(int.Parse(numStr)); } else if (f.Length < 19) { if (numStr == "") { return((long)0); } return(long.Parse(numStr)); } } return(numStr == "" ? 0m : decimal.Parse(numStr)); }); DbfTypeMap.Add('B', (i, b, f, e) => BitConverter.ToInt32(b)); DbfTypeMap.Add('O', (i, b, f, e) => BitConverter.ToDouble(b)); DbfTypeMap.Add('F', (i, b, f, e) => { var numStr = e.GetString(b).Trim(); return(numStr == "" ? 0f : float.Parse(numStr)); }); DbfTypeMap.Add('I', (i, b, f, e) => BitConverter.ToInt32(b)); DbfTypeMap.Add('L', (i, b, f, e) => BitConverter.ToBoolean(b)); DbfTypeMap.Add('Q', CopyFieldBuffer); DbfTypeMap.Add('P', CopyFieldBuffer); this.dbf = dbf; TextEncoding = textEncoding; dbfHeader = dbf.GetHeader(); if (IsVisualFoxPro(dbfHeader)) { // Special handling for VFP DbfTypeMap['B'] = (i, b, f, e) => BitConverter.ToDouble(b); // VarChar/VarBinary // SPECIAL CASE for VARCHAR/BINARY DbfTypeMap['V'] = (i, b, f, e) => f.Flags.HasFlag(DbfFieldFlags.Binary) ? CopyFieldBuffer(i, b, f, e) : e.GetString(b); // _NullFlags nullField = dbfHeader.Fields.FirstOrDefault(x => x.Type == '0'); nullFieldDataHandler = DbfTypeMap['0'] = CopyFieldBuffer; if (nullField != null) { if (nullField.Length == 1) { nullFieldHandlerFactory = (i, b, f, e) => new UIntNullFieldHandler(b[0]); } else { nullFieldHandlerFactory = (i, b, f, e) => new BitArrayNullFieldHandler(b.ToArray()); } } } }
private bool IsVisualFoxPro(DbfHeader dbfHeader) { return(dbfHeader.Type == DbfType.VisualFoxPro || dbfHeader.Type == DbfType.VisualFoxProVar || dbfHeader.Type == DbfType.VisualFoxProAutoInc); }