dart_pkpass/lib/src/pass_file.dart
The one with the braid e345763813 feat: add String localization support
Signed-off-by: The one with the braid <the-one@with-the-braid.cf>
2023-08-27 19:50:37 +02:00

135 lines
3.8 KiB
Dart

import 'dart:convert';
import 'dart:typed_data';
import 'package:archive/archive.dart';
import 'package:crypto/crypto.dart';
import 'package:intl/locale.dart';
import 'package:pkpass/pkpass.dart';
import 'package:pkpass/src/utils/file_matcher.dart';
import 'package:pkpass/src/utils/lproj_parser.dart';
final _utf8codec = Utf8Codec();
final _jsonCodec = JsonCodec();
class PassFile {
const PassFile(this.metadata, this._folder);
static Future<PassFile> parse(Uint8List pass) async {
final codec = ZipDecoder();
Archive archive;
try {
archive = codec.decodeBytes(pass);
} catch (e) {
throw InvalidEncodingError();
}
Map<String, String> manifest;
try {
final file = archive.files
.singleWhere((element) => element.name == 'manifest.json');
manifest = (_jsonCodec.decode(
_utf8codec.decode(
file.rawContent?.toUint8List() ?? (file.content as Uint8List),
),
) as Map)
.cast<String, String>();
} catch (e) {
throw ManifestNotFoundError();
}
final folder = <ArchiveFile>[];
await Future.wait(
manifest.entries.map(
(manifestEntry) async {
final file = archive.files
.singleWhere((element) => element.name == manifestEntry.key);
final content =
file.rawContent?.toUint8List() ?? file.content as Uint8List;
String hash = sha1.convert(content).toString();
final checksum = manifestEntry.value;
if (hash != checksum) {
throw ManifestChecksumError(expected: checksum, actual: hash);
}
folder.add(file);
},
),
);
final passFile =
archive.singleWhere((element) => element.name == 'pass.json');
final PassMetadata metadata = PassMetadata.fromJson(
_jsonCodec.decode(passFile.stringContent) as Map<String, Object?>,
);
return PassFile(metadata, folder);
}
final PassMetadata metadata;
final List<ArchiveFile> _folder;
Uint8List? _matchUtf8List({
required String name,
required Locale? locale,
required int scale,
}) {
final files = _folder.map((e) => e.name).toList();
final path = FileMatcher.matchFile(
files: files,
name: name,
scale: scale,
locale: locale,
extension: 'png',
);
if (path == null) return null;
final file = _folder.singleWhere((element) => element.name == path);
final content = file.rawContent?.toUint8List() ?? file.content as Uint8List;
return content;
}
Uint8List? getBackground({Locale? locale, int scale = 1}) =>
_matchUtf8List(name: 'background', locale: locale, scale: scale);
Uint8List? getFooter({Locale? locale, int scale = 1}) =>
_matchUtf8List(name: 'footer', locale: locale, scale: scale);
Uint8List? getIcon({Locale? locale, int scale = 1}) =>
_matchUtf8List(name: 'icon', locale: locale, scale: scale);
Uint8List? getLogo({Locale? locale, int scale = 1}) =>
_matchUtf8List(name: 'logo', locale: locale, scale: scale);
Uint8List? getStrip({Locale? locale, int scale = 1}) =>
_matchUtf8List(name: 'strip', locale: locale, scale: scale);
Uint8List? getThumbnail({Locale? locale, int scale = 1}) =>
_matchUtf8List(name: 'thumbnail', locale: locale, scale: scale);
Map<String, String>? getLocalizations(Locale? locale) {
final files = _folder.map((e) => e.name).toList();
final paths = FileMatcher.matchLocale(
files: files,
name: 'pass',
extension: 'strings',
locale: locale,
);
print(paths);
if (paths.isEmpty) return null;
final file = _folder.singleWhere((element) => element.name == paths.first);
return LProjParser.parse(file.stringContent);
}
}
extension on ArchiveFile {
String get stringContent =>
_utf8codec.decode(rawContent?.toUint8List() ?? (content as Uint8List));
}