readHeaderWithCharset method
Read the header data from the DBF file.
@param channel A readable byte channel. If you have an InputStream you need to use, you can call java.nio.Channels.getChannel(InputStream in). @ If errors occur while reading.
Implementation
Future<void> readHeaderWithCharset(
AFileReader channel, Charset charset) async {
Endian endian = Endian.little;
// type of file.
int magic = await channel.getByte();
if (magic != MAGIC) {
throw ArgumentError('Unsupported DBF file Type $magic');
}
// parse the update date information.
int tempUpdateYear = await channel.getByte();
int tempUpdateMonth = await channel.getByte();
int tempUpdateDay = await channel.getByte();
// ouch Y2K uncompliant
if (tempUpdateYear > 90) {
tempUpdateYear = tempUpdateYear + 1900;
} else {
tempUpdateYear = tempUpdateYear + 2000;
}
date = DateTime.utc(tempUpdateYear, tempUpdateMonth - 1, tempUpdateDay);
// read the number of records.
recordCnt = await channel.getInt32(endian);
// read the length of the header structure.
// ahhh.. unsigned little-endian shorts
// mask out the byte and or it with shifted 2nd byte
var list = await channel.get(2);
headerLength = (list[0] & 0xff) | ((list[1] & 0xff) << 8);
// read the length of a record
// ahhh.. unsigned little-endian shorts
list = await channel.get(2);
recordLength = (list[0] & 0xff) | ((list[1] & 0xff) << 8);
// skip the reserved bytes in the header.
await channel.skip(20);
// calculate the number of Fields in the header
fieldCnt =
(headerLength - FILE_DESCRIPTOR_SIZE - 1) ~/ FILE_DESCRIPTOR_SIZE;
// read all of the header records
List<DbaseField> lfields = [];
for (var i = 0; i < fieldCnt; i++) {
DbaseField field = DbaseField();
List<int> buffer = (await channel.get(11));
String name = await charset.decode(buffer);
int nullPoint = name.indexOf(String.fromCharCode(0));
if (nullPoint != -1) {
name = name.substring(0, nullPoint);
}
field.fieldName = name.trim();
// read the field type
field.fieldType = await channel.getByte();
// read the field data address, offset from the start of the record.
field.fieldDataAddress = await channel.getInt32(endian);
// read the field length in bytes
int length = await channel.getByte();
if (length < 0) {
length = length + 256;
}
field.fieldLength = length;
if (length > largestFieldSize) {
largestFieldSize = length;
}
// read the field decimal count in bytes
field.decimalCount = await channel.getByte();
// reserved bytes.
await channel.skip(14);
// some broken shapefiles have 0-length attributes. The reference
// implementation
// (ArcExplorer 2.0, built with MapObjects) just ignores them.
if (field.fieldLength > 0) {
lfields.add(field);
}
}
// Last byte is a marker for the end of the field definitions.
await channel.skip(1);
fields = lfields;
}