parseAdiString static method
- String str, {
- bool ignoreIllegals = true,
- NonAsciiParseOption nonAsciiParse = NonAsciiParseOption.parseByCharacter,
Parse from ADI strings.
- @param str The ADI string to be parsed
- @param ignoreIllegals Whether to ignore illegal data. When this argument is set to true, the method skips malformed fields, unexpected control markers, and unsupported values whenever it can continue scanning. Otherwise it throws an exception immediately.
- @param nonAsciiParse How to interpret ADI field lengths when non-ASCII characters are present in texts generated by non-standard programs.
Set ignoreIllegals to true does not mean it never throws an exception.
When the ADI string is broken severely (eg. an unterminated token or a
byte-length that cuts through a UTF-8 rune), exceptions may still occur.
Implementation
static Adif parseAdiString(
String str, {
bool ignoreIllegals = true,
NonAsciiParseOption nonAsciiParse = NonAsciiParseOption.parseByCharacter,
}) {
final userdefMetas = <UserdefMeta>[];
String adifVer = adifVersion;
String? programId;
String? programVersion;
DateTime? createdTimestamp;
var cursor = 0;
var foundHeaderEnd = false;
while (true) {
final field = _readNextAdiField(
str,
cursor,
ignoreIllegals: ignoreIllegals,
nonAsciiParse: nonAsciiParse,
);
if (field == null) {
break;
}
cursor = field.nextIndex;
if (field.isControl) {
if (field.fieldName == 'EOH') {
foundHeaderEnd = true;
break;
}
if (!ignoreIllegals) {
throw FormatException('Unexpected ${field.fieldName} before <EOH>');
}
continue;
}
final normalizedFieldName = field.fieldName.toUpperCase();
final value = field.value!;
try {
switch (normalizedFieldName) {
case 'ADIF_VER':
adifVer = value;
case 'CREATED_TIMESTAMP':
createdTimestamp = _parseAdiTimestamp(value);
case 'PROGRAMID':
programId = value;
case 'PROGRAMVERSION':
programVersion = value;
default:
final match = _adiUserdefPattern.firstMatch(normalizedFieldName);
if (match == null) {
continue;
}
final (:name, :enums, :range) = _parseUserdefPayload(value);
userdefMetas.add(
UserdefMeta(name, field.type ?? 'S', enums: enums, range: range),
);
}
} catch (_) {
if (!ignoreIllegals) {
rethrow;
}
}
}
if (!foundHeaderEnd && !ignoreIllegals) {
throw FormatException('ADI header is missing <EOH>');
}
final qsos = <Qso>[];
final adifFields = <AdifField>[];
final appFields = <Appdef>[];
final userFields = <Userdef>[];
while (true) {
final field = _readNextAdiField(
str,
cursor,
ignoreIllegals: ignoreIllegals,
nonAsciiParse: nonAsciiParse,
);
if (field == null) {
if (!ignoreIllegals &&
(adifFields.isNotEmpty ||
appFields.isNotEmpty ||
userFields.isNotEmpty)) {
throw FormatException('ADI record is missing <EOR>');
}
break;
}
cursor = field.nextIndex;
if (field.isControl) {
if (field.fieldName == 'EOR') {
qsos.add(
Qso(
List<AdifField>.from(adifFields),
List<Appdef>.from(appFields),
List<Userdef>.from(userFields),
),
);
adifFields.clear();
appFields.clear();
userFields.clear();
} else if (!ignoreIllegals) {
throw FormatException(
'Unexpected ${field.fieldName} inside a record',
);
}
continue;
}
final rawFieldName = field.fieldName;
final normalizedFieldName = rawFieldName.toUpperCase();
final value = field.value!;
try {
if (normalizedFieldName.startsWith(_adiAppPrefix)) {
final (embeddedProgramId, appFieldName) = _parseAppWireFieldName(
rawFieldName,
);
final type =
field.type ??
(throw FormatException(
'APP field $rawFieldName is missing explicit type information',
));
final appValue = _createCustomValueForAdiParse(
value,
type,
nonAsciiParse: nonAsciiParse,
);
appFields.add(Appdef(embeddedProgramId, appFieldName, appValue));
continue;
}
final userdefMatch = _adiUserdefPattern.firstMatch(normalizedFieldName);
if (userdefMatch != null) {
final fieldId = int.parse(userdefMatch.group(1)!);
final metadata =
userdefMetas.getByIndex(fieldId) ??
(throw FormatException('USERDEF$fieldId is undefined in header'));
final userValue = _createCustomValueForAdiParse(
value,
metadata.type,
enums: metadata.enums,
range: metadata.range,
nonAsciiParse: nonAsciiParse,
);
userFields.add(Userdef(metadata.name, userValue));
continue;
}
adifFields.add(
_createAdifFieldForAdiParse(
normalizedFieldName,
value,
nonAsciiParse,
),
);
} catch (_) {
if (!ignoreIllegals) {
rethrow;
}
}
}
final adif = Adif(
programId ?? 'unknown',
programVersion ?? '',
qsos,
adifVer: adifVer,
);
adif.createdTimestamp = createdTimestamp;
return adif;
}