Skip to content

Commit

Permalink
feat: add acf file parser
Browse files Browse the repository at this point in the history
  • Loading branch information
MuZhou233 committed Jan 15, 2024
1 parent 8881334 commit 92efd1a
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
73 changes: 73 additions & 0 deletions lib/common/acf_parser.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:petitparser/definition.dart';
import 'package:petitparser/parser.dart';

/// Based on official JSON implementation: https://github.com/petitparser/dart-petitparser-examples
/// Internal ACF parser.
final _acfParser = AcfDefinition().build();

/// Converts the given ACF-string [input] to its corresponding object.
ACF parseAcf(String input) => _acfParser.parse(input).value;

/// Type definition for ACF data.
typedef ACF = Object? /* Map<String, ACF>|String */;

/// ACF grammar definition.
class AcfDefinition extends GrammarDefinition<ACF> {
@override
Parser<ACF> start() => ref0(entry).map((entry) => {entry.key: entry.value});
Parser<ACF> value() => [
ref0(object),
ref0(stringToken),
failure('value expected'),
].toChoiceParser();

Parser<MapEntry<String, ACF>> entry() => seq3(
ref0(stringToken).trim(),
whitespace().optional(),
ref0(value),
).map3((key, _, value) => MapEntry(key, value));

Parser<Map<String, ACF>> object() => seq5(
char('{'),
whitespace().plus(),
ref0(objectElements),
whitespace().plus(),
char('}'),
).map5((_, __, elements, ___, ____) => elements);
Parser<Map<String, ACF>> objectElements() => ref0(entry)
.starSeparated(whitespace())
.map((list) => Map.fromEntries(list.elements));

Parser<String> stringToken() => seq3(
char('"'),
ref0(characterPrimitive).star(),
char('"'),
).map3((_, chars, __) => chars.join());
Parser<String> characterPrimitive() => [
ref0(characterNormal),
ref0(characterEscape),
ref0(characterUnicode),
].toChoiceParser();
Parser<String> characterNormal() => pattern(r'^"\');
Parser<String> characterEscape() => seq2(
char(r'\'),
anyOf(jsonEscapeChars.keys.join()),
).map2((_, char) => jsonEscapeChars[char]!);
Parser<String> characterUnicode() => seq2(
string(r'\u'),
pattern('0-9A-Fa-f').timesString(4, '4-digit hex number expected'),
).map2((_, value) => String.fromCharCode(int.parse(value, radix: 16)));
}

/// Escape characters of JSON strings.
const Map<String, String> jsonEscapeChars = {
r'\': r'\',
'/': '/',
'"': '"',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
};
73 changes: 73 additions & 0 deletions lib/common/acf_parser_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:petitparser/debug.dart';

import 'acf_parser.dart';

const input = r'''
"AppState"
{
"appid" "250900"
"universe" "1"
"LauncherPath" "C:\\Program Files (x86)\\Steam\\steam.exe"
"name" "The Binding of Isaac: Rebirth"
"StateFlags" "4"
"installdir" "The Binding of Isaac Rebirth"
"lastupdated" "1702484397"
"SizeOnDisk" "1163117782"
"StagingSize" "0"
"buildid" "10102354"
"LastOwner" "76561198424783854"
"UpdateResult" "0"
"BytesToDownload" "0"
"BytesDownloaded" "0"
"BytesToStage" "0"
"BytesStaged" "0"
"TargetBuildID" "0"
"AutoUpdateBehavior" "0"
"AllowOtherDownloadsWhileRunning" "0"
"ScheduledAutoUpdate" "0"
"InstalledDepots"
{
"250902"
{
"manifest" "4994611894646808503"
"size" "326498528"
}
"250905"
{
"manifest" "1709017229885880564"
"size" "165283102"
"dlcappid" "401920"
}
"250908"
{
"manifest" "7333987924869605149"
"size" "147989670"
"dlcappid" "570660"
}
"250911"
{
"manifest" "7652847940910762229"
"size" "655313480"
"dlcappid" "1426300"
}
}
"SharedDepots"
{
"228986" "228980"
}
"UserConfig"
{
"language" "english"
}
"MountedConfig"
{
"language" "english"
}
}
''';

void main() {
final parser = AcfDefinition().build();
trace(parser).parse(input);
print(parser.parse(input).value);
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ dependencies:
package_info_plus: ^5.0.1
device_info_plus: ^9.1.1
path: ^1.8.3
petitparser: ^6.0.2

# others
json_annotation: ^4.8.1
Expand Down

0 comments on commit 92efd1a

Please sign in to comment.