Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,104 changes: 14,100 additions & 4 deletions lib/data/latest.dart

Large diffs are not rendered by default.

3,689 changes: 3,685 additions & 4 deletions lib/data/latest_10y.dart

Large diffs are not rendered by default.

24,765 changes: 24,761 additions & 4 deletions lib/data/latest_all.dart

Large diffs are not rendered by default.

48 changes: 21 additions & 27 deletions lib/src/tzdata/zicfile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
// ignore_for_file: non_constant_identifier_names

import 'dart:collection';
import 'dart:convert' show ascii;
import 'dart:typed_data';

/// Time Zone information file magic header "TZif"
Expand Down Expand Up @@ -60,11 +59,7 @@ class _Header {

factory _Header.fromBytes(List<int> rawData) {
final data = rawData is Uint8List ? rawData : Uint8List.fromList(rawData);

final bdata = data.buffer.asByteData(
data.offsetInBytes,
data.lengthInBytes,
);
final bdata = ByteData.sublistView(data);

final tzh_ttisgmtcnt = bdata.getInt32(0);
final tzh_ttisstdcnt = bdata.getInt32(4);
Expand All @@ -84,16 +79,16 @@ class _Header {
}
}

/// Read NULL-terminated string
/// Read NUL-terminated string
String _readByteString(Uint8List data, int offset) {
for (var i = offset; i < data.length; i++) {
if (data[i] == 0) {
return ascii.decode(
data.buffer.asUint8List(data.offsetInBytes + offset, i - offset),
);
}
var i = offset;
for (; i < data.length; i++) {
final byte = data[i];
if (byte >= 1 && byte < 0x80) continue;
if (byte == 0) break;
throw FormatException('Not ASCII', data, i);
}
return ascii.decode(data.buffer.asUint8List(data.offsetInBytes + offset));
return String.fromCharCodes(data, offset, i);
}

/// This exception is thrown when Zone Info data is invalid.
Expand Down Expand Up @@ -171,10 +166,7 @@ class Location {
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 bdata = ByteData.sublistView(data);

final magic1 = bdata.getUint32(0);
if (magic1 != _ziMagic) {
Expand All @@ -187,7 +179,7 @@ class Location {
switch (version1) {
case 0:
final header = _Header.fromBytes(
Uint8List.view(bdata.buffer, offset, _Header.size),
Uint8List.sublistView(bdata, offset, _Header.size),
);

// calculating data offsets
Expand Down Expand Up @@ -218,9 +210,10 @@ class Location {
}

// function to read from abbreviation buffer
final abbreviationsData = data.buffer.asUint8List(
data.offsetInBytes + abbreviationsOffset,
header.tzh_charcnt,
final abbreviationsData = Uint8List.sublistView(
data,
abbreviationsOffset,
abbreviationsOffset + header.tzh_charcnt,
);
final abbreviations = <String>[];
final abbreviationsCache = HashMap<int, int>();
Expand Down Expand Up @@ -298,7 +291,7 @@ class Location {
case 51:
// skip old version header/data
final header1 = _Header.fromBytes(
Uint8List.view(bdata.buffer, offset, _Header.size),
Uint8List.sublistView(bdata, offset, offset + _Header.size),
);
offset += _Header.size + header1.dataLength(4);

Expand All @@ -320,7 +313,7 @@ class Location {
offset += 20;

final header2 = _Header.fromBytes(
Uint8List.view(bdata.buffer, offset, _Header.size),
Uint8List.sublistView(bdata, offset, offset + _Header.size),
);

// calculating data offsets
Expand Down Expand Up @@ -351,9 +344,10 @@ class Location {
}

// function to read from abbreviation buffer
final abbreviationsData = data.buffer.asUint8List(
data.offsetInBytes + abbreviationsOffset,
header2.tzh_charcnt,
final abbreviationsData = Uint8List.sublistView(
data,
abbreviationsOffset,
abbreviationsOffset + header2.tzh_charcnt,
);
final abbreviations = <String>[];
final abbreviationsCache = HashMap<int, int>();
Expand Down
50 changes: 31 additions & 19 deletions lib/src/tzdb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
library;

import 'dart:collection';
import 'dart:convert' show ascii;
import 'dart:typed_data';
import 'location.dart';
import 'location_database.dart';
Expand All @@ -26,7 +25,7 @@ List<int> tzdbSerialize(LocationDatabase db) {
}

final r = Uint8List(bufferLength);
final rb = r.buffer.asByteData();
final rb = ByteData.sublistView(r);

var offset = 0;
for (final b in locationsInBytes) {
Expand All @@ -42,7 +41,7 @@ List<int> tzdbSerialize(LocationDatabase db) {
/// Deserialize TimeZone Database
Iterable<Location> tzdbDeserialize(List<int> rawData) sync* {
final data = rawData is Uint8List ? rawData : Uint8List.fromList(rawData);
final bdata = data.buffer.asByteData(data.offsetInBytes, data.lengthInBytes);
final bdata = ByteData.sublistView(data);

var offset = 0;
while (offset < data.length) {
Expand All @@ -52,7 +51,7 @@ Iterable<Location> tzdbDeserialize(List<int> rawData) sync* {
offset += 8;

yield _deserializeLocation(
data.buffer.asUint8List(data.offsetInBytes + offset, length),
Uint8List.sublistView(data, offset, offset + length),
);
offset += length;
}
Expand All @@ -78,10 +77,10 @@ Uint8List _serializeLocation(Location location) {
zoneAbbreviationOffsets.add(ai);
}

final List<int> encName = ascii.encode(location.name);
final name = location.name;

final nameOffset = 32;
final nameLength = encName.length;
final nameLength = name.length;
final abbreviationsOffset = nameOffset + nameLength;
final zonesOffset = _align(abbreviationsOffset + abbreviationsLength, 4);
final zonesLength = location.zones.length;
Expand All @@ -91,7 +90,7 @@ Uint8List _serializeLocation(Location location) {
final bufferLength = _align(transitionsOffset + transitionsLength * 9, 8);

final result = Uint8List(bufferLength);
final buffer = ByteData.view(result.buffer);
final buffer = ByteData.sublistView(result);

// write header
buffer.setUint32(0, nameOffset);
Expand All @@ -104,9 +103,13 @@ Uint8List _serializeLocation(Location location) {
buffer.setUint32(28, transitionsLength);

// write name
offset = nameOffset;
for (final c in encName) {
buffer.setUint8(offset++, c);
for (var i = 0; i < name.length; i++) {
final char = name.codeUnitAt(i);
if (char <= 0x7f) {
buffer.setUint8(nameOffset + i, char);
} else {
throw FormatException('Not ASCII', name, i);
}
}

// Write abbreviations.
Expand Down Expand Up @@ -145,7 +148,7 @@ Uint8List _serializeLocation(Location location) {
}

Location _deserializeLocation(Uint8List data) {
final bdata = data.buffer.asByteData(data.offsetInBytes, data.lengthInBytes);
final bdata = ByteData.sublistView(data);
var offset = 0;

// Header
Expand All @@ -169,9 +172,8 @@ Location _deserializeLocation(Uint8List data) {
final transitionsOffset = bdata.getUint32(24);
final transitionsLength = bdata.getUint32(28);

final name = ascii.decode(
data.buffer.asUint8List(data.offsetInBytes + nameOffset, nameLength),
);
assert(_allAscii(data, nameOffset, nameOffset + nameLength));
final name = String.fromCharCodes(data, nameOffset, nameOffset + nameLength);
final abbreviations = <String>[];
final zones = <TimeZone>[];
final transitionAt = <int>[];
Expand All @@ -184,9 +186,8 @@ Location _deserializeLocation(Uint8List data) {
final abbreviationsEnd = abbreviationsOffset + abbreviationsLength;
for (var i = abbreviationsOffset; i < abbreviationsEnd; i++) {
if (data[i] == 0) {
final abbreviation = ascii.decode(
data.buffer.asUint8List(data.offsetInBytes + offset, i - offset),
);
assert(_allAscii(data, offset, i));
final abbreviation = String.fromCharCodes(data, offset, i);
abbreviations.add(abbreviation);
offset = i + 1;
}
Expand Down Expand Up @@ -236,6 +237,17 @@ Location _deserializeLocation(Uint8List data) {
}

int _align(int offset, int boundary) {
final i = offset % boundary;
return i == 0 ? offset : offset + (boundary - i);
assert(boundary > 1 && _isPowerOf2(boundary));
final mask = boundary - 1;
return (offset + mask) & ~mask;
}

bool _isPowerOf2(int value) => value > 0 && (value & (value - 1)) == 0;

bool _allAscii(Uint8List bytes, int start, int end) {
var bits = 0;
for (var i = start; i < end; i++) {
bits |= bytes[i];
}
return bits <= 0x7f;
}
43 changes: 31 additions & 12 deletions tool/encode_dart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,41 @@ Future<void> main(List<String> args) async {
final bytes = File(tzDataPath).readAsBytesSync();
final generatedDartFile = generateDartFile(
name: p.basenameWithoutExtension(tzDataPath),
data: bytesAsString(bytes),
data: bytes,
);
File(dartLibraryPath).writeAsStringSync(generatedDartFile);
}

String bytesAsString(Uint8List bytes) {
assert(bytes.length.isEven);
return bytes.buffer
.asUint16List()
.map((u) => '\\u${u.toRadixString(16).padLeft(4, '0')}')
.join();
String bytesAsString(
Uint8List bytes, {
String prefix = '',
String indent = '',
}) {
final buffer = StringBuffer();
buffer.write('\'');
var column = prefix.length + 1;
for (var index = 0; index < bytes.length; index++) {
final byte = bytes[index];
if (column > 74) {
// Not space for one encoding + "';".
buffer
..write('\'\n')
..write(indent)
..write('\'');
column = indent.length + 1;
}
buffer
..write(byte < 16 ? r'\x0' : r'\x')
..write(byte.toRadixString(16));
column += 4;
}
buffer.write('\'');
return buffer.toString();
}

String generateDartFile({required String name, required String data}) =>
'''// This is a generated file. Do not edit.
String generateDartFile({required String name, required Uint8List data}) =>
'''
// This is a generated file. Do not edit.
import 'dart:typed_data';

import '../src/env.dart';
Expand All @@ -35,14 +55,13 @@ import '../src/exceptions.dart';
void initializeTimeZones() {
try {
initializeDatabase(
Uint16List.fromList(_embeddedData.codeUnits).buffer.asUint8List());
Uint8List.fromList(_embeddedData.codeUnits));
}
// ignore: avoid_catches_without_on_clauses
catch (e) {
throw TimeZoneInitException(e.toString());
}
}

const _embeddedData =
'$data';
const _embeddedData = ${bytesAsString(data, prefix: 'const _embeddedData = ', indent: ' ')};
''';