rendered paste body public enum DbfVersion : byte
{
FoxBASE = 0x02,
FoxBASENoMemo = 0x03,
VisualFoxPro = 0x30,
VisualFoxProAutoInc = 0x31,
dBASEIVTable = 0x43,
dBASEIVSystem = 0x63,
FoxBASEMemo = 0x83,
dBASEIVMemo = 0x8B,
dBASEIVTableMemo = 0xCB,
FoxPro2xMemo = 0xF5,
FoxBASE2 = 0xFB
}
[Flags()]
public enum FieldFlags : byte
{
SystemColumn = 0x01,
Nullable = 0x02,
Binary = 0x04,
AutoIncrement = 0x0C
}
public class Header
{
public DbfVersion Info;
public byte[] LastUpdate;
public int NumRecords;
public short NumBytesHdr;
public short NumBytesRcd;
public byte[] Reserved1;
public byte IncompleteTrans;
public byte Encryption;
public byte[] Reserved2;
public byte MDXFlg;
public byte LangDriverId;
public byte[] Reserved3;
public List<Field> FieldList;
public static Header Read(BinaryReader Reader)
{
Header Result = new Header();
Reader.BaseStream.Seek(0, SeekOrigin.Begin);
Result.Info = (DbfVersion)Reader.ReadByte();
Result.LastUpdate = Reader.ReadBytes(3);
Result.NumRecords = Reader.ReadInt32();
Result.NumBytesHdr = Reader.ReadInt16();
Result.NumBytesRcd = Reader.ReadInt16();
Result.Reserved1 = Reader.ReadBytes(2);
Result.IncompleteTrans = Reader.ReadByte();
Result.Encryption = Reader.ReadByte();
Result.Reserved2 = Reader.ReadBytes(12);
Result.MDXFlg = Reader.ReadByte();
Result.LangDriverId = Reader.ReadByte();
Result.Reserved3 = Reader.ReadBytes(2);
Result.FieldList = new List<Field>();
Reader.BaseStream.Seek(32, SeekOrigin.Begin);
while (true)
{
Field field;
if (Reader.PeekChar() == (char)0x0D)
{
break;
}
field = Field.Read(Reader);
if (field.Type != '0')
{
Result.FieldList.Add(field);
}
}
return Result;
}
}
public struct Field
{
public string Name;
public char Type;
public int Offset;
public byte Length;
public byte Decimal;
public FieldFlags Flags;
public int AutoIncrementNext;
public byte AutoIncrementStep;
public byte[] Reserved;
public static Field Read(BinaryReader Reader)
{
Field field = new Field();
field.Name = new string(Reader.ReadChars(11));
if (field.Name.IndexOf('\0') > 0)
{
field.Name = field.Name.Substring(0, field.Name.IndexOf('\0'));
}
field.Type = Reader.ReadChar();
field.Offset = Reader.ReadInt32();
field.Length = Reader.ReadByte();
field.Decimal = Reader.ReadByte();
field.Flags = (FieldFlags)Reader.ReadByte();
field.AutoIncrementNext = Reader.ReadInt32();
field.AutoIncrementStep = Reader.ReadByte();
field.Reserved = Reader.ReadBytes(8);
return field;
}
}
public class Row
{
private DbfFile m_Dbf;
private byte[] m_RawData;
public bool Deleted;
public Dictionary<string, object> Data;
public int Offset;
public int RecordNumber;
public Row(DbfFile Dbf, int RecordNumber)
{
m_Dbf = Dbf;
Data = new Dictionary<string, object>();
m_RawData = Dbf.RawReadRecord(RecordNumber);
Offset = Dbf.Header.NumBytesHdr + (Dbf.Header.NumBytesRcd * (RecordNumber - 1));
this.RecordNumber = RecordNumber;
Deleted = (m_RawData[0] == 0x2A);
foreach (Field field in Dbf.Header.FieldList)
{
Data.Add(field.Name, Translator.ToNET(field.Type, field.Offset, field.Length, field.Decimal, m_RawData));
}
}
public Row(DbfFile Dbf)
{
m_Dbf = Dbf;
Data = new Dictionary<string, object>();
Offset = Dbf.Header.NumBytesHdr + (Dbf.Header.NumBytesRcd * (Dbf.Header.NumRecords));
Deleted = false;
m_RawData = new byte[Dbf.Header.NumBytesRcd];
m_RawData[0] = 0x20;
foreach (Field field in Dbf.Header.FieldList)
{
Data.Add(field.Name, null);
}
}
public void Write()
{
byte[] RawData = (byte[])m_RawData.Clone();
RawData[0] = (byte)(Deleted ? 0x2A : 0x20);
foreach (Field field in m_Dbf.Header.FieldList)
{
byte[] fieldData = Translator.ToDBF(field.Type, field.Length, field.Decimal, Data[field.Name], field.Flags == FieldFlags.Nullable);
byte[] oldFieldData = new byte[field.Length];
for (int i = 0; i < field.Length; i++)
{
oldFieldData[i] = RawData[field.Offset + i];
}
for (int i = 0; i < field.Length; i++)
{
if (fieldData[i] != oldFieldData[i])
{
System.Diagnostics.Debug.WriteLine(string.Format("[{5,10}, {6}]{0,3}: [(New) 0x{1,2:X} '{2}'] vs. [(Old) 0x{3,2:X} '{4}']", i, fieldData[i], (char)fieldData[i], oldFieldData[i], (char)oldFieldData[i], field.Name, field.Type));
}
}
fieldData.CopyTo(RawData, field.Offset);
}
m_Dbf.RawWriteRecord(RecordNumber, RawData);
}
}
public class DbfFile
{
private Header m_Header;
private string m_FileName = "";
private Stream m_FileStream;
private BinaryReader m_Reader;
private BinaryWriter m_Writer;
public Header Header
{
get { return m_Header; }
set
{
m_Writer.BaseStream.Seek(0, SeekOrigin.Begin);
m_Writer.Write((byte)Header.Info);
m_Writer.Write(Header.LastUpdate);
m_Writer.Write(Header.NumRecords);
m_Writer.Write(Header.NumBytesHdr);
m_Writer.Write(Header.NumBytesRcd);
m_Writer.Write(Header.Reserved1);
m_Writer.Write(Header.IncompleteTrans);
m_Writer.Write(Header.Encryption);
m_Writer.Write(Header.Reserved2);
m_Writer.Write(Header.MDXFlg);
m_Writer.Write(Header.LangDriverId);
m_Writer.Write(Header.Reserved3);
m_Header = value;
}
}
public DbfFile(string FileName)
{
m_FileName = FileName;
m_FileStream = File.Open(FileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
m_Reader = new BinaryReader(m_FileStream);
m_Writer = new BinaryWriter(m_FileStream);
m_Header = Header.Read(m_Reader);
}
~DbfFile()
{
m_Reader.Close();
m_Writer.Close();
m_FileStream.Close();
}
public byte[] RawReadRecord(int RecordNumber)
{
m_Reader.BaseStream.Seek(Header.NumBytesHdr + ((RecordNumber - 1) * Header.NumBytesRcd), SeekOrigin.Begin);
byte[] Ret = m_Reader.ReadBytes(Header.NumBytesRcd);
return Ret;
}
public void RawWriteRecord(int RecordNumber, byte[] RecordData)
{
if (RecordData.Length != Header.NumBytesRcd)
{
throw new Exception("RecordData size does not match size in header");
}
if (Header.NumBytesHdr + ((RecordNumber - 1) * Header.NumBytesRcd) > m_Writer.BaseStream.Length)
{
m_Writer.BaseStream.SetLength(Header.NumBytesHdr + ((RecordNumber - 1) * Header.NumBytesRcd));
Header.NumRecords++;
}
m_Writer.BaseStream.Seek(Header.NumBytesHdr + ((RecordNumber - 1) * Header.NumBytesRcd), SeekOrigin.Begin);
m_Writer.Write(RecordData);
}
}