All pastes #231539 Raw Edit

Macca

public text v1 · immutable
#231539 ·published 2006-10-31 21:37 UTC
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);
		}
	}