readHeaderWithCharset method

Future<void> readHeaderWithCharset(
  1. AFileReader channel,
  2. Charset charset
)

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;
}