/// <summary> /// /// </summary> /// <param name="values"></param> public ADIFDataSet(List <Dictionary <string, string> > values) { if (values != null) { Header = new ADIFHeader(); QSOs = new ADIFQSOCollection(); foreach (var value in values) { var qso = new ADIFQSO(); foreach (var key in value.Keys) { var tag = TagFactory.TagFromName(key); if (tag != null) { if (value[key] != null) { tag.SetValue(value[key]); } if (tag.Header) { Header.Add(tag); } else { qso.Add(tag); } } } if (qso.Count > 0) { QSOs.Add(qso); } } } }
/// <summary> /// /// </summary> void Initialize() { // find the position of <EOH> var headerEndingPos = this.data.IndexOf($"{Values.TAG_OPENING}{TagNames.EndHeader}{Values.TAG_CLOSING}", StringComparison.OrdinalIgnoreCase); if (headerEndingPos < 0) { throw new InvalidOperationException("No header ending tag was found."); } this.i = 0; var tag = string.Empty; var valueLength = string.Empty; var value = string.Empty; var isUserFieldDef = false; var fieldId = -1; var userDefDataType = string.Empty; while (this.i < headerEndingPos) { // skip comments if (this.data[this.i] == Values.COMMENT_INDICATOR) { while (this.i < headerEndingPos) { if (this.data[this.i] == Values.LINE_ENDING) { break; } this.i++; } } else { // find the beginning of a tag if (this.data[this.i] == Values.TAG_OPENING) { this.i++; // record the key while (this.i < headerEndingPos && this.data[this.i] != Values.VALUE_LENGTH_CHAR) { tag = $"{tag}{this.data[this.i]}"; //tag + this.data[this.i]; this.i++; // handle user-defined field definitions if (tag.Equals(TagNames.UserDef, StringComparison.OrdinalIgnoreCase)) { isUserFieldDef = true; var fieldNumber = string.Empty; // read the field ID while (this.i < headerEndingPos && this.data[this.i] != Values.VALUE_LENGTH_CHAR) { fieldNumber = fieldNumber + this.data[this.i]; this.i++; } // iterate past the : this.i++; fieldId = fieldNumber.ToInt32(); // read the value length while (this.i < headerEndingPos && this.data[this.i] != Values.VALUE_LENGTH_CHAR) { valueLength = valueLength + this.data[this.i]; this.i++; } // iterate past the : this.i++; // read the data type while (this.i < headerEndingPos && this.data[this.i] != Values.TAG_CLOSING) { userDefDataType = userDefDataType + this.data[this.i]; this.i++; } // iterate past the tag closing this.i++; break; } // end if we found a user-defined field definition } if (!isUserFieldDef) { // iterate past the : this.i++; // find out how long the value is while (this.i < headerEndingPos && this.data[this.i] != Values.TAG_CLOSING) { valueLength = valueLength + this.data[this.i]; this.i++; } // iterate past the tag closing > this.i++; } var len = valueLength.ToInt32(); // copy the value into the buffer while (len > 0 && this.i < headerEndingPos) { value = value + this.data[this.i]; len--; this.i++; } ; if (!isUserFieldDef) { this.headers[tag.Trim().ToUpper()] = value; } else { var userDefLen = value.Length; var x = 0; var fieldName = string.Empty; var curlyBraceVal = string.Empty; string[] enumVals = null; var min = 0d; var max = 0d; // read the field name while (userDefLen > 0 && value[x] != Values.COMMA) { fieldName = fieldName + value[x]; userDefLen--; x++; } ; while (userDefLen > 0 && value[x] != Values.CURLY_BRACE_OPEN) { x++; userDefLen--; } if (userDefLen > 0 && value[x] == Values.CURLY_BRACE_OPEN) { x++; // iterate past the curly braces // read the value between the curly braces while (userDefLen > 0 && value[x] != Values.CURLY_BRACE_CLOSE) { curlyBraceVal = curlyBraceVal + value[x]; userDefLen--; x++; } ; } if (!string.IsNullOrWhiteSpace(curlyBraceVal)) { // determine how to parse the optional curly brace string (e.g. as enum or range) if (DataTypes.Enumeration.Equals(userDefDataType, StringComparison.OrdinalIgnoreCase)) { // split by comma enumVals = curlyBraceVal.Split(new[] { Values.COMMA }, StringSplitOptions.RemoveEmptyEntries); } else { // parse as range if (curlyBraceVal.Contains(Values.COLON.ToString())) { var minMaxArray = curlyBraceVal.Split(new[] { Values.COLON }, StringSplitOptions.RemoveEmptyEntries); if (minMaxArray.Length == 2) { min = minMaxArray[0].ToDouble(); max = minMaxArray[1].ToDouble(); } } } } userDefinedFields.Add(new UserDefTag() { FieldId = fieldId, FieldName = fieldName, UpperBound = max, LowerBound = min, CustomOptions = enumVals, DataType = userDefDataType?.ToUpper() }); } // end if we are processing a user-defined field definition // clear our variables tag = string.Empty; valueLength = string.Empty; value = string.Empty; isUserFieldDef = false; userDefDataType = string.Empty; fieldId = -1; } } this.i++; } // iterate past the <EOH> header ending tag this.i = headerEndingPos + 5; // parse the header tags into ITag objects foreach (var header in headers) { // get the tag name and build it var headerTag = TagFactory.TagFromName(header.Key); if (headerTag != null && headerTag.Header) { headerTag.SetValue(header.Value); headerInternal.Add(headerTag); } } // add the user-defined fields to the headers foreach (var userDefined in userDefinedFields) { headerInternal.Add(userDefined); } if (this.i >= this.data.Length) { throw new InvalidOperationException("ADIF data contains no QSO records."); } } // end method
/// <summary> /// /// </summary> public ADIFDataSet Parse() { this.headers = new Dictionary <string, string>(); this.body = new Dictionary <int, Dictionary <string, string> >(); this.userDefinedFields = new List <UserDefTag>(); this.appDefinedFields = new List <AppDefTag>(); headerInternal = new ADIFHeader(); if (string.IsNullOrWhiteSpace(this.data)) { throw new InvalidOperationException("No ADIF data found."); } Initialize(); var qsoCount = -1; while (this.i < this.data.Length) { var qso = GetQSO(); if (qso != null && qso.Count > 0) { body.Add(++qsoCount, qso); } } var result = new ADIFDataSet { Header = headerInternal, QSOs = new ADIFQSOCollection() }; foreach (var key in body.Keys) { var currentQso = body[key]; var qso = new ADIFQSO(); foreach (var entry in currentQso) { // get the tag name and build it var tag = TagFactory.TagFromName(entry.Key); if (tag == null) { if (IsUserDefinedField(entry.Key, out UserDefTag userTag)) { tag = new UserDefValueTag(userTag); } else if (IsAppDefinedField(entry.Key, out AppDefTag appTag)) { tag = appTag; } } if (tag != null) { tag.SetValue(entry.Value); qso.Add(tag); } } result.QSOs.Add(qso); } return(result); }
/// <summary> /// /// </summary> public string ToADIF(EmitFlags flags = EmitFlags.None) { var formatString = (flags & EmitFlags.LowercaseTagNames) == EmitFlags.LowercaseTagNames ? "a" : "A"; if ((flags & EmitFlags.MirrorOperatorAndStationCallSign) == EmitFlags.MirrorOperatorAndStationCallSign) { if (QSOs != null) { for (var q = 0; q < QSOs.Count; q++) { if (QSOs[q] != null) { var qso = QSOs[q]; if (qso.Contains(TagNames.Operator) && !qso.Contains(TagNames.StationCallSign)) { var stationCallSignTag = TagFactory.TagFromName(TagNames.StationCallSign); var operatorTag = qso[qso.IndexOf(TagNames.Operator)]; stationCallSignTag.SetValue(operatorTag.Value); QSOs[q].Insert(QSOs[q].IndexOf(TagNames.Operator), stationCallSignTag); } else if (!qso.Contains(TagNames.Operator) && qso.Contains(TagNames.StationCallSign)) { var operatorTag = TagFactory.TagFromName(TagNames.Operator); var stationCallSignTag = qso[qso.IndexOf(TagNames.StationCallSign)]; operatorTag.SetValue(stationCallSignTag.Value); QSOs[q].Insert(QSOs[q].IndexOf(TagNames.StationCallSign), operatorTag); } } } } if ((flags & EmitFlags.AddCreatedTimestampIfNotPresent) == EmitFlags.AddCreatedTimestampIfNotPresent) { if (Header == null) { Header = new ADIFHeader(); } if (!Header.Contains(TagNames.CreatedTimestamp)) { Header.Add(new CreatedTimestampTag(DateTime.UtcNow)); } } if ((flags & EmitFlags.AddProgramIdIfNotPresent) == EmitFlags.AddProgramIdIfNotPresent) { if (Header == null) { Header = new ADIFHeader(); } if (!Header.Contains(TagNames.ProgramId)) { Header.Add(new ProgramIdTag(Values.DEFAULT_PROGRAM_ID)); } } } return(ToString(formatString, CultureInfo.CurrentCulture)); }