Example #1
0
        public RawWhoisSection Parse(IEnumerable <string> lines, string keyValueDelimitator = ":")
        {
            if (lines == null)
            {
                throw new ArgumentException("lines should not be null");
            }

            var records = new Dictionary <string, StringBuilder>(StringComparer.OrdinalIgnoreCase);
            HashSet <string> localFieldNamesSet  = new HashSet <string>();
            List <string>    localFieldNamesList = new List <string>();

            string currentFieldName = null;

            string skipPartsOverrideType = null;

            // Will store the first key found in the record
            string firstKey = null;

            // Will store the first value of the first key found in the record
            // If the value of the first key actually spans multiple lines,
            // this variable will only contain the first line of the value
            string firstKeyValue = null;

            foreach (var line in lines)
            {
                // Afrinic contains an invalid line like: DUMMY for 5490
                // TODO: Remove this if
                if (!string.IsNullOrWhiteSpace(line) && !line.StartsWith("dummy for ", StringComparison.OrdinalIgnoreCase) && !line.StartsWith("#") && !line.StartsWith("%"))
                {
                    // StringSplitOptions.None means leep empty records
                    var parts = line.Split(new string[] { keyValueDelimitator }, StringSplitOptions.None);

                    /*
                     * If skipParts > 0 we need to remove one or more fields before we continue.
                     * We do this for RWhois records. For these types of records we set skipParts to 1
                     * to ignore the first field (network field below). Example:
                     *
                     * network:Class-Name:network
                     * network:ID:NET-207-115-64-0-19
                     * network:Auth-Area:207.115.64.0/19
                     */
                    if (this.skipParts > 0 && parts.Length >= this.skipParts)
                    {
                        if (skipPartsOverrideType == null)
                        {
                            skipPartsOverrideType = parts[0];
                        }
                        else if (skipPartsOverrideType != parts[0])
                        {
                            // TODO: Log when the record type suddenly changes
                        }

                        var newParts = new string[parts.Length - this.skipParts];
                        Array.Copy(parts, this.skipParts, newParts, 0, newParts.Length);
                        parts = newParts;
                    }

                    if (parts.Length >= 2)
                    {
                        // If there are at least two parts it means we can parse both a key and a value
                        var key   = parts[0].Trim();
                        var value = string.Join(keyValueDelimitator, parts, 1, parts.Length - 1).Trim();

                        if (key.Length > 0)
                        {
                            currentFieldName = key;
                            this.AddToRecord(records: records, fieldName: currentFieldName, newValueLine: value);

                            if (firstKey == null)
                            {
                                firstKey      = key;
                                firstKeyValue = value;
                            }

                            if (!localFieldNamesSet.Contains(key))
                            {
                                localFieldNamesSet.Add(key);
                                localFieldNamesList.Add(key);
                            }
                        }
                        //// TODO: else log
                    }
                    else if (parts.Length == 1)
                    {
                        if (currentFieldName != null)
                        {
                            // If there is at least one part
                            var value = parts[0];
                            this.AddToRecord(records: records, fieldName: currentFieldName, newValueLine: value);
                        }
                        //// TODO: else log
                    }
                    //// TODO: else log
                }
                //// TODO: else log
            }

            string sectionType = null;
            string sectionId   = null;

            if (skipPartsOverrideType != null)
            {
                sectionType = skipPartsOverrideType;

                // If the records do not contain a Class-Name but this is a RWhois record
                // where the type is the first column, then create a Class-Name record
                if (!records.ContainsKey("Class-Name"))
                {
                    // TODO: Log
                    records["Class-Name"] = new StringBuilder(skipPartsOverrideType);
                }
            }

            // Try to locate the Class-Name and ID, wherever they are in the records
            var extractedClassName = RecordUtils.FindValueForKey(records, "Class-Name");
            var extractedId        = RecordUtils.FindFirstValueForKeys(records, new List <string>()
            {
                "ID"
            });

            if (sectionType == null && extractedClassName != null)
            {
                sectionType = extractedClassName;
            }

            if (sectionId == null && extractedId != null)
            {
                sectionId = extractedId;
            }

            // We could not extract the type yet, so we will go looking for the value in the first
            // record of the section
            if (sectionType == null && firstKey != null)
            {
                sectionType = firstKey;
            }
            //// TODO: else log

            // We could not extract the ID yet, so we will go looking for the key in the first
            // record of the section
            if (sectionId == null && firstKeyValue != null)
            {
                sectionId = firstKeyValue;
            }
            //// TODO: else log

            if (!string.IsNullOrWhiteSpace(sectionType) && !string.IsNullOrWhiteSpace(sectionId) && records.Count > 0)
            {
                HashSet <string> globalFieldNamesSet;
                List <string>    globalFieldNamesList;

                if (!this.TypeToFieldNamesSet.TryGetValue(sectionType, out globalFieldNamesSet))
                {
                    globalFieldNamesSet = new HashSet <string>();
                    this.TypeToFieldNamesSet.Add(sectionType, globalFieldNamesSet);
                }

                if (!this.TypeToFieldNamesList.TryGetValue(sectionType, out globalFieldNamesList))
                {
                    globalFieldNamesList = new List <string>();
                    this.TypeToFieldNamesList.Add(sectionType, globalFieldNamesList);
                }

                foreach (var fieldName in localFieldNamesSet)
                {
                    if (!globalFieldNamesSet.Contains(fieldName))
                    {
                        globalFieldNamesSet.Add(fieldName);
                        globalFieldNamesList.Add(fieldName);
                    }
                }

                return(new RawWhoisSection(sectionType, sectionId, records));
            }
            //// TODO: else log

            return(null);
        }