/// <summary>Parses a single row of data from the specified string.</summary> /// <param name="properties">The csv properties.</param> /// <param name="layout">The row layout.</param> /// <param name="data">The buffer to parse.</param> /// <returns>Returns a new <see cref="Row" /> instance.</returns> public static Row ParseRow(CsvProperties properties, RowLayout layout, string data) { try { var fieldCount = layout.FieldCount; var fieldNumber = 0; var ident = new Queue <char>(); var identInARowCount = 0; var currentValue = new List <char>(); var i = -1; var values = new object[fieldCount]; while (fieldNumber < fieldCount) { ++i; if ((i == data.Length) && (fieldNumber == (fieldCount - 1))) { break; } if (i >= data.Length) { throw new InvalidDataException("Unexpected end of input!"); } if (properties.Separator == data[i]) { if (ident.Count == 0) { identInARowCount = 0; if (properties.StringMarker.HasValue) { values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(), properties.StringMarker.Value.ToString(), properties.Format); } else { values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(), string.Empty, properties.Format); } fieldNumber++; currentValue.Clear(); continue; } } if (properties.StringMarker == data[i]) { identInARowCount++; if ((ident.Count > 0) && (ident.Peek() == data[i])) { ident.Dequeue(); if (identInARowCount > 1) { // escaped char currentValue.Add(data[i]); } } else { ident.Enqueue(data[i]); } } else { identInARowCount = 0; currentValue.Add(data[i]); } } if (ident.Count > 0) { throw new InvalidDataException("Invalid ident/escaping!"); } if (properties.StringMarker.HasValue) { values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(), properties.StringMarker.Value.ToString(), properties.Format); } else { values[fieldNumber] = layout.ParseValue(fieldNumber, new string(currentValue.ToArray()).Unescape(), string.Empty, properties.Format); } fieldNumber++; if (i < data.Length) { if (properties.Separator == data[i]) { i++; } if (i < data.Length) { throw new InvalidDataException("Additional data at end of line!"); } } return(new Row(layout, values, false)); } catch (EndOfStreamException) { if (data.Length > 0) { throw; } return(null); } catch (Exception ex) { throw new InvalidDataException("Error while reading row data!", ex); } }
internal static Row ReadCurrentRow(DataReader reader, int version, RowLayout layout) { if (version < 1) { throw new ArgumentOutOfRangeException(nameof(version)); } if (version > 4) { throw new NotSupportedException("Version not supported!"); } var dataStart = reader.BaseStream.Position; var dataSize = reader.Read7BitEncodedInt32(); if (dataSize == 0) { return(null); } var values = new object[layout.FieldCount]; for (var i = 0; i < layout.FieldCount; i++) { var field = layout[i]; var dataType = field.DataType; switch (dataType) { case DataType.Binary: if (version >= 3) { values[i] = reader.ReadBytes(); } else { var size = reader.ReadInt32(); values[i] = reader.ReadBytes(size); } break; case DataType.Bool: values[i] = reader.ReadBool(); break; case DataType.DateTime: values[i] = new DateTime(reader.ReadInt64(), field.DateTimeKind); break; case DataType.TimeSpan: values[i] = new TimeSpan(reader.ReadInt64()); break; case DataType.Int8: values[i] = reader.ReadInt8(); break; case DataType.Int16: values[i] = reader.ReadInt16(); break; case DataType.Int32: if (version == 1) { values[i] = reader.ReadInt32(); break; } values[i] = reader.Read7BitEncodedInt32(); break; case DataType.Int64: if (version == 1) { values[i] = reader.ReadInt64(); break; } values[i] = reader.Read7BitEncodedInt64(); break; case DataType.UInt32: if (version == 1) { values[i] = reader.ReadUInt32(); break; } values[i] = reader.Read7BitEncodedUInt32(); break; case DataType.UInt64: if (version == 1) { values[i] = reader.ReadUInt64(); break; } values[i] = reader.Read7BitEncodedUInt64(); break; case DataType.UInt8: values[i] = reader.ReadUInt8(); break; case DataType.UInt16: values[i] = reader.ReadUInt16(); break; case DataType.Char: values[i] = reader.ReadChar(); break; case DataType.Single: values[i] = reader.ReadSingle(); break; case DataType.Double: values[i] = reader.ReadDouble(); break; case DataType.Decimal: values[i] = reader.ReadDecimal(); break; case DataType.String: values[i] = reader.ReadString(); break; case DataType.Enum: values[i] = layout.EnumValue(i, reader.Read7BitEncodedInt64()); break; case DataType.User: values[i] = layout.ParseValue(i, reader.ReadString(), null); break; default: throw new NotImplementedException($"Datatype {dataType} not implemented!"); } } var skip = (dataStart + dataSize) - reader.BaseStream.Position; if (skip < 0) { throw new FormatException(); } if (skip > 0) { reader.BaseStream.Seek(skip, SeekOrigin.Current); } return(new Row(layout, values, false)); }