using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace FastReport.Map.Import.Shp
{
///
/// Represents loading map data from dbf-file.
///
public class DbfFileImport
{
#region Fields
private string filter;
private Stream stream;
private MapLayer layer;
private List fields;
private Encoding encoding;
#endregion // Fields
#region Properties
///
/// Gets or sets the filter string used in an open file dialog.
///
public string Filter
{
get { return filter; }
protected set { filter = value; }
}
#endregion // Properties
#region Constructors
///
/// Initializes a new instance of the class.
///
public DbfFileImport()
{
filter = GetFilter();
fields = new List();
encoding = Encoding.ASCII;
}
#endregion // Constructors
#region Private Methods
private void LoadFieldsDescription()
{
byte[] buffer = new byte[11];
string name = "";
string type = "";
int length = 0;
stream.Seek(32, SeekOrigin.Begin);
for (int i = 0; i < 128; i++)
{
stream.Read(buffer, 0, 11);
name = encoding.GetString(buffer);
name = name.Remove(name.IndexOf('\0'));
stream.Read(buffer, 0, 1);
type = encoding.GetString(buffer, 0, 1);
stream.Seek(4, SeekOrigin.Current);
stream.Read(buffer, 0, 1);
length = (int)buffer[0];
fields.Add(new DBaseFieldDescription(name, type, length));
stream.Seek(15, SeekOrigin.Current);
stream.Read(buffer, 0, 1);
if (buffer[0] == 0x0D)
{
break;
}
else
{
stream.Seek(-1, SeekOrigin.Current);
}
}
}
private string LoadField(int length)
{
string field = "";
byte[] buffer = new byte[length];
stream.Read(buffer, 0, length);
field = encoding.GetString(buffer);
return field;
}
private string LoadChar(int length)
{
string field = LoadField(length);
field = field.TrimEnd(null);
return field;
}
private string LoadDate(int length)
{
string field = LoadField(length);
char[] f = field.ToCharArray();
field = f[6].ToString() + f[7].ToString() + "." + f[4].ToString() + f[5].ToString() + "." + f[0].ToString() + f[1].ToString() + f[2].ToString() + f[3].ToString();
return field;
}
private string LoadNumeric(int length)
{
string field = LoadField(length);
field = field.Trim();
return field;
}
private string LoadLogical(int length)
{
string field = LoadField(length).ToUpper();
if (field == "T" || field == "Y")
{
field = "true";
}
else if (field == "F" || field == "N")
{
field = "false";
}
else
{
field = "";
}
return field;
}
private void LoadRecords(int numRecords, int recordLength)
{
for (int i = 0; i < numRecords; i++)
{
stream.Seek(1, SeekOrigin.Current);
foreach (DBaseFieldDescription f in fields)
{
string value = "";
switch (f.Type)
{
case DBaseFieldType.Char:
value = LoadChar(f.Length);
break;
case DBaseFieldType.Date:
value = LoadDate(f.Length);
break;
case DBaseFieldType.Numeric:
value = LoadNumeric(f.Length);
break;
case DBaseFieldType.Logical:
value = LoadLogical(f.Length);
break;
}
if (i < layer.Shapes.Count)
layer.Shapes[i].SpatialData.SetValue(f.Name, value);
}
}
}
private Encoding GetEncoding(int id)
{
int codepage = 0;
#region switch
switch (id)
{
case 1:
codepage = 437;
break;
case 2:
codepage = 850;
break;
case 3:
codepage = 1252;
break;
case 4:
codepage = 10000;
break;
case 8:
codepage = 865;
break;
case 9:
codepage = 437;
break;
case 10:
codepage = 850;
break;
case 11:
codepage = 437;
break;
case 13:
codepage = 437;
break;
case 14:
codepage = 850;
break;
case 15:
codepage = 437;
break;
case 16:
codepage = 850;
break;
case 17:
codepage = 437;
break;
case 18:
codepage = 850;
break;
case 19:
codepage = 932;
break;
case 20:
codepage = 850;
break;
case 21:
codepage = 437;
break;
case 22:
codepage = 850;
break;
case 23:
codepage = 865;
break;
case 24:
codepage = 437;
break;
case 25:
codepage = 437;
break;
case 26:
codepage = 850;
break;
case 27:
codepage = 437;
break;
case 28:
codepage = 863;
break;
case 29:
codepage = 850;
break;
case 31:
codepage = 852;
break;
case 34:
codepage = 852;
break;
case 35:
codepage = 852;
break;
case 36:
codepage = 860;
break;
case 37:
codepage = 850;
break;
case 38:
codepage = 866;
break;
case 55:
codepage = 850;
break;
case 64:
codepage = 852;
break;
case 77:
codepage = 936;
break;
case 78:
codepage = 949;
break;
case 79:
codepage = 950;
break;
case 80:
codepage = 874;
break;
case 87:
codepage = 0;
break;
case 88:
codepage = 1252;
break;
case 89:
codepage = 1252;
break;
case 100:
codepage = 852;
break;
case 101:
codepage = 866;
break;
case 102:
codepage = 865;
break;
case 103:
codepage = 861;
break;
case 104:
codepage = 895;
break;
case 105:
codepage = 620;
break;
case 106:
codepage = 737;
break;
case 107:
codepage = 857;
break;
case 108:
codepage = 863;
break;
case 120:
codepage = 950;
break;
case 121:
codepage = 949;
break;
case 122:
codepage = 936;
break;
case 123:
codepage = 932;
break;
case 124:
codepage = 874;
break;
case 134:
codepage = 737;
break;
case 135:
codepage = 852;
break;
case 136:
codepage = 857;
break;
case 150:
codepage = 10007;
break;
case 151:
codepage = 10029;
break;
case 152:
codepage = 10006;
break;
case 200:
codepage = 1250;
break;
case 201:
codepage = 1251;
break;
case 202:
codepage = 1254;
break;
case 203:
codepage = 1253;
break;
case 204:
codepage = 1257;
break;
default:
codepage = 0;
break;
}
#endregion // switch
if (codepage == 0)
{
return Encoding.ASCII;
}
else
{
return Encoding.GetEncoding(codepage);
}
}
private void LoadFileHeader()
{
byte[] buffer = new byte[4];
stream.Seek(0, SeekOrigin.Begin);
stream.Read(buffer, 0, 1);
stream.Seek(4, SeekOrigin.Begin);
stream.Read(buffer, 0, 4);
if (!BitConverter.IsLittleEndian)
{
Array.Reverse(buffer, 0, 4);
}
int numRecords = BitConverter.ToInt32(buffer, 0);
stream.Read(buffer, 0, 2);
if (!BitConverter.IsLittleEndian)
{
Array.Reverse(buffer, 0, 2);
}
int headerLength = (int)BitConverter.ToInt16(buffer, 0);
stream.Read(buffer, 0, 2);
if (!BitConverter.IsLittleEndian)
{
Array.Reverse(buffer, 0, 2);
}
int recordLength = (int)BitConverter.ToInt16(buffer, 0);
stream.Seek(29, SeekOrigin.Begin);
stream.Read(buffer, 0, 1);
encoding = GetEncoding((int)buffer[0]);
LoadFieldsDescription();
LoadRecords(numRecords, recordLength);
}
private void LoadFile(MapLayer layer, Stream stream)
{
this.stream = stream;
this.layer = layer;
LoadFileHeader();
}
#endregion // Private Methods
#region Protected Methods
///
/// Returns a file filter for an open file dialog.
///
/// String that contains a file filter.
protected string GetFilter()
{
return new FastReport.Utils.MyRes("FileFilters").Get("DbfFile");
}
#endregion // Protected Methods
#region Public Methods
///
/// Imports the map data from a specified file into a specfied layer.
///
/// The MapObject for an importing map.
/// The name of a file that contains map.
public void ImportFile(MapLayer layer, string filename)
{
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
LoadFile(layer, stream);
}
}
#endregion // Public Methods
}
///
/// Represents the description of dBase field.
///
public class DBaseFieldDescription
{
#region Fields
private string name;
private DBaseFieldType type;
private int length;
#endregion // Fields
#region Properties
///
/// Gets the field name.
///
public string Name
{
get { return name; }
}
///
/// Gets the field type.
///
public DBaseFieldType Type
{
get { return type; }
}
///
/// Gets the field length.
///
public int Length
{
get { return length; }
}
#endregion // Properties
#region Constructors
///
/// Initializes a new instance of the class.
///
public DBaseFieldDescription()
{
name = "";
type = DBaseFieldType.Char;
length = 0;
}
///
/// Initializes a new instance of the class with a specified parameters.
///
/// The field name.
/// The field type.
/// The field length.
public DBaseFieldDescription(string name, DBaseFieldType type, int length)
{
this.name = name;
this.type = type;
this.length = length;
}
///
/// Initializes a new instance of the class with a specified parameters.
///
/// The field name.
/// The field type.
/// The field length.
public DBaseFieldDescription(string name, string type, int length)
{
this.name = name;
InitType(type);
this.length = length;
}
#endregion // Constructors
#region Private Methods
private void InitType(string type)
{
if (type == "C")
{
this.type = DBaseFieldType.Char;
}
else if (type == "D")
{
this.type = DBaseFieldType.Date;
}
else if (type == "N")
{
this.type = DBaseFieldType.Numeric;
}
else if (type == "L")
{
this.type = DBaseFieldType.Logical;
}
else if (type == "M")
{
this.type = DBaseFieldType.Memo;
}
else
{
this.type = DBaseFieldType.Char;
}
}
#endregion // Private Methods
}
///
/// The type of dBase field.
///
public enum DBaseFieldType
{
///
/// Character field.
///
Char,
///
/// Date field.
///
Date,
///
/// Numeric field.
///
Numeric,
///
/// Logical field.
///
Logical,
///
/// Memo field.
///
Memo
}
}