Import dotnetDBF for error handling.
This commit is contained in:
9
dotnetdbf/.gitignore
vendored
Normal file
9
dotnetdbf/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
bin
|
||||
obj
|
||||
/packages
|
||||
|
||||
*.suo
|
||||
|
||||
*.user
|
||||
.idea/*
|
||||
.vs/*
|
||||
44
dotnetdbf/DBFBase.cs
Normal file
44
dotnetdbf/DBFBase.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Serves as the base class of DBFReader adn DBFWriter.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
Support for choosing implemented character Sets as
|
||||
suggested by Nick Voznesensky <darkers@mail.ru>
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
*/
|
||||
/**
|
||||
Base class for DBFReader and DBFWriter.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public abstract class DBFBase
|
||||
{
|
||||
|
||||
public Encoding CharEncoding { get; set; } = Encoding.GetEncoding("utf-8");
|
||||
|
||||
public int BlockSize { get; set; } = 512;
|
||||
|
||||
private string _nullSymbol;
|
||||
public string NullSymbol
|
||||
{
|
||||
get => _nullSymbol ?? DBFFieldType.Unknown;
|
||||
set
|
||||
{
|
||||
if (value != null && value.Length != 1)
|
||||
throw new ArgumentException(nameof(NullSymbol));
|
||||
_nullSymbol = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
62
dotnetdbf/DBFException.cs
Normal file
62
dotnetdbf/DBFException.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
DBFException
|
||||
Represents exceptions happen in the JAvaDBF classes.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBTException : DBFException
|
||||
{
|
||||
|
||||
public DBTException(string msg) : base(msg)
|
||||
{
|
||||
}
|
||||
|
||||
public DBTException(string msg, Exception internalException)
|
||||
: base(msg, internalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DBFRecordException : DBFException
|
||||
{
|
||||
public int Record { get; }
|
||||
|
||||
public DBFRecordException(string msg, int record) : base(msg)
|
||||
{
|
||||
Record = record;
|
||||
}
|
||||
|
||||
public DBFRecordException(string msg, Exception internalException)
|
||||
: base(msg, internalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DBFException : IOException
|
||||
{
|
||||
public DBFException() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public DBFException(string msg) : base(msg)
|
||||
{
|
||||
}
|
||||
|
||||
public DBFException(string msg, Exception internalException)
|
||||
: base(msg, internalException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
309
dotnetdbf/DBFField.cs
Normal file
309
dotnetdbf/DBFField.cs
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
DBFField
|
||||
Class represents a "field" (or column) definition of a DBF data structure.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
[DebuggerDisplay("Field:{Name}, Length:{FieldLength}")]
|
||||
public class DBFField
|
||||
{
|
||||
public const int SIZE = 32;
|
||||
public byte dataType; /* 11 */
|
||||
public byte decimalCount; /* 17 */
|
||||
public int fieldLength; /* 16 */
|
||||
public byte[] fieldName = new byte[11]; /* 0-10*/
|
||||
public byte indexFieldFlag; /* 31 */
|
||||
|
||||
/* other class variables */
|
||||
public int nameNullIndex = 0;
|
||||
public int reserv1; /* 12-15 */
|
||||
public short reserv2; /* 18-19 */
|
||||
public short reserv3; /* 21-22 */
|
||||
public byte[] reserv4 = new byte[7]; /* 24-30 */
|
||||
public byte setFieldsFlag; /* 23 */
|
||||
public byte workAreaId; /* 20 */
|
||||
|
||||
public DBFField()
|
||||
{
|
||||
}
|
||||
|
||||
public DBFField(string fieldName, NativeDbType type)
|
||||
{
|
||||
Name = fieldName;
|
||||
DataType = type;
|
||||
}
|
||||
|
||||
public DBFField(string fieldName,
|
||||
NativeDbType type,
|
||||
int fieldLength)
|
||||
{
|
||||
Name = fieldName;
|
||||
DataType = type;
|
||||
FieldLength = fieldLength;
|
||||
}
|
||||
|
||||
public DBFField(string fieldName,
|
||||
NativeDbType type,
|
||||
int fieldLength,
|
||||
int decimalCount)
|
||||
{
|
||||
Name = fieldName;
|
||||
DataType = type;
|
||||
FieldLength = fieldLength;
|
||||
DecimalCount = decimalCount;
|
||||
}
|
||||
|
||||
public int Size => SIZE;
|
||||
|
||||
/**
|
||||
Returns the name of the field.
|
||||
|
||||
@return Name of the field as String.
|
||||
*/
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => Encoding.ASCII.GetString(fieldName, 0, nameNullIndex);
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentException("Field name cannot be null");
|
||||
}
|
||||
|
||||
if (value.Length == 0
|
||||
|| value.Length > 10)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Field name should be of length 0-10");
|
||||
}
|
||||
|
||||
fieldName = Encoding.ASCII.GetBytes(value);
|
||||
nameNullIndex = fieldName.Length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the data type of the field.
|
||||
|
||||
@return Data type as byte.
|
||||
*/
|
||||
|
||||
public Type Type => Utils.TypeForNativeDBType(DataType);
|
||||
|
||||
|
||||
public NativeDbType DataType
|
||||
{
|
||||
get => (NativeDbType)dataType;
|
||||
set
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case NativeDbType.Date:
|
||||
fieldLength = 8; /* fall through */
|
||||
goto default;
|
||||
case NativeDbType.Memo:
|
||||
fieldLength = 10;
|
||||
goto default;
|
||||
case NativeDbType.Logical:
|
||||
fieldLength = 1;
|
||||
goto default;
|
||||
default:
|
||||
dataType = (byte)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns field length.
|
||||
|
||||
@return field length as int.
|
||||
*/
|
||||
|
||||
public int FieldLength
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DataType == NativeDbType.Char)
|
||||
{
|
||||
return fieldLength + (decimalCount * 256);
|
||||
}
|
||||
|
||||
return fieldLength;
|
||||
}
|
||||
/**
|
||||
Length of the field.
|
||||
This method should be called before calling setDecimalCount().
|
||||
|
||||
@param Length of the field as int.
|
||||
*/
|
||||
set
|
||||
{
|
||||
if (value <= 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Field length should be a positive number");
|
||||
}
|
||||
|
||||
switch (DataType)
|
||||
{
|
||||
case NativeDbType.Date:
|
||||
case NativeDbType.Memo:
|
||||
case NativeDbType.Logical:
|
||||
throw new NotSupportedException(
|
||||
"Cannot set length on this type of field");
|
||||
case NativeDbType.Char when value > 255:
|
||||
fieldLength = value % 256;
|
||||
decimalCount = (byte) (value / 256);
|
||||
return;
|
||||
default:
|
||||
fieldLength = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the decimal part. This is applicable
|
||||
only if the field type if of numeric in nature.
|
||||
|
||||
If the field is specified to hold integral values
|
||||
the value returned by this method will be zero.
|
||||
|
||||
@return decimal field size as int.
|
||||
*/
|
||||
|
||||
public int DecimalCount
|
||||
{
|
||||
get => decimalCount;
|
||||
/**
|
||||
Sets the decimal place size of the field.
|
||||
Before calling this method the size of the field
|
||||
should be set by calling setFieldLength().
|
||||
|
||||
@param Size of the decimal field.
|
||||
*/
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Decimal length should be a positive number");
|
||||
}
|
||||
|
||||
if (value > fieldLength)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Decimal length should be less than field length");
|
||||
}
|
||||
|
||||
decimalCount = (byte) value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Read(BinaryReader reader)
|
||||
{
|
||||
var t_byte = reader.ReadByte(); /* 0 */
|
||||
if (t_byte == DBFFieldType.EndOfField)
|
||||
{
|
||||
//System.out.println( "End of header found");
|
||||
return false;
|
||||
}
|
||||
|
||||
reader.Read(fieldName, 1, 10); /* 1-10 */
|
||||
fieldName[0] = t_byte;
|
||||
|
||||
for (var i = 0; i < fieldName.Length; i++)
|
||||
{
|
||||
if (fieldName[i]
|
||||
== 0)
|
||||
{
|
||||
nameNullIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dataType = reader.ReadByte(); /* 11 */
|
||||
reserv1 = reader.ReadInt32(); /* 12-15 */
|
||||
fieldLength = reader.ReadByte(); /* 16 */
|
||||
decimalCount = reader.ReadByte(); /* 17 */
|
||||
reserv2 = reader.ReadInt16(); /* 18-19 */
|
||||
workAreaId = reader.ReadByte(); /* 20 */
|
||||
reserv3 = reader.ReadInt16(); /* 21-22 */
|
||||
setFieldsFlag = reader.ReadByte(); /* 23 */
|
||||
reader.Read(reserv4, 0, 7); /* 24-30 */
|
||||
indexFieldFlag = reader.ReadByte(); /* 31 */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the content of DBFField object into the stream as per
|
||||
DBF format specifications.
|
||||
|
||||
@param os OutputStream
|
||||
@throws IOException if any stream related issues occur.
|
||||
*/
|
||||
|
||||
public void Write(BinaryWriter writer)
|
||||
{
|
||||
// Field Name
|
||||
writer.Write(fieldName); /* 0-10 */
|
||||
writer.Write(new byte[11 - fieldName.Length],
|
||||
0,
|
||||
11 - fieldName.Length);
|
||||
|
||||
// data type
|
||||
writer.Write(dataType); /* 11 */
|
||||
writer.Write(reserv1); /* 12-15 */
|
||||
writer.Write((byte) fieldLength); /* 16 */
|
||||
writer.Write(decimalCount); /* 17 */
|
||||
writer.Write(reserv2); /* 18-19 */
|
||||
writer.Write(workAreaId); /* 20 */
|
||||
writer.Write(reserv3); /* 21-22 */
|
||||
writer.Write(setFieldsFlag); /* 23 */
|
||||
writer.Write(reserv4); /* 24-30*/
|
||||
writer.Write(indexFieldFlag); /* 31 */
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a DBFField object from the data read from the given DataInputStream.
|
||||
|
||||
The data in the DataInputStream object is supposed to be organised correctly
|
||||
and the stream "pointer" is supposed to be positioned properly.
|
||||
|
||||
@param in DataInputStream
|
||||
@return Returns the created DBFField object.
|
||||
@throws IOException If any stream reading problems occurs.
|
||||
*/
|
||||
|
||||
internal static DBFField CreateField(BinaryReader reader)
|
||||
{
|
||||
var field = new DBFField();
|
||||
if (field.Read(reader))
|
||||
{
|
||||
return field;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
dotnetdbf/DBFFieldType.cs
Normal file
86
dotnetdbf/DBFFieldType.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
DBFFieldType
|
||||
Class for reading the records assuming that the given
|
||||
InputStream comtains DBF data.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
author (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
*/
|
||||
|
||||
using System.Data;
|
||||
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public enum NativeDbType : byte
|
||||
{
|
||||
Autoincrement = (byte) 0x2B, //+ in ASCII
|
||||
Timestamp = (byte) 0x40, //@ in ASCII
|
||||
Binary = (byte) 0x42, //B in ASCII
|
||||
Char = (byte) 0x43, //C in ASCII
|
||||
Date = (byte) 0x44, //D in ASCII
|
||||
Float = (byte) 0x46, //F in ASCII
|
||||
Ole = (byte) 0x47, //G in ASCII
|
||||
Long = (byte) 0x49, //I in ASCII
|
||||
Logical = (byte) 0x4C, //L in ASCII
|
||||
Memo = (byte) 0x4D, //M in ASCII
|
||||
Numeric = (byte) 0x4E, //N in ASCII
|
||||
Double = (byte) 0x4F, //O in ASCII
|
||||
}
|
||||
|
||||
public static class DBFFieldType
|
||||
{
|
||||
public const byte EndOfData = 0x1A; //^Z End of File
|
||||
public const byte EndOfField = 0x0D; //End of Field
|
||||
public const byte False = 0x46; //F in Ascii
|
||||
public const byte Space = 0x20; //Space in ascii
|
||||
public const byte True = 0x54; //T in ascii
|
||||
public const byte UnknownByte = 0x3F; //Unknown Bool value
|
||||
public const string Unknown = "?"; //Unknown value
|
||||
|
||||
public static DbType FromNative(NativeDbType @byte)
|
||||
{
|
||||
switch (@byte)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
return DbType.AnsiStringFixedLength;
|
||||
case NativeDbType.Logical:
|
||||
return DbType.Boolean;
|
||||
case NativeDbType.Numeric:
|
||||
return DbType.Decimal;
|
||||
case NativeDbType.Date:
|
||||
return DbType.Date;
|
||||
case NativeDbType.Float:
|
||||
return DbType.Decimal;
|
||||
case NativeDbType.Memo:
|
||||
return DbType.AnsiString;
|
||||
default:
|
||||
return DbType.Object;
|
||||
}
|
||||
}
|
||||
|
||||
public static NativeDbType FromDbType(DbType dbType)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case DbType.AnsiStringFixedLength:
|
||||
return NativeDbType.Char;
|
||||
case DbType.Boolean:
|
||||
return NativeDbType.Logical;
|
||||
case DbType.Decimal:
|
||||
return NativeDbType.Numeric;
|
||||
case DbType.Date:
|
||||
return NativeDbType.Date;
|
||||
case DbType.AnsiString:
|
||||
return NativeDbType.Memo;
|
||||
default:
|
||||
throw new DBFException(
|
||||
$"Unsupported Type {dbType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
182
dotnetdbf/DBFHeader.cs
Normal file
182
dotnetdbf/DBFHeader.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
DBFHeader
|
||||
Class for reading the metadata assuming that the given
|
||||
InputStream carries DBF data.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
[Obsolete("Use DBFSignature instead", error:true)]
|
||||
public static class DBFSigniture
|
||||
{
|
||||
public const byte NotSet = 0,
|
||||
WithMemo = 0x80,
|
||||
DBase3 = 0x03,
|
||||
DBase3WithMemo = DBase3 | WithMemo;
|
||||
}
|
||||
|
||||
public static class DBFSignature
|
||||
{
|
||||
public const byte NotSet = 0,
|
||||
WithMemo = 0x80,
|
||||
DBase3 = 0x03,
|
||||
DBase3WithMemo = DBase3 | WithMemo;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum MemoFlags : byte
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public class DBFHeader
|
||||
{
|
||||
public const byte HeaderRecordTerminator = 0x0D;
|
||||
|
||||
internal byte Signature { get; set; } /* 0 */
|
||||
internal byte Year { set; get; } /* 1 */
|
||||
internal byte Month { set; get; } /* 2 */
|
||||
internal byte Day { set; get; } /* 3 */
|
||||
internal int NumberOfRecords { set; get; } /* 4-7 */
|
||||
internal short HeaderLength { set; get; } /* 8-9 */
|
||||
internal short RecordLength { set; get; } /* 10-11 */
|
||||
private short _reserv1; /* 12-13 */
|
||||
private byte _incompleteTransaction; /* 14 */
|
||||
private byte _encryptionFlag; /* 15 */
|
||||
private int _freeRecordThread; /* 16-19 */
|
||||
private int _reserv2; /* 20-23 */
|
||||
private int _reserv3; /* 24-27 */
|
||||
private byte _mdxFlag; /* 28 */
|
||||
internal byte LanguageDriver { get; set; } /* 29 */
|
||||
private short _reserv4; /* 30-31 */
|
||||
internal DBFField[] FieldArray { set; get; } /* each 32 bytes */
|
||||
|
||||
|
||||
public DBFHeader()
|
||||
{
|
||||
Signature = DBFSignature.DBase3;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal short Size => (short) (sizeof(byte) +
|
||||
sizeof(byte) + sizeof(byte) + sizeof(byte) +
|
||||
sizeof(int) +
|
||||
sizeof(short) +
|
||||
sizeof(short) +
|
||||
sizeof(short) +
|
||||
sizeof(byte) +
|
||||
sizeof(byte) +
|
||||
sizeof(int) +
|
||||
sizeof(int) +
|
||||
sizeof(int) +
|
||||
sizeof(byte) +
|
||||
sizeof(byte) +
|
||||
sizeof(short) +
|
||||
(DBFField.SIZE * FieldArray.Length) +
|
||||
sizeof(byte));
|
||||
|
||||
internal short RecordSize
|
||||
{
|
||||
get
|
||||
{
|
||||
var tRecordLength = 0;
|
||||
for (var i = 0; i < FieldArray.Length; i++)
|
||||
{
|
||||
tRecordLength += FieldArray[i].FieldLength;
|
||||
}
|
||||
|
||||
return (short) (tRecordLength + 1);
|
||||
}
|
||||
}
|
||||
|
||||
internal void Read(BinaryReader dataInput)
|
||||
{
|
||||
Signature = dataInput.ReadByte(); /* 0 */
|
||||
Year = dataInput.ReadByte(); /* 1 */
|
||||
Month = dataInput.ReadByte(); /* 2 */
|
||||
Day = dataInput.ReadByte(); /* 3 */
|
||||
NumberOfRecords = dataInput.ReadInt32(); /* 4-7 */
|
||||
|
||||
HeaderLength = dataInput.ReadInt16(); /* 8-9 */
|
||||
RecordLength = dataInput.ReadInt16(); /* 10-11 */
|
||||
|
||||
_reserv1 = dataInput.ReadInt16(); /* 12-13 */
|
||||
_incompleteTransaction = dataInput.ReadByte(); /* 14 */
|
||||
_encryptionFlag = dataInput.ReadByte(); /* 15 */
|
||||
_freeRecordThread = dataInput.ReadInt32(); /* 16-19 */
|
||||
_reserv2 = dataInput.ReadInt32(); /* 20-23 */
|
||||
_reserv3 = dataInput.ReadInt32(); /* 24-27 */
|
||||
_mdxFlag = dataInput.ReadByte(); /* 28 */
|
||||
LanguageDriver = dataInput.ReadByte(); /* 29 */
|
||||
_reserv4 = dataInput.ReadInt16(); /* 30-31 */
|
||||
|
||||
|
||||
var v_fields = new List<DBFField>();
|
||||
|
||||
var field = DBFField.CreateField(dataInput); /* 32 each */
|
||||
while (field != null)
|
||||
{
|
||||
v_fields.Add(field);
|
||||
field = DBFField.CreateField(dataInput);
|
||||
}
|
||||
|
||||
FieldArray = v_fields.ToArray();
|
||||
//System.out.println( "Number of fields: " + _fieldArray.length);
|
||||
}
|
||||
|
||||
internal void Write(BinaryWriter dataOutput)
|
||||
{
|
||||
dataOutput.Write(Signature); /* 0 */
|
||||
var tNow = DateTime.Now;
|
||||
Year = (byte) (tNow.Year - 1900);
|
||||
Month = (byte) (tNow.Month);
|
||||
Day = (byte) (tNow.Day);
|
||||
|
||||
dataOutput.Write(Year); /* 1 */
|
||||
dataOutput.Write(Month); /* 2 */
|
||||
dataOutput.Write(Day); /* 3 */
|
||||
|
||||
//System.out.println( "Number of records in O/S: " + numberOfRecords);
|
||||
dataOutput.Write(NumberOfRecords); /* 4-7 */
|
||||
|
||||
HeaderLength = Size;
|
||||
dataOutput.Write(HeaderLength); /* 8-9 */
|
||||
|
||||
RecordLength = RecordSize;
|
||||
dataOutput.Write(RecordLength); /* 10-11 */
|
||||
|
||||
dataOutput.Write(_reserv1); /* 12-13 */
|
||||
dataOutput.Write(_incompleteTransaction); /* 14 */
|
||||
dataOutput.Write(_encryptionFlag); /* 15 */
|
||||
dataOutput.Write(_freeRecordThread); /* 16-19 */
|
||||
dataOutput.Write(_reserv2); /* 20-23 */
|
||||
dataOutput.Write(_reserv3); /* 24-27 */
|
||||
|
||||
dataOutput.Write(_mdxFlag); /* 28 */
|
||||
dataOutput.Write(LanguageDriver); /* 29 */
|
||||
dataOutput.Write(_reserv4); /* 30-31 */
|
||||
|
||||
foreach (var field in FieldArray)
|
||||
{
|
||||
field.Write(dataOutput);
|
||||
}
|
||||
|
||||
dataOutput.Write(HeaderRecordTerminator); /* n+1 */
|
||||
}
|
||||
}
|
||||
}
|
||||
487
dotnetdbf/DBFReader.cs
Normal file
487
dotnetdbf/DBFReader.cs
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
DBFReader
|
||||
Class for reading the records assuming that the given
|
||||
InputStream contains DBF data.
|
||||
|
||||
This file is part of DotNetDBF package.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBFReader : DBFBase, IDisposable
|
||||
{
|
||||
private BinaryReader _dataInputStream;
|
||||
private DBFHeader _header;
|
||||
private Stream _dataMemo;
|
||||
|
||||
private string _dataMemoLoc;
|
||||
|
||||
private int[] _selectFields = new int[] {};
|
||||
private int[] _orderedSelectFields = new int[] {};
|
||||
/* Class specific variables */
|
||||
private bool _isClosed = true;
|
||||
|
||||
|
||||
/**
|
||||
Initializes a DBFReader object.
|
||||
|
||||
When this constructor returns the object
|
||||
will have completed reading the header (meta date) and
|
||||
header information can be queried there on. And it will
|
||||
be ready to return the first row.
|
||||
|
||||
@param InputStream where the data is read from.
|
||||
*/
|
||||
|
||||
|
||||
public void SetSelectFields(params string[] aParams)
|
||||
{
|
||||
_selectFields =
|
||||
aParams.Select(
|
||||
it =>
|
||||
Array.FindIndex(_header.FieldArray,
|
||||
jt => jt.Name.Equals(it, StringComparison.OrdinalIgnoreCase))).ToArray();
|
||||
_orderedSelectFields = _selectFields.OrderBy(it => it).ToArray();
|
||||
}
|
||||
|
||||
public DBFField[] GetSelectFields()
|
||||
{
|
||||
return _selectFields.Any()
|
||||
? _selectFields.Select(it => _header.FieldArray[it]).ToArray()
|
||||
: _header.FieldArray;
|
||||
}
|
||||
|
||||
|
||||
public DBFReader(string anIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dataInputStream = new BinaryReader(
|
||||
File.Open(anIn,
|
||||
FileMode.Open,
|
||||
FileAccess.Read,
|
||||
FileShare.Read)
|
||||
);
|
||||
|
||||
var dbtPath = Path.ChangeExtension(anIn, "dbt");
|
||||
if (File.Exists(dbtPath))
|
||||
{
|
||||
_dataMemoLoc = dbtPath;
|
||||
}
|
||||
|
||||
_isClosed = false;
|
||||
_header = new DBFHeader();
|
||||
_header.Read(_dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
var t_dataStartIndex = _header.HeaderLength
|
||||
- (32 + (32 * _header.FieldArray.Length))
|
||||
- 1;
|
||||
if (t_dataStartIndex > 0)
|
||||
{
|
||||
_dataInputStream.ReadBytes((t_dataStartIndex));
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new DBFException("Failed To Read DBF", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public DBFReader(Stream anIn)
|
||||
{
|
||||
try
|
||||
{
|
||||
_dataInputStream = new BinaryReader(anIn);
|
||||
_isClosed = false;
|
||||
_header = new DBFHeader();
|
||||
_header.Read(_dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
var t_dataStartIndex = _header.HeaderLength
|
||||
- (32 + (32 * _header.FieldArray.Length))
|
||||
- 1;
|
||||
if (t_dataStartIndex > 0)
|
||||
{
|
||||
_dataInputStream.ReadBytes((t_dataStartIndex));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Failed To Read DBF", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of records in the DBF.
|
||||
*/
|
||||
|
||||
public int RecordCount => _header.NumberOfRecords;
|
||||
|
||||
/**
|
||||
Returns the asked Field. In case of an invalid index,
|
||||
it returns a ArrayIndexOutOfBoundsException.
|
||||
|
||||
@param index. Index of the field. Index of the first field is zero.
|
||||
*/
|
||||
|
||||
public DBFField[] Fields => _header.FieldArray;
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing,
|
||||
/// or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public string DataMemoLoc
|
||||
{
|
||||
get => _dataMemoLoc;
|
||||
set => _dataMemoLoc = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public delegate Stream LazyStream();
|
||||
|
||||
private Stream _loadedStream;
|
||||
|
||||
private LazyStream GetLazyStreamFromLocation()
|
||||
{
|
||||
|
||||
if (_dataMemo == null && !string.IsNullOrEmpty(_dataMemoLoc))
|
||||
{
|
||||
return () => _loadedStream ??
|
||||
(_loadedStream = File.Open(_dataMemoLoc, FileMode.Open, FileAccess.Read,
|
||||
FileShare.Read));
|
||||
}
|
||||
if (_dataMemo != null)
|
||||
{
|
||||
return () => _dataMemo;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream DataMemo
|
||||
{
|
||||
get => _dataMemo;
|
||||
set => _dataMemo = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb =
|
||||
new StringBuilder(_header.Year + "/" + _header.Month + "/"
|
||||
+ _header.Day + "\n"
|
||||
+ "Total records: " + _header.NumberOfRecords +
|
||||
"\nHeader length: " + _header.HeaderLength +
|
||||
"");
|
||||
|
||||
for (var i = 0; i < _header.FieldArray.Length; i++)
|
||||
{
|
||||
sb.Append(_header.FieldArray[i].Name);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
|
||||
|
||||
_loadedStream?.Close();
|
||||
_dataMemo?.Close();
|
||||
_dataInputStream.Close();
|
||||
|
||||
_dataMemo?.Dispose();
|
||||
|
||||
|
||||
|
||||
_isClosed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads the returns the next row in the DBF stream.
|
||||
@returns The next row as an Object array. Types of the elements
|
||||
these arrays follow the convention mentioned in the class description.
|
||||
*/
|
||||
|
||||
public object[] NextRecord(bool throwOnParsingError = true)
|
||||
{
|
||||
return NextRecord(_selectFields, _orderedSelectFields, throwOnParsingError);
|
||||
}
|
||||
|
||||
internal object[] NextRecord(IEnumerable<int> selectIndexes, IList<int> sortedIndexes, bool throwOnParsingError = true)
|
||||
{
|
||||
if (_isClosed)
|
||||
{
|
||||
throw new DBFException("Source is not open");
|
||||
}
|
||||
var tOrderdSelectIndexes = sortedIndexes;
|
||||
|
||||
var recordObjects = new object[_header.FieldArray.Length];
|
||||
|
||||
try
|
||||
{
|
||||
var isDeleted = false;
|
||||
do
|
||||
{
|
||||
if (isDeleted)
|
||||
{
|
||||
_dataInputStream.ReadBytes(_header.RecordLength - 1);
|
||||
}
|
||||
|
||||
int t_byte = _dataInputStream.ReadByte();
|
||||
if (t_byte == DBFFieldType.EndOfData)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
isDeleted = (t_byte == '*');
|
||||
} while (isDeleted);
|
||||
|
||||
var j = 0;
|
||||
var k = -1;
|
||||
for (var i = 0; i < _header.FieldArray.Length; i++)
|
||||
{
|
||||
if (tOrderdSelectIndexes.Count == j && j != 0
|
||||
||
|
||||
(tOrderdSelectIndexes.Count > j && tOrderdSelectIndexes[j] > i && tOrderdSelectIndexes[j] != k))
|
||||
{
|
||||
_dataInputStream.BaseStream.Seek(_header.FieldArray[i].FieldLength, SeekOrigin.Current);
|
||||
continue;
|
||||
}
|
||||
if (tOrderdSelectIndexes.Count > j)
|
||||
k = tOrderdSelectIndexes[j];
|
||||
j++;
|
||||
|
||||
|
||||
switch (_header.FieldArray[i].DataType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
|
||||
var b_array = new byte[
|
||||
_header.FieldArray[i].FieldLength
|
||||
];
|
||||
_dataInputStream.Read(b_array, 0, b_array.Length);
|
||||
|
||||
recordObjects[i] = CharEncoding.GetString(b_array).TrimEnd();
|
||||
break;
|
||||
|
||||
case NativeDbType.Date:
|
||||
|
||||
var t_byte_year = new byte[4];
|
||||
_dataInputStream.Read(t_byte_year,
|
||||
0,
|
||||
t_byte_year.Length);
|
||||
|
||||
var t_byte_month = new byte[2];
|
||||
_dataInputStream.Read(t_byte_month,
|
||||
0,
|
||||
t_byte_month.Length);
|
||||
|
||||
var t_byte_day = new byte[2];
|
||||
_dataInputStream.Read(t_byte_day,
|
||||
0,
|
||||
t_byte_day.Length);
|
||||
|
||||
try
|
||||
{
|
||||
var tYear = CharEncoding.GetString(t_byte_year);
|
||||
var tMonth = CharEncoding.GetString(t_byte_month);
|
||||
var tDay = CharEncoding.GetString(t_byte_day);
|
||||
|
||||
if (int.TryParse(tYear, out var tIntYear) &&
|
||||
int.TryParse(tMonth, out var tIntMonth) &&
|
||||
int.TryParse(tDay, out var tIntDay))
|
||||
{
|
||||
recordObjects[i] = new DateTime(
|
||||
tIntYear,
|
||||
tIntMonth,
|
||||
tIntDay);
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
/* this field may be empty or may have improper value set */
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Float:
|
||||
|
||||
try
|
||||
{
|
||||
var t_float = new byte[
|
||||
_header.FieldArray[i].FieldLength
|
||||
];
|
||||
_dataInputStream.Read(t_float, 0, t_float.Length);
|
||||
var tParsed = CharEncoding.GetString(t_float);
|
||||
var tLast = tParsed.Substring(tParsed.Length - 1);
|
||||
if (tParsed.Length > 0
|
||||
&& tLast != " "
|
||||
&& tLast != NullSymbol)
|
||||
{
|
||||
//
|
||||
// A Float in FoxPro has 20 significant digits, since it is
|
||||
// stored as a string with possible E-postfix notation.
|
||||
// An IEEE 754 float or double can not handle this number of digits
|
||||
// correctly. Therefor the only correct implementation is to use a decimal.
|
||||
//
|
||||
recordObjects[i] = decimal.Parse(tParsed,
|
||||
NumberStyles.Float | NumberStyles.AllowLeadingWhite,
|
||||
NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
if (throwOnParsingError)
|
||||
throw new DBFException("Failed to parse Float", e);
|
||||
|
||||
recordObjects[i] = default(decimal);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Numeric:
|
||||
|
||||
try
|
||||
{
|
||||
var t_numeric = new byte[
|
||||
_header.FieldArray[i].FieldLength
|
||||
];
|
||||
_dataInputStream.Read(t_numeric,
|
||||
0,
|
||||
t_numeric.Length);
|
||||
var tParsed =
|
||||
CharEncoding.GetString(t_numeric);
|
||||
var tLast = tParsed.Substring(tParsed.Length - 1);
|
||||
if (tParsed.Length > 0
|
||||
&& tLast != " "
|
||||
&& tLast != NullSymbol)
|
||||
{
|
||||
recordObjects[i] = decimal.Parse(tParsed,
|
||||
NumberStyles.Float | NumberStyles.AllowLeadingWhite,
|
||||
NumberFormatInfo.InvariantInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch (FormatException e)
|
||||
{
|
||||
if (throwOnParsingError)
|
||||
throw new DBFException(
|
||||
"Failed to parse Number", e);
|
||||
|
||||
recordObjects[i] = default(decimal);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Logical:
|
||||
|
||||
var t_logical = _dataInputStream.ReadByte();
|
||||
//todo find out whats really valid
|
||||
if (t_logical == 'Y' || t_logical == 't'
|
||||
|| t_logical == 'T'
|
||||
|| t_logical == 't')
|
||||
{
|
||||
recordObjects[i] = true;
|
||||
}
|
||||
else if (t_logical == DBFFieldType.UnknownByte)
|
||||
{
|
||||
recordObjects[i] = DBNull.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
recordObjects[i] = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case NativeDbType.Memo:
|
||||
if (
|
||||
|
||||
string.IsNullOrEmpty(_dataMemoLoc) &&
|
||||
|
||||
_dataMemo is null)
|
||||
{
|
||||
throw new Exception("Memo Location Not Set");
|
||||
}
|
||||
|
||||
|
||||
var rawMemoPointer = _dataInputStream.ReadBytes(_header.FieldArray[i].FieldLength);
|
||||
var memoPointer = CharEncoding.GetString(rawMemoPointer);
|
||||
if (string.IsNullOrEmpty(memoPointer))
|
||||
{
|
||||
recordObjects[i] = DBNull.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!long.TryParse(memoPointer, out var tBlock))
|
||||
{
|
||||
//Because Memo files can vary and are often the least important data,
|
||||
//we will return null when it doesn't match our format.
|
||||
recordObjects[i] = DBNull.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
recordObjects[i] = new MemoValue(tBlock, this,
|
||||
_dataMemoLoc,
|
||||
GetLazyStreamFromLocation());
|
||||
break;
|
||||
default:
|
||||
{
|
||||
byte[] data = _dataInputStream.ReadBytes(_header.FieldArray[i].FieldLength);
|
||||
|
||||
recordObjects[i] = data != null ? (object)data : DBNull.Value;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EndOfStreamException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Problem Reading File", e);
|
||||
}
|
||||
|
||||
return selectIndexes.Any() ? selectIndexes.Select(it => recordObjects[it]).ToArray() : recordObjects;
|
||||
}
|
||||
}
|
||||
}
|
||||
528
dotnetdbf/DBFWriter.cs
Normal file
528
dotnetdbf/DBFWriter.cs
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
DBFWriter
|
||||
Class for defining a DBF structure and addin data to that structure and
|
||||
finally writing it to an OutputStream.
|
||||
|
||||
This file is part of DotNetDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBFWriter : DBFBase, IDisposable
|
||||
{
|
||||
private DBFHeader header;
|
||||
private Stream raf;
|
||||
private int recordCount;
|
||||
private List<object> v_records = new List<object>();
|
||||
private Stream _dataMemo;
|
||||
|
||||
private string _dataMemoLoc;
|
||||
|
||||
/// Creates an empty Object.
|
||||
public DBFWriter()
|
||||
{
|
||||
header = new DBFHeader();
|
||||
}
|
||||
|
||||
|
||||
/// Creates a DBFWriter which can append to records to an existing DBF file.
|
||||
/// @param dbfFile. The file passed in should be a valid DBF file.
|
||||
/// @exception Throws DBFException if the passed in file does exist but not a valid DBF file, or if an IO error occurs.
|
||||
public DBFWriter(string dbfFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
raf =
|
||||
File.Open(dbfFile,
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite);
|
||||
|
||||
DataMemoLoc = Path.ChangeExtension(dbfFile, "dbt");
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if (raf.Length == 0)
|
||||
{
|
||||
header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
header.Read(new BinaryReader(raf));
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
/* check whether the last byte is 0x1A (end of file marker for dbf files) - in this case move 1 byte back to ignore it when writing new records */
|
||||
var lastByte = raf.ReadByte(); /* Advances to end of stream */
|
||||
if (lastByte == DBFFieldType.EndOfData)
|
||||
{
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new DBFException("Specified file is not found. ", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException(" while reading header", e);
|
||||
}
|
||||
recordCount = header.NumberOfRecords;
|
||||
}
|
||||
|
||||
public DBFWriter(Stream dbfFile)
|
||||
{
|
||||
raf = dbfFile;
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if (raf.Length == 0)
|
||||
{
|
||||
header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
header.Read(new BinaryReader(raf));
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
/* check whether the last byte is 0x1A (end of file marker for dbf files) - in this case move 1 byte back to ignore it when writing new records */
|
||||
var lastByte = raf.ReadByte(); /* Advances to end of stream */
|
||||
if (lastByte == DBFFieldType.EndOfData)
|
||||
{
|
||||
raf.Seek(-1, SeekOrigin.End);
|
||||
}
|
||||
|
||||
recordCount = header.NumberOfRecords;
|
||||
}
|
||||
|
||||
public byte Signature
|
||||
{
|
||||
get => header.Signature;
|
||||
set => header.Signature = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string DataMemoLoc
|
||||
{
|
||||
get => _dataMemoLoc;
|
||||
set
|
||||
{
|
||||
_dataMemoLoc = value;
|
||||
|
||||
_dataMemo?.Close();
|
||||
_dataMemo = File.Open(_dataMemoLoc,
|
||||
FileMode.OpenOrCreate,
|
||||
FileAccess.ReadWrite);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream DataMemo
|
||||
{
|
||||
get => _dataMemo;
|
||||
set => _dataMemo = value;
|
||||
}
|
||||
|
||||
public byte LanguageDriver
|
||||
{
|
||||
set
|
||||
{
|
||||
if (header.LanguageDriver != 0x00)
|
||||
{
|
||||
throw new DBFException("LanguageDriver has already been set");
|
||||
}
|
||||
|
||||
header.LanguageDriver = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public DBFField[] Fields
|
||||
{
|
||||
get => header.FieldArray;
|
||||
|
||||
|
||||
set
|
||||
{
|
||||
if (header.FieldArray != null)
|
||||
{
|
||||
throw new DBFException("Fields has already been set");
|
||||
}
|
||||
|
||||
if (value == null
|
||||
|| value.Length == 0)
|
||||
{
|
||||
throw new DBFException("Should have at least one field");
|
||||
}
|
||||
|
||||
for (var i = 0; i < value.Length; i++)
|
||||
{
|
||||
if (value[i] == null)
|
||||
{
|
||||
throw new DBFException("Field " + (i + 1) + " is null");
|
||||
}
|
||||
}
|
||||
|
||||
header.FieldArray = value;
|
||||
|
||||
try
|
||||
{
|
||||
if (raf != null
|
||||
&& raf.Length == 0)
|
||||
{
|
||||
/*
|
||||
this is a new/non-existent file. So write header before proceeding
|
||||
*/
|
||||
header.Write(new BinaryWriter(raf));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Error accessing file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing,
|
||||
/// or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/**
|
||||
Add a record.
|
||||
*/
|
||||
|
||||
public void WriteRecord(params object[] values)
|
||||
{
|
||||
if (raf == null)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Not initialized with file for WriteRecord use, use AddRecord instead");
|
||||
}
|
||||
AddRecord(values, true);
|
||||
}
|
||||
|
||||
public void AddRecord(params object[] values)
|
||||
{
|
||||
if (raf != null)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Appending to a file, requires using WriteRecord instead");
|
||||
}
|
||||
AddRecord(values, false);
|
||||
}
|
||||
|
||||
private void AddRecord(object[] values, bool writeImmediately)
|
||||
{
|
||||
if (header.FieldArray == null)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Fields should be set before adding records");
|
||||
}
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
throw new DBFException("Null cannot be added as row");
|
||||
}
|
||||
|
||||
if (values.Length
|
||||
!= header.FieldArray.Length)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Invalid record. Invalid number of fields in row");
|
||||
}
|
||||
|
||||
for (var i = 0; i < header.FieldArray.Length; i++)
|
||||
{
|
||||
var fld = header.FieldArray[i];
|
||||
var val = values[i];
|
||||
|
||||
if (val is null || val is DBNull)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
void ThrowErrorIfNot<T>()
|
||||
{
|
||||
if (!(val is T))
|
||||
{
|
||||
throw new DBFRecordException($"Invalid value '{val}' for field {i}({fld.Name}{fld.DataType})", 0);
|
||||
}
|
||||
}
|
||||
|
||||
switch (fld.DataType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
//ignore all objects have ToString()
|
||||
break;
|
||||
|
||||
case NativeDbType.Logical:
|
||||
ThrowErrorIfNot<bool>();
|
||||
break;
|
||||
|
||||
case NativeDbType.Numeric:
|
||||
ThrowErrorIfNot<IConvertible>();
|
||||
break;
|
||||
|
||||
case NativeDbType.Date:
|
||||
ThrowErrorIfNot<DateTime>();
|
||||
break;
|
||||
|
||||
case NativeDbType.Float:
|
||||
ThrowErrorIfNot<IConvertible>();
|
||||
break;
|
||||
case NativeDbType.Memo:
|
||||
ThrowErrorIfNot<MemoValue>();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeImmediately)
|
||||
{
|
||||
v_records.Add(values);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteRecord(new BinaryWriter(raf), values);
|
||||
recordCount++;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException(
|
||||
"Error occured while writing record. ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///Writes the set data to the OutputStream.
|
||||
public void Write(Stream tOut)
|
||||
{
|
||||
try
|
||||
{
|
||||
var outStream = new BinaryWriter(tOut);
|
||||
|
||||
header.NumberOfRecords = v_records.Count;
|
||||
header.Write(outStream);
|
||||
|
||||
/* Now write all the records */
|
||||
var t_recCount = v_records.Count;
|
||||
for (var i = 0; i < t_recCount; i++)
|
||||
{
|
||||
/* iterate through records */
|
||||
|
||||
var t_values = (object[]) v_records[i];
|
||||
|
||||
WriteRecord(outStream, t_values);
|
||||
}
|
||||
|
||||
outStream.Write(DBFFieldType.EndOfData);
|
||||
outStream.Flush();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new DBFException("Error Writing", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
/* everything is written already. just update the header for record count and the END_OF_DATA mark */
|
||||
header.NumberOfRecords = recordCount;
|
||||
if (raf != null)
|
||||
{
|
||||
raf.Seek(0, SeekOrigin.Begin);
|
||||
header.Write(new BinaryWriter(raf));
|
||||
raf.Seek(0, SeekOrigin.End);
|
||||
raf.WriteByte(DBFFieldType.EndOfData);
|
||||
|
||||
raf.Close();
|
||||
_dataMemo?.Close();
|
||||
|
||||
} else if (!string.IsNullOrEmpty(DataMemoLoc))
|
||||
{
|
||||
DataMemo.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void WriteRecord(BinaryWriter dataOutput, object[] objectArray)
|
||||
{
|
||||
dataOutput.Write((byte) ' ');
|
||||
for (var j = 0; j < header.FieldArray.Length; j++)
|
||||
{
|
||||
/* iterate through fields */
|
||||
|
||||
switch (header.FieldArray[j].DataType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var str_value = objectArray[j].ToString();
|
||||
dataOutput.Write(
|
||||
Utils.textPadding(str_value,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].
|
||||
FieldLength
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding("",
|
||||
CharEncoding,
|
||||
header.FieldArray[j].
|
||||
FieldLength
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Date:
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tDate = (DateTime) objectArray[j];
|
||||
|
||||
dataOutput.Write(
|
||||
CharEncoding.GetBytes(tDate.ToString("yyyyMMdd")));
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.FillArray(new byte[8], DBFFieldType.Space));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Float:
|
||||
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tDouble = Convert.ToDecimal(objectArray[j]);
|
||||
dataOutput.Write(
|
||||
Utils.NumericFormating(
|
||||
tDouble,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
header.FieldArray[j].DecimalCount
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding(
|
||||
NullSymbol,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
Utils.ALIGN_RIGHT
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Numeric:
|
||||
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tDecimal = Convert.ToDecimal(objectArray[j]);
|
||||
dataOutput.Write(
|
||||
Utils.NumericFormating(
|
||||
tDecimal,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
header.FieldArray[j].DecimalCount
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding(
|
||||
NullSymbol,
|
||||
CharEncoding,
|
||||
header.FieldArray[j].FieldLength,
|
||||
Utils.ALIGN_RIGHT
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
case NativeDbType.Logical:
|
||||
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
if ((bool) objectArray[j])
|
||||
{
|
||||
dataOutput.Write(DBFFieldType.True);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(DBFFieldType.False);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(DBFFieldType.UnknownByte);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NativeDbType.Memo:
|
||||
if (objectArray[j] != null && objectArray[j] != DBNull.Value)
|
||||
{
|
||||
var tMemoValue = ((MemoValue) objectArray[j]);
|
||||
|
||||
tMemoValue.Write(this);
|
||||
|
||||
dataOutput.Write(Utils.NumericFormating(tMemoValue.Block, CharEncoding, 10, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
dataOutput.Write(
|
||||
Utils.textPadding("",
|
||||
CharEncoding,
|
||||
10
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new DBFException("Unknown field type "
|
||||
+ header.FieldArray[j].DataType);
|
||||
}
|
||||
} /* iterating through the fields */
|
||||
}
|
||||
}
|
||||
}
|
||||
37
dotnetdbf/DBTHeader.cs
Normal file
37
dotnetdbf/DBTHeader.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class DBTHeader
|
||||
{
|
||||
public const byte FieldTerminator = 0x1A;
|
||||
|
||||
|
||||
private int _nextBlock; /* 0-3*/
|
||||
private byte _version = 0x03;
|
||||
|
||||
|
||||
internal int NextBlock
|
||||
{
|
||||
get => _nextBlock;
|
||||
set => _nextBlock = value;
|
||||
}
|
||||
|
||||
internal byte Version
|
||||
{
|
||||
get => _version;
|
||||
set => _version = value;
|
||||
}
|
||||
|
||||
internal void Write(BinaryWriter dataOutput)
|
||||
{
|
||||
dataOutput.Write(_nextBlock);
|
||||
dataOutput.Write(new byte[12]);
|
||||
dataOutput.Write(_version);
|
||||
dataOutput.Write(new byte[495]);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
dotnetdbf/DotNetDBF.csproj
Normal file
33
dotnetdbf/DotNetDBF.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net35;netstandard2.0</TargetFrameworks>
|
||||
<SignAssembly>True</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>sn.snk</AssemblyOriginatorKeyFile>
|
||||
<Version>7.0.0.0</Version>
|
||||
<Company>Ekon Benefits</Company>
|
||||
<Copyright>Copyright 2009-2017</Copyright>
|
||||
<Description>This is a basic file parser for reading and writing xBase DBF files particularlly Clipper. Code originally derived from javadbf.</Description>
|
||||
<PackageProjectUrl>https://github.com/ekonbenefits/dotnetdbf</PackageProjectUrl>
|
||||
<PackageTags>clipper xbase dbf</PackageTags>
|
||||
<Authors>Anil Kumar, Jay Tuley</Authors>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<RepositoryUrl>https://github.com/ekonbenefits/dotnetdbf.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<IncludeSource>True</IncludeSource>
|
||||
<PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="original java src\**" />
|
||||
<EmbeddedResource Remove="original java src\**" />
|
||||
<None Remove="original java src\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
33
dotnetdbf/DotNetDBF.sln
Normal file
33
dotnetdbf/DotNetDBF.sln
Normal file
@@ -0,0 +1,33 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.9
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetDBF", "DotNetDBF\DotNetDBF.csproj", "{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetDBF.Enumerable", "DotNetDBF.Enumerable\DotNetDBF.Enumerable.csproj", "{3BB97ECD-325D-4288-B355-57CFC1404019}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetDBF.Test", "DotNetDBF.Test\DotNetDBF.Test.csproj", "{8D5436E3-F584-40A0-ACDC-65346ECEADB0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5E9AE18-1EA3-4C90-AFAB-5323093BE4AC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3BB97ECD-325D-4288-B355-57CFC1404019}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D5436E3-F584-40A0-ACDC-65346ECEADB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
9
dotnetdbf/DotNetDBF.sln.DotSettings
Normal file
9
dotnetdbf/DotNetDBF.sln.DotSettings
Normal file
@@ -0,0 +1,9 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DBT/@EntryIndexedValue">DBT</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters /></data></s:String>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue"><data /></s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=javadbf/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=LGPL/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=reserv/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Tuley/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
164
dotnetdbf/MemoValue.cs
Normal file
164
dotnetdbf/MemoValue.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public class MemoValue
|
||||
{
|
||||
public const string MemoTerminator = "\x1A";
|
||||
private bool _loaded;
|
||||
private bool _new;
|
||||
|
||||
|
||||
public MemoValue(string aValue)
|
||||
{
|
||||
_lockName = $"DotNetDBF.Memo.new.{Guid.NewGuid()}";
|
||||
Value = aValue;
|
||||
}
|
||||
|
||||
|
||||
internal MemoValue(long block, DBFBase aBase,
|
||||
string fileLoc, DBFReader.LazyStream fileStream)
|
||||
{
|
||||
_block = block;
|
||||
_base = aBase;
|
||||
_fileLoc = fileLoc;
|
||||
_fileStream = fileStream;
|
||||
if (string.IsNullOrEmpty(fileLoc))
|
||||
{
|
||||
_lockName = fileStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
_lockName = $"DotNetDBF.Memo.read.{_fileLoc}";
|
||||
}
|
||||
}
|
||||
|
||||
private readonly DBFBase _base;
|
||||
private readonly object _lockName;
|
||||
private long _block;
|
||||
private readonly string _fileLoc;
|
||||
private string _value;
|
||||
private readonly DBFReader.LazyStream _fileStream;
|
||||
|
||||
internal long Block => _block;
|
||||
|
||||
internal void Write(DBFWriter aBase)
|
||||
{
|
||||
lock (_lockName)
|
||||
{
|
||||
if (!_new)
|
||||
return;
|
||||
|
||||
var raf = aBase.DataMemo;
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if (raf == null)
|
||||
{
|
||||
throw new InvalidDataException("Null Memo Field Stream from Writer");
|
||||
}
|
||||
|
||||
var tWriter = new BinaryWriter(raf, aBase.CharEncoding); //Don't close the stream could be used else where;
|
||||
|
||||
if (raf.Length == 0)
|
||||
{
|
||||
var tHeader = new DBTHeader();
|
||||
tHeader.Write(tWriter);
|
||||
}
|
||||
|
||||
var tValue = _value;
|
||||
if ((tValue.Length + sizeof(int)) % aBase.BlockSize != 0)
|
||||
{
|
||||
tValue = tValue + MemoTerminator;
|
||||
}
|
||||
|
||||
var tPosition = raf.Seek(0, SeekOrigin.End); //Got To End Of File
|
||||
var tBlockDiff = tPosition % aBase.BlockSize;
|
||||
if (tBlockDiff != 0)
|
||||
{
|
||||
tPosition = raf.Seek(aBase.BlockSize - tBlockDiff, SeekOrigin.Current);
|
||||
}
|
||||
_block = tPosition / aBase.BlockSize;
|
||||
var tData = aBase.CharEncoding.GetBytes(tValue);
|
||||
var tDataLength = tData.Length;
|
||||
var tNewDiff = (tDataLength % aBase.BlockSize);
|
||||
tWriter.Write(tData);
|
||||
if (tNewDiff != 0)
|
||||
tWriter.Seek(aBase.BlockSize - (tDataLength % aBase.BlockSize), SeekOrigin.Current);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lockName)
|
||||
{
|
||||
if (_new || _loaded) return _value;
|
||||
var fileStream = _fileStream();
|
||||
|
||||
var reader = new BinaryReader(fileStream);
|
||||
|
||||
{
|
||||
reader.BaseStream.Seek(_block * _base.BlockSize, SeekOrigin.Begin);
|
||||
var builder = new StringBuilder();
|
||||
int termIndex;
|
||||
var softReturn = _base.CharEncoding.GetString(new byte[] {0x8d, 0x0a});
|
||||
|
||||
do
|
||||
{
|
||||
var data = reader.ReadBytes(_base.BlockSize);
|
||||
if ((data.Length == 0))
|
||||
{
|
||||
throw new DBTException("Missing Data for block or no 1a memo terminator");
|
||||
}
|
||||
var stringVal = _base.CharEncoding.GetString(data);
|
||||
termIndex = stringVal.IndexOf(MemoTerminator, StringComparison.Ordinal);
|
||||
if (termIndex != -1)
|
||||
stringVal = stringVal.Substring(0, termIndex);
|
||||
builder.Append(stringVal);
|
||||
} while (termIndex == -1);
|
||||
_value = builder.ToString().Replace(softReturn, string.Empty);
|
||||
}
|
||||
_loaded = true;
|
||||
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_lockName)
|
||||
{
|
||||
_new = true;
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _lockName.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is MemoValue m)
|
||||
{
|
||||
return ReferenceEquals(this, obj) || Value.Equals(m.Value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
dotnetdbf/Properties/MoreAssemblyInfo.cs
Normal file
3
dotnetdbf/Properties/MoreAssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("DotNetDBF.Enumerable,PublicKey=00240000048000009400000006020000002400005253413100040000010001008713EA5197F8878AF1E1CDEF220E2D0A898944AD1643B851775EB8624697A183FBCD2ED8C1A58CE185B657D6381419AFF8B0DE8F8934F2B7E5DC7C19C11DE8D146B113F6794BF604BD2A11334DCF1022A485DD7A6E6BED8873D26363E9692136598B7750AD633747922657FF215347614DE2FDFA7866843F2924C9E5DB2545E1")]
|
||||
11
dotnetdbf/README.md
Normal file
11
dotnetdbf/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
dotnetdbf
|
||||
=========
|
||||
|
||||
This is a basic file parser written in C# for reading and writing xBase DBF files, particularly Clipper.
|
||||
|
||||
For .net 4.0 projects there is an enumeration framework in which makes it easy to use Linq to Objects.
|
||||
|
||||
Code derived from javadbf.
|
||||
|
||||
## Get The Binaries
|
||||
Use [NuGet](http://nuget.org/packages/dotnetdbf/) from Visual Studio
|
||||
175
dotnetdbf/Utils.cs
Normal file
175
dotnetdbf/Utils.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
Utils
|
||||
Class for contining utility functions.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
original author (javadbf): anil@linuxense.com 2004/03/31
|
||||
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
ported to C# (DotNetDBF): Jay Tuley <jay+dotnetdbf@tuley.name> 6/28/2007
|
||||
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace DotNetDBF
|
||||
{
|
||||
public static class Utils
|
||||
{
|
||||
public const int ALIGN_LEFT = 10;
|
||||
public const int ALIGN_RIGHT = 12;
|
||||
|
||||
public static byte[] FillArray(byte[] anArray, byte value)
|
||||
{
|
||||
for (var i = 0; i < anArray.Length; i++)
|
||||
{
|
||||
anArray[i] = value;
|
||||
}
|
||||
return anArray;
|
||||
}
|
||||
|
||||
public static byte[] trimLeftSpaces(byte[] arr)
|
||||
{
|
||||
var tList = new List<byte>(arr.Length);
|
||||
|
||||
for (var i = 0; i < arr.Length; i++)
|
||||
{
|
||||
if (arr[i] != ' ')
|
||||
{
|
||||
tList.Add(arr[i]);
|
||||
}
|
||||
}
|
||||
return tList.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] textPadding(string text,
|
||||
Encoding charEncoding,
|
||||
int length)
|
||||
{
|
||||
return textPadding(text, charEncoding, length, ALIGN_LEFT);
|
||||
}
|
||||
|
||||
public static byte[] textPadding(string text,
|
||||
Encoding charEncoding,
|
||||
int length,
|
||||
int alignment)
|
||||
{
|
||||
return
|
||||
textPadding(text,
|
||||
charEncoding,
|
||||
length,
|
||||
alignment,
|
||||
DBFFieldType.Space);
|
||||
}
|
||||
|
||||
public static byte[] textPadding(string text,
|
||||
Encoding charEncoding,
|
||||
int length,
|
||||
int alignment,
|
||||
byte paddingByte)
|
||||
{
|
||||
var tEncoding = charEncoding;
|
||||
var inputBytes = tEncoding.GetBytes(text);
|
||||
if (inputBytes.Length >= length)
|
||||
{
|
||||
return inputBytes.Take(length).ToArray();
|
||||
}
|
||||
|
||||
var byte_array = FillArray(new byte[length], paddingByte);
|
||||
|
||||
switch (alignment)
|
||||
{
|
||||
case ALIGN_LEFT:
|
||||
Array.Copy(inputBytes,
|
||||
0,
|
||||
byte_array,
|
||||
0,
|
||||
inputBytes.Length);
|
||||
break;
|
||||
|
||||
case ALIGN_RIGHT:
|
||||
var t_offset = length - text.Length;
|
||||
Array.Copy(inputBytes,
|
||||
0,
|
||||
byte_array,
|
||||
t_offset,
|
||||
inputBytes.Length);
|
||||
break;
|
||||
}
|
||||
|
||||
return byte_array;
|
||||
}
|
||||
|
||||
public static byte[] NumericFormating(IFormattable doubleNum,
|
||||
Encoding charEncoding,
|
||||
int fieldLength,
|
||||
int sizeDecimalPart)
|
||||
{
|
||||
var sizeWholePart = fieldLength
|
||||
-
|
||||
(sizeDecimalPart > 0 ? (sizeDecimalPart + 1) : 0);
|
||||
|
||||
var format = new StringBuilder(fieldLength);
|
||||
|
||||
for (var i = 0; i < sizeWholePart; i++)
|
||||
{
|
||||
format.Append(i + 1 == sizeWholePart ? "0" : "#");
|
||||
}
|
||||
|
||||
if (sizeDecimalPart > 0)
|
||||
{
|
||||
format.Append(".");
|
||||
|
||||
for (var i = 0; i < sizeDecimalPart; i++)
|
||||
{
|
||||
format.Append("0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return
|
||||
textPadding(
|
||||
doubleNum.ToString(format.ToString(),
|
||||
NumberFormatInfo.InvariantInfo),
|
||||
charEncoding,
|
||||
fieldLength,
|
||||
ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
public static bool contains(byte[] arr, byte value)
|
||||
{
|
||||
return
|
||||
Array.Exists(arr,
|
||||
delegate(byte anItem) { return anItem == value; });
|
||||
}
|
||||
|
||||
|
||||
public static Type TypeForNativeDBType(NativeDbType aType)
|
||||
{
|
||||
switch (aType)
|
||||
{
|
||||
case NativeDbType.Char:
|
||||
return typeof(string);
|
||||
case NativeDbType.Date:
|
||||
return typeof(DateTime);
|
||||
case NativeDbType.Numeric:
|
||||
return typeof(decimal);
|
||||
case NativeDbType.Logical:
|
||||
return typeof(bool);
|
||||
case NativeDbType.Float:
|
||||
return typeof(decimal);
|
||||
case NativeDbType.Memo:
|
||||
return typeof(MemoValue);
|
||||
default:
|
||||
return typeof(Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
dotnetdbf/original java src/DBFBase.java
Normal file
36
dotnetdbf/original java src/DBFBase.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
$Id: DBFBase.java,v 1.3 2004/03/31 15:59:40 anil Exp $
|
||||
Serves as the base class of DBFReader adn DBFWriter.
|
||||
|
||||
@author: anil@linuxense.com
|
||||
|
||||
Support for choosing implemented character Sets as
|
||||
suggested by Nick Voznesensky <darkers@mail.ru>
|
||||
*/
|
||||
/**
|
||||
Base class for DBFReader and DBFWriter.
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
public abstract class DBFBase {
|
||||
|
||||
protected String characterSetName = "8859_1";
|
||||
protected final int END_OF_DATA = 0x1A;
|
||||
|
||||
/*
|
||||
If the library is used in a non-latin environment use this method to set
|
||||
corresponding character set. More information:
|
||||
http://www.iana.org/assignments/character-sets
|
||||
Also see the documentation of the class java.nio.charset.Charset
|
||||
*/
|
||||
public String getCharactersetName() {
|
||||
|
||||
return this.characterSetName;
|
||||
}
|
||||
|
||||
public void setCharactersetName( String characterSetName) {
|
||||
|
||||
this.characterSetName = characterSetName;
|
||||
}
|
||||
|
||||
}
|
||||
27
dotnetdbf/original java src/DBFException.java
Normal file
27
dotnetdbf/original java src/DBFException.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
DBFException
|
||||
Represents exceptions happen in the JAvaDBF classes.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFException.java,v 1.2 2004/03/31 10:40:18 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DBFException extends IOException {
|
||||
|
||||
public DBFException() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
public DBFException( String msg) {
|
||||
|
||||
super( msg);
|
||||
}
|
||||
}
|
||||
283
dotnetdbf/original java src/DBFField.java
Normal file
283
dotnetdbf/original java src/DBFField.java
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
DBFField
|
||||
Class represents a "field" (or column) definition of a DBF data structure.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFField.java,v 1.7 2004/03/31 10:50:11 anil Exp $
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
DBFField represents a field specification in an dbf file.
|
||||
|
||||
DBFField objects are either created and added to a DBFWriter object or obtained
|
||||
from DBFReader object through getField( int) query.
|
||||
|
||||
*/
|
||||
public class DBFField {
|
||||
|
||||
public static final byte FIELD_TYPE_C = (byte)'C';
|
||||
public static final byte FIELD_TYPE_L = (byte)'L';
|
||||
public static final byte FIELD_TYPE_N = (byte)'N';
|
||||
public static final byte FIELD_TYPE_F = (byte)'F';
|
||||
public static final byte FIELD_TYPE_D = (byte)'D';
|
||||
public static final byte FIELD_TYPE_M = (byte)'M';
|
||||
|
||||
/* Field struct variables start here */
|
||||
byte[] fieldName = new byte[ 11]; /* 0-10*/
|
||||
byte dataType; /* 11 */
|
||||
int reserv1; /* 12-15 */
|
||||
int fieldLength; /* 16 */
|
||||
byte decimalCount; /* 17 */
|
||||
short reserv2; /* 18-19 */
|
||||
byte workAreaId; /* 20 */
|
||||
short reserv3; /* 21-22 */
|
||||
byte setFieldsFlag; /* 23 */
|
||||
byte[] reserv4 = new byte[ 7]; /* 24-30 */
|
||||
byte indexFieldFlag; /* 31 */
|
||||
/* Field struct variables end here */
|
||||
|
||||
/* other class variables */
|
||||
int nameNullIndex = 0;
|
||||
|
||||
/**
|
||||
Creates a DBFField object from the data read from the given DataInputStream.
|
||||
|
||||
The data in the DataInputStream object is supposed to be organised correctly
|
||||
and the stream "pointer" is supposed to be positioned properly.
|
||||
|
||||
@param in DataInputStream
|
||||
@return Returns the created DBFField object.
|
||||
@throws IOException If any stream reading problems occures.
|
||||
*/
|
||||
protected static DBFField createField( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
DBFField field = new DBFField();
|
||||
|
||||
byte t_byte = in.readByte(); /* 0 */
|
||||
if( t_byte == (byte)0x0d) {
|
||||
|
||||
//System.out.println( "End of header found");
|
||||
return null;
|
||||
}
|
||||
|
||||
in.readFully( field.fieldName, 1, 10); /* 1-10 */
|
||||
field.fieldName[0] = t_byte;
|
||||
|
||||
for( int i=0; i<field.fieldName.length; i++) {
|
||||
|
||||
if( field.fieldName[ i] == (byte)0) {
|
||||
|
||||
field.nameNullIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
field.dataType = in.readByte(); /* 11 */
|
||||
field.reserv1 = Utils.readLittleEndianInt( in); /* 12-15 */
|
||||
field.fieldLength = in.readUnsignedByte(); /* 16 */
|
||||
field.decimalCount = in.readByte(); /* 17 */
|
||||
field.reserv2 = Utils.readLittleEndianShort( in); /* 18-19 */
|
||||
field.workAreaId = in.readByte(); /* 20 */
|
||||
field.reserv2 = Utils.readLittleEndianShort( in); /* 21-22 */
|
||||
field.setFieldsFlag = in.readByte(); /* 23 */
|
||||
in.readFully( field.reserv4); /* 24-30 */
|
||||
field.indexFieldFlag = in.readByte(); /* 31 */
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the content of DBFField object into the stream as per
|
||||
DBF format specifications.
|
||||
|
||||
@param os OutputStream
|
||||
@throws IOException if any stream related issues occur.
|
||||
*/
|
||||
protected void write( DataOutput out)
|
||||
throws IOException {
|
||||
|
||||
//DataOutputStream out = new DataOutputStream( os);
|
||||
|
||||
// Field Name
|
||||
out.write( fieldName); /* 0-10 */
|
||||
out.write( new byte[ 11 - fieldName.length]);
|
||||
|
||||
// data type
|
||||
out.writeByte( dataType); /* 11 */
|
||||
out.writeInt( 0x00); /* 12-15 */
|
||||
out.writeByte( fieldLength); /* 16 */
|
||||
out.writeByte( decimalCount); /* 17 */
|
||||
out.writeShort( (short)0x00); /* 18-19 */
|
||||
out.writeByte( (byte)0x00); /* 20 */
|
||||
out.writeShort( (short)0x00); /* 21-22 */
|
||||
out.writeByte( (byte)0x00); /* 23 */
|
||||
out.write( new byte[7]); /* 24-30*/
|
||||
out.writeByte( (byte)0x00); /* 31 */
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the name of the field.
|
||||
|
||||
@return Name of the field as String.
|
||||
*/
|
||||
public String getName() {
|
||||
|
||||
return new String( this.fieldName, 0, nameNullIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the data type of the field.
|
||||
|
||||
@return Data type as byte.
|
||||
*/
|
||||
public byte getDataType() {
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns field length.
|
||||
|
||||
@return field length as int.
|
||||
*/
|
||||
public int getFieldLength() {
|
||||
|
||||
return fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the decimal part. This is applicable
|
||||
only if the field type if of numeric in nature.
|
||||
|
||||
If the field is specified to hold integral values
|
||||
the value returned by this method will be zero.
|
||||
|
||||
@return decimal field size as int.
|
||||
*/
|
||||
public int getDecimalCount() {
|
||||
|
||||
return decimalCount;
|
||||
}
|
||||
|
||||
// Setter methods
|
||||
|
||||
// byte[] fieldName = new byte[ 11]; /* 0-10*/
|
||||
// byte dataType; /* 11 */
|
||||
// int reserv1; /* 12-15 */
|
||||
// byte fieldLength; /* 16 */
|
||||
// byte decimalCount; /* 17 */
|
||||
// short reserv2; /* 18-19 */
|
||||
// byte workAreaId; /* 20 */
|
||||
// short reserv3; /* 21-22 */
|
||||
// byte setFieldsFlag; /* 23 */
|
||||
// byte[] reserv4 = new byte[ 7]; /* 24-30 */
|
||||
// byte indexFieldFlag; /* 31 */
|
||||
|
||||
/**
|
||||
* @deprecated This method is depricated as of version 0.3.3.1 and is replaced by {@link #setName( String)}.
|
||||
*/
|
||||
public void setFieldName( String value) {
|
||||
|
||||
setName( value);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the name of the field.
|
||||
|
||||
@param name of the field as String.
|
||||
@since 0.3.3.1
|
||||
*/
|
||||
public void setName( String value) {
|
||||
|
||||
if( value == null) {
|
||||
|
||||
throw new IllegalArgumentException( "Field name cannot be null");
|
||||
}
|
||||
|
||||
if( value.length() == 0 || value.length() > 10) {
|
||||
|
||||
throw new IllegalArgumentException( "Field name should be of length 0-10");
|
||||
}
|
||||
|
||||
this.fieldName = value.getBytes();
|
||||
this.nameNullIndex = this.fieldName.length;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the data type of the field.
|
||||
|
||||
@param type of the field. One of the following:<br>
|
||||
C, L, N, F, D, M
|
||||
*/
|
||||
public void setDataType( byte value) {
|
||||
|
||||
switch( value) {
|
||||
|
||||
case 'D':
|
||||
this.fieldLength = 8; /* fall through */
|
||||
case 'C':
|
||||
case 'L':
|
||||
case 'N':
|
||||
case 'F':
|
||||
case 'M':
|
||||
|
||||
this.dataType = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException( "Unknown data type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Length of the field.
|
||||
This method should be called before calling setDecimalCount().
|
||||
|
||||
@param Length of the field as int.
|
||||
*/
|
||||
public void setFieldLength( int value) {
|
||||
|
||||
if( value <= 0) {
|
||||
|
||||
throw new IllegalArgumentException( "Field length should be a positive number");
|
||||
}
|
||||
|
||||
if( this.dataType == FIELD_TYPE_D) {
|
||||
|
||||
throw new UnsupportedOperationException( "Cannot do this on a Date field");
|
||||
}
|
||||
|
||||
fieldLength = value;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the decimal place size of the field.
|
||||
Before calling this method the size of the field
|
||||
should be set by calling setFieldLength().
|
||||
|
||||
@param Size of the decimal field.
|
||||
*/
|
||||
public void setDecimalCount( int value) {
|
||||
|
||||
if( value < 0) {
|
||||
|
||||
throw new IllegalArgumentException( "Decimal length should be a positive number");
|
||||
}
|
||||
|
||||
if( value > fieldLength) {
|
||||
|
||||
throw new IllegalArgumentException( "Decimal length should be less than field length");
|
||||
}
|
||||
|
||||
decimalCount = (byte)value;
|
||||
}
|
||||
|
||||
}
|
||||
167
dotnetdbf/original java src/DBFHeader.java
Normal file
167
dotnetdbf/original java src/DBFHeader.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
DBFHeader
|
||||
Class for reading the metadata assuming that the given
|
||||
InputStream carries DBF data.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
Author: anil@linuxense.com
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
class DBFHeader {
|
||||
|
||||
static final byte SIG_DBASE_III = (byte)0x03;
|
||||
/* DBF structure start here */
|
||||
|
||||
byte signature; /* 0 */
|
||||
byte year; /* 1 */
|
||||
byte month; /* 2 */
|
||||
byte day; /* 3 */
|
||||
int numberOfRecords; /* 4-7 */
|
||||
short headerLength; /* 8-9 */
|
||||
short recordLength; /* 10-11 */
|
||||
short reserv1; /* 12-13 */
|
||||
byte incompleteTransaction; /* 14 */
|
||||
byte encryptionFlag; /* 15 */
|
||||
int freeRecordThread; /* 16-19 */
|
||||
int reserv2; /* 20-23 */
|
||||
int reserv3; /* 24-27 */
|
||||
byte mdxFlag; /* 28 */
|
||||
byte languageDriver; /* 29 */
|
||||
short reserv4; /* 30-31 */
|
||||
DBFField []fieldArray; /* each 32 bytes */
|
||||
byte terminator1; /* n+1 */
|
||||
|
||||
//byte[] databaseContainer; /* 263 bytes */
|
||||
/* DBF structure ends here */
|
||||
|
||||
DBFHeader() {
|
||||
|
||||
this.signature = SIG_DBASE_III;
|
||||
this.terminator1 = 0x0D;
|
||||
}
|
||||
|
||||
void read( DataInput dataInput) throws IOException {
|
||||
|
||||
signature = dataInput.readByte(); /* 0 */
|
||||
year = dataInput.readByte(); /* 1 */
|
||||
month = dataInput.readByte(); /* 2 */
|
||||
day = dataInput.readByte(); /* 3 */
|
||||
numberOfRecords = Utils.readLittleEndianInt( dataInput); /* 4-7 */
|
||||
|
||||
headerLength = Utils.readLittleEndianShort( dataInput); /* 8-9 */
|
||||
recordLength = Utils.readLittleEndianShort( dataInput); /* 10-11 */
|
||||
|
||||
reserv1 = Utils.readLittleEndianShort( dataInput); /* 12-13 */
|
||||
incompleteTransaction = dataInput.readByte(); /* 14 */
|
||||
encryptionFlag = dataInput.readByte(); /* 15 */
|
||||
freeRecordThread = Utils.readLittleEndianInt( dataInput); /* 16-19 */
|
||||
reserv2 = dataInput.readInt(); /* 20-23 */
|
||||
reserv3 = dataInput.readInt(); /* 24-27 */
|
||||
mdxFlag = dataInput.readByte(); /* 28 */
|
||||
languageDriver = dataInput.readByte(); /* 29 */
|
||||
reserv4 = Utils.readLittleEndianShort( dataInput); /* 30-31 */
|
||||
|
||||
Vector v_fields = new Vector();
|
||||
|
||||
DBFField field = DBFField.createField( dataInput); /* 32 each */
|
||||
while( field != null) {
|
||||
|
||||
v_fields.addElement( field);
|
||||
field = DBFField.createField( dataInput);
|
||||
}
|
||||
|
||||
fieldArray = new DBFField[ v_fields.size()];
|
||||
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
fieldArray[ i] = (DBFField)v_fields.elementAt( i);
|
||||
}
|
||||
//System.out.println( "Number of fields: " + fieldArray.length);
|
||||
|
||||
}
|
||||
|
||||
void write( DataOutput dataOutput) throws IOException {
|
||||
|
||||
dataOutput.writeByte( signature); /* 0 */
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
year = (byte)( calendar.get( Calendar.YEAR) - 1900);
|
||||
month = (byte)( calendar.get( Calendar.MONTH)+1);
|
||||
day = (byte)( calendar.get( Calendar.DAY_OF_MONTH));
|
||||
|
||||
dataOutput.writeByte( year); /* 1 */
|
||||
dataOutput.writeByte( month); /* 2 */
|
||||
dataOutput.writeByte( day); /* 3 */
|
||||
|
||||
//System.out.println( "Number of records in O/S: " + numberOfRecords);
|
||||
numberOfRecords = Utils.littleEndian( numberOfRecords);
|
||||
dataOutput.writeInt( numberOfRecords); /* 4-7 */
|
||||
|
||||
headerLength = findHeaderLength();
|
||||
dataOutput.writeShort( Utils.littleEndian( headerLength)); /* 8-9 */
|
||||
|
||||
recordLength = findRecordLength();
|
||||
dataOutput.writeShort( Utils.littleEndian( recordLength)); /* 10-11 */
|
||||
|
||||
dataOutput.writeShort( Utils.littleEndian( reserv1)); /* 12-13 */
|
||||
dataOutput.writeByte( incompleteTransaction); /* 14 */
|
||||
dataOutput.writeByte( encryptionFlag); /* 15 */
|
||||
dataOutput.writeInt( Utils.littleEndian( freeRecordThread));/* 16-19 */
|
||||
dataOutput.writeInt( Utils.littleEndian( reserv2)); /* 20-23 */
|
||||
dataOutput.writeInt( Utils.littleEndian( reserv3)); /* 24-27 */
|
||||
|
||||
dataOutput.writeByte( mdxFlag); /* 28 */
|
||||
dataOutput.writeByte( languageDriver); /* 29 */
|
||||
dataOutput.writeShort( Utils.littleEndian( reserv4)); /* 30-31 */
|
||||
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
//System.out.println( "Length: " + fieldArray[i].getFieldLength());
|
||||
fieldArray[i].write( dataOutput);
|
||||
}
|
||||
|
||||
dataOutput.writeByte( terminator1); /* n+1 */
|
||||
}
|
||||
|
||||
private short findHeaderLength() {
|
||||
|
||||
return (short)(
|
||||
1+
|
||||
3+
|
||||
4+
|
||||
2+
|
||||
2+
|
||||
2+
|
||||
1+
|
||||
1+
|
||||
4+
|
||||
4+
|
||||
4+
|
||||
1+
|
||||
1+
|
||||
2+
|
||||
(32*fieldArray.length)+
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
private short findRecordLength() {
|
||||
|
||||
int recordLength = 0;
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
recordLength += fieldArray[i].getFieldLength();
|
||||
}
|
||||
|
||||
return (short)(recordLength + 1);
|
||||
}
|
||||
}
|
||||
315
dotnetdbf/original java src/DBFReader.java
Normal file
315
dotnetdbf/original java src/DBFReader.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
DBFReader
|
||||
Class for reading the records assuming that the given
|
||||
InputStream comtains DBF data.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
Author: anil@linuxense.com
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFReader.java,v 1.8 2004/03/31 10:54:03 anil Exp $
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
DBFReader class can creates objects to represent DBF data.
|
||||
|
||||
This Class is used to read data from a DBF file. Meta data and
|
||||
records can be queried against this document.
|
||||
|
||||
<p>
|
||||
DBFReader cannot write anythng to a DBF file. For creating DBF files
|
||||
use DBFWriter.
|
||||
|
||||
<p>
|
||||
Fetching rocord is possible only in the forward direction and
|
||||
cannot re-wound. In such situation, a suggested approach is to reconstruct the object.
|
||||
|
||||
<p>
|
||||
The nextRecord() method returns an array of Objects and the types of these
|
||||
Object are as follows:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>xBase Type</th><th>Java Type</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>C</td><td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>N</td><td>Integer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>F</td><td>Double</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L</td><td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>D</td><td>java.util.Date</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
*/
|
||||
public class DBFReader extends DBFBase {
|
||||
|
||||
DataInputStream dataInputStream;
|
||||
DBFHeader header;
|
||||
|
||||
/* Class specific variables */
|
||||
boolean isClosed = true;
|
||||
|
||||
/**
|
||||
Initializes a DBFReader object.
|
||||
|
||||
When this constructor returns the object
|
||||
will have completed reading the hader (meta date) and
|
||||
header information can be quried there on. And it will
|
||||
be ready to return the first row.
|
||||
|
||||
@param InputStream where the data is read from.
|
||||
*/
|
||||
public DBFReader( InputStream in) throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
this.dataInputStream = new DataInputStream( in);
|
||||
this.isClosed = false;
|
||||
this.header = new DBFHeader();
|
||||
this.header.read( this.dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
int t_dataStartIndex = this.header.headerLength - ( 32 + (32*this.header.fieldArray.length)) - 1;
|
||||
if( t_dataStartIndex > 0) {
|
||||
|
||||
dataInputStream.skip( t_dataStartIndex);
|
||||
}
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
|
||||
StringBuffer sb = new StringBuffer( this.header.year + "/" + this.header.month + "/" + this.header.day + "\n"
|
||||
+ "Total records: " + this.header.numberOfRecords +
|
||||
"\nHEader length: " + this.header.headerLength +
|
||||
"");
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
sb.append( this.header.fieldArray[i].getName());
|
||||
sb.append( "\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of records in the DBF.
|
||||
*/
|
||||
public int getRecordCount() {
|
||||
|
||||
return this.header.numberOfRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the asked Field. In case of an invalid index,
|
||||
it returns a ArrayIndexOutofboundsException.
|
||||
|
||||
@param index. Index of the field. Index of the first field is zero.
|
||||
*/
|
||||
public DBFField getField( int index)
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
return this.header.fieldArray[ index];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of field in the DBF.
|
||||
*/
|
||||
public int getFieldCount()
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
if( this.header.fieldArray != null) {
|
||||
|
||||
return this.header.fieldArray.length;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads the returns the next row in the DBF stream.
|
||||
@returns The next row as an Object array. Types of the elements
|
||||
these arrays follow the convention mentioned in the class description.
|
||||
*/
|
||||
public Object[] nextRecord()
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
Object recordObjects[] = new Object[ this.header.fieldArray.length];
|
||||
|
||||
try {
|
||||
|
||||
boolean isDeleted = false;
|
||||
do {
|
||||
|
||||
if( isDeleted) {
|
||||
|
||||
dataInputStream.skip( this.header.recordLength-1);
|
||||
}
|
||||
|
||||
int t_byte = dataInputStream.readByte();
|
||||
if( t_byte == END_OF_DATA) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
isDeleted = ( t_byte == '*');
|
||||
} while( isDeleted);
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
switch( this.header.fieldArray[i].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
|
||||
byte b_array[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( b_array);
|
||||
recordObjects[i] = new String( b_array, characterSetName);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
|
||||
byte t_byte_year[] = new byte[ 4];
|
||||
dataInputStream.read( t_byte_year);
|
||||
|
||||
byte t_byte_month[] = new byte[ 2];
|
||||
dataInputStream.read( t_byte_month);
|
||||
|
||||
byte t_byte_day[] = new byte[ 2];
|
||||
dataInputStream.read( t_byte_day);
|
||||
|
||||
try {
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar(
|
||||
Integer.parseInt( new String( t_byte_year)),
|
||||
Integer.parseInt( new String( t_byte_month)) - 1,
|
||||
Integer.parseInt( new String( t_byte_day))
|
||||
);
|
||||
|
||||
recordObjects[i] = calendar.getTime();
|
||||
}
|
||||
catch ( NumberFormatException e) {
|
||||
/* this field may be empty or may have improper value set */
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
||||
try {
|
||||
|
||||
byte t_float[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( t_float);
|
||||
t_float = Utils.trimLeftSpaces( t_float);
|
||||
if( t_float.length > 0 && !Utils.contains( t_float, (byte)'?')) {
|
||||
|
||||
recordObjects[i] = new Float( new String( t_float));
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch( NumberFormatException e) {
|
||||
|
||||
throw new DBFException( "Failed to parse Float: " + e.getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
||||
try {
|
||||
|
||||
byte t_numeric[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( t_numeric);
|
||||
t_numeric = Utils.trimLeftSpaces( t_numeric);
|
||||
|
||||
if( t_numeric.length > 0 && !Utils.contains( t_numeric, (byte)'?')) {
|
||||
|
||||
recordObjects[i] = new Double( new String( t_numeric));
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch( NumberFormatException e) {
|
||||
|
||||
throw new DBFException( "Failed to parse Number: " + e.getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
|
||||
byte t_logical = dataInputStream.readByte();
|
||||
if( t_logical == 'Y' || t_logical == 't' || t_logical == 'T' || t_logical == 't') {
|
||||
|
||||
recordObjects[i] = Boolean.TRUE;
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = Boolean.FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
// TODO Later
|
||||
recordObjects[i] = new String( "null");
|
||||
break;
|
||||
|
||||
default:
|
||||
recordObjects[i] = new String( "null");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( EOFException e) {
|
||||
|
||||
return null;
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
|
||||
return recordObjects;
|
||||
}
|
||||
}
|
||||
350
dotnetdbf/original java src/DBFWriter.java
Normal file
350
dotnetdbf/original java src/DBFWriter.java
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
DBFWriter
|
||||
Class for defining a DBF structure and addin data to that structure and
|
||||
finally writing it to an OutputStream.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFWriter.java,v 1.9 2004/03/31 10:57:16 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
An object of this class can create a DBF file.
|
||||
|
||||
Create an object, <br>
|
||||
then define fields by creating DBFField objects and<br>
|
||||
add them to the DBFWriter object<br>
|
||||
add records using the addRecord() method and then<br>
|
||||
call write() method.
|
||||
*/
|
||||
public class DBFWriter extends DBFBase {
|
||||
|
||||
/* other class variables */
|
||||
DBFHeader header;
|
||||
Vector v_records = new Vector();
|
||||
int recordCount = 0;
|
||||
RandomAccessFile raf = null; /* Open and append records to an existing DBF */
|
||||
boolean appendMode = false;
|
||||
|
||||
/**
|
||||
Creates an empty Object.
|
||||
*/
|
||||
public DBFWriter() {
|
||||
|
||||
this.header = new DBFHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a DBFWriter which can append to records to an existing DBF file.
|
||||
@param dbfFile. The file passed in shouls be a valid DBF file.
|
||||
@exception Throws DBFException if the passed in file does exist but not a valid DBF file, or if an IO error occurs.
|
||||
*/
|
||||
public DBFWriter( File dbfFile)
|
||||
throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
this.raf = new RandomAccessFile( dbfFile, "rw");
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if( !dbfFile.exists() || dbfFile.length() == 0) {
|
||||
|
||||
this.header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
this.header.read( raf);
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
this.raf.seek( this.raf.length()-1 /* to ignore the END_OF_DATA byte at EoF */);
|
||||
}
|
||||
catch( FileNotFoundException e) {
|
||||
|
||||
throw new DBFException( "Specified file is not found. " + e.getMessage());
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage() + " while reading header");
|
||||
}
|
||||
|
||||
this.recordCount = this.header.numberOfRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets fields.
|
||||
*/
|
||||
public void setFields( DBFField[] fields)
|
||||
throws DBFException {
|
||||
|
||||
if( this.header.fieldArray != null) {
|
||||
|
||||
throw new DBFException( "Fields has already been set");
|
||||
}
|
||||
|
||||
if( fields == null || fields.length == 0) {
|
||||
|
||||
throw new DBFException( "Should have at least one field");
|
||||
}
|
||||
|
||||
for( int i=0; i<fields.length; i++) {
|
||||
|
||||
if( fields[i] == null) {
|
||||
|
||||
throw new DBFException( "Field " + (i+1) + " is null");
|
||||
}
|
||||
}
|
||||
|
||||
this.header.fieldArray = fields;
|
||||
|
||||
try {
|
||||
|
||||
if( this.raf != null && this.raf.length() == 0) {
|
||||
|
||||
/*
|
||||
this is a new/non-existent file. So write header before proceeding
|
||||
*/
|
||||
this.header.write( this.raf);
|
||||
}
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( "Error accesing file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add a record.
|
||||
*/
|
||||
public void addRecord( Object[] values)
|
||||
throws DBFException {
|
||||
|
||||
if( this.header.fieldArray == null) {
|
||||
|
||||
throw new DBFException( "Fields should be set before adding records");
|
||||
}
|
||||
|
||||
if( values == null) {
|
||||
|
||||
throw new DBFException( "Null cannot be added as row");
|
||||
}
|
||||
|
||||
if( values.length != this.header.fieldArray.length) {
|
||||
|
||||
throw new DBFException( "Invalid record. Invalid number of fields in row");
|
||||
}
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
if( values[i] == null) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
switch( this.header.fieldArray[i].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
if( !(values[i] instanceof String)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if( !( values[i] instanceof Boolean)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if( !( values[i] instanceof Double)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if( !( values[i] instanceof Date)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
if( !(values[i] instanceof Double)) {
|
||||
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( this.raf == null) {
|
||||
|
||||
v_records.addElement( values);
|
||||
}
|
||||
else {
|
||||
|
||||
try {
|
||||
|
||||
writeRecord( this.raf, values);
|
||||
this.recordCount++;
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( "Error occured while writing record. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the set data to the OutputStream.
|
||||
*/
|
||||
public void write( OutputStream out)
|
||||
throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
if( this.raf == null) {
|
||||
|
||||
DataOutputStream outStream = new DataOutputStream( out);
|
||||
|
||||
this.header.numberOfRecords = v_records.size();
|
||||
this.header.write( outStream);
|
||||
|
||||
/* Now write all the records */
|
||||
int t_recCount = v_records.size();
|
||||
for( int i=0; i<t_recCount; i++) { /* iterate through records */
|
||||
|
||||
Object[] t_values = (Object[])v_records.elementAt( i);
|
||||
|
||||
writeRecord( outStream, t_values);
|
||||
}
|
||||
|
||||
outStream.write( END_OF_DATA);
|
||||
outStream.flush();
|
||||
}
|
||||
else {
|
||||
|
||||
/* everything is written already. just update the header for record count and the END_OF_DATA mark */
|
||||
this.header.numberOfRecords = this.recordCount;
|
||||
this.raf.seek( 0);
|
||||
this.header.write( this.raf);
|
||||
this.raf.seek( raf.length());
|
||||
this.raf.writeByte( END_OF_DATA);
|
||||
this.raf.close();
|
||||
}
|
||||
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void write()
|
||||
throws DBFException {
|
||||
|
||||
this.write( null);
|
||||
}
|
||||
|
||||
private void writeRecord( DataOutput dataOutput, Object []objectArray)
|
||||
throws IOException {
|
||||
|
||||
dataOutput.write( (byte)' ');
|
||||
for( int j=0; j<this.header.fieldArray.length; j++) { /* iterate throught fields */
|
||||
|
||||
switch( this.header.fieldArray[j].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
String str_value = objectArray[j].toString();
|
||||
dataOutput.write( Utils.textPadding( str_value, characterSetName, this.header.fieldArray[j].getFieldLength()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( Utils.textPadding( "", this.characterSetName, this.header.fieldArray[j].getFieldLength()));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
calendar.setTime( (Date)objectArray[j]);
|
||||
StringBuffer t_sb = new StringBuffer();
|
||||
dataOutput.write( String.valueOf( calendar.get( Calendar.YEAR)).getBytes());
|
||||
dataOutput.write( Utils.textPadding( String.valueOf( calendar.get( Calendar.MONTH)+1), this.characterSetName, 2, Utils.ALIGN_RIGHT, (byte)'0'));
|
||||
dataOutput.write( Utils.textPadding( String.valueOf( calendar.get( Calendar.DAY_OF_MONTH)), this.characterSetName, 2, Utils.ALIGN_RIGHT, (byte)'0'));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( " ".getBytes());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
dataOutput.write( Utils.doubleFormating( (Double)objectArray[j], this.characterSetName, this.header.fieldArray[j].getFieldLength(), this.header.fieldArray[j].getDecimalCount()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( Utils.textPadding( "?", this.characterSetName, this.header.fieldArray[j].getFieldLength(), Utils.ALIGN_RIGHT));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
dataOutput.write(
|
||||
Utils.doubleFormating( (Double)objectArray[j], this.characterSetName, this.header.fieldArray[j].getFieldLength(), this.header.fieldArray[j].getDecimalCount()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write(
|
||||
Utils.textPadding( "?", this.characterSetName, this.header.fieldArray[j].getFieldLength(), Utils.ALIGN_RIGHT));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'L':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
if( (Boolean)objectArray[j] == Boolean.TRUE) {
|
||||
|
||||
dataOutput.write( (byte)'T');
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write((byte)'F');
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( (byte)'?');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new DBFException( "Unknown field type " + this.header.fieldArray[j].getDataType());
|
||||
}
|
||||
} /* iterating through the fields */
|
||||
}
|
||||
}
|
||||
172
dotnetdbf/original java src/Utils.java
Normal file
172
dotnetdbf/original java src/Utils.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Utils
|
||||
Class for contining utility functions.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: Utils.java,v 1.7 2004/03/31 16:00:34 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
/**
|
||||
Miscelaneous functions required by the JavaDBF package.
|
||||
*/
|
||||
public final class Utils {
|
||||
|
||||
public static final int ALIGN_LEFT = 10;
|
||||
public static final int ALIGN_RIGHT = 12;
|
||||
|
||||
private Utils(){}
|
||||
|
||||
public static int readLittleEndianInt( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
int bigEndian = 0;
|
||||
for( int shiftBy=0; shiftBy<32; shiftBy+=8) {
|
||||
|
||||
bigEndian |= (in.readUnsignedByte()&0xff) << shiftBy;
|
||||
}
|
||||
|
||||
return bigEndian;
|
||||
}
|
||||
|
||||
public static short readLittleEndianShort( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
int low = in.readUnsignedByte() & 0xff;
|
||||
int high = in.readUnsignedByte();
|
||||
|
||||
return (short )(high << 8 | low);
|
||||
}
|
||||
|
||||
public static byte[] trimLeftSpaces( byte [] arr) {
|
||||
|
||||
StringBuffer t_sb = new StringBuffer( arr.length);
|
||||
|
||||
for( int i=0; i<arr.length; i++) {
|
||||
|
||||
if( arr[i] != ' ') {
|
||||
|
||||
t_sb.append( (char)arr[ i]);
|
||||
}
|
||||
}
|
||||
|
||||
return t_sb.toString().getBytes();
|
||||
}
|
||||
|
||||
public static short littleEndian( short value) {
|
||||
|
||||
short num1 = value;
|
||||
short mask = (short)0xff;
|
||||
|
||||
short num2 = (short)(num1&mask);
|
||||
num2<<=8;
|
||||
mask<<=8;
|
||||
|
||||
num2 |= (num1&mask)>>8;
|
||||
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static int littleEndian(int value) {
|
||||
|
||||
int num1 = value;
|
||||
int mask = 0xff;
|
||||
int num2 = 0x00;
|
||||
|
||||
num2 |= num1 & mask;
|
||||
|
||||
for( int i=1; i<4; i++) {
|
||||
|
||||
num2<<=8;
|
||||
mask <<= 8;
|
||||
num2 |= (num1 & mask)>>(8*i);
|
||||
}
|
||||
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
return textPadding( text, characterSetName, length, Utils.ALIGN_LEFT);
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length, int alignment) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
return textPadding( text, characterSetName, length, alignment, (byte)' ');
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length, int alignment,
|
||||
byte paddingByte) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
if( text.length() >= length) {
|
||||
|
||||
return text.substring( 0, length).getBytes( characterSetName);
|
||||
}
|
||||
|
||||
byte byte_array[] = new byte[ length];
|
||||
Arrays.fill( byte_array, paddingByte);
|
||||
|
||||
switch( alignment) {
|
||||
|
||||
case ALIGN_LEFT:
|
||||
System.arraycopy( text.getBytes( characterSetName), 0, byte_array, 0, text.length());
|
||||
break;
|
||||
|
||||
case ALIGN_RIGHT:
|
||||
int t_offset = length - text.length();
|
||||
System.arraycopy( text.getBytes( characterSetName), 0, byte_array, t_offset, text.length());
|
||||
break;
|
||||
}
|
||||
|
||||
return byte_array;
|
||||
}
|
||||
|
||||
public static byte[] doubleFormating( Double doubleNum, String characterSetName, int fieldLength, int sizeDecimalPart) throws java.io.UnsupportedEncodingException{
|
||||
|
||||
int sizeWholePart = fieldLength - (sizeDecimalPart>0?( sizeDecimalPart + 1):0);
|
||||
|
||||
StringBuffer format = new StringBuffer( fieldLength);
|
||||
|
||||
for( int i=0; i<sizeWholePart; i++) {
|
||||
|
||||
format.append( "#");
|
||||
}
|
||||
|
||||
if( sizeDecimalPart > 0) {
|
||||
|
||||
format.append( ".");
|
||||
|
||||
for( int i=0; i<sizeDecimalPart; i++) {
|
||||
|
||||
format.append( "0");
|
||||
}
|
||||
}
|
||||
|
||||
DecimalFormat df = new DecimalFormat( format.toString());
|
||||
|
||||
return textPadding( df.format( doubleNum.doubleValue()).toString(), characterSetName, fieldLength, ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
public static boolean contains( byte[] arr, byte value) {
|
||||
|
||||
boolean found = false;
|
||||
for( int i=0; i<arr.length; i++) {
|
||||
|
||||
if( arr[i] == value) {
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
BIN
dotnetdbf/sn.snk
Normal file
BIN
dotnetdbf/sn.snk
Normal file
Binary file not shown.
Reference in New Issue
Block a user