Skip to content

Commit 5512621

Browse files
committed
updated to null-safety
1 parent 7593094 commit 5512621

File tree

12 files changed

+120
-77
lines changed

12 files changed

+120
-77
lines changed

.github/workflows/testing.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
steps:
3636
- uses: actions/checkout@v2
3737

38-
- uses: axel-op/dart-package-analyzer/with-full-sdk@stable
38+
- uses: axel-op/dart-package-analyzer@v3
3939
id: analysis # set an id for the current step
4040
with:
4141
githubToken: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.0
2+
3+
- package is now null-safety
4+
15
## 0.1.2+2
26

37
- remove dart:io - more web compatibility

analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ include: package:effective_dart/analysis_options.yaml
33
linter:
44
rules:
55
lines_longer_than_80_chars: false
6+
avoid_equals_and_hash_code_on_mutable_classes: false
67

78
analyzer:
89
exclude:

example/main.dart

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import 'dart:io';
33

44
import 'package:freewig/freewig.dart';
55

6-
Future<Cartridge> parseFile(File file) async {
6+
Future<Cartridge?> parseFile(File file) async {
77
final bytes = await file.readAsBytes();
88
final completer = Completer<Cartridge>();
9-
await Future<Cartridge>(() => parseData(bytes))
9+
await Future<Cartridge?>(() => parseData(bytes))
1010
.then(completer.complete)
1111
.catchError(completer.completeError);
1212
return completer.future;
@@ -16,34 +16,42 @@ void main(List<String> arguments) async {
1616
var file = File(arguments[0]); // path/incl/cartridge.gwc
1717
var cartridge = await parseFile(file);
1818

19-
var export = Directory('export');
20-
var exists = await export.exists();
21-
if (exists) {
22-
await export.delete(recursive: true);
23-
}
24-
await export.create(recursive: true);
19+
if (cartridge != null) {
20+
var export = Directory('export');
21+
var exists = await export.exists();
22+
if (exists) {
23+
await export.delete(recursive: true);
24+
}
25+
await export.create(recursive: true);
2526

26-
var contents = '';
27-
contents += 'Cartridge-Id: ${cartridge.cartridgeGuid}\n';
28-
contents += 'Name: ${cartridge.cartridgeName}\n';
29-
contents += 'Description: ${cartridge.cartridgeDesc}\n';
30-
contents += 'StartLocation: ${cartridge.startLocationDesc}\n';
31-
contents += 'Latitude: ${cartridge.latLng.latitude}\n';
32-
contents += 'Longitude: ${cartridge.latLng.longitude}\n';
33-
contents += 'Player: ${cartridge.playerName}\n';
34-
contents += 'Author: ${cartridge.author}\n';
35-
contents += 'Type: ${cartridge.typeOfCartridge}\n';
36-
contents += 'Device: ${cartridge.recommendDevice}\n';
37-
contents += 'Version: ${cartridge.version}\n';
38-
contents += '\n';
39-
contents += 'Completion-Code: ${cartridge.completionCode}\n';
40-
contents += '\n';
41-
contents += 'ItemCount: ${cartridge.mediaObjects.length}\n';
42-
var infoFile = File('${export.path}/cartridge_info.txt');
43-
await infoFile.writeAsString(contents);
27+
var contents = '';
28+
contents += 'Cartridge-Id: ${cartridge.cartridgeGuid}\n';
29+
contents += 'Name: ${cartridge.cartridgeName}\n';
30+
contents += 'Description: ${cartridge.cartridgeDesc}\n';
31+
contents += 'StartLocation: ${cartridge.startLocationDesc}\n';
32+
contents += 'Latitude: ${cartridge.latLng.latitude}\n';
33+
contents += 'Longitude: ${cartridge.latLng.longitude}\n';
34+
contents += 'Player: ${cartridge.playerName}\n';
35+
contents += 'Author: ${cartridge.author}\n';
36+
contents += 'Type: ${cartridge.typeOfCartridge}\n';
37+
contents += 'Device: ${cartridge.recommendDevice}\n';
38+
contents += 'Version: ${cartridge.version}\n';
39+
contents += '\n';
40+
contents += 'Completion-Code: ${cartridge.completionCode}\n';
41+
contents += '\n';
42+
contents += 'ItemCount: ${cartridge.mediaCount}\n';
43+
var infoFile = File('${export.path}/cartridge_info.txt');
44+
await infoFile.writeAsString(contents);
4445

45-
cartridge.mediaObjects.forEach((index, data) async {
46-
var objectFile = File('${export.path}/object_$index.${data.objectType}');
47-
await objectFile.writeAsBytes(data.data);
48-
});
46+
for (var index = 0; index < cartridge.mediaCount; index++) {
47+
final data = cartridge.getMedia(index);
48+
if (data != null) {
49+
var objectFile =
50+
File('${export.path}/object_$index.${data.objectType}');
51+
await objectFile.writeAsBytes(data.data);
52+
}
53+
}
54+
} else {
55+
print("The cartridge is invalid");
56+
}
4957
}

lib/src/binary_reader.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class BinaryReader {
2323

2424
/// Initialise the [BinaryReader] with data and endian, so the reader knows how to
2525
/// interpret the bytes.
26-
BinaryReader({ByteData byteData, Endian endian})
26+
BinaryReader({required ByteData byteData, Endian endian = Endian.little})
2727
: _byteData = byteData,
2828
_endian = endian,
2929
_index = 0;

lib/src/latlng.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,20 @@ class LatLng {
3232
return _format(_longitude, 'EW');
3333
}
3434

35+
@override
36+
String toString() {
37+
return "$latitude $longitude".trim();
38+
}
39+
3540
String _format(double value, String suffix) {
3641
final isNegative = value < 0;
3742
value = value.abs();
3843

3944
final degrees = value.floor();
45+
if (degrees == 360) {
46+
return "";
47+
}
48+
4049
final minutes = (value - degrees) * 60.0;
4150

4251
var result = '';

lib/src/models/cartridge.dart

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@
1212
* all copies or substantial portions of the Software.
1313
*/
1414

15-
import 'package:meta/meta.dart';
16-
1715
import '../../freewig.dart';
1816
import '../binary_reader.dart';
1917
import 'media.dart';
2018

2119
/// A [Cartridge] represents the GWC file
22-
@immutable
2320
class Cartridge {
2421
/// The altitude of the start coordinate
2522
final double altitude;
@@ -60,16 +57,20 @@ class Cartridge {
6057
/// Completion code (can be encrypted with lua)
6158
final String completionCode;
6259

63-
/// Map of all [Media] objects
64-
final Map<int, Media> mediaObjects;
65-
6660
final int _splashScreenId;
6761

6862
final int _smallIconId;
6963

64+
final BinaryReader _source;
65+
66+
final Map<int, int> _references;
67+
68+
var _lastObject = -1;
69+
70+
Media? _lastMedia;
71+
7072
Cartridge._(
7173
this.cartridgeGuid,
72-
this.mediaObjects,
7374
this.altitude,
7475
this.author,
7576
this.cartridgeDesc,
@@ -84,11 +85,13 @@ class Cartridge {
8485
this.startLocationDesc,
8586
this.typeOfCartridge,
8687
this.version,
88+
this._references,
89+
this._source,
8790
);
8891

8992
/// Reading the GWC file and create a [Cartridge] or null in case of any
9093
/// parsing error.
91-
factory Cartridge(BinaryReader reader) {
94+
static Cartridge? create(BinaryReader reader) {
9295
try {
9396
final count = reader.getUShort();
9497
final references = <int, int>{};
@@ -129,14 +132,8 @@ class Cartridge {
129132

130133
final completionCode = reader.getASCIIZ();
131134

132-
// initialise objects after cartridge data is loaded
133-
final objects = <int, Media>{};
134-
references.forEach((index, address) =>
135-
{objects.putIfAbsent(index, () => Media(reader, index, address))});
136-
137135
return Cartridge._(
138136
cartridgeGuid,
139-
objects,
140137
altitude,
141138
author,
142139
cartridgeDesc,
@@ -154,6 +151,8 @@ class Cartridge {
154151
startLocationDesc,
155152
typeOfCartridge,
156153
version,
154+
references,
155+
reader,
157156
);
158157
} on Exception catch (ex) {
159158
print('Exception: $ex');
@@ -166,22 +165,42 @@ class Cartridge {
166165
identical(this, other) ||
167166
other is Cartridge &&
168167
runtimeType == other.runtimeType &&
169-
cartridgeGuid == other.cartridgeGuid &&
170-
mediaObjects == other.mediaObjects;
168+
cartridgeGuid == other.cartridgeGuid;
171169

172170
@override
173-
int get hashCode => cartridgeGuid.hashCode ^ mediaObjects.hashCode;
171+
int get hashCode => cartridgeGuid.hashCode;
172+
173+
/// get Media with objectId or null, if not available
174+
Media? getMedia(int objectId) {
175+
if (_lastObject == objectId && _lastMedia != null) {
176+
return _lastMedia!;
177+
}
178+
179+
if (_references.containsKey(objectId)) {
180+
final address = _references[objectId];
181+
final media = Media.create(_source, objectId, address!);
182+
183+
if (media != null) {
184+
if (media.data.length < 128000) {
185+
_lastObject = objectId;
186+
_lastMedia = media;
187+
}
188+
189+
return media;
190+
}
191+
}
192+
return null;
193+
}
194+
195+
/// get the count of attached media
196+
int get mediaCount => _references.length;
174197

175198
/// get splash screen media or null if not available
176-
Media get splashScreen => mediaObjects.containsKey(_splashScreenId)
177-
? mediaObjects[_splashScreenId]
178-
: null;
199+
Media? get splashScreen => getMedia(_splashScreenId);
179200

180201
/// get small icon media or null if not available
181-
Media get smallIcon => mediaObjects.containsKey(_smallIconId)
182-
? mediaObjects[_smallIconId]
183-
: null;
202+
Media? get smallIcon => getMedia(_smallIconId);
184203

185204
/// get luac media or null if not available
186-
Media get luac => mediaObjects.containsKey(0) ? mediaObjects[0] : null;
205+
Media? get luac => getMedia(0);
187206
}

lib/src/models/media.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ class Media {
3434
///
3535
/// It starts at address (from [SeekOrigin.begin]) and uses the data for
3636
/// interpret the data as media. If it can be read, the return will be a
37-
/// [Media] object. In case of an exception the result will be null.
38-
factory Media(BinaryReader reader, int objectId, int address) {
37+
/// [Media] object. In case of an exception or empty data the result will be null.
38+
static Media? create(BinaryReader reader, int objectId, int address) {
3939
try {
40-
Uint8List data;
40+
Uint8List? data;
4141
var objectType = 0;
4242
reader.seek(address, SeekOrigin.begin);
4343
if (objectId == 0) {
@@ -48,8 +48,11 @@ class Media {
4848
data = _readMediaData(reader);
4949
}
5050
}
51-
final object = Media._(_getObjectType(objectType), data);
52-
return object;
51+
if (data != null) {
52+
final object = Media._(_getObjectType(objectType), data);
53+
return object;
54+
}
55+
return null;
5356
} on Exception catch (ex) {
5457
print('Exception: $ex');
5558
return null;

lib/src/parser.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import 'models/cartridge.dart';
2020
/// Parses a byte list and create a [Cartridge]
2121
///
2222
/// If the byte list is a valid GWC file, the result will be [Cartridge] or null, if the parser failed.
23-
Cartridge parseData(Uint8List bytes) {
23+
Cartridge? parseData(Uint8List bytes) {
2424
try {
2525
const header = {0x02, 0x0a, 0x43, 0x41, 0x52, 0x54, 0x00}; // magic header
2626
final reader = BinaryReader(
@@ -34,7 +34,7 @@ Cartridge parseData(Uint8List bytes) {
3434
}
3535
}
3636

37-
return Cartridge(reader);
37+
return Cartridge.create(reader);
3838
} on Exception catch (_) {
3939
return null;
4040
}

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
name: freewig
2-
version: 0.1.2+2
2+
version: 0.2.0
33
description: >
44
Freewig can be used to extract the meta data and media files from Wherigo Cartridges
55
homepage: https://github.com/mars3142/freewig
66

77
environment:
8-
sdk: '>=2.7.0 <3.0.0'
8+
sdk: '>=2.12.0 <3.0.0'
99

1010
dependencies:
1111
meta: ^1.1.8

0 commit comments

Comments
 (0)