Location.fromBytes constructor
Deserialize Location from bytes
Implementation
factory Location.fromBytes(String name, List<int> rawData) {
  final data = rawData is Uint8List ? rawData : Uint8List.fromList(rawData);
  final bdata =
      data.buffer.asByteData(data.offsetInBytes, data.lengthInBytes);
  final magic1 = bdata.getUint32(0);
  if (magic1 != _ziMagic) {
    throw InvalidZoneInfoDataException('Invalid magic header "$magic1"');
  }
  final version1 = bdata.getUint8(4);
  var offset = 20;
  switch (version1) {
    case 0:
      final header = _Header.fromBytes(
          Uint8List.view(bdata.buffer, offset, _Header.size));
      // calculating data offsets
      final dataOffset = offset + _Header.size;
      final transitionAtOffset = dataOffset;
      final transitionZoneOffset =
          transitionAtOffset + header.tzh_timecnt * 5;
      final abbreviationsOffset =
          transitionZoneOffset + header.tzh_typecnt * 6;
      final leapOffset = abbreviationsOffset + header.tzh_charcnt;
      final stdOrWctOffset = leapOffset + header.tzh_leapcnt * 8;
      final utcOrGmtOffset = stdOrWctOffset + header.tzh_ttisstdcnt;
      // read transitions
      final transitionAt = <int>[];
      final transitionZone = <int>[];
      offset = transitionAtOffset;
      for (var i = 0; i < header.tzh_timecnt; i++) {
        transitionAt.add(bdata.getInt32(offset));
        offset += 4;
      }
      for (var i = 0; i < header.tzh_timecnt; i++) {
        transitionZone.add(bdata.getUint8(offset));
        offset += 1;
      }
      // function to read from abbreviation buffer
      final abbreviationsData = data.buffer.asUint8List(
          data.offsetInBytes + abbreviationsOffset, header.tzh_charcnt);
      final abbreviations = <String>[];
      final abbreviationsCache = HashMap<int, int>();
      int readAbbreviation(int offset) {
        var result = abbreviationsCache[offset];
        if (result == null) {
          result = abbreviations.length;
          abbreviationsCache[offset] = result;
          abbreviations.add(_readByteString(abbreviationsData, offset));
        }
        return result;
      }
      // read zones
      final zones = <TimeZone>[];
      offset = transitionZoneOffset;
      for (var i = 0; i < header.tzh_typecnt; i++) {
        final tt_gmtoff = bdata.getInt32(offset);
        final tt_isdst = bdata.getInt8(offset + 4);
        final tt_abbrind = bdata.getUint8(offset + 5);
        offset += 6;
        zones.add(TimeZone(tt_gmtoff,
            isDst: tt_isdst == 1,
            abbreviationIndex: readAbbreviation(tt_abbrind)));
      }
      // read leap seconds
      final leapAt = <int>[];
      final leapDiff = <int>[];
      offset = leapOffset;
      for (var i = 0; i < header.tzh_leapcnt; i++) {
        leapAt.add(bdata.getInt32(offset));
        leapDiff.add(bdata.getInt32(offset + 4));
        offset += 5;
      }
      // read std flags
      final isStd = <int>[];
      offset = stdOrWctOffset;
      for (var i = 0; i < header.tzh_ttisstdcnt; i++) {
        isStd.add(bdata.getUint8(offset));
        offset += 1;
      }
      // read utc flags
      final isUtc = <int>[];
      offset = utcOrGmtOffset;
      for (var i = 0; i < header.tzh_ttisgmtcnt; i++) {
        isUtc.add(bdata.getUint8(offset));
        offset += 1;
      }
      return Location(name, transitionAt, transitionZone, abbreviations,
          zones, leapAt, leapDiff, isStd, isUtc);
    case 50:
    case 51:
      // skip old version header/data
      final header1 = _Header.fromBytes(
          Uint8List.view(bdata.buffer, offset, _Header.size));
      offset += _Header.size + header1.dataLength(4);
      final magic2 = bdata.getUint32(offset);
      if (magic2 != _ziMagic) {
        throw InvalidZoneInfoDataException(
            'Invalid second magic header "$magic2"');
      }
      final version2 = bdata.getUint8(offset + 4);
      if (version2 != version1) {
        throw InvalidZoneInfoDataException(
            'Second version "$version2" doesn\'t match first version '
            '"$version1"');
      }
      offset += 20;
      final header2 = _Header.fromBytes(
          Uint8List.view(bdata.buffer, offset, _Header.size));
      // calculating data offsets
      final dataOffset = offset + _Header.size;
      final transitionAtOffset = dataOffset;
      final transitionZoneOffset =
          transitionAtOffset + header2.tzh_timecnt * 9;
      final abbreviationsOffset =
          transitionZoneOffset + header2.tzh_typecnt * 6;
      final leapOffset = abbreviationsOffset + header2.tzh_charcnt;
      final stdOrWctOffset = leapOffset + header2.tzh_leapcnt * 12;
      final utcOrGmtOffset = stdOrWctOffset + header2.tzh_ttisstdcnt;
      // read transitions
      final transitionAt = <int>[];
      final transitionZone = <int>[];
      offset = transitionAtOffset;
      for (var i = 0; i < header2.tzh_timecnt; i++) {
        transitionAt.add(bdata.getInt64(offset));
        offset += 8;
      }
      for (var i = 0; i < header2.tzh_timecnt; i++) {
        transitionZone.add(bdata.getUint8(offset));
        offset += 1;
      }
      // function to read from abbreviation buffer
      final abbreviationsData = data.buffer.asUint8List(
          data.offsetInBytes + abbreviationsOffset, header2.tzh_charcnt);
      final abbreviations = <String>[];
      final abbreviationsCache = HashMap<int, int>();
      int readAbbreviation(int offset) {
        var result = abbreviationsCache[offset];
        if (result == null) {
          result = abbreviations.length;
          abbreviationsCache[offset] = result;
          abbreviations.add(_readByteString(abbreviationsData, offset));
        }
        return result;
      }
      // read transition info
      final zones = <TimeZone>[];
      offset = transitionZoneOffset;
      for (var i = 0; i < header2.tzh_typecnt; i++) {
        final tt_gmtoff = bdata.getInt32(offset);
        final tt_isdst = bdata.getInt8(offset + 4);
        final tt_abbrind = bdata.getUint8(offset + 5);
        offset += 6;
        zones.add(TimeZone(tt_gmtoff,
            isDst: tt_isdst == 1,
            abbreviationIndex: readAbbreviation(tt_abbrind)));
      }
      // read leap seconds
      final leapAt = <int>[];
      final leapDiff = <int>[];
      offset = leapOffset;
      for (var i = 0; i < header2.tzh_leapcnt; i++) {
        leapAt.add(bdata.getInt64(offset));
        leapDiff.add(bdata.getInt32(offset + 8));
        offset += 9;
      }
      // read std flags
      final isStd = <int>[];
      offset = stdOrWctOffset;
      for (var i = 0; i < header2.tzh_ttisstdcnt; i++) {
        isStd.add(bdata.getUint8(offset));
        offset += 1;
      }
      // read utc flags
      final isUtc = <int>[];
      offset = utcOrGmtOffset;
      for (var i = 0; i < header2.tzh_ttisgmtcnt; i++) {
        isUtc.add(bdata.getUint8(offset));
        offset += 1;
      }
      return Location(name, transitionAt, transitionZone, abbreviations,
          zones, leapAt, leapDiff, isStd, isUtc);
    default:
      throw InvalidZoneInfoDataException('Unknown version: $version1');
  }
}